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
|
||||
@cindex yank media from window-system selections
|
||||
|
||||
Data saved within window system selections is not restricted to
|
||||
plain text. It is possible for selection data to encompass images or
|
||||
other binary data of the like, as well as rich text content instanced
|
||||
by HTML, and also PostScript. Since the selection data types incident
|
||||
to this data are at variance with those for plain text, the insertion
|
||||
of such data is facilitated by a set of functions dubbed
|
||||
@dfn{yank-media handlers}, which are registered by each major mode
|
||||
undertaking its insertion and called where warranted upon the
|
||||
Data saved within window system selections and the MS-Windows
|
||||
clipboard is not restricted to plain text. It is possible for selection
|
||||
data to encompass images or other binary data of the like, as well as
|
||||
rich text content instanced by HTML, and also PostScript. Since the
|
||||
selection data types incident to this data are at variance with those
|
||||
for plain text, the insertion of such data is facilitated by a set of
|
||||
functions dubbed @dfn{yank-media handlers}, which are registered by each
|
||||
major mode undertaking its insertion and called where warranted upon the
|
||||
execution of the @code{yank-media} command.
|
||||
|
||||
@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
|
||||
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.
|
||||
|
|
|
@ -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))
|
||||
(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)
|
||||
(eq data-type 'STRING))
|
||||
(with-demoted-errors "w32-get-clipboard-data:%S"
|
||||
(w32-get-clipboard-data)))
|
||||
((eq data-type 'TARGETS)
|
||||
(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])))
|
||||
((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)))))
|
||||
|
||||
(defun w32--selection-owner-p (selection)
|
||||
|
|
|
@ -2476,10 +2476,9 @@ To work around that, do:
|
|||
(when (and (file-exists-p file)
|
||||
(not (yes-or-no-p (format "%s exists; overwrite?" file))))
|
||||
(user-error "%s exists" file))
|
||||
(with-temp-buffer
|
||||
(set-buffer-multibyte nil)
|
||||
(insert image)
|
||||
(write-region (point-min) (point-max) file))
|
||||
(let ((coding-system-for-write 'emacs-internal))
|
||||
(with-temp-file file
|
||||
(insert image)))
|
||||
(insert (format "<img src=%S>\n" (file-relative-name file)))
|
||||
(insert-image
|
||||
(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,
|
||||
Lisp_Object spec_file, Lisp_Object spec_data);
|
||||
extern bool w32_can_use_native_image_api (Lisp_Object);
|
||||
extern bool w32_gdiplus_startup (void);
|
||||
extern void w32_gdiplus_shutdown (void);
|
||||
|
||||
extern size_t w32_image_size (Emacs_Pixmap);
|
||||
|
||||
#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 "coding.h"
|
||||
|
||||
#include "w32gdiplus.h"
|
||||
#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;
|
||||
GdiplusShutdown_Proc fn_GdiplusShutdown;
|
||||
GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
|
||||
|
@ -86,6 +50,7 @@ GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
|
|||
GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
|
||||
GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
|
||||
GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
|
||||
GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0;
|
||||
SHCreateMemStream_Proc fn_SHCreateMemStream;
|
||||
GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
|
||||
GdipDisposeImage_Proc fn_GdipDisposeImage;
|
||||
|
@ -96,6 +61,7 @@ GdipGetImageEncoders_Proc fn_GdipGetImageEncoders;
|
|||
GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile;
|
||||
GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail;
|
||||
GdipSaveImageToFile_Proc fn_GdipSaveImageToFile;
|
||||
GdipImageRotateFlip_Proc fn_GdipImageRotateFlip;
|
||||
|
||||
static bool
|
||||
gdiplus_init (void)
|
||||
|
@ -146,6 +112,10 @@ gdiplus_init (void)
|
|||
get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream");
|
||||
if (!fn_GdipCreateBitmapFromStream)
|
||||
return false;
|
||||
fn_GdipCreateBitmapFromScan0 = (GdipCreateBitmapFromScan0_Proc)
|
||||
get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromScan0");
|
||||
if (!fn_GdipCreateBitmapFromScan0)
|
||||
return false;
|
||||
fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc)
|
||||
get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap");
|
||||
if (!fn_GdipCreateHBITMAPFromBitmap)
|
||||
|
@ -196,52 +166,14 @@ gdiplus_init (void)
|
|||
get_proc_addr (gdiplus_lib, "GdipSaveImageToFile");
|
||||
if (!fn_GdipSaveImageToFile)
|
||||
return false;
|
||||
fn_GdipImageRotateFlip = (GdipImageRotateFlip_Proc)
|
||||
get_proc_addr (gdiplus_lib, "GdipImageRotateFlip");
|
||||
if (!fn_GdipImageRotateFlip)
|
||||
return false;
|
||||
|
||||
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 */
|
||||
|
||||
static int gdip_initialized;
|
||||
|
@ -252,8 +184,8 @@ static GdiplusStartupOutput output;
|
|||
|
||||
|
||||
/* Initialize GDI+, return true if successful. */
|
||||
static bool
|
||||
gdiplus_startup (void)
|
||||
bool
|
||||
w32_gdiplus_startup (void)
|
||||
{
|
||||
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. */
|
||||
return false;
|
||||
}
|
||||
return gdiplus_startup ();
|
||||
return w32_gdiplus_startup ();
|
||||
}
|
||||
|
||||
enum PropertyItem_type {
|
||||
|
@ -549,8 +481,8 @@ static struct thumb_type_data thumb_types [] =
|
|||
};
|
||||
|
||||
|
||||
static int
|
||||
get_encoder_clsid (const char *type, CLSID *clsid)
|
||||
int
|
||||
w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid)
|
||||
{
|
||||
/* A simple cache based on the assumptions that many thumbnails will
|
||||
be generated using the same TYPE. */
|
||||
|
@ -625,7 +557,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */)
|
|||
|
||||
if (!gdiplus_started)
|
||||
{
|
||||
if (!gdiplus_startup ())
|
||||
if (!w32_gdiplus_startup ())
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
@ -649,7 +581,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */)
|
|||
CLSID thumb_clsid;
|
||||
if (status == Ok
|
||||
/* 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. */
|
||||
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 <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 "w32common.h" /* os_subtype */
|
||||
#include "w32term.h" /* for all of the w32 includes */
|
||||
#include "w32select.h"
|
||||
#include "blockinput.h"
|
||||
#include "coding.h"
|
||||
#include "w32gdiplus.h"
|
||||
|
||||
#ifdef CYGWIN
|
||||
#include <string.h>
|
||||
|
@ -787,6 +797,166 @@ DEFUN ("w32-set-clipboard-data", Fw32_set_clipboard_data,
|
|||
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,
|
||||
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. */)
|
||||
(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);
|
||||
|
||||
/* 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_get_clipboard_data);
|
||||
defsubr (&Sw32__get_clipboard_data_media);
|
||||
defsubr (&Sw32_selection_exists_p);
|
||||
defsubr (&Sw32_selection_targets);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue