Add support for 'yank-media' on MS-Windows
Adds the capacity to handle types different from strings to the clipboard management functions on MS-Windows, and some logic required to convert media types names and content to be what yank-media and the modes that use it expect (bug#71909). * lisp/term/w32-win.el (w32--selection-target-translations): New variable that holds the name translations for media types. (w32--translate-selection-target): New function, translate the name of a media type. (w32--translate-reverse-selection-target): New function, reverse translation. (w32--get-selection): Modified to translate target names when asked for targets, and retrieve media types when asked for them. (w32--mime-type-textual-p): New function, checks if a MIME type is textual. * lisp/textmodes/sgml-mode.el (html-mode--image-yank-handler): Fixed the image save mechanism, that added line feed characters on MS-Windows, breaking binary formats. * src/w32image.c (gdiplus_init): Modified to fetch more functions fromm gdiplus. (get_encoder_clsid): Renamed to 'w32_gdip_get_encoder_clsid' and made nonstatic. (gdiplus_startup): Renamed to 'w32_gdiplus_startup' and made nonstatic. * src/w32select.c (stdfmt_name): Made global, was static function. (convert_dibv5_to_png): New function to convert DIBV5 clipboard format to PNG. (get_clipboard_format_name): New function get the name of a format given its index. (Fw32__get_clipboard_data_media): New function, retrieves and converts media content. (syms_of_w32select): Export new lisp functions. * src/w32gdiplus.h: New file, for definitions in w32image.c * doc/lispref/frames.texi: Updated with MS-Windows support. * etc/NEWS: Added entry about new feature.
This commit is contained in:
parent
5ee56b8693
commit
8e7f5f97db
8 changed files with 389 additions and 123 deletions
|
@ -4759,14 +4759,14 @@ to encoding or decoding by any coding system.
|
||||||
@section Yanking Media
|
@section Yanking Media
|
||||||
@cindex yank media from window-system selections
|
@cindex yank media from window-system selections
|
||||||
|
|
||||||
Data saved within window system selections is not restricted to
|
Data saved within window system selections and the MS-Windows
|
||||||
plain text. It is possible for selection data to encompass images or
|
clipboard is not restricted to plain text. It is possible for selection
|
||||||
other binary data of the like, as well as rich text content instanced
|
data to encompass images or other binary data of the like, as well as
|
||||||
by HTML, and also PostScript. Since the selection data types incident
|
rich text content instanced by HTML, and also PostScript. Since the
|
||||||
to this data are at variance with those for plain text, the insertion
|
selection data types incident to this data are at variance with those
|
||||||
of such data is facilitated by a set of functions dubbed
|
for plain text, the insertion of such data is facilitated by a set of
|
||||||
@dfn{yank-media handlers}, which are registered by each major mode
|
functions dubbed @dfn{yank-media handlers}, which are registered by each
|
||||||
undertaking its insertion and called where warranted upon the
|
major mode undertaking its insertion and called where warranted upon the
|
||||||
execution of the @code{yank-media} command.
|
execution of the @code{yank-media} command.
|
||||||
|
|
||||||
@defun yank-media-handler types handler
|
@defun yank-media-handler types handler
|
||||||
|
|
6
etc/NEWS
6
etc/NEWS
|
@ -820,6 +820,12 @@ DirectWrite rendering parameters.
|
||||||
To show color Emoji in Emacs, customize the default fontset to use a
|
To show color Emoji in Emacs, customize the default fontset to use a
|
||||||
color Emoji font installed on your system for the 'emoji' script.
|
color Emoji font installed on your system for the 'emoji' script.
|
||||||
|
|
||||||
|
+++
|
||||||
|
** Emacs on MS-Windows now supports 'yank-media'.
|
||||||
|
This command inserts clipboard data of different formats into the
|
||||||
|
current buffer, if the major mode supports it.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
This file is part of GNU Emacs.
|
This file is part of GNU Emacs.
|
||||||
|
|
|
@ -442,15 +442,82 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.")
|
||||||
(w32-set-clipboard-data (string-replace "\0" "\\0" value))
|
(w32-set-clipboard-data (string-replace "\0" "\\0" value))
|
||||||
(put 'x-selections (or type 'PRIMARY) value)))
|
(put 'x-selections (or type 'PRIMARY) value)))
|
||||||
|
|
||||||
(defun w32--get-selection (&optional type data-type)
|
(defvar w32--selection-target-translations
|
||||||
|
'((PNG . image/png)
|
||||||
|
(DIBV5 . image/png)
|
||||||
|
(HTML\ Format . text/html)))
|
||||||
|
|
||||||
|
(defun w32--translate-selection-target (target)
|
||||||
|
(let ((xlat (assoc target w32--selection-target-translations)))
|
||||||
|
(if xlat
|
||||||
|
(cdr xlat)
|
||||||
|
target)))
|
||||||
|
|
||||||
|
(defun w32--translate-reverse-selection-target (target)
|
||||||
|
(append
|
||||||
|
(mapcar #'car
|
||||||
|
(seq-filter
|
||||||
|
(lambda (x)
|
||||||
|
(eq target
|
||||||
|
(w32--translate-selection-target (car x))))
|
||||||
|
w32--selection-target-translations))
|
||||||
|
(list target)))
|
||||||
|
|
||||||
|
(defvar w32--textual-mime-types
|
||||||
|
'("application/xml"
|
||||||
|
"application/json"
|
||||||
|
"application/yaml"
|
||||||
|
"application/json-seq"
|
||||||
|
"\\`text/"
|
||||||
|
"+xml\\'"
|
||||||
|
"+json\\'"
|
||||||
|
"+yaml\\'"
|
||||||
|
"+json-seq\\'"))
|
||||||
|
|
||||||
|
(defun w32--mime-type-textual-p (mime-type)
|
||||||
|
"Returns t if MIME-TYPE, a symbol, names a textual MIME type.
|
||||||
|
|
||||||
|
This function is intended to classify clipboard data. All MIME subtypes
|
||||||
|
of text/ are considered textual. Also those with suffixes +xml, +json,
|
||||||
|
+yaml, +json-seq. And application/xml, application/json,
|
||||||
|
application/yaml, application/json-seq.
|
||||||
|
|
||||||
|
This classification is not exhaustive. Some MIME types not listed may
|
||||||
|
also be textual."
|
||||||
|
(string-match-p
|
||||||
|
(mapconcat #'identity w32--textual-mime-types "\\|")
|
||||||
|
(symbol-name mime-type)))
|
||||||
|
|
||||||
|
(defun w32--get-selection (&optional type data-type)
|
||||||
(cond ((and (eq type 'CLIPBOARD)
|
(cond ((and (eq type 'CLIPBOARD)
|
||||||
(eq data-type 'STRING))
|
(eq data-type 'STRING))
|
||||||
(with-demoted-errors "w32-get-clipboard-data:%S"
|
(with-demoted-errors "w32-get-clipboard-data:%S"
|
||||||
(w32-get-clipboard-data)))
|
(w32-get-clipboard-data)))
|
||||||
((eq data-type 'TARGETS)
|
((eq data-type 'TARGETS)
|
||||||
(if (eq type 'CLIPBOARD)
|
(if (eq type 'CLIPBOARD)
|
||||||
(w32-selection-targets type)
|
(vconcat
|
||||||
|
(delete-dups
|
||||||
|
(seq-map #'w32--translate-selection-target
|
||||||
|
(w32-selection-targets type))))
|
||||||
(if (get 'x-selections (or type 'PRIMARY)) '[STRING])))
|
(if (get 'x-selections (or type 'PRIMARY)) '[STRING])))
|
||||||
|
((eq type 'CLIPBOARD)
|
||||||
|
(let ((tmp-file (make-temp-file "emacs-clipboard"))
|
||||||
|
(is-textual (w32--mime-type-textual-p data-type)))
|
||||||
|
(unwind-protect
|
||||||
|
(let* ((data-types (w32--translate-reverse-selection-target data-type))
|
||||||
|
(data (w32--get-clipboard-data-media data-types tmp-file is-textual)))
|
||||||
|
(cond
|
||||||
|
;; data is in the file
|
||||||
|
((eq data t)
|
||||||
|
(with-temp-buffer
|
||||||
|
(set-buffer-multibyte nil)
|
||||||
|
(insert-file-contents-literally tmp-file)
|
||||||
|
(buffer-string)))
|
||||||
|
;; data is in data var
|
||||||
|
((stringp data) data)
|
||||||
|
;; No data
|
||||||
|
(t nil)))
|
||||||
|
(delete-file tmp-file))))
|
||||||
(t (get 'x-selections (or type 'PRIMARY)))))
|
(t (get 'x-selections (or type 'PRIMARY)))))
|
||||||
|
|
||||||
(defun w32--selection-owner-p (selection)
|
(defun w32--selection-owner-p (selection)
|
||||||
|
|
|
@ -2476,10 +2476,9 @@ To work around that, do:
|
||||||
(when (and (file-exists-p file)
|
(when (and (file-exists-p file)
|
||||||
(not (yes-or-no-p (format "%s exists; overwrite?" file))))
|
(not (yes-or-no-p (format "%s exists; overwrite?" file))))
|
||||||
(user-error "%s exists" file))
|
(user-error "%s exists" file))
|
||||||
(with-temp-buffer
|
(let ((coding-system-for-write 'emacs-internal))
|
||||||
(set-buffer-multibyte nil)
|
(with-temp-file file
|
||||||
(insert image)
|
(insert image)))
|
||||||
(write-region (point-min) (point-max) file))
|
|
||||||
(insert (format "<img src=%S>\n" (file-relative-name file)))
|
(insert (format "<img src=%S>\n" (file-relative-name file)))
|
||||||
(insert-image
|
(insert-image
|
||||||
(create-image file (mailcap-mime-type-to-extension type) nil
|
(create-image file (mailcap-mime-type-to-extension type) nil
|
||||||
|
|
112
src/w32gdiplus.h
Normal file
112
src/w32gdiplus.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#ifdef WINDOWSNT
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc)
|
||||||
|
(ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *);
|
||||||
|
typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc)
|
||||||
|
(GpImage *, PROPID, UINT *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc)
|
||||||
|
(GpImage *, PROPID, UINT, PropertyItem *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc)
|
||||||
|
(GpImage *, UINT *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc)
|
||||||
|
(GpImage *, GUID *, UINT);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc)
|
||||||
|
(GpImage *, GDIPCONST GUID *, UINT *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc)
|
||||||
|
(GpImage*, GDIPCONST GUID *, UINT);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc)
|
||||||
|
(WCHAR *, GpBitmap **);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
|
||||||
|
(IStream *, GpBitmap **);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc)
|
||||||
|
(INT, INT, INT, PixelFormat, BYTE*, GpBitmap**);
|
||||||
|
typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc)
|
||||||
|
(GpBitmap *, HBITMAP *, ARGB);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc)
|
||||||
|
(UINT, UINT, ImageCodecInfo *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc)
|
||||||
|
(GDIPCONST WCHAR *,GpImage **);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc)
|
||||||
|
(GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc)
|
||||||
|
(GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *,
|
||||||
|
GDIPCONST EncoderParameters *);
|
||||||
|
typedef GpStatus (WINGDIPAPI *GdipImageRotateFlip_Proc)
|
||||||
|
(GpImage *image, RotateFlipType rfType);
|
||||||
|
|
||||||
|
extern GdiplusStartup_Proc fn_GdiplusStartup;
|
||||||
|
extern GdiplusShutdown_Proc fn_GdiplusShutdown;
|
||||||
|
extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
|
||||||
|
extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem;
|
||||||
|
extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount;
|
||||||
|
extern GdipImageGetFrameDimensionsList_Proc fn_GdipImageGetFrameDimensionsList;
|
||||||
|
extern GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
|
||||||
|
extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
|
||||||
|
extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
|
||||||
|
extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
|
||||||
|
extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0;
|
||||||
|
extern SHCreateMemStream_Proc fn_SHCreateMemStream;
|
||||||
|
extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
|
||||||
|
extern GdipDisposeImage_Proc fn_GdipDisposeImage;
|
||||||
|
extern GdipGetImageHeight_Proc fn_GdipGetImageHeight;
|
||||||
|
extern GdipGetImageWidth_Proc fn_GdipGetImageWidth;
|
||||||
|
extern GdipGetImageEncodersSize_Proc fn_GdipGetImageEncodersSize;
|
||||||
|
extern GdipGetImageEncoders_Proc fn_GdipGetImageEncoders;
|
||||||
|
extern GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
|
||||||
|
extern GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
|
||||||
|
extern GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
|
||||||
|
extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
|
||||||
|
|
||||||
|
# undef GdiplusStartup
|
||||||
|
# undef GdiplusShutdown
|
||||||
|
# undef GdipGetPropertyItemSize
|
||||||
|
# undef GdipGetPropertyItem
|
||||||
|
# undef GdipImageGetFrameDimensionsCount
|
||||||
|
# undef GdipImageGetFrameDimensionsList
|
||||||
|
# undef GdipImageGetFrameCount
|
||||||
|
# undef GdipImageSelectActiveFrame
|
||||||
|
# undef GdipCreateBitmapFromFile
|
||||||
|
# undef GdipCreateBitmapFromStream
|
||||||
|
# undef GdipCreateBitmapFromScan0
|
||||||
|
# undef SHCreateMemStream
|
||||||
|
# undef GdipCreateHBITMAPFromBitmap
|
||||||
|
# undef GdipDisposeImage
|
||||||
|
# undef GdipGetImageHeight
|
||||||
|
# undef GdipGetImageWidth
|
||||||
|
# undef GdipGetImageEncodersSize
|
||||||
|
# undef GdipGetImageEncoders
|
||||||
|
# undef GdipLoadImageFromFile
|
||||||
|
# undef GdipGetImageThumbnail
|
||||||
|
# undef GdipSaveImageToFile
|
||||||
|
# undef GdipSaveImageRotateFlip
|
||||||
|
|
||||||
|
# define GdiplusStartup fn_GdiplusStartup
|
||||||
|
# define GdiplusShutdown fn_GdiplusShutdown
|
||||||
|
# define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize
|
||||||
|
# define GdipGetPropertyItem fn_GdipGetPropertyItem
|
||||||
|
# define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount
|
||||||
|
# define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList
|
||||||
|
# define GdipImageGetFrameCount fn_GdipImageGetFrameCount
|
||||||
|
# define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame
|
||||||
|
# define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile
|
||||||
|
# define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream
|
||||||
|
# define GdipCreateBitmapFromScan0 fn_GdipCreateBitmapFromScan0
|
||||||
|
# define SHCreateMemStream fn_SHCreateMemStream
|
||||||
|
# define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap
|
||||||
|
# define GdipDisposeImage fn_GdipDisposeImage
|
||||||
|
# define GdipGetImageHeight fn_GdipGetImageHeight
|
||||||
|
# define GdipGetImageWidth fn_GdipGetImageWidth
|
||||||
|
# define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize
|
||||||
|
# define GdipGetImageEncoders fn_GdipGetImageEncoders
|
||||||
|
# define GdipLoadImageFromFile fn_GdipLoadImageFromFile
|
||||||
|
# define GdipGetImageThumbnail fn_GdipGetImageThumbnail
|
||||||
|
# define GdipSaveImageToFile fn_GdipSaveImageToFile
|
||||||
|
# define GdipImageRotateFlip fn_GdipImageRotateFlip
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid);
|
|
@ -45,7 +45,9 @@ struct image;
|
||||||
extern int w32_load_image (struct frame *f, struct image *img,
|
extern int w32_load_image (struct frame *f, struct image *img,
|
||||||
Lisp_Object spec_file, Lisp_Object spec_data);
|
Lisp_Object spec_file, Lisp_Object spec_data);
|
||||||
extern bool w32_can_use_native_image_api (Lisp_Object);
|
extern bool w32_can_use_native_image_api (Lisp_Object);
|
||||||
|
extern bool w32_gdiplus_startup (void);
|
||||||
extern void w32_gdiplus_shutdown (void);
|
extern void w32_gdiplus_shutdown (void);
|
||||||
|
|
||||||
extern size_t w32_image_size (Emacs_Pixmap);
|
extern size_t w32_image_size (Emacs_Pixmap);
|
||||||
|
|
||||||
#define FACE_DEFAULT (~0)
|
#define FACE_DEFAULT (~0)
|
||||||
|
|
104
src/w32image.c
104
src/w32image.c
|
@ -38,44 +38,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "coding.h"
|
#include "coding.h"
|
||||||
|
|
||||||
|
#include "w32gdiplus.h"
|
||||||
#ifdef WINDOWSNT
|
#ifdef WINDOWSNT
|
||||||
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc)
|
|
||||||
(ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *);
|
|
||||||
typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc)
|
|
||||||
(GpImage *, PROPID, UINT *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc)
|
|
||||||
(GpImage *, PROPID, UINT, PropertyItem *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc)
|
|
||||||
(GpImage *, UINT *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc)
|
|
||||||
(GpImage *, GUID *, UINT);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc)
|
|
||||||
(GpImage *, GDIPCONST GUID *, UINT *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc)
|
|
||||||
(GpImage*, GDIPCONST GUID *, UINT);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc)
|
|
||||||
(WCHAR *, GpBitmap **);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
|
|
||||||
(IStream *, GpBitmap **);
|
|
||||||
typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc)
|
|
||||||
(GpBitmap *, HBITMAP *, ARGB);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc)
|
|
||||||
(UINT, UINT, ImageCodecInfo *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc)
|
|
||||||
(GDIPCONST WCHAR *,GpImage **);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc)
|
|
||||||
(GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *);
|
|
||||||
typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc)
|
|
||||||
(GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *,
|
|
||||||
GDIPCONST EncoderParameters *);
|
|
||||||
|
|
||||||
GdiplusStartup_Proc fn_GdiplusStartup;
|
GdiplusStartup_Proc fn_GdiplusStartup;
|
||||||
GdiplusShutdown_Proc fn_GdiplusShutdown;
|
GdiplusShutdown_Proc fn_GdiplusShutdown;
|
||||||
GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
|
GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
|
||||||
|
@ -86,6 +50,7 @@ GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
|
||||||
GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
|
GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
|
||||||
GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
|
GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
|
||||||
GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
|
GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
|
||||||
|
GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0;
|
||||||
SHCreateMemStream_Proc fn_SHCreateMemStream;
|
SHCreateMemStream_Proc fn_SHCreateMemStream;
|
||||||
GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
|
GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
|
||||||
GdipDisposeImage_Proc fn_GdipDisposeImage;
|
GdipDisposeImage_Proc fn_GdipDisposeImage;
|
||||||
|
@ -96,6 +61,7 @@ GdipGetImageEncoders_Proc fn_GdipGetImageEncoders;
|
||||||
GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
|
GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
|
||||||
GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
|
GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
|
||||||
GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
|
GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
|
||||||
|
GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
gdiplus_init (void)
|
gdiplus_init (void)
|
||||||
|
@ -146,6 +112,10 @@ gdiplus_init (void)
|
||||||
get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream");
|
get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream");
|
||||||
if (!fn_GdipCreateBitmapFromStream)
|
if (!fn_GdipCreateBitmapFromStream)
|
||||||
return false;
|
return false;
|
||||||
|
fn_GdipCreateBitmapFromScan0 = (GdipCreateBitmapFromScan0_Proc)
|
||||||
|
get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromScan0");
|
||||||
|
if (!fn_GdipCreateBitmapFromScan0)
|
||||||
|
return false;
|
||||||
fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc)
|
fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc)
|
||||||
get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap");
|
get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap");
|
||||||
if (!fn_GdipCreateHBITMAPFromBitmap)
|
if (!fn_GdipCreateHBITMAPFromBitmap)
|
||||||
|
@ -196,52 +166,14 @@ gdiplus_init (void)
|
||||||
get_proc_addr (gdiplus_lib, "GdipSaveImageToFile");
|
get_proc_addr (gdiplus_lib, "GdipSaveImageToFile");
|
||||||
if (!fn_GdipSaveImageToFile)
|
if (!fn_GdipSaveImageToFile)
|
||||||
return false;
|
return false;
|
||||||
|
fn_GdipImageRotateFlip = (GdipImageRotateFlip_Proc)
|
||||||
|
get_proc_addr (gdiplus_lib, "GdipImageRotateFlip");
|
||||||
|
if (!fn_GdipImageRotateFlip)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
# undef GdiplusStartup
|
|
||||||
# undef GdiplusShutdown
|
|
||||||
# undef GdipGetPropertyItemSize
|
|
||||||
# undef GdipGetPropertyItem
|
|
||||||
# undef GdipImageGetFrameDimensionsCount
|
|
||||||
# undef GdipImageGetFrameDimensionsList
|
|
||||||
# undef GdipImageGetFrameCount
|
|
||||||
# undef GdipImageSelectActiveFrame
|
|
||||||
# undef GdipCreateBitmapFromFile
|
|
||||||
# undef GdipCreateBitmapFromStream
|
|
||||||
# undef SHCreateMemStream
|
|
||||||
# undef GdipCreateHBITMAPFromBitmap
|
|
||||||
# undef GdipDisposeImage
|
|
||||||
# undef GdipGetImageHeight
|
|
||||||
# undef GdipGetImageWidth
|
|
||||||
# undef GdipGetImageEncodersSize
|
|
||||||
# undef GdipGetImageEncoders
|
|
||||||
# undef GdipLoadImageFromFile
|
|
||||||
# undef GdipGetImageThumbnail
|
|
||||||
# undef GdipSaveImageToFile
|
|
||||||
|
|
||||||
# define GdiplusStartup fn_GdiplusStartup
|
|
||||||
# define GdiplusShutdown fn_GdiplusShutdown
|
|
||||||
# define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize
|
|
||||||
# define GdipGetPropertyItem fn_GdipGetPropertyItem
|
|
||||||
# define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount
|
|
||||||
# define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList
|
|
||||||
# define GdipImageGetFrameCount fn_GdipImageGetFrameCount
|
|
||||||
# define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame
|
|
||||||
# define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile
|
|
||||||
# define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream
|
|
||||||
# define SHCreateMemStream fn_SHCreateMemStream
|
|
||||||
# define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap
|
|
||||||
# define GdipDisposeImage fn_GdipDisposeImage
|
|
||||||
# define GdipGetImageHeight fn_GdipGetImageHeight
|
|
||||||
# define GdipGetImageWidth fn_GdipGetImageWidth
|
|
||||||
# define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize
|
|
||||||
# define GdipGetImageEncoders fn_GdipGetImageEncoders
|
|
||||||
# define GdipLoadImageFromFile fn_GdipLoadImageFromFile
|
|
||||||
# define GdipGetImageThumbnail fn_GdipGetImageThumbnail
|
|
||||||
# define GdipSaveImageToFile fn_GdipSaveImageToFile
|
|
||||||
|
|
||||||
#endif /* WINDOWSNT */
|
#endif /* WINDOWSNT */
|
||||||
|
|
||||||
static int gdip_initialized;
|
static int gdip_initialized;
|
||||||
|
@ -252,8 +184,8 @@ static GdiplusStartupOutput output;
|
||||||
|
|
||||||
|
|
||||||
/* Initialize GDI+, return true if successful. */
|
/* Initialize GDI+, return true if successful. */
|
||||||
static bool
|
bool
|
||||||
gdiplus_startup (void)
|
w32_gdiplus_startup (void)
|
||||||
{
|
{
|
||||||
GpStatus status;
|
GpStatus status;
|
||||||
|
|
||||||
|
@ -305,7 +237,7 @@ w32_can_use_native_image_api (Lisp_Object type)
|
||||||
But we don't yet support these in image.c. */
|
But we don't yet support these in image.c. */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return gdiplus_startup ();
|
return w32_gdiplus_startup ();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PropertyItem_type {
|
enum PropertyItem_type {
|
||||||
|
@ -549,8 +481,8 @@ static struct thumb_type_data thumb_types [] =
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int
|
int
|
||||||
get_encoder_clsid (const char *type, CLSID *clsid)
|
w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid)
|
||||||
{
|
{
|
||||||
/* A simple cache based on the assumptions that many thumbnails will
|
/* A simple cache based on the assumptions that many thumbnails will
|
||||||
be generated using the same TYPE. */
|
be generated using the same TYPE. */
|
||||||
|
@ -625,7 +557,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */)
|
||||||
|
|
||||||
if (!gdiplus_started)
|
if (!gdiplus_started)
|
||||||
{
|
{
|
||||||
if (!gdiplus_startup ())
|
if (!w32_gdiplus_startup ())
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +581,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */)
|
||||||
CLSID thumb_clsid;
|
CLSID thumb_clsid;
|
||||||
if (status == Ok
|
if (status == Ok
|
||||||
/* Get the GUID of the TYPE's encoder. */
|
/* Get the GUID of the TYPE's encoder. */
|
||||||
&& get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0)
|
&& w32_gdip_get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0)
|
||||||
{
|
{
|
||||||
/* Save the thumbnail image to a file of specified TYPE. */
|
/* Save the thumbnail image to a file of specified TYPE. */
|
||||||
wchar_t thumb_file_w[MAX_PATH];
|
wchar_t thumb_file_w[MAX_PATH];
|
||||||
|
|
194
src/w32select.c
194
src/w32select.c
|
@ -73,12 +73,22 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <wingdi.h>
|
||||||
|
#include <wtypes.h>
|
||||||
|
#include <gdiplus.h>
|
||||||
|
#ifndef CF_DIBV5
|
||||||
|
# define CF_DIBV5 17
|
||||||
|
# undef CF_MAX
|
||||||
|
# define CF_MAX 18
|
||||||
|
#endif
|
||||||
#include "lisp.h"
|
#include "lisp.h"
|
||||||
#include "w32common.h" /* os_subtype */
|
#include "w32common.h" /* os_subtype */
|
||||||
#include "w32term.h" /* for all of the w32 includes */
|
#include "w32term.h" /* for all of the w32 includes */
|
||||||
#include "w32select.h"
|
#include "w32select.h"
|
||||||
#include "blockinput.h"
|
#include "blockinput.h"
|
||||||
#include "coding.h"
|
#include "coding.h"
|
||||||
|
#include "w32gdiplus.h"
|
||||||
|
|
||||||
#ifdef CYGWIN
|
#ifdef CYGWIN
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -787,6 +797,166 @@ DEFUN ("w32-set-clipboard-data", Fw32_set_clipboard_data,
|
||||||
return (ok ? string : Qnil);
|
return (ok ? string : Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Xlib-like names for standard Windows clipboard data formats.
|
||||||
|
They are in upper-case to mimic xselect.c. A couple of the names
|
||||||
|
were changed to be more like their X counterparts. */
|
||||||
|
static const char *stdfmt_name[] = {
|
||||||
|
"UNDEFINED",
|
||||||
|
"STRING",
|
||||||
|
"BITMAP",
|
||||||
|
"METAFILE",
|
||||||
|
"SYMLINK",
|
||||||
|
"DIF",
|
||||||
|
"TIFF",
|
||||||
|
"OEM_STRING",
|
||||||
|
"DIB",
|
||||||
|
"PALETTE",
|
||||||
|
"PENDATA",
|
||||||
|
"RIFF",
|
||||||
|
"WAVE",
|
||||||
|
"UTF8_STRING",
|
||||||
|
"ENHMETAFILE",
|
||||||
|
"FILE_NAMES", /* DND */
|
||||||
|
"LOCALE", /* not used */
|
||||||
|
"DIBV5"
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Must be called with block_input() active. */
|
||||||
|
static bool
|
||||||
|
convert_dibv5_to_png (char *data, int size, char *temp_file)
|
||||||
|
{
|
||||||
|
CLSID clsid_png;
|
||||||
|
|
||||||
|
if (!w32_gdiplus_startup ()
|
||||||
|
|| !w32_gdip_get_encoder_clsid ("png", &clsid_png))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BITMAPV5HEADER *bmi = (void *) data;
|
||||||
|
int stride = bmi->bV5SizeImage / bmi->bV5Height;
|
||||||
|
long offset = bmi->bV5Size + bmi->bV5ClrUsed * sizeof (RGBQUAD);
|
||||||
|
if (bmi->bV5Compression == BI_BITFIELDS)
|
||||||
|
offset += 12;
|
||||||
|
BYTE *scan0 = data + offset;
|
||||||
|
|
||||||
|
GpBitmap *bitmap = NULL;
|
||||||
|
|
||||||
|
GpStatus status
|
||||||
|
= GdipCreateBitmapFromScan0 (bmi->bV5Width, bmi->bV5Height, stride,
|
||||||
|
PixelFormat32bppARGB, scan0, &bitmap);
|
||||||
|
|
||||||
|
if (status != Ok)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* The bitmap comes upside down. */
|
||||||
|
GdipImageRotateFlip (bitmap, RotateNoneFlipY);
|
||||||
|
|
||||||
|
WCHAR wide_filename[MAX_PATH];
|
||||||
|
filename_to_utf16 (temp_file, wide_filename);
|
||||||
|
|
||||||
|
status = GdipSaveImageToFile (bitmap, wide_filename, &clsid_png, NULL);
|
||||||
|
GdipDisposeImage (bitmap);
|
||||||
|
if (status != Ok)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_clipboard_format_name (int format_index, char *name)
|
||||||
|
{
|
||||||
|
*name = 0;
|
||||||
|
format_index = EnumClipboardFormats (format_index);
|
||||||
|
if (format_index == 0)
|
||||||
|
return 0;
|
||||||
|
if (format_index < CF_MAX)
|
||||||
|
strcpy (name, stdfmt_name[format_index]);
|
||||||
|
GetClipboardFormatName (format_index, name, 256);
|
||||||
|
return format_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN ("w32--get-clipboard-data-media", Fw32__get_clipboard_data_media,
|
||||||
|
Sw32__get_clipboard_data_media, 3, 3, 0,
|
||||||
|
doc: /* Gets media (not plain text) clipboard data in one of the given formats.
|
||||||
|
|
||||||
|
FORMATS is a list of formats.
|
||||||
|
TEMP-FILE-IN is the name of the file to store the data.
|
||||||
|
|
||||||
|
Elements in FORMATS are symbols naming a format, such a image/png, or
|
||||||
|
image/jpeg. For compatibility with X systems, some conventional
|
||||||
|
format names are translated to equivalent MIME types, as configured with
|
||||||
|
the variable 'w32--selection-target-translations'.
|
||||||
|
|
||||||
|
The file named in TEMP-FILE-IN must be created by the caller, and also
|
||||||
|
deleted if required.
|
||||||
|
|
||||||
|
Returns nil it there is no such format, or something failed.
|
||||||
|
If it returns t, then the caller should read the file to get the data.
|
||||||
|
If it returns a string, then that is the data and the file is not used.
|
||||||
|
|
||||||
|
When returning a string, it will be unibyte if IS-TEXTUAL is nil (the
|
||||||
|
content is binary data). */)
|
||||||
|
(Lisp_Object formats, Lisp_Object temp_file_in, Lisp_Object is_textual)
|
||||||
|
{
|
||||||
|
CHECK_LIST (formats);
|
||||||
|
CHECK_STRING (temp_file_in);
|
||||||
|
|
||||||
|
temp_file_in = Fexpand_file_name (temp_file_in, Qnil);
|
||||||
|
char *temp_file = SSDATA (ENCODE_FILE (temp_file_in));
|
||||||
|
|
||||||
|
Lisp_Object result = Qnil;
|
||||||
|
|
||||||
|
block_input();
|
||||||
|
if (!OpenClipboard (NULL))
|
||||||
|
{
|
||||||
|
unblock_input();
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int format_index = 0;;)
|
||||||
|
{
|
||||||
|
static char name[256];
|
||||||
|
format_index = get_clipboard_format_name (format_index, name);
|
||||||
|
if (format_index == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If name doesn't match any of the formats, try the next format. */
|
||||||
|
bool match = false;
|
||||||
|
for (Lisp_Object tail = formats; CONSP (tail); tail = XCDR (tail))
|
||||||
|
if (strcmp (name, SSDATA (SYMBOL_NAME (XCAR (tail)))) == 0)
|
||||||
|
match = true;
|
||||||
|
if (!match)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Of the standard formats, only DIBV5 is supported. */
|
||||||
|
if (format_index < CF_MAX && format_index != CF_DIBV5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Found the format. */
|
||||||
|
HANDLE d = GetClipboardData (format_index);
|
||||||
|
if (!d)
|
||||||
|
break;
|
||||||
|
int size = GlobalSize (d);
|
||||||
|
char *data = GlobalLock (d);
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
if (strcmp (name, "DIBV5") == 0)
|
||||||
|
{
|
||||||
|
if (convert_dibv5_to_png (data, size, temp_file))
|
||||||
|
result = Qt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (NILP (is_textual))
|
||||||
|
result = make_unibyte_string (data, size);
|
||||||
|
else
|
||||||
|
result = make_string (data, size);
|
||||||
|
}
|
||||||
|
GlobalUnlock (d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CloseClipboard ();
|
||||||
|
unblock_input ();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data,
|
DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data,
|
||||||
Sw32_get_clipboard_data, 0, 1, 0,
|
Sw32_get_clipboard_data, 0, 1, 0,
|
||||||
|
@ -1069,29 +1239,6 @@ for `CLIPBOARD'. The return value is a vector of symbols, each symbol
|
||||||
representing a data format that is currently available in the clipboard. */)
|
representing a data format that is currently available in the clipboard. */)
|
||||||
(Lisp_Object selection, Lisp_Object terminal)
|
(Lisp_Object selection, Lisp_Object terminal)
|
||||||
{
|
{
|
||||||
/* Xlib-like names for standard Windows clipboard data formats.
|
|
||||||
They are in upper-case to mimic xselect.c. A couple of the names
|
|
||||||
were changed to be more like their X counterparts. */
|
|
||||||
static const char *stdfmt_name[] = {
|
|
||||||
"UNDEFINED",
|
|
||||||
"STRING",
|
|
||||||
"BITMAP",
|
|
||||||
"METAFILE",
|
|
||||||
"SYMLINK",
|
|
||||||
"DIF",
|
|
||||||
"TIFF",
|
|
||||||
"OEM_STRING",
|
|
||||||
"DIB",
|
|
||||||
"PALETTE",
|
|
||||||
"PENDATA",
|
|
||||||
"RIFF",
|
|
||||||
"WAVE",
|
|
||||||
"UTF8_STRING",
|
|
||||||
"ENHMETAFILE",
|
|
||||||
"FILE_NAMES", /* DND */
|
|
||||||
"LOCALE", /* not used */
|
|
||||||
"DIBV5"
|
|
||||||
};
|
|
||||||
CHECK_SYMBOL (selection);
|
CHECK_SYMBOL (selection);
|
||||||
|
|
||||||
/* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
|
/* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check
|
||||||
|
@ -1166,6 +1313,7 @@ syms_of_w32select (void)
|
||||||
{
|
{
|
||||||
defsubr (&Sw32_set_clipboard_data);
|
defsubr (&Sw32_set_clipboard_data);
|
||||||
defsubr (&Sw32_get_clipboard_data);
|
defsubr (&Sw32_get_clipboard_data);
|
||||||
|
defsubr (&Sw32__get_clipboard_data_media);
|
||||||
defsubr (&Sw32_selection_exists_p);
|
defsubr (&Sw32_selection_exists_p);
|
||||||
defsubr (&Sw32_selection_targets);
|
defsubr (&Sw32_selection_targets);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue