+++ /dev/null
-/* 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 <http://www.gnu.org/licenses/>.
- */
-
-/*
- * 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 <string.h>
-#include <stdlib.h>
-
-/* For C-style COM wrapper macros */
-#define COBJMACROS
-
-/* for CIDA */
-#include <shlobj.h>
-
-#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);
- }
-}