From 392071b66d30954be82d01140ab2fd7a1ad2ee80 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?utf8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Tue, 5 Jun 2018 23:37:10 +0000 Subject: [PATCH] GDK W32: Remove unused files --- gdk/win32/gdkselection-win32.c | 2866 -------------------------------- gdk/win32/gdkselection-win32.h | 230 --- 2 files changed, 3096 deletions(-) delete mode 100644 gdk/win32/gdkselection-win32.c delete mode 100644 gdk/win32/gdkselection-win32.h diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c deleted file mode 100644 index 86e7b92ea8..0000000000 --- a/gdk/win32/gdkselection-win32.c +++ /dev/null @@ -1,2866 +0,0 @@ -/* GDK - The GIMP Drawing Kit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * Copyright (C) 1998-2002 Tor Lillqvist - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -/* - * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS - * file for a list of people on the GTK+ Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. - */ - -/* -GTK+ selection works like this: -There are three selections that matter - GDK_SELECTION_CLIPBOARD, -GDK_SELECTION_PRIMARY and DND. Primary selection is only handled -internally by GTK+ (it's not portable to Windows). DND is actually -represented by two selections - LOCAL and OLE2, one for each DnD protocol, -but they work the same way. - -"Target" is a GdkAtom describing a clipboard format. - -For Clipboard: -GTK+ calls gtk_clipboard_set_contents(), which first ensures the -clipboard is owned by the clipboard widget (which also indirectly -causes an SelectionRequest xevent to be sent to it), then clears the old -supported targets from the clipboard, then adds all the -targets it's given to the clipboard. No data is sent anywhere. - -gtk_clipboard_set_contents() is also given a callback to invoke when -the actual data is needed. This callback is implemented by the widget -from which the data can be put into clipboard. - -GTK+ might also call gtk_clipboard_set_can_store(), which sets the -targets for which the data can be put into system clipboard, so that -it remains usable even if the application is no longer around. Usually -all data formats are storable, except for the shortcut formats, which -refer to actual widgets directly, and are thus only working while -the application is alive. - -("C:" means clipboard client (requestor), "S:" means clipboard server (provider)) - -When something needs to be obtained from clipboard, GTK+ calls -C: gtk_selection_convert(). -That function has a shortcut where it directly gets the selection contents by calling -S: gtk_selection_invoke_handler(), -asking the widget to provide data, and then calling -C: gtk_selection_retrieval_report() -to report the data back to the caller. - -If that shortcut isn't possible (selection is owned by another process), -gtk_selection_convert() calls -C:gdk_selection_convert() (_gdk_x11_display_convert_selection()) - -On X11 gdk_selection_convert() just calls -C:XConvertSelection(), -which sends SelectionRequest xevent to the window that owns the selection. -The client gives its clipboard window as the requestor for that event, -and gives the property as GDK_SELECTION. - -Server-side GTK+ catches SelectionRequest in a -S:_gtk_selection_request() -event handler, which calls -S:gtk_selection_invoke_handler() -to get the data, and then calls -S:gdk_property_change() (_gdk_x11_surface_change_property()) -to submit the data, by setting the property given by the message sender -(GDK_SELECTION) on the requestor window (our client clipboard window). - -On X11 data submission takes from of -S:XChangeProperty() -call, which causes SelectionNotify (and PropertyNotify for INCR) -xevent to be sent, which client-side GTK+ catches and handles in -C:_gtk_selection_notify() -(and -C:_gtk_selection_property_notify(), -for INCR) -event handler, which calls -C:gtk_selection_retrieval_report() -to report back to the caller. The caller gets the property -data from the window, and returns it up the stack. - -On X11 the "TARGETS" target might be given in a SelectionRequest xmessage to request -all supported targets for a selection. - -If data must be stored on the clipboard, because the application is quitting, -GTK+ will call -S:gdk_clipboard_store() -> gdk_display_store_clipboard() (gdk_x11_display_store_clipboard()) -on all the clipboards it owns. -X11 gdk_display_store_clipboard() puts a list of storeable targets into GDK_SELECTION -property of the clipboard window, then calls -S:XConvertSelection() -on the clipboard manager window (retrieved from the CLIPBOARD_MANAGER atom), -and the clipboard manager responds by requesting all these formats and storing the data, -then responds with SelectionNotify xevent to allow the application to quit. - -When clipboard owner changes, the old owner receives SelectionClear xevent, -GTK+ handles it by clearing the clipboard object on its own level, GDK -is not involved. - -On Windows: -Clipboard is opened by OpenClipboard(), emptied by EmptyClipboard() (which also -makes the window the clipboard owner), data is put into it by SetClipboardData(). -Clipboard is closed with CloseClipboard(). -If SetClipboardData() is given a NULL data value, the owner will later -receive WM_RENDERFORMAT message, in response to which it must call -SetClipboardData() with the provided handle and the actual data this time. -This way applications can avoid storing everything in the clipboard -all the time, only putting the data there as it is requested by other applications. -At some undefined points of time an application might get WM_RENDERALLFORMATS -message, it should respond by opening the clipboard and rendering -into it all the data that it offers, as if responding to multiple WM_RENDERFORMAT -messages. - -On GDK-Win32: -GTK+ calls gtk_clipboard_set_contents(), which first ensures the -clipboard is owned by the clipboard widget (calls OpenClipboard(), -then EmptyClipboard() to become the owner, then -sends a TARGETS GDK_SELECTION_REQUEST to itself, without closing the clipboard), -then clears the old supported targets from the clipboard, then adds all the -targets it's given to the clipboard. No data is sent anywhere. - -gtk_clipboard_set_contents() is also given a callback to invoke when -the actual data is needed. This callback is implemented by the widget -from which the data can be put into clipboard. - -GTK+ might also call gtk_clipboard_set_can_store(), which sets the -targets for which the data can be put into system clipboard, so that -it remains usable even if the application is no longer around. Usually -all data formats are storable, except for the shortcut formats, which -refer to actual widgets directly, and are thus only working while -the application is alive. - -("C:" means clipboard client (requestor), "S:" means clipboard server (provider)) -("transmute" here means "change the format of some data"; this term is used here - instead of "convert" to avoid clashing with g(t|d)k_selection_convert(), which - is completely unrelated) - -When something needs to be obtained from clipboard, GTK+ calls -C: gtk_selection_convert(). -That function has a shortcut where it directly gets the selection contents by calling -S: gtk_selection_invoke_handler(), -asking the widget to provide data, and then calling -C: gtk_selection_retrieval_report() -to report the data back to the caller. - -If that shortcut isn't possible (selection is owned by another process), -gtk_selection_convert() calls -C:gdk_selection_convert() (_gdk_win32_display_convert_selection()) - -On GDK-Win32 gdk_selection_convert() just calls -C:OpenClipboard() -to open clipboard (if that fails, it shedules a timeout to regularly -try to open clipboard for the next 30 seconds, and do the actions -outlined below once the clipboard is opened, or notify about -conversion failure after 30 seconds), -C:EnumClipboardFormats() (2000+) -to get the list of supported formats, figures out the format it should -use to request the data (first it looks for supported formats with names -that match the target name, then looks through compatibility -formats for the target and checks whether these are supported). -Note that it has no list of supported targets at hand, -just the single requested target, and thus it might have -to do some transmutation between formats; the caller up the stack -either only supports just one format that it asks for, -or supports multiple formats and asks for them in sequence (from -the most preferred to the least preferred), until one call succeeds, -or supports multiple formats and asks for the TARGETS format first, -and then figures out what to ask for - GDK can't know that. -Either way, GDK has to call -C:GetClipboardData() -to get the data (this causes WM_RENDERFORMAT to be sent to the owner, -if the owner uses delayed rendering for the requested format, otherwise -it just picks the data right from the OS) - -Server-side GDK catches WM_RENDERFORMAT, figures out a target -to request (this one is easier, as it has the list of supported -targets saved up), and posts a GDK_SELECTION_REQUEST event, then runs the main loop, -while GTK+ catches the event in a -S:_gtk_selection_request() -event handler, which calls -S:gtk_selection_invoke_handler() -to get the data, and then calls -S:gdk_property_change() (_gdk_win32_surface_change_property()) -to submit the data, by first transmuting it to the format actually requested -by the sender of WM_RENDERFORMAT, and then by returning thedata back up the stack, -to the WM_RENDERFORMAT handler, which then calls -S:SetClipboardData() -with the handle provided by the sender. - -Meanwhile, the client code, still in -C:_gdk_win32_display_convert_selection(), -gets the data in response to GetClipboardData(), -transmutes it (if needed) to the target format, sets the requested -window property to that data (unlike change_property!), -calls -C:CloseClipboard() (if there are no more clipboard opeartions -scheduled) -and posts a GDK_SELECTION_NOTIFY event, which GTK+ catches in -C:_gtk_selection_notify() -event handler, which calls -C:gtk_selection_retrieval_report() -to report back to the caller. The caller gets the property -data from the window, and returns it up the stack. - -On GDK-Win32 the "TARGETS" target might be given in a GDK_SELECTION_REQUEST to request -all supported targets for a selection. -Note that this server side - -client side should call gdk_selection_convert() -> gdk_selection_convert() with "TARGETS" target -to get the list of targets offered by the clipboard holder. It never causes GDK_SELECTION_REQUEST -to be generated, just queries the system clipboard. -On server side GDK_SELECTION_REQUEST is only generated internally: -in response to WM_RENDERFORMAT (it renders a target), -in response to idataobject_getdata() (it renders a target), -after DnD ends (with a DELETE target, this is caught by GTK to make it delete the selection), -and in response to owner change, with TARGETS target, which makes it register its formats by calling -S:SetClipboardData(..., NULL) - -If data must be stored on the clipboard, because the application is quitting, -GTK+ will call -S:gdk_clipboard_store() -> gdk_display_store_clipboard() (gdk_win32_display_store_clipboard()) -on all the clipboards it owns. -GDK-Win32 gdk_display_store_clipboard() sends WM_RENDERALLFORMATS to the window, -then posts a GDK_SELECTION_NOTIFY event allow the application to quit. - -When clipboard owner changes, the old owner receives WM_DESTROYCLIPBOARD message, -GDK handles it by posting a GDK_SELECTION_CLEAR event, which -GTK+ handles by clearing the clipboard object on its own level. - -Any operations that require OpenClipboard()/CloseClipboard() combo (i.e. -everything, except for WM_RENDERFORMAT handling) must be put into a queue, -and then a once-per-second-for-up-to-30-seconds timeout must be added. -The timeout function must call OpenClipboard(), -and then proceed to perform the queued actions on the clipboard, once it opened, -or return and try again a second later, as long as there are still items in the queue, -and remove the queue items that are older than 30 seconds. -Once the queue is empty, the clipboard is closed. - -DND: -GDK-Win32: -S:idataobject_getdata() -sends a GDK_SELECTION_REQUEST event, which results in a call to -S:_gdk_win32_surface_change_property() -which passes clipboard data back via the selection singleton. -GDK-Win32 uses delayed rendering for all formats, even text. - -GTK+ will call -C:gtk_selection_convert() -> gdk_selection_convert() (_gdk_win32_display_convert_selection()) -to get the data associated with the drag, when GTK+ apps want to inspect the data, -but with a OLE2_DND selection instead of CLIPBOARD selection. - -_gdk_win32_display_convert_selection() queries the droptarget global variable, -which should already contain a matched list of supported formats and targets, -picks a format there, then queries it from the IDataObject that the droptarget kept around. -Then optionally transmutes the data, and sets the property. Then posts GDK_SELECTION_NOTIFY. - -GTK+ catches that event and processes it, causeing "selection-received" signal to -be emitted on the selection widget, and its handler is -C:gtk_drag_selection_received(), -which emits the "drag-data-received" signal for the app. -*/ - -#include "config.h" -#include -#include - -/* For C-style COM wrapper macros */ -#define COBJMACROS - -/* for CIDA */ -#include - -#include "gdkproperty.h" -#include "gdkdisplay.h" -#include "gdkprivate-win32.h" -#include "gdkselection-win32.h" -#include "gdk/gdkdndprivate.h" -#include "gdkwin32dnd-private.h" -#include "gdkwin32.h" - -typedef struct _GdkWin32ClipboardQueueInfo GdkWin32ClipboardQueueInfo; - -typedef enum _GdkWin32ClipboardQueueAction GdkWin32ClipboardQueueAction; - -enum _GdkWin32ClipboardQueueAction -{ - GDK_WIN32_CLIPBOARD_QUEUE_ACTION_CONVERT = 0, - GDK_WIN32_CLIPBOARD_QUEUE_ACTION_TARGETS -}; - -struct _GdkWin32ClipboardQueueInfo -{ - GdkDisplay *display; - GdkSurface *requestor; - GdkAtom selection; - GdkAtom target; - guint32 time; - - /* Number of seconds since we started our - * attempts to open clipboard. - */ - guint32 idle_time; - - /* What to do once clipboard is opened */ - GdkWin32ClipboardQueueAction action; -}; - -/* List of GdkWin32ClipboardQueueInfo slices */ -static GList *clipboard_queue = NULL; - -#define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0]) -#define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1]) - -G_DEFINE_TYPE (GdkWin32Selection, gdk_win32_selection, G_TYPE_OBJECT) - -static void -gdk_win32_selection_class_init (GdkWin32SelectionClass *klass) -{ -} - -void -_gdk_win32_selection_init (void) -{ - _win32_selection = GDK_WIN32_SELECTION (g_object_new (GDK_TYPE_WIN32_SELECTION, NULL)); -} - -static void -gdk_win32_selection_init (GdkWin32Selection *win32_selection) -{ - GArray *atoms; - GArray *cfs; - GSList *pixbuf_formats; - GSList *rover; - int i; - GArray *comp; - GdkSelTargetFormat fmt; - - win32_selection->ignore_destroy_clipboard = FALSE; - win32_selection->clipboard_opened_for = INVALID_HANDLE_VALUE; - - win32_selection->dnd_target_state = GDK_WIN32_DND_NONE; - win32_selection->dnd_source_state = GDK_WIN32_DND_NONE; - win32_selection->dnd_data_object_target = NULL; - win32_selection->property_change_format = 0; - win32_selection->property_change_data = NULL; - win32_selection->property_change_target_atom = 0; - - atoms = g_array_sized_new (FALSE, TRUE, sizeof (GdkAtom), GDK_WIN32_ATOM_INDEX_LAST); - g_array_set_size (atoms, GDK_WIN32_ATOM_INDEX_LAST); - cfs = g_array_sized_new (FALSE, TRUE, sizeof (UINT), GDK_WIN32_CF_INDEX_LAST); - g_array_set_size (cfs, GDK_WIN32_CF_INDEX_LAST); - - win32_selection->known_atoms = atoms; - win32_selection->known_clipboard_formats = cfs; - - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_GDK_SELECTION) = g_intern_static_string ("GDK_SELECTION"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CLIPBOARD_MANAGER) = g_intern_static_string ("CLIPBOARD_MANAGER"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_WM_TRANSIENT_FOR) = g_intern_static_string ("WM_TRANSIENT_FOR"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_TARGETS) = g_intern_static_string ("TARGETS"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_DELETE) = g_intern_static_string ("DELETE"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_SAVE_TARGETS) = g_intern_static_string ("SAVE_TARGETS"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_UTF8_STRING) = g_intern_static_string ("UTF8_STRING"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_TEXT) = g_intern_static_string ("TEXT"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_COMPOUND_TEXT) = g_intern_static_string ("COMPOUND_TEXT"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST) = g_intern_static_string ("text/uri-list"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_TEXT_HTML) = g_intern_static_string ("text/html"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG) = g_intern_static_string ("image/png"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_JPEG) = g_intern_static_string ("image/jpeg"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP) = g_intern_static_string ("image/bmp"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_GIF) = g_intern_static_string ("image/gif"); - - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_LOCAL_DND_SELECTION) = g_intern_static_string ("LocalDndSelection"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_DROPFILES_DND) = g_intern_static_string ("DROPFILES_DND"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_OLE2_DND) = g_intern_static_string ("OLE2_DND"); - - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_PNG)= g_intern_static_string ("PNG"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_JFIF) = g_intern_static_string ("JFIF"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_GIF) = g_intern_static_string ("GIF"); - - /* These are a bit unusual. It's here to allow GTK+ applications - * to actually support CF_DIB and Shell ID List clipboard formats on their own, - * instead of allowing GDK to use them internally for interoperability. - */ - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CF_DIB) = g_intern_static_string ("CF_DIB"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CFSTR_SHELLIDLIST) = g_intern_static_string (CFSTR_SHELLIDLIST); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CF_UNICODETEXT) = g_intern_static_string ("CF_UNICODETEXT"); - _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CF_TEXT) = g_intern_static_string ("CF_TEXT"); - - /* MS Office 2007, at least, offers images in common file formats - * using clipboard format names like "PNG" and "JFIF". So we follow - * the lead and map the GDK target name "image/png" to the clipboard - * format name "PNG" etc. - */ - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG) = RegisterClipboardFormatA ("PNG"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF) = RegisterClipboardFormatA ("JFIF"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF) = RegisterClipboardFormatA ("GIF"); - - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_UNIFORMRESOURCELOCATORW) = RegisterClipboardFormatA ("UniformResourceLocatorW"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST) = RegisterClipboardFormatA (CFSTR_SHELLIDLIST); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_HTML_FORMAT) = RegisterClipboardFormatA ("HTML Format"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_TEXT_HTML) = RegisterClipboardFormatA ("text/html"); - - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_PNG) = RegisterClipboardFormatA ("image/png"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_JPEG) = RegisterClipboardFormatA ("image/jpeg"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_BMP) = RegisterClipboardFormatA ("image/bmp"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_GIF) = RegisterClipboardFormatA ("image/gif"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_TEXT_URI_LIST) = RegisterClipboardFormatA ("text/uri-list"); - _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_UTF8_STRING) = RegisterClipboardFormatA ("UTF8_STRING"); - - win32_selection->sel_prop_table = g_hash_table_new (NULL, NULL); - win32_selection->sel_owner_table = g_hash_table_new (NULL, NULL); - - pixbuf_formats = gdk_pixbuf_get_formats (); - - win32_selection->n_known_pixbuf_formats = 0; - for (rover = pixbuf_formats; rover != NULL; rover = rover->next) - { - gchar **mime_types = - gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) rover->data); - - gchar **mime_type; - - for (mime_type = mime_types; *mime_type != NULL; mime_type++) - win32_selection->n_known_pixbuf_formats++; - } - - win32_selection->known_pixbuf_formats = g_new (GdkAtom, win32_selection->n_known_pixbuf_formats); - - i = 0; - for (rover = pixbuf_formats; rover != NULL; rover = rover->next) - { - gchar **mime_types = - gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) rover->data); - - gchar **mime_type; - - for (mime_type = mime_types; *mime_type != NULL; mime_type++) - win32_selection->known_pixbuf_formats[i++] = g_intern_string (*mime_type); - } - - g_slist_free (pixbuf_formats); - - win32_selection->dnd_selection_targets = g_array_new (FALSE, FALSE, sizeof (GdkSelTargetFormat)); - win32_selection->clipboard_selection_targets = g_array_new (FALSE, FALSE, sizeof (GdkSelTargetFormat)); - win32_selection->compatibility_formats = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_array_unref); - - /* GTK+ actually has more text formats, but it's unlikely that we'd - * get anything other than UTF8_STRING these days. - * GTKTEXTBUFFERCONTENTS format can potentially be converted to - * W32-compatible rich text format, but that's too complex to address right now. - */ - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 3); - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_UTF8_STRING); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_UTF8_STRING); - fmt.transmute = FALSE; - g_array_append_val (comp, fmt); - - fmt.format = CF_UNICODETEXT; - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - fmt.format = CF_TEXT; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_formats, fmt.target, comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 3); - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_PNG); - fmt.transmute = FALSE; - g_array_append_val (comp, fmt); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG); - g_array_append_val (comp, fmt); - - fmt.format = CF_DIB; - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_formats, fmt.target, comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 4); - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_JPEG); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_JPEG); - fmt.transmute = FALSE; - g_array_append_val (comp, fmt); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF); - g_array_append_val (comp, fmt); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - fmt.format = CF_DIB; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_formats, fmt.target, comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 4); - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_GIF); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_GIF); - fmt.transmute = FALSE; - g_array_append_val (comp, fmt); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF); - g_array_append_val (comp, fmt); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - fmt.format = CF_DIB; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_formats, fmt.target, comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 2); - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_BMP); - fmt.transmute = FALSE; - g_array_append_val (comp, fmt); - - fmt.format = CF_DIB; - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_formats, fmt.target, comp); - - -/* Not implemented, but definitely possible - comp = g_array_sized_new (FALSE, FALSE, 2); - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_TEXT_URI_LIST); - fmt.transmute = FALSE; - g_array_append_val (comp, fmt); - - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_formats, fmt.target, comp); -*/ - - win32_selection->compatibility_targets = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_array_unref); - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 2); - fmt.format = CF_TEXT; - fmt.transmute = FALSE; - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CF_TEXT); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_UTF8_STRING); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_targets, GINT_TO_POINTER (CF_TEXT), comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 2); - fmt.format = CF_UNICODETEXT; - fmt.transmute = FALSE; - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CF_UNICODETEXT); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_UTF8_STRING); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_targets, GINT_TO_POINTER (CF_UNICODETEXT), comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 3); - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG); - fmt.transmute = FALSE; - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_PNG); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_targets, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG)), comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 4); - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF); - fmt.transmute = FALSE; - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_JFIF); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_JPEG); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP); - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_targets, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF)), comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 4); - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF); - fmt.transmute = FALSE; - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_GIF); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_GIF); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP); - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_targets, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF)), comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 3); - fmt.format = CF_DIB; - fmt.transmute = FALSE; - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CF_DIB); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_targets, GINT_TO_POINTER (CF_DIB), comp); - - - comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), 3); - fmt.format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST); - fmt.transmute = FALSE; - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_CFSTR_SHELLIDLIST); - g_array_append_val (comp, fmt); - - fmt.target = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST); - fmt.transmute = TRUE; - g_array_append_val (comp, fmt); - - g_hash_table_replace (win32_selection->compatibility_targets, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST)), comp); -} - -/* The specifications for COMPOUND_TEXT and STRING specify that C0 and - * C1 are not allowed except for \n and \t, however the X conversions - * routines for COMPOUND_TEXT only enforce this in one direction, - * causing cut-and-paste of \r and \r\n separated text to fail. - * This routine strips out all non-allowed C0 and C1 characters - * from the input string and also canonicalizes \r, and \r\n to \n - */ -static gchar * -sanitize_utf8 (const gchar *src, - gint length) -{ - GString *result = g_string_sized_new (length + 1); - const gchar *p = src; - const gchar *endp = src + length; - - while (p < endp) - { - if (*p == '\r') - { - p++; - if (*p == '\n') - p++; - - g_string_append_c (result, '\n'); - } - else - { - gunichar ch = g_utf8_get_char (p); - char buf[7]; - gint buflen; - - if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0))) - { - buflen = g_unichar_to_utf8 (ch, buf); - g_string_append_len (result, buf, buflen); - } - - p = g_utf8_next_char (p); - } - } - g_string_append_c (result, '\0'); - - return g_string_free (result, FALSE); -} - -static gchar * -_gdk_utf8_to_string_target_internal (const gchar *str, - gint length) -{ - GError *error = NULL; - - gchar *tmp_str = sanitize_utf8 (str, length); - gchar *result = g_convert_with_fallback (tmp_str, -1, - "ISO-8859-1", "UTF-8", - NULL, NULL, NULL, &error); - if (!result) - { - g_warning ("Error converting from UTF-8 to STRING: %s", - error->message); - g_error_free (error); - } - - g_free (tmp_str); - return result; -} - -static void -selection_property_store (GdkSurface *owner, - GdkAtom type, - gint format, - guchar *data, - gint length) -{ - GdkSelProp *prop; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - prop = g_hash_table_lookup (win32_sel->sel_prop_table, GDK_SURFACE_HWND (owner)); - - if (prop != NULL) - { - g_free (prop->data); - g_free (prop); - g_hash_table_remove (win32_sel->sel_prop_table, GDK_SURFACE_HWND (owner)); - } - - prop = g_new (GdkSelProp, 1); - - prop->data = data; - prop->length = length; - prop->bitness = format; - prop->target = type; - - g_hash_table_insert (win32_sel->sel_prop_table, GDK_SURFACE_HWND (owner), prop); -} - -void -_gdk_dropfiles_store (gchar *data) -{ - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - if (data != NULL) - { - g_assert (win32_sel->dropfiles_prop == NULL); - - win32_sel->dropfiles_prop = g_new (GdkSelProp, 1); - win32_sel->dropfiles_prop->data = (guchar *) data; - win32_sel->dropfiles_prop->length = strlen (data) + 1; - win32_sel->dropfiles_prop->bitness = 8; - win32_sel->dropfiles_prop->target = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST); - } - else - { - if (win32_sel->dropfiles_prop != NULL) - { - g_free (win32_sel->dropfiles_prop->data); - g_free (win32_sel->dropfiles_prop); - } - win32_sel->dropfiles_prop = NULL; - } -} - -static void -generate_selection_notify (GdkSurface *requestor, - GdkAtom selection, - GdkAtom target, - GdkAtom property, - guint32 time) -{ - GdkEvent tmp_event; - - memset (&tmp_event, 0, sizeof (tmp_event)); - tmp_event.selection.type = GDK_SELECTION_NOTIFY; - tmp_event.selection.window = requestor; - tmp_event.selection.send_event = FALSE; - tmp_event.selection.selection = selection; - tmp_event.selection.target = target; - tmp_event.selection.property = property; - tmp_event.selection.requestor = 0; - tmp_event.selection.time = time; - - gdk_event_set_display (&tmp_event, gdk_window_get_display (requestor)); - gdk_display_put_event (gdk_window_get_display (requestor), &tmp_event); -} - -void -_gdk_win32_clear_clipboard_queue () -{ - GList *tmp_list, *next; - GdkWin32ClipboardQueueInfo *info; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - GDK_NOTE (DND, g_print ("Clear clipboard queue\n")); - - for (tmp_list = clipboard_queue; tmp_list; tmp_list = next) - { - info = (GdkWin32ClipboardQueueInfo *) tmp_list->data; - next = g_list_next (tmp_list); - clipboard_queue = g_list_remove_link (clipboard_queue, tmp_list); - g_list_free (tmp_list); - switch (info->action) - { - case GDK_WIN32_CLIPBOARD_QUEUE_ACTION_TARGETS: - break; - case GDK_WIN32_CLIPBOARD_QUEUE_ACTION_CONVERT: - generate_selection_notify (info->requestor, info->selection, info->target, NULL, info->time); - break; - } - g_clear_object (&info->requestor); - g_slice_free (GdkWin32ClipboardQueueInfo, info); - } - - win32_sel->targets_request_pending = FALSE; -} - -/* Send ourselves a selection request message with - * the TARGETS target, we will do multiple SetClipboarData(...,NULL) - * calls in response to announce the formats we support. - */ -static void -send_targets_request (guint time) -{ - GdkSurface *owner; - GdkEvent tmp_event; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - if (win32_sel->targets_request_pending) - return; - - owner = _gdk_win32_display_get_selection_owner (gdk_display_get_default (), - GDK_SELECTION_CLIPBOARD); - - if (owner == NULL) - return; - - if (win32_sel->clipboard_opened_for == INVALID_HANDLE_VALUE) - { - if (OpenClipboard (GDK_SURFACE_HWND (owner))) - { - win32_sel->clipboard_opened_for = GDK_SURFACE_HWND (owner); - GDK_NOTE (DND, g_print ("Opened clipboard for 0x%p @ %s:%d\n", win32_sel->clipboard_opened_for, __FILE__, __LINE__)); - } - } - - GDK_NOTE (DND, g_print ("... sending GDK_SELECTION_REQUEST to ourselves\n")); - memset (&tmp_event, 0, sizeof (tmp_event)); - tmp_event.selection.type = GDK_SELECTION_REQUEST; - tmp_event.selection.window = owner; - tmp_event.selection.send_event = FALSE; - tmp_event.selection.selection = GDK_SELECTION_CLIPBOARD; - tmp_event.selection.target = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TARGETS); - tmp_event.selection.property = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_GDK_SELECTION); - tmp_event.selection.requestor = owner; - tmp_event.selection.time = time; - win32_sel->property_change_target_atom = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TARGETS); - - gdk_event_set_display (&tmp_event, gdk_window_get_display (owner)); - gdk_display_put_event (gdk_window_get_display (owner), &tmp_event); - win32_sel->targets_request_pending = TRUE; -} - -#define CLIPBOARD_IDLE_ABORT_TIME 30 - -static const gchar * -predefined_name (UINT fmt) -{ -#define CASE(fmt) case fmt: return #fmt - switch (fmt) - { - CASE (CF_TEXT); - CASE (CF_BITMAP); - CASE (CF_METAFILEPICT); - CASE (CF_SYLK); - CASE (CF_DIF); - CASE (CF_TIFF); - CASE (CF_OEMTEXT); - CASE (CF_DIB); - CASE (CF_PALETTE); - CASE (CF_PENDATA); - CASE (CF_RIFF); - CASE (CF_WAVE); - CASE (CF_UNICODETEXT); - CASE (CF_ENHMETAFILE); - CASE (CF_HDROP); - CASE (CF_LOCALE); - CASE (CF_DIBV5); - CASE (CF_MAX); - - CASE (CF_OWNERDISPLAY); - CASE (CF_DSPTEXT); - CASE (CF_DSPBITMAP); - CASE (CF_DSPMETAFILEPICT); - CASE (CF_DSPENHMETAFILE); -#undef CASE - default: - return NULL; - } -} - -gchar * -_gdk_win32_get_clipboard_format_name (UINT fmt, - gboolean *is_predefined) -{ - gint registered_name_w_len = 1024; - wchar_t *registered_name_w = g_malloc (registered_name_w_len); - gchar *registered_name = NULL; - int gcfn_result; - const gchar *predef = predefined_name (fmt); - - /* FIXME: cache the result in a hash table */ - - do - { - gcfn_result = GetClipboardFormatNameW (fmt, registered_name_w, registered_name_w_len); - - if (gcfn_result > 0 && gcfn_result < registered_name_w_len) - { - registered_name = g_utf16_to_utf8 (registered_name_w, -1, NULL, NULL, NULL); - g_clear_pointer (®istered_name_w, g_free); - if (!registered_name) - gcfn_result = 0; - else - *is_predefined = FALSE; - break; - } - - /* If GetClipboardFormatNameW() used up all the space, it means that - * we probably need a bigger buffer, but cap this at 1 kilobyte. - */ - if (gcfn_result == 0 || registered_name_w_len > 1024 * 1024) - { - gcfn_result = 0; - g_clear_pointer (®istered_name_w, g_free); - break; - } - - registered_name_w_len *= 2; - registered_name_w = g_realloc (registered_name_w, registered_name_w_len); - gcfn_result = registered_name_w_len; - } while (gcfn_result == registered_name_w_len); - - if (registered_name == NULL && - predef != NULL) - { - registered_name = g_strdup (predef); - *is_predefined = TRUE; - } - - return registered_name; -} - -static GArray * -get_compatibility_formats_for_target (GdkAtom target) -{ - GArray *result = NULL; - gint i; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - result = g_hash_table_lookup (win32_sel->compatibility_formats, target); - - if (result != NULL) - return result; - - for (i = 0; i < win32_sel->n_known_pixbuf_formats; i++) - { - if (target != win32_sel->known_pixbuf_formats[i]) - continue; - - /* Any format known to gdk-pixbuf can be presented as PNG or BMP */ - result = g_hash_table_lookup (win32_sel->compatibility_formats, - _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_PNG)); - break; - } - - return result; -} - -static GArray * -_gdk_win32_selection_get_compatibility_targets_for_format (UINT format) -{ - GArray *result = NULL; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - result = g_hash_table_lookup (win32_sel->compatibility_targets, GINT_TO_POINTER (format)); - - if (result != NULL) - return result; - - /* TODO: reverse gdk-pixbuf conversion? We have to somehow - * match gdk-pixbuf format names to the corresponding clipboard - * format names. The former are known only at runtime, - * the latter are presently unknown... - * Maybe try to get the data and then just feed it to gdk-pixbuf, - * see if it knows what it is? - */ - - return result; -} - -void -_gdk_win32_add_format_to_targets (UINT format, - GArray *array, - GList **list) -{ - gboolean predef; - gchar *format_name = _gdk_win32_get_clipboard_format_name (format, &predef); - GdkAtom target_atom; - GdkSelTargetFormat target_selformat; - GArray *target_selformats; - gint i,j; - - if (format_name != NULL) - { - target_atom = g_intern_string (format_name); - GDK_NOTE (DND, g_print ("Maybe add as-is format %s (0x%p)\n", format_name, target_atom)); - g_free (format_name); - if (array && target_atom != 0) - { - for (j = 0; j < array->len; j++) - if (g_array_index (array, GdkSelTargetFormat, j).target == target_atom) - break; - if (j == array->len) - { - target_selformat.format = format; - target_selformat.target = target_atom; - target_selformat.transmute = FALSE; - g_array_append_val (array, target_selformat); - } - } - if (list && target_atom != 0 && g_list_find (*list, target_atom) == NULL) - *list = g_list_prepend (*list, target_atom); - } - - target_selformats = _gdk_win32_selection_get_compatibility_targets_for_format (format); - - if (array && target_selformats != NULL) - for (i = 0; i < target_selformats->len; i++) - { - target_selformat = g_array_index (target_selformats, GdkSelTargetFormat, i); - - for (j = 0; j < array->len; j++) - if (g_array_index (array, GdkSelTargetFormat, j).target == target_selformat.target && - g_array_index (array, GdkSelTargetFormat, j).format == target_selformat.format) - break; - - if (j == array->len) - g_array_append_val (array, target_selformat); - } - - if (list && target_selformats != NULL) - for (i = 0; i < target_selformats->len; i++) - { - target_selformat = g_array_index (target_selformats, GdkSelTargetFormat, i); - - if (g_list_find (*list, target_selformat.target) == NULL) - *list = g_list_prepend (*list, target_selformat.target); - } -} - -static void -transmute_cf_unicodetext_to_utf8_string (const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length, - GDestroyNotify *set_data_destroy) -{ - wchar_t *ptr, *p, *q; - gchar *result; - glong wclen, u8_len; - - /* Strip out \r */ - ptr = (wchar_t *) data; - p = ptr; - q = ptr; - wclen = 0; - - while (p < ptr + length / 2) - { - if (*p != L'\r') - { - *q++ = *p; - wclen++; - } - p++; - } - - result = g_utf16_to_utf8 (ptr, wclen, NULL, &u8_len, NULL); - - if (result) - { - *set_data = (guchar *) result; - - if (set_data_length) - *set_data_length = u8_len + 1; - if (set_data_destroy) - *set_data_destroy = (GDestroyNotify) g_free; - } -} - -static void -transmute_utf8_string_to_cf_unicodetext (const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length, - GDestroyNotify *set_data_destroy) -{ - glong wclen; - GError *err = NULL; - glong size; - gint i; - wchar_t *wcptr, *p; - - wcptr = g_utf8_to_utf16 ((char *) data, length, NULL, &wclen, &err); - if (err != NULL) - { - g_warning ("Failed to convert utf8: %s", err->message); - g_clear_error (&err); - return; - } - - wclen++; /* Terminating 0 */ - size = wclen * 2; - for (i = 0; i < wclen; i++) - if (wcptr[i] == L'\n' && (i == 0 || wcptr[i - 1] != L'\r')) - size += 2; - - *set_data = g_malloc0 (size); - if (set_data_length) - *set_data_length = size; - if (set_data_destroy) - *set_data_destroy = (GDestroyNotify) g_free; - - p = (wchar_t *) *set_data; - - for (i = 0; i < wclen; i++) - { - if (wcptr[i] == L'\n' && (i == 0 || wcptr[i - 1] != L'\r')) - *p++ = L'\r'; - *p++ = wcptr[i]; - } - - g_free (wcptr); -} - -static int -wchar_to_str (const wchar_t *wstr, - char **retstr, - UINT cp) -{ - char *str; - int len; - int lenc; - - len = WideCharToMultiByte (cp, 0, wstr, -1, NULL, 0, NULL, NULL); - - if (len <= 0) - return -1; - - str = g_malloc (sizeof (char) * len); - - lenc = WideCharToMultiByte (cp, 0, wstr, -1, str, len, NULL, NULL); - - if (lenc != len) - { - g_free (str); - - return -3; - } - - *retstr = str; - - return 0; -} - -static void -transmute_utf8_string_to_cf_text (const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length, - GDestroyNotify *set_data_destroy) -{ - glong rlen; - GError *err = NULL; - glong size; - gint i; - char *strptr, *p; - wchar_t *wcptr; - - wcptr = g_utf8_to_utf16 ((char *) data, length, NULL, NULL, &err); - if (err != NULL) - { - g_warning ("Failed to convert utf8: %s", err->message); - g_clear_error (&err); - return; - } - - if (wchar_to_str (wcptr, &strptr, CP_ACP) != 0) - { - g_warning ("Failed to convert utf-16 %S to ACP", wcptr); - g_free (wcptr); - return; - } - - rlen = strlen (strptr); - g_free (wcptr); - - rlen++; /* Terminating 0 */ - size = rlen * sizeof (char); - for (i = 0; i < rlen; i++) - if (strptr[i] == '\n' && (i == 0 || strptr[i - 1] != '\r')) - size += sizeof (char); - - *set_data = g_malloc0 (size); - if (set_data_length) - *set_data_length = size; - if (set_data_destroy) - *set_data_destroy = (GDestroyNotify) g_free; - - p = (char *) *set_data; - - for (i = 0; i < rlen; i++) - { - if (strptr[i] == '\n' && (i == 0 || strptr[i - 1] != '\r')) - *p++ = '\r'; - *p++ = strptr[i]; - } - - g_free (strptr); -} - -static int -str_to_wchar (const char *str, - wchar_t **wretstr, - UINT cp) -{ - wchar_t *wstr; - int len; - int lenc; - - len = MultiByteToWideChar (cp, 0, str, -1, NULL, 0); - - if (len <= 0) - return -1; - - wstr = g_malloc (sizeof (wchar_t) * len); - - lenc = MultiByteToWideChar (cp, 0, str, -1, wstr, len); - - if (lenc != len) - { - g_free (wstr); - - return -3; - } - - *wretstr = wstr; - - return 0; -} - -static void -transmute_cf_text_to_utf8_string (const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length, - GDestroyNotify *set_data_destroy) -{ - char *ptr, *p, *q; - gchar *result; - glong wclen, u8_len; - wchar_t *wstr; - - /* Strip out \r */ - ptr = (gchar *) data; - p = ptr; - q = ptr; - wclen = 0; - - while (p < ptr + length / 2) - { - if (*p != '\r') - { - *q++ = *p; - wclen++; - } - p++; - } - - if (str_to_wchar (ptr, &wstr, CP_ACP) < 0) - return; - - result = g_utf16_to_utf8 (wstr, -1, NULL, &u8_len, NULL); - - if (result) - { - *set_data = (guchar *) result; - - if (set_data_length) - *set_data_length = u8_len + 1; - if (set_data_destroy) - *set_data_destroy = (GDestroyNotify) g_free; - } - - g_free (wstr); -} - -static void -transmute_cf_dib_to_image_bmp (const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length, - GDestroyNotify *set_data_destroy) -{ - /* Need to add a BMP file header so gdk-pixbuf can load - * it. - * - * If the data is from Mozilla Firefox or IE7, and - * starts with an "old fashioned" BITMAPINFOHEADER, - * i.e. with biSize==40, and biCompression == BI_RGB and - * biBitCount==32, we assume that the "extra" byte in - * each pixel in fact is alpha. - * - * The gdk-pixbuf bmp loader doesn't trust 32-bit BI_RGB - * bitmaps to in fact have alpha, so we have to convince - * it by changing the bitmap header to a version 5 - * BI_BITFIELDS one with explicit alpha mask indicated. - * - * The RGB bytes that are in bitmaps on the clipboard - * originating from Firefox or IE7 seem to be - * premultiplied with alpha. The gdk-pixbuf bmp loader - * of course doesn't expect that, so we have to undo the - * premultiplication before feeding the bitmap to the - * bmp loader. - * - * Note that for some reason the bmp loader used to want - * the alpha bytes in its input to actually be - * 255-alpha, but here we assume that this has been - * fixed before this is committed. - */ - BITMAPINFOHEADER *bi = (BITMAPINFOHEADER *) data; - BITMAPFILEHEADER *bf; - gpointer result; - gint data_length = length; - gint new_length; - gboolean make_dibv5 = FALSE; - BITMAPV5HEADER *bV5; - guchar *p; - guint i; - - if (bi->biSize == sizeof (BITMAPINFOHEADER) && - bi->biPlanes == 1 && - bi->biBitCount == 32 && - bi->biCompression == BI_RGB && -#if 0 - /* Maybe check explicitly for Mozilla or IE7? - * - * If the clipboard format - * application/x-moz-nativeimage is present, that is - * a reliable indicator that the data is offered by - * Mozilla one would think. For IE7, - * UniformResourceLocatorW is presumably not that - * uniqie, so probably need to do some - * GetClipboardOwner(), GetWindowThreadProcessId(), - * OpenProcess(), GetModuleFileNameEx() dance to - * check? - */ - (IsClipboardFormatAvailable - (RegisterClipboardFormatA ("application/x-moz-nativeimage")) || - IsClipboardFormatAvailable - (RegisterClipboardFormatA ("UniformResourceLocatorW"))) && -#endif - TRUE) - { - /* We turn the BITMAPINFOHEADER into a - * BITMAPV5HEADER before feeding it to gdk-pixbuf. - */ - new_length = (data_length + - sizeof (BITMAPFILEHEADER) + - (sizeof (BITMAPV5HEADER) - sizeof (BITMAPINFOHEADER))); - make_dibv5 = TRUE; - } - else - { - new_length = data_length + sizeof (BITMAPFILEHEADER); - } - - result = g_try_malloc (new_length); - - if (result == NULL) - return; - - bf = (BITMAPFILEHEADER *) result; - bf->bfType = 0x4d42; /* "BM" */ - bf->bfSize = new_length; - bf->bfReserved1 = 0; - bf->bfReserved2 = 0; - - *set_data = result; - - if (set_data_length) - *set_data_length = new_length; - if (set_data_destroy) - *set_data_destroy = g_free; - - if (!make_dibv5) - { - bf->bfOffBits = (sizeof (BITMAPFILEHEADER) + - bi->biSize + - bi->biClrUsed * sizeof (RGBQUAD)); - - if (bi->biCompression == BI_BITFIELDS && bi->biBitCount >= 16) - { - /* Screenshots taken with PrintScreen or - * Alt + PrintScreen are found on the clipboard in - * this format. In this case the BITMAPINFOHEADER is - * followed by three DWORD specifying the masks of the - * red green and blue components, so adjust the offset - * accordingly. */ - bf->bfOffBits += (3 * sizeof (DWORD)); - } - - memcpy ((char *) result + sizeof (BITMAPFILEHEADER), - bi, - data_length); - - return; - } - - bV5 = (BITMAPV5HEADER *) ((char *) result + sizeof (BITMAPFILEHEADER)); - - bV5->bV5Size = sizeof (BITMAPV5HEADER); - bV5->bV5Width = bi->biWidth; - bV5->bV5Height = bi->biHeight; - bV5->bV5Planes = 1; - bV5->bV5BitCount = 32; - bV5->bV5Compression = BI_BITFIELDS; - bV5->bV5SizeImage = 4 * bV5->bV5Width * ABS (bV5->bV5Height); - bV5->bV5XPelsPerMeter = bi->biXPelsPerMeter; - bV5->bV5YPelsPerMeter = bi->biYPelsPerMeter; - bV5->bV5ClrUsed = 0; - bV5->bV5ClrImportant = 0; - /* Now the added mask fields */ - bV5->bV5RedMask = 0x00ff0000; - bV5->bV5GreenMask = 0x0000ff00; - bV5->bV5BlueMask = 0x000000ff; - bV5->bV5AlphaMask = 0xff000000; - ((char *) &bV5->bV5CSType)[3] = 's'; - ((char *) &bV5->bV5CSType)[2] = 'R'; - ((char *) &bV5->bV5CSType)[1] = 'G'; - ((char *) &bV5->bV5CSType)[0] = 'B'; - /* Ignore colorspace and profile fields */ - bV5->bV5Intent = LCS_GM_GRAPHICS; - bV5->bV5Reserved = 0; - - bf->bfOffBits = (sizeof (BITMAPFILEHEADER) + - bV5->bV5Size); - - p = ((guchar *) result) + sizeof (BITMAPFILEHEADER) + sizeof (BITMAPV5HEADER); - memcpy (p, ((char *) bi) + bi->biSize, - data_length - sizeof (BITMAPINFOHEADER)); - - for (i = 0; i < bV5->bV5SizeImage/4; i++) - { - if (p[3] != 0) - { - gdouble inverse_alpha = 255./p[3]; - - p[0] = p[0] * inverse_alpha + 0.5; - p[1] = p[1] * inverse_alpha + 0.5; - p[2] = p[2] * inverse_alpha + 0.5; - } - - p += 4; - } -} - -static void -transmute_cf_shell_id_list_to_text_uri_list (const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length, - GDestroyNotify *set_data_destroy) -{ - guint i; - CIDA *cida = (CIDA *) data; - guint number_of_ids = cida->cidl; - GString *result = g_string_new (NULL); - PCIDLIST_ABSOLUTE folder_id = HIDA_GetPIDLFolder (cida); - wchar_t path_w[MAX_PATH + 1]; - - for (i = 0; i < number_of_ids; i++) - { - PCUIDLIST_RELATIVE file_id = HIDA_GetPIDLItem (cida, i); - PIDLIST_ABSOLUTE file_id_full = ILCombine (folder_id, file_id); - - if (SHGetPathFromIDListW (file_id_full, path_w)) - { - gchar *filename = g_utf16_to_utf8 (path_w, -1, NULL, NULL, NULL); - - if (filename) - { - gchar *uri = g_filename_to_uri (filename, NULL, NULL); - - if (uri) - { - g_string_append (result, uri); - g_string_append (result, "\r\n"); - g_free (uri); - } - - g_free (filename); - } - } - - ILFree (file_id_full); - } - - *set_data = (guchar *) result->str; - if (set_data_length) - *set_data_length = result->len; - if (set_data_destroy) - *set_data_destroy = g_free; - - g_string_free (result, FALSE); -} - -void -transmute_image_bmp_to_cf_dib (const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length, - GDestroyNotify *set_data_destroy) -{ - gint size; - guchar *ptr; - - g_return_if_fail (length >= sizeof (BITMAPFILEHEADER)); - - /* No conversion is needed, just strip the BITMAPFILEHEADER */ - size = length - sizeof (BITMAPFILEHEADER); - ptr = g_malloc (size); - - memcpy (ptr, data + sizeof (BITMAPFILEHEADER), size); - - *set_data = ptr; - - if (set_data_length) - *set_data_length = size; - if (set_data_destroy) - *set_data_destroy = g_free; -} - -static void -transmute_selection_format (UINT from_format, - GdkAtom to_target, - const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length) -{ - if ((to_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_PNG) && - from_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_PNG)) || - (to_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_JPEG) && - from_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_JFIF)) || - (to_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_GIF) && - from_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_GIF))) - { - /* No transmutation needed */ - *set_data = g_memdup (data, length); - *set_data_length = length; - } - else if (to_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_UTF8_STRING) && - from_format == CF_UNICODETEXT) - { - transmute_cf_unicodetext_to_utf8_string (data, length, set_data, set_data_length, NULL); - } - else if (to_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_UTF8_STRING) && - from_format == CF_TEXT) - { - transmute_cf_text_to_utf8_string (data, length, set_data, set_data_length, NULL); - } - else if (to_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_BMP) && - (from_format == CF_DIB || from_format == CF_DIBV5)) - { - transmute_cf_dib_to_image_bmp (data, length, set_data, set_data_length, NULL); - } - else if (to_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST) && - from_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST)) - { - transmute_cf_shell_id_list_to_text_uri_list (data, length, set_data, set_data_length, NULL); - } - else - { - g_warning ("Don't know how to transmute format 0x%x to target 0x%p", from_format, to_target); - } -} - -void -transmute_selection_target (GdkAtom from_target, - UINT to_format, - const guchar *data, - gint length, - guchar **set_data, - gint *set_data_length) -{ - if ((from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_PNG) && - to_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_PNG)) || - (from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_JPEG) && - to_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_JFIF)) || - (from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_GIF) && - to_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_GIF))) - { - /* No conversion needed */ - *set_data = g_memdup (data, length); - *set_data_length = length; - } - else if (from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_UTF8_STRING) && - to_format == CF_UNICODETEXT) - { - transmute_utf8_string_to_cf_unicodetext (data, length, set_data, set_data_length, NULL); - } - else if (from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_UTF8_STRING) && - to_format == CF_TEXT) - { - transmute_utf8_string_to_cf_text (data, length, set_data, set_data_length, NULL); - } - else if (from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_BMP) && - to_format == CF_DIB) - { - transmute_image_bmp_to_cf_dib (data, length, set_data, set_data_length, NULL); - } - else if (from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_IMAGE_BMP) && - to_format == CF_DIBV5) - { - transmute_image_bmp_to_cf_dib (data, length, set_data, set_data_length, NULL); - } -/* - else if (from_target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST) && - to_format == _gdk_win32_selection_cf (GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST)) - { - transmute_text_uri_list_to_shell_id_list (data, length, set_data, set_data_length, NULL); - } -*/ - else - { - g_warning ("Don't know how to transmute from target 0x%p to format 0x%x", from_target, to_format); - } -} - -static GdkAtom -convert_clipboard_selection_to_targets_target (GdkSurface *requestor) -{ - gint fmt; - int i; - int format_count = CountClipboardFormats (); - GArray *targets = g_array_sized_new (FALSE, FALSE, sizeof (GdkSelTargetFormat), format_count); - - for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); ) - _gdk_win32_add_format_to_targets (fmt, targets, NULL); - - GDK_NOTE (DND, { - g_print ("... "); - for (i = 0; i < targets->len; i++) - { - const char *atom_name = (const char *)g_array_index (targets, GdkSelTargetFormat, i).target; - - g_print ("%s", atom_name); - if (i < targets->len - 1) - g_print (", "); - } - g_print ("\n"); - }); - - if (targets->len > 0) - { - gint len = targets->len; - GdkAtom *targets_only = g_new0 (GdkAtom, len); - - for (i = 0; i < targets->len; i++) - targets_only[i] = g_array_index (targets, GdkSelTargetFormat, i).target; - - g_array_free (targets, TRUE); - selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM, - 32, (guchar *) targets_only, - len * sizeof (GdkAtom)); - return _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_GDK_SELECTION); - } - else - { - g_array_free (targets, TRUE); - return NULL; - } -} - -static GdkAtom -convert_clipboard_selection_to_target (GdkSurface *requestor, - GdkAtom target) -{ - UINT format; - HANDLE hdata; - guchar *ptr; - gint length; - gboolean transmute = FALSE; - GdkAtom result = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_GDK_SELECTION); - gboolean found; - const char *atom_name; - - atom_name = (const char *)target; - - for (format = 0, found = FALSE; - !found && 0 != (format = EnumClipboardFormats (format)); - ) - { - gboolean predef; - gchar *format_name = _gdk_win32_get_clipboard_format_name (format, &predef); - - if (format_name == NULL) - continue; - - found = g_strcmp0 (format_name, atom_name) == 0; - g_free (format_name); - } - - if (format == 0) - { - gint i; - GArray *compat_formats = get_compatibility_formats_for_target (target); - - for (i = 0; compat_formats != NULL && i < compat_formats->len; i++) - { - if (!IsClipboardFormatAvailable (g_array_index (compat_formats, GdkSelTargetFormat, i).format)) - continue; - - format = g_array_index (compat_formats, GdkSelTargetFormat, i).format; - transmute = g_array_index (compat_formats, GdkSelTargetFormat, i).transmute; - break; - } - } - - if (format == 0) - return NULL; - - if ((hdata = GetClipboardData (format)) == NULL) - return NULL; - - if ((ptr = GlobalLock (hdata)) != NULL) - { - guchar *data = NULL; - gint data_len = 0; - length = GlobalSize (hdata); - - GDK_NOTE (DND, g_print ("... format 0x%x: %d bytes\n", format, length)); - - if (transmute) - { - transmute_selection_format (format, target, ptr, length, &data, &data_len); - } - else - { - data = g_memdup (ptr, length); - data_len = length; - } - - if (data) - selection_property_store (requestor, target, - 8, data, data_len); - else - result = NULL; - - GlobalUnlock (hdata); - } - - return result; -} - -static GdkAtom -convert_selection_with_opened_clipboard (GdkDisplay *display, - GdkSurface *requestor, - GdkAtom target, - guint32 time) -{ - GdkAtom property; - - if (target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TARGETS)) - property = convert_clipboard_selection_to_targets_target (requestor); - else - property = convert_clipboard_selection_to_target (requestor, target); - - return property; -} - -static void -announce_delayrendered_targets_with_opened_clipboard (GdkWin32Selection *win32_sel) -{ - gint i; - /* Announce the formats we support, but don't actually put any data out there. - * Other processes will send us WM_RENDERFORMAT to get the data. - */ - for (i = 0; i < win32_sel->clipboard_selection_targets->len; i++) - { - GdkSelTargetFormat *fmt = &g_array_index (win32_sel->clipboard_selection_targets, GdkSelTargetFormat, i); - - /* Some calls here may be duplicates, but we don't really care */ - if (fmt->format != 0) - SetClipboardData (fmt->format, NULL); - } -} - -static gboolean -open_clipboard_timeout (gpointer data) -{ - GList *tmp_list, *next; - GdkWin32ClipboardQueueInfo *info; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - GDK_NOTE (DND, g_print ("Open clipboard timeout ticks\n")); - - /* Clear out old and invalid entries */ - for (tmp_list = clipboard_queue; tmp_list; tmp_list = next) - { - info = (GdkWin32ClipboardQueueInfo *) tmp_list->data; - next = g_list_next (tmp_list); - - if (GDK_SURFACE_DESTROYED (info->requestor) || - info->idle_time >= CLIPBOARD_IDLE_ABORT_TIME) - { - clipboard_queue = g_list_remove_link (clipboard_queue, tmp_list); - g_list_free (tmp_list); - switch (info->action) - { - case GDK_WIN32_CLIPBOARD_QUEUE_ACTION_TARGETS: - break; - case GDK_WIN32_CLIPBOARD_QUEUE_ACTION_CONVERT: - generate_selection_notify (info->requestor, info->selection, info->target, NULL, info->time); - break; - } - g_clear_object (&info->requestor); - g_slice_free (GdkWin32ClipboardQueueInfo, info); - } - } - - if (clipboard_queue == NULL) - { - GDK_NOTE (DND, g_print ("Stopping open clipboard timer\n")); - - if (win32_sel->clipboard_opened_for != INVALID_HANDLE_VALUE) - { - API_CALL (CloseClipboard, ()); - win32_sel->clipboard_opened_for = INVALID_HANDLE_VALUE; - GDK_NOTE (DND, g_print ("Closed clipboard @ %s:%d\n", __FILE__, __LINE__)); - } - - return FALSE; - } - - for (tmp_list = clipboard_queue; tmp_list; tmp_list = next) - { - GdkAtom property; - - info = (GdkWin32ClipboardQueueInfo *) tmp_list->data; - next = g_list_next (tmp_list); - - /* CONVERT works with any opened clipboard, - * but TARGETS needs to open the clipboard with the hande of the - * owner window. - */ - if (info->action == GDK_WIN32_CLIPBOARD_QUEUE_ACTION_TARGETS && - win32_sel->clipboard_opened_for == NULL) - { - GDK_NOTE (DND, g_print ("Need to re-open clipboard, closing\n")); - API_CALL (CloseClipboard, ()); - win32_sel->clipboard_opened_for = INVALID_HANDLE_VALUE; - } - - if (win32_sel->clipboard_opened_for == INVALID_HANDLE_VALUE) - { - if (!OpenClipboard (GDK_SURFACE_HWND (info->requestor))) - { - info->idle_time += 1; - continue; - } - win32_sel->clipboard_opened_for = GDK_SURFACE_HWND (info->requestor); - GDK_NOTE (DND, g_print ("Opened clipboard for 0x%p @ %s:%d\n", win32_sel->clipboard_opened_for, __FILE__, __LINE__)); - } - - clipboard_queue = g_list_remove_link (clipboard_queue, tmp_list); - g_list_free (tmp_list); - - switch (info->action) - { - case GDK_WIN32_CLIPBOARD_QUEUE_ACTION_CONVERT: - property = convert_selection_with_opened_clipboard (info->display, - info->requestor, - info->target, - info->time); - generate_selection_notify (info->requestor, - GDK_SELECTION_CLIPBOARD, - info->target, - property, - info->time); - break; - case GDK_WIN32_CLIPBOARD_QUEUE_ACTION_TARGETS: - announce_delayrendered_targets_with_opened_clipboard (win32_sel); - break; - default: - g_assert_not_reached (); - } - - g_clear_object (&info->requestor); - g_slice_free (GdkWin32ClipboardQueueInfo, info); - } - - if (clipboard_queue != NULL) - return TRUE; - - if (win32_sel->clipboard_opened_for != INVALID_HANDLE_VALUE) - { - API_CALL (CloseClipboard, ()); - win32_sel->clipboard_opened_for = INVALID_HANDLE_VALUE; - GDK_NOTE (DND, g_print ("Closed clipboard @ %s:%d\n", __FILE__, __LINE__)); - } - - GDK_NOTE (DND, g_print ("Stopping open clipboard timer\n")); - - return FALSE; -} - -static void -queue_open_clipboard (GdkWin32ClipboardQueueAction action, - GdkDisplay *display, - GdkSurface *requestor, - GdkAtom target, - guint32 time) -{ - guint id; - GList *tmp_list, *next; - GdkWin32ClipboardQueueInfo *info; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - for (tmp_list = clipboard_queue; tmp_list; tmp_list = next) - { - info = (GdkWin32ClipboardQueueInfo *) tmp_list->data; - next = g_list_next (tmp_list); - - if (info->action == action && - info->requestor == requestor) - return; - } - - info = g_slice_new (GdkWin32ClipboardQueueInfo); - - info->display = display; - g_set_object (&info->requestor, requestor); - info->selection = GDK_SELECTION_CLIPBOARD; - info->target = target; - info->idle_time = 0; - info->time = time; - info->action = action; - - GDK_NOTE (DND, g_print ("Queueing open clipboard\n")); - - if (win32_sel->clipboard_opened_for == INVALID_HANDLE_VALUE && - clipboard_queue == NULL) - { - id = g_timeout_add_seconds (1, (GSourceFunc) open_clipboard_timeout, NULL); - g_source_set_name_by_id (id, "[gdk-win32] open_clipboard_timeout"); - GDK_NOTE (DND, g_print ("Started open clipboard timer\n")); - } - - clipboard_queue = g_list_append (clipboard_queue, info); -} - -gboolean -_gdk_win32_display_set_selection_owner (GdkDisplay *display, - GdkSurface *owner, - GdkAtom selection, - guint32 time, - gboolean send_event) -{ - HWND hwnd; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - g_return_val_if_fail (selection != NULL, FALSE); - - GDK_NOTE (DND, { - const char *sel_name = (const char *)selection; - - g_print ("gdk_selection_owner_set_for_display: %p %s\n", - (owner ? GDK_SURFACE_HWND (owner) : NULL), - sel_name); - }); - - if (selection != GDK_SELECTION_CLIPBOARD) - { - if (owner != NULL) - g_hash_table_insert (win32_sel->sel_owner_table, selection, GDK_SURFACE_HWND (owner)); - else - g_hash_table_remove (win32_sel->sel_owner_table, selection); - - return TRUE; - } - - /* Rest of this function handles the CLIPBOARD selection */ - if (owner != NULL) - { - if (GDK_SURFACE_DESTROYED (owner)) - return FALSE; - - hwnd = GDK_SURFACE_HWND (owner); - } - else - hwnd = NULL; - - if (win32_sel->clipboard_opened_for != hwnd && - win32_sel->clipboard_opened_for != INVALID_HANDLE_VALUE) - { - API_CALL (CloseClipboard, ()); - win32_sel->clipboard_opened_for = INVALID_HANDLE_VALUE; - GDK_NOTE (DND, g_print ("Closed clipboard @ %s:%d\n", __FILE__, __LINE__)); - } - - if (!OpenClipboard (hwnd)) - { - if (GetLastError () != ERROR_ACCESS_DENIED) - WIN32_API_FAILED ("OpenClipboard"); - - return FALSE; - } - - win32_sel->clipboard_opened_for = hwnd; - GDK_NOTE (DND, g_print ("Opened clipboard for 0x%p @ %s:%d\n", win32_sel->clipboard_opened_for, __FILE__, __LINE__)); - win32_sel->ignore_destroy_clipboard = TRUE; - GDK_NOTE (DND, g_print ("... EmptyClipboard()\n")); - if (!API_CALL (EmptyClipboard, ())) - { - win32_sel->ignore_destroy_clipboard = FALSE; - API_CALL (CloseClipboard, ()); - win32_sel->clipboard_opened_for = INVALID_HANDLE_VALUE; - GDK_NOTE (DND, g_print ("Closed clipboard @ %s:%d\n", __FILE__, __LINE__)); - return FALSE; - } - win32_sel->ignore_destroy_clipboard = FALSE; - - /* Any queued clipboard operations were just made pointless - * by EmptyClipboard(). - */ - _gdk_win32_clear_clipboard_queue (); - - /* This is kind of risky, but we don't close the clipboard - * to ensure that it's still open when GDK_SELECTION_REQUEST - * is handled. - */ - if (owner == NULL) - { - if (!API_CALL (CloseClipboard, ())) - return FALSE; - GDK_NOTE (DND, g_print ("Closed clipboard @ %s:%d\n", __FILE__, __LINE__)); - win32_sel->clipboard_opened_for = INVALID_HANDLE_VALUE; - } - - send_targets_request (time); - - return TRUE; -} - -GdkSurface* -_gdk_win32_display_get_selection_owner (GdkDisplay *display, - GdkAtom selection) -{ - GdkSurface *window; - HWND selection_owner; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - g_return_val_if_fail (selection != NULL, NULL); - - if (selection == GDK_SELECTION_CLIPBOARD) - selection_owner = GetClipboardOwner (); - else - selection_owner = g_hash_table_lookup (win32_sel->sel_owner_table, selection); - - if (selection_owner) - window = gdk_win32_surface_lookup_for_display (display, - selection_owner); - else - window = NULL; - - GDK_NOTE (DND, { - const char *sel_name = (const char *)selection; - - g_print ("gdk_selection_owner_get: %s = %p\n", - sel_name, - (window ? GDK_SURFACE_HWND (window) : NULL)); - }); - - return window; -} - -static GdkAtom -convert_dnd_selection_to_target (GdkAtom target, - GdkSurface *requestor) -{ - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - UINT format; - gint i, with_transmute; - guchar *ptr; - gint length; - gboolean transmute = FALSE; - GdkWin32DragContext *context_win32; - FORMATETC fmt; - STGMEDIUM storage; - HRESULT hr; - GdkAtom result = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND); - - g_assert (win32_sel->target_drag_context != NULL); - g_assert (win32_sel->dnd_data_object_target != NULL); - - context_win32 = GDK_WIN32_DRAG_CONTEXT (win32_sel->target_drag_context); - - fmt.ptd = NULL; - fmt.dwAspect = DVASPECT_CONTENT; - fmt.lindex = -1; - fmt.tymed = TYMED_HGLOBAL; - - /* We rely on GTK+ applications to synthesize the DELETE request - * for themselves, since they do know whether a DnD operation was a - * move and whether was successful. Therefore, we do not need to - * actually send anything here. Just report back without storing - * any data. - */ - if (target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_DELETE)) - return result; - - for (format = 0, with_transmute = 0; format == 0 && with_transmute < 2; with_transmute++) - { - for (i = 0; - i < context_win32->droptarget_format_target_map->len; - i++) - { - GdkSelTargetFormat selformat = g_array_index (context_win32->droptarget_format_target_map, GdkSelTargetFormat, i); - - if (selformat.target != target || - selformat.transmute != (with_transmute == 0 ? FALSE : TRUE)) - continue; - - fmt.cfFormat = selformat.format; - - hr = IDataObject_QueryGetData (win32_sel->dnd_data_object_target, &fmt); - - if (!SUCCEEDED (hr) || hr != S_OK) - continue; - - format = selformat.format; - transmute = selformat.transmute; - break; - } - } - - if (format == 0) - return NULL; - - hr = IDataObject_GetData (win32_sel->dnd_data_object_target, &fmt, &storage); - - if (!SUCCEEDED (hr) || hr != S_OK) - return NULL; - - if ((ptr = GlobalLock (storage.hGlobal)) != NULL) - { - guchar *data = NULL; - gint data_len = 0; - - SetLastError (0); - length = GlobalSize (storage.hGlobal); - - if (GetLastError () == NO_ERROR) - { - if (transmute) - { - transmute_selection_format (format, target, ptr, length, &data, &data_len); - } - else - { - data = g_memdup (ptr, length); - data_len = length; - } - - if (data) - selection_property_store (requestor, target, 8, - data, data_len); - else - result = NULL; - } - else - result = NULL; - - GlobalUnlock (storage.hGlobal); - } - else - result = NULL; - - ReleaseStgMedium (&storage); - - return result; -} - -void -_gdk_win32_display_convert_selection (GdkDisplay *display, - GdkSurface *requestor, - GdkAtom selection, - GdkAtom target, - guint32 time) -{ - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - GdkAtom property = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_GDK_SELECTION); - - g_return_if_fail (selection != NULL); - g_return_if_fail (requestor != NULL); - - if (GDK_SURFACE_DESTROYED (requestor)) - return; - - GDK_NOTE (DND, { - const char *sel_name = (const char *)selection; - const char *tgt_name = (const char *)target; - - g_print ("gdk_selection_convert: %p %s %s\n", - GDK_SURFACE_HWND (requestor), - sel_name, tgt_name); - }); - - if (selection == GDK_SELECTION_CLIPBOARD) - { - if (win32_sel->clipboard_opened_for != INVALID_HANDLE_VALUE || - OpenClipboard (GDK_SURFACE_HWND (requestor))) - { - if (win32_sel->clipboard_opened_for == INVALID_HANDLE_VALUE) - { - win32_sel->clipboard_opened_for = GDK_SURFACE_HWND (requestor); - GDK_NOTE (DND, g_print ("Opened clipboard for 0x%p @ %s:%d\n", win32_sel->clipboard_opened_for, __FILE__, __LINE__)); - } - - queue_open_clipboard (GDK_WIN32_CLIPBOARD_QUEUE_ACTION_CONVERT, display, requestor, target, time); - open_clipboard_timeout (NULL); - } - else - { - queue_open_clipboard (GDK_WIN32_CLIPBOARD_QUEUE_ACTION_CONVERT, display, requestor, target, time); - /* Do not generate a selection notify message */ - return; - } - } - else if (selection == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_DROPFILES_DND)) - { - /* This means he wants the names of the dropped files. - * gdk_dropfiles_filter already has stored the text/uri-list - * data temporarily in dropfiles_prop. - */ - if (win32_sel->dropfiles_prop != NULL) - { - selection_property_store - (requestor, win32_sel->dropfiles_prop->target, win32_sel->dropfiles_prop->bitness, - win32_sel->dropfiles_prop->data, win32_sel->dropfiles_prop->length); - g_clear_pointer (&win32_sel->dropfiles_prop, g_free); - } - } - else if (selection == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND)) - { - property = convert_dnd_selection_to_target (target, requestor); - } - else - property = NULL; - - /* Generate a selection notify message so that we actually fetch the - * data (if property == GDK_SELECTION) or indicating failure (if - * property == NULL). - */ - generate_selection_notify (requestor, selection, target, property, time); -} - -void -_gdk_win32_selection_property_change (GdkWin32Selection *win32_sel, - GdkSurface *window, - GdkAtom property, - GdkAtom type, - gint format, - GdkPropMode mode, - const guchar *data, - gint nelements) -{ - if (property == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_GDK_SELECTION) && - win32_sel->property_change_target_atom == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TARGETS)) - { - win32_sel->property_change_target_atom = 0; - - if (win32_sel->clipboard_opened_for == INVALID_HANDLE_VALUE && - OpenClipboard (GDK_SURFACE_HWND (window))) - { - win32_sel->clipboard_opened_for = GDK_SURFACE_HWND (window); - GDK_NOTE (DND, g_print ("Opened clipboard for 0x%p @ %s:%d\n", win32_sel->clipboard_opened_for, __FILE__, __LINE__)); - } - - if (win32_sel->clipboard_opened_for == INVALID_HANDLE_VALUE) - { - queue_open_clipboard (GDK_WIN32_CLIPBOARD_QUEUE_ACTION_TARGETS, NULL, window, type, GDK_CURRENT_TIME); - return; - } - else - { - queue_open_clipboard (GDK_WIN32_CLIPBOARD_QUEUE_ACTION_TARGETS, NULL, window, type, GDK_CURRENT_TIME); - open_clipboard_timeout (NULL); - } - } - else if (property == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND) && - mode == GDK_PROP_MODE_REPLACE && - win32_sel->property_change_target_atom == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_DELETE)) - { - /* no-op on Windows */ - win32_sel->property_change_target_atom = 0; - } - else if (mode == GDK_PROP_MODE_REPLACE && - (win32_sel->property_change_target_atom == 0 || - win32_sel->property_change_data == NULL || - win32_sel->property_change_format == 0)) - { - g_warning ("Setting selection property with 0x%p == NULL or 0x%x == 0 or 0x%p == 0", - win32_sel->property_change_data, - win32_sel->property_change_format, - win32_sel->property_change_target_atom); - } - else if (mode == GDK_PROP_MODE_REPLACE && - win32_sel->property_change_data != NULL && - win32_sel->property_change_format != 0) - { - guchar *set_data = NULL; - gint set_data_length = 0; - gint byte_length = format / 8 * nelements; - - if (win32_sel->property_change_transmute) - transmute_selection_target (type, - win32_sel->property_change_format, - data, - byte_length, - &set_data, - &set_data_length); - else - { - set_data_length = byte_length; - set_data = g_memdup (data, set_data_length); - } - - if (set_data != NULL && set_data_length > 0) - { - HGLOBAL hdata; - - if ((hdata = GlobalAlloc (GMEM_MOVEABLE, set_data_length)) != 0) - { - gchar *ucptr; - win32_sel->property_change_data->tymed = TYMED_HGLOBAL; - win32_sel->property_change_data->pUnkForRelease = NULL; - win32_sel->property_change_data->hGlobal = hdata; - ucptr = GlobalLock (hdata); - memcpy (ucptr, set_data, set_data_length); - GlobalUnlock (hdata); - } - else - { - WIN32_API_FAILED ("GlobalAlloc"); - } - - g_free (set_data); - } - - win32_sel->property_change_format = 0; - win32_sel->property_change_data = 0; - win32_sel->property_change_target_atom = 0; - } - else - { - const char *prop_name = (const char *)property; - const char *type_name = (const char *)type; - gchar *datastring = _gdk_win32_data_to_string (data, MIN (10, format*nelements/8)); - - g_warning ("Unsupported property change on window 0x%p, %s property %s, %d-bit, target 0x%x of %d bytes: %s", - window, - (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" : - (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" : - (mode == GDK_PROP_MODE_APPEND ? "APPEND" : - "???"))), - prop_name, - format, - type_name, - nelements, - datastring); - g_free (datastring); - } -} - -gint -_gdk_win32_display_get_selection_property (GdkDisplay *display, - GdkSurface *requestor, - guchar **data, - GdkAtom *ret_type, - gint *ret_format) -{ - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - GdkSelProp *prop; - - g_return_val_if_fail (requestor != NULL, 0); - g_return_val_if_fail (GDK_IS_SURFACE (requestor), 0); - - if (GDK_SURFACE_DESTROYED (requestor)) - return 0; - - GDK_NOTE (DND, g_print ("gdk_selection_property_get: %p", - GDK_SURFACE_HWND (requestor))); - - prop = g_hash_table_lookup (win32_sel->sel_prop_table, GDK_SURFACE_HWND (requestor)); - - if (prop == NULL) - { - GDK_NOTE (DND, g_print (" (nothing)\n")); - *data = NULL; - - return 0; - } - - *data = g_malloc (prop->length + 1); - (*data)[prop->length] = '\0'; - if (prop->length > 0) - memmove (*data, prop->data, prop->length); - - GDK_NOTE (DND, { - const char *type_name = (const char *)prop->target; - - g_print (" %s format:%d length:%"G_GSIZE_FORMAT"\n", type_name, prop->bitness, prop->length); - g_free (type_name); - }); - - if (ret_type) - *ret_type = prop->target; - - if (ret_format) - *ret_format = prop->bitness; - - return prop->length; -} - -void -_gdk_selection_property_delete (GdkSurface *window) -{ - GDK_NOTE (DND, g_print ("_gdk_selection_property_delete: %p (no-op)\n", - GDK_SURFACE_HWND (window))); - -#if 0 - prop = g_hash_table_lookup (sel_prop_table, GDK_SURFACE_HWND (window)); - if (prop != NULL) - { - g_free (prop->data); - g_free (prop); - g_hash_table_remove (sel_prop_table, GDK_SURFACE_HWND (window)); - } -#endif -} - -void -_gdk_win32_display_send_selection_notify (GdkDisplay *display, - GdkSurface *requestor, - GdkAtom selection, - GdkAtom target, - GdkAtom property, - guint32 time) -{ - GDK_NOTE (DND, { - const char *sel_name = (const char *)selection; - const char *tgt_name = (const char *)target; - const char *prop_name = (const char *)property; - - g_print ("gdk_selection_send_notify_for_display: %p %s %s %s (no-op)\n", - requestor, sel_name, tgt_name, prop_name); - }); -} - -/* It's hard to say whether implementing this actually is of any use - * on the Win32 platform? gtk calls only - * gdk_text_property_to_utf8_list_for_display(). - */ -gint -gdk_text_property_to_text_list_for_display (GdkDisplay *display, - GdkAtom encoding, - gint format, - const guchar *text, - gint length, - gchar ***list) -{ - gchar *result; - const gchar *charset; - gchar *source_charset; - - GDK_NOTE (DND, { - const char *enc_name = (const char *)encoding; - - g_print ("gdk_text_property_to_text_list_for_display: %s %d %.20s %d\n", - enc_name, format, text, length); - }); - - if (!list) - return 0; - - if (encoding == g_intern_static_string ("STRING")) - source_charset = g_strdup ("ISO-8859-1"); - else if (encoding == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_UTF8_STRING)) - source_charset = g_strdup ("UTF-8"); - else - source_charset = g_strdup ((const char *)encoding); - - g_get_charset (&charset); - - result = g_convert ((const gchar *) text, length, charset, source_charset, - NULL, NULL, NULL); - g_free (source_charset); - - if (!result) - return 0; - - *list = g_new (gchar *, 1); - **list = result; - - return 1; -} - -void -gdk_free_text_list (gchar **list) -{ - g_return_if_fail (list != NULL); - - g_free (*list); - g_free (list); -} - -static gint -make_list (const gchar *text, - gint length, - gboolean latin1, - gchar ***list) -{ - GSList *strings = NULL; - gint n_strings = 0; - gint i; - const gchar *p = text; - const gchar *q; - GSList *tmp_list; - GError *error = NULL; - - while (p < text + length) - { - gchar *str; - - q = p; - while (*q && q < text + length) - q++; - - if (latin1) - { - str = g_convert (p, q - p, - "UTF-8", "ISO-8859-1", - NULL, NULL, &error); - - if (!str) - { - g_warning ("Error converting selection from STRING: %s", - error->message); - g_error_free (error); - } - } - else - str = g_strndup (p, q - p); - - if (str) - { - strings = g_slist_prepend (strings, str); - n_strings++; - } - - p = q + 1; - } - - if (list) - *list = g_new (gchar *, n_strings + 1); - - (*list)[n_strings] = NULL; - - i = n_strings; - tmp_list = strings; - while (tmp_list) - { - if (list) - (*list)[--i] = tmp_list->data; - else - g_free (tmp_list->data); - - tmp_list = tmp_list->next; - } - - g_slist_free (strings); - - return n_strings; -} - -gint -_gdk_win32_display_text_property_to_utf8_list (GdkDisplay *display, - GdkAtom encoding, - gint format, - const guchar *text, - gint length, - gchar ***list) -{ - g_return_val_if_fail (text != NULL, 0); - g_return_val_if_fail (length >= 0, 0); - - if (encoding == g_intern_static_string ("STRING")) - { - return make_list ((gchar *)text, length, TRUE, list); - } - else if (encoding == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_UTF8_STRING)) - { - return make_list ((gchar *)text, length, FALSE, list); - } - else - { - const char *enc_name = (const char *)encoding; - - g_warning ("gdk_text_property_to_utf8_list_for_display: encoding %s not handled\n", enc_name); - - if (list) - *list = NULL; - - return 0; - } -} - -gchar * -_gdk_win32_display_utf8_to_string_target (GdkDisplay *display, - const gchar *str) -{ - return _gdk_utf8_to_string_target_internal (str, strlen (str)); -} - -void -gdk_win32_selection_clear_targets (GdkDisplay *display, - GdkAtom selection) -{ - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - - if (selection == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND) || - selection == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_LOCAL_DND_SELECTION)) - { - g_array_set_size (win32_sel->dnd_selection_targets, 0); - } - else if (selection == GDK_SELECTION_CLIPBOARD) - { - g_array_set_size (win32_sel->clipboard_selection_targets, 0); - } - else if (selection == GDK_SELECTION_PRIMARY) - { - /* Do nothing */ - } - else - { - const char *sel_name = (const char *)selection; - - g_warning ("Unsupported generic selection %s (0x%p)", sel_name, selection); - } -} - -gint -_gdk_win32_add_target_to_selformats (GdkAtom target, - GArray *array) -{ - gint added_count = 0; - const char *target_name; - wchar_t *target_name_w; - GdkSelTargetFormat fmt; - gint i; - GArray *compatibility_formats; - gint starting_point; - - for (i = 0; i < array->len; i++) - if (g_array_index (array, GdkSelTargetFormat, i).target == target) - break; - - /* Don't put duplicates into the array */ - if (i < array->len) - return added_count; - - if (target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_TARGETS) || - target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_COMPOUND_TEXT) || target == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_SAVE_TARGETS)) - { - /* Add the "we don't really support transferring that to - * other processes" format, just to keep the taget around. - */ - fmt.target = target; - fmt.format = 0; - fmt.transmute = FALSE; - g_array_append_val (array, fmt); - added_count += 1; - return added_count; - } - - /* Only check the newly-added pairs for duplicates, - * all the ones that exist right now have different targets. - */ - starting_point = array->len; - - target_name = (const char *)target; - target_name_w = g_utf8_to_utf16 (target_name, -1, NULL, NULL, NULL); - - if (target_name_w == NULL) - return added_count; - - fmt.format = RegisterClipboardFormatW (target_name_w); - GDK_NOTE (DND, g_print ("Registered clipboard format %S as 0x%x\n", target_name_w, fmt.format)); - g_free (target_name_w); - fmt.target = target; - fmt.transmute = FALSE; - - /* Add the "as-is" format */ - g_array_append_val (array, fmt); - added_count += 1; - - compatibility_formats = get_compatibility_formats_for_target (target); - for (i = 0; compatibility_formats != NULL && i < compatibility_formats->len; i++) - { - gint j; - - fmt = g_array_index (compatibility_formats, GdkSelTargetFormat, i); - - /* Don't put duplicates into the array */ - for (j = starting_point; j < array->len; j++) - if (g_array_index (array, GdkSelTargetFormat, j).format == fmt.format) - break; - - if (j < array->len) - continue; - - /* Add a compatibility format */ - g_array_append_val (array, fmt); - added_count += 1; - } - - return added_count; -} - -/* This function is called from gtk_selection_add_target() and - * gtk_selection_add_targets() in gtkselection.c. It is this function - * that takes care of setting those clipboard formats for which we use - * delayed rendering (that is, all formats, as we use delayed rendering - * for everything). This function only registers the formats, but does - * not announce them as supported. That is handled as a special case - * in gdk_surface_property_change(). - * - * Implementation detail: - * This function will be called repeatedly, every time the PRIMARY selection changes. - * It will also be called immediately before the CLIPBOARD selection changes. - * We let GTK+ handle the PRIMARY selection internally and do nothing here - * (therefore it's not possible to middle-click-paste between processes, - * unless one process deliberately puts PRIMARY selection contents into - * CLIPBOARD selection, and the other process does paste on middle-click). - */ -void -gdk_win32_display_add_selection_targets (GdkDisplay *display, - GdkSurface *owner, - GdkAtom selection, - GdkAtom *targets, - guint ntargets) -{ - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - gint i; - - GDK_NOTE (DND, { - const char *sel_name = (const char *)selection; - - g_print ("gdk_win32_selection_add_targets: %p: %s: ", - owner ? GDK_SURFACE_HWND (owner) : NULL, - sel_name); - - for (i = 0; i < ntargets; i++) - { - const char *tgt_name = (const char *)targets[i]; - - g_print ("%s", tgt_name); - if (i < ntargets - 1) - g_print (", "); - } - g_print ("\n"); - }); - - if (selection == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND) || - selection == _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_LOCAL_DND_SELECTION) || - selection == GDK_SELECTION_CLIPBOARD) - { - GArray *fmts = NULL; - gint added_count = 0; - - if (selection == GDK_SELECTION_CLIPBOARD) - fmts = win32_sel->clipboard_selection_targets; - else - fmts = win32_sel->dnd_selection_targets; - - for (i = 0; i < ntargets; i++) - added_count += _gdk_win32_add_target_to_selformats (targets[i], fmts); - - /* Re-announce our list of supported formats */ - if (added_count > 0) - send_targets_request (GDK_CURRENT_TIME); - } - else if (selection == GDK_SELECTION_PRIMARY) - { - /* Do nothing */ - } - else - { - const char *sel_name = (const char *)selection; - - g_warning ("Unsupported generic selection %s (0x%p)", sel_name, selection); - } -} diff --git a/gdk/win32/gdkselection-win32.h b/gdk/win32/gdkselection-win32.h deleted file mode 100644 index bbd3a7cd85..0000000000 --- a/gdk/win32/gdkselection-win32.h +++ /dev/null @@ -1,230 +0,0 @@ -/* GDK - The GIMP Drawing Kit - * - * gdkselection-win32.h: Private Win32 specific selection object - * - * Copyright © 2017 LRN - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - */ - -#ifndef __GDK_SELECTION_WIN32_H__ -#define __GDK_SELECTION_WIN32_H__ - -G_BEGIN_DECLS - -#define _gdk_win32_selection_get() (_win32_selection) -#define _gdk_atom_array_index(a, i) (g_array_index (a, GdkAtom, i)) -#define _gdk_win32_selection_atom(i) (_gdk_atom_array_index (_gdk_win32_selection_get ()->known_atoms, i)) -#define _gdk_cf_array_index(a, i) (g_array_index (a, UINT, i)) -#define _gdk_win32_selection_cf(i) (_gdk_cf_array_index (_gdk_win32_selection_get ()->known_clipboard_formats, i)) - -/* Maps targets to formats or vice versa, depending on the - * semantics of the array that holds these. - * Also remembers whether the data needs to be transmuted. - */ -typedef struct { - gint format; - GdkAtom target; - gboolean transmute; -} GdkSelTargetFormat; - -/* We emulate the GDK_SELECTION window properties of windows (as used - * in the X11 backend) by using a hash table from window handles to - * GdkSelProp structs. - */ -typedef struct { - guchar *data; - gsize length; - gint bitness; - GdkAtom target; -} GdkSelProp; - -/* OLE-based DND state */ -typedef enum { - GDK_WIN32_DND_NONE, - GDK_WIN32_DND_PENDING, - GDK_WIN32_DND_DROPPED, - GDK_WIN32_DND_FAILED, - GDK_WIN32_DND_DRAGGING, -} GdkWin32DndState; - -enum _GdkWin32AtomIndex -{ -/* GdkAtoms: properties, targets and types */ - GDK_WIN32_ATOM_INDEX_GDK_SELECTION = 0, - GDK_WIN32_ATOM_INDEX_CLIPBOARD_MANAGER, - GDK_WIN32_ATOM_INDEX_WM_TRANSIENT_FOR, - GDK_WIN32_ATOM_INDEX_TARGETS, - GDK_WIN32_ATOM_INDEX_DELETE, - GDK_WIN32_ATOM_INDEX_SAVE_TARGETS, - GDK_WIN32_ATOM_INDEX_UTF8_STRING, - GDK_WIN32_ATOM_INDEX_TEXT, - GDK_WIN32_ATOM_INDEX_COMPOUND_TEXT, - GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST, - GDK_WIN32_ATOM_INDEX_TEXT_HTML, - GDK_WIN32_ATOM_INDEX_IMAGE_PNG, - GDK_WIN32_ATOM_INDEX_IMAGE_JPEG, - GDK_WIN32_ATOM_INDEX_IMAGE_BMP, - GDK_WIN32_ATOM_INDEX_IMAGE_GIF, -/* DND selections */ - GDK_WIN32_ATOM_INDEX_LOCAL_DND_SELECTION, - GDK_WIN32_ATOM_INDEX_DROPFILES_DND, - GDK_WIN32_ATOM_INDEX_OLE2_DND, -/* Clipboard formats */ - GDK_WIN32_ATOM_INDEX_PNG, - GDK_WIN32_ATOM_INDEX_JFIF, - GDK_WIN32_ATOM_INDEX_GIF, - GDK_WIN32_ATOM_INDEX_CF_DIB, - GDK_WIN32_ATOM_INDEX_CFSTR_SHELLIDLIST, - GDK_WIN32_ATOM_INDEX_CF_TEXT, - GDK_WIN32_ATOM_INDEX_CF_UNICODETEXT, - GDK_WIN32_ATOM_INDEX_LAST -}; - -typedef enum _GdkWin32AtomIndex GdkWin32AtomIndex; - -enum _GdkWin32CFIndex -{ - GDK_WIN32_CF_INDEX_PNG = 0, - GDK_WIN32_CF_INDEX_JFIF, - GDK_WIN32_CF_INDEX_GIF, - GDK_WIN32_CF_INDEX_UNIFORMRESOURCELOCATORW, - GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST, - GDK_WIN32_CF_INDEX_HTML_FORMAT, - GDK_WIN32_CF_INDEX_TEXT_HTML, - GDK_WIN32_CF_INDEX_IMAGE_PNG, - GDK_WIN32_CF_INDEX_IMAGE_JPEG, - GDK_WIN32_CF_INDEX_IMAGE_BMP, - GDK_WIN32_CF_INDEX_IMAGE_GIF, - GDK_WIN32_CF_INDEX_TEXT_URI_LIST, - GDK_WIN32_CF_INDEX_UTF8_STRING, - GDK_WIN32_CF_INDEX_LAST -}; - -typedef enum _GdkWin32CFIndex GdkWin32CFIndex; - -#define GDK_TYPE_WIN32_SELECTION (gdk_win32_selection_get_type ()) -#define GDK_WIN32_SELECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_WIN32_SELECTION, GdkWin32Selection)) -#define GDK_WIN32_SELECTION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_WIN32_SELECTION, GdkWin32SelectionClass)) -#define GDK_IS_WIN32_SELECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_WIN32_SELECTION)) -#define GDK_IS_WIN32_SELECTION_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_WIN32_SELECTION)) -#define GDK_WIN32_SELECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_WIN32_SELECTION, GdkWin32SelectionClass)) - -typedef struct _GdkWin32Selection GdkWin32Selection; -typedef struct _GdkWin32SelectionClass GdkWin32SelectionClass; - -/* This object is just a sink to hold all the selection- and dnd-related data - * that otherwise would be in global variables. - */ -struct _GdkWin32Selection -{ - GObject *parent_instance; - GHashTable *sel_prop_table; - GdkSelProp *dropfiles_prop; - /* We store the owner of each selection in this table. Obviously, this only - * is valid intra-app, and in fact it is necessary for the intra-app DND to work. - */ - GHashTable *sel_owner_table; - - /* GdkAtoms for well-known image formats */ - GdkAtom *known_pixbuf_formats; - int n_known_pixbuf_formats; - - /* GArray of GdkAtoms for various known Selection and DnD strings. - * Size is guaranteed to be at least GDK_WIN32_ATOM_INDEX_LAST - */ - GArray *known_atoms; - - /* GArray of UINTs for various known clipboard formats. - * Size is guaranteed to be at least GDK_WIN32_CF_INDEX_LAST. - */ - GArray *known_clipboard_formats; - - GdkWin32DndState dnd_target_state; - GdkWin32DndState dnd_source_state; - - /* Holds a reference to the data object for the target drop site. - */ - IDataObject *dnd_data_object_target; - - /* Carries DnD target context from idroptarget_*() to convert_selection() */ - GdkDragContext *target_drag_context; - - /* Carries W32 format ID from idataobject_getdata() to property_change() */ - UINT property_change_format; - /* Carries the W32-wrapped data between idataobject_getdata() and property_change() */ - LPSTGMEDIUM property_change_data; - /* Carries the transmute field of the GdkSelTargetFormat from from idataobject_getdata() to property_change() */ - gboolean property_change_transmute; - /* Carries the target atom from GDK_SELECTION_REQUEST issuer to property_change() */ - GdkAtom property_change_target_atom; - - /* TRUE when we are emptying the clipboard ourselves */ - gboolean ignore_destroy_clipboard; - - /* Array of GdkSelTargetFormats describing the targets supported by the clipboard selection */ - GArray *clipboard_selection_targets; - - /* Same for the DnD selection (applies for both LOCAL and OLE2 DnD) */ - GArray *dnd_selection_targets; - - /* If TRUE, then we queued a GDK_SELECTION_REQUEST with TARGETS - * target. This field is checked to prevent queueing - * multiple selection requests. - */ - gboolean targets_request_pending; - - /* The handle that was given to OpenClipboard(). - * NULL is a valid handle, - * INVALID_HANDLE_VALUE means that the clipboard is closed. - */ - HWND clipboard_opened_for; - - /* A target-keyed hash table of GArrays of GdkSelTargetFormats describing compatibility formats for a target */ - GHashTable *compatibility_formats; - /* A format-keyed hash table of GArrays of GdkAtoms describing compatibility targets for a format */ - GHashTable *compatibility_targets; - - /* Last observer owner of the clipboard, as reported by the OS. - * This is compared to GetClipboardOwner() return value to see - * whether the owner changed. - */ - HWND stored_hwnd_owner; -}; - -struct _GdkWin32SelectionClass -{ - GObjectClass parent_class; -}; - -GType gdk_win32_selection_get_type (void) G_GNUC_CONST; - -void _gdk_win32_clear_clipboard_queue (); -gchar * _gdk_win32_get_clipboard_format_name (UINT fmt, - gboolean *is_predefined); -void _gdk_win32_add_format_to_targets (UINT format, - GArray *array, - GList **list); -gint _gdk_win32_add_target_to_selformats (GdkAtom target, - GArray *array); -void _gdk_win32_selection_property_change (GdkWin32Selection *win32_sel, - GdkSurface *window, - GdkAtom property, - GdkAtom type, - gint format, - GdkPropMode mode, - const guchar *data, - gint nelements); - -#endif /* __GDK_SELECTION_WIN32_H__ */ -- 2.30.2