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:
Cecilio Pardo 2024-10-28 22:18:13 +01:00 committed by Eli Zaretskii
parent 5ee56b8693
commit 8e7f5f97db
8 changed files with 389 additions and 123 deletions

View file

@ -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

View file

@ -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.

View file

@ -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)

View file

@ -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
View 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);

View file

@ -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)

View file

@ -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];

View file

@ -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);