diff options
| author | Cecilio Pardo <cpardo@imayhem.com> | 2024-10-28 22:18:13 +0100 |
|---|---|---|
| committer | Eli Zaretskii <eliz@gnu.org> | 2024-11-03 15:12:20 +0200 |
| commit | 8e7f5f97db647ce6e9606364dc15d8bbd7ef6016 (patch) | |
| tree | aa033dc97c284c7842dc291c6a9f7fbcd044fce8 /src/w32select.c | |
| parent | 5ee56b86938b7759dd92f507d03907280f48ffca (diff) | |
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.
Diffstat (limited to 'src/w32select.c')
| -rw-r--r-- | src/w32select.c | 194 |
1 files changed, 171 insertions, 23 deletions
diff --git a/src/w32select.c b/src/w32select.c index 006bf408b47..7e8dc3f0702 100644 --- a/src/w32select.c +++ b/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); |
