diff options
author | Tor Lillqvist <tml@novell.com> | 2009-01-30 01:16:47 +0000 |
---|---|---|
committer | Tor Lillqvist <tml@src.gnome.org> | 2009-01-30 01:16:47 +0000 |
commit | 3f4c73d0d5b3479fbacf32a2462c97d433e96d97 (patch) | |
tree | d6234ed136ff4d1b9cb244c5dcf95be4960e8a8b | |
parent | 934014af3dd0896a66b3ee135f3304ace2336cc7 (diff) | |
download | gdk-pixbuf-3f4c73d0d5b3479fbacf32a2462c97d433e96d97.tar.gz |
Bug 559408 - Transparency lost when images are copied between GTK+ and the
2009-01-29 Tor Lillqvist <tml@novell.com>
Bug 559408 - Transparency lost when images are copied between GTK+
and the clipboard on Windows
The code in gdkselection-win32.c is simplified quite a lot. When
an image is stored on the clipboard from GTK+, only the "PNG" and
CF_DIB formats are advertised. PNG is our preferred format because
it can losslessly represent any image that gdk-pixbuf can handle,
even with alpha, unambiguously. CF_DIB is also advertised because
of its ubiquitous support in Windows software.
Delayed rendering is used as before, so for other data than text
nothing is actually stored on the clipboard until some app asks
for it.
It's pointless to advertise images formats like "image/png" or
"image/x-MS-bmp" that no other Windows application is going to
look for anyway. Likewise it's pointless to store text under
formats like "text/plain" or "UTF8_STRING". Just store
CF_UNICODETEXT. CF_TEXT will be available as a synthesized format
anyways.
Office 2007 offers and asks for images in PNG format using the
registered clipboard format name "PNG", so we do likewise. If the
"PNG" format is available that is preferred when copying to GTK+
from the clipboard.
Unfortunately Word 2007 still uses CF_DIB without handling
alpha. But PowerPoint 2007 uses PNG if available and handles alpha
correctly. Both Word and Powerpoint offer PNG with alpha nicely.
Firefox and IE7 offer images that contain alpha as 32-bit version
3 BI_RGB DIBs with the undocumented "extra" bytes actually being
alpha. Also, alpha is premultiplied into the RGB bytes, presumably
because that is how AlphaBlend() wants such DIBs. That is also
taken care of. At least for Firefox it easy to be sure that a
CF_DIB on the clipboard is from Firefox.
Also some general stylistic cleanup, comment improvements, and
improvements of debugging printout especially in the clipboard
handling. Those are not detailled below.
* gdk/win32/gdkprivate-win32.h
* gdk/win32/gdkglobals-win32.c
* gdk/win32/gdkgmain-win32.c: Move some globals that were used
only in gdkselection-win32.c to be local to that file.
* gdk/win32/gdkproperty-win32.c (gdk_property_change): Don't
bother checking if text to be placed on the clipboard consists of
only ASCII.
* gdk/win32/gdkselection-win32.c: Add static variables for a list
of GdkPixbuf-supported formats, well-known registered clipboard
formats for images, and for GdkAtoms for well-known image and text
formats.
(_gdk_win32_selection_init): Initialize above static variables.
(selection_property_store) (gdk_selection_property_get)
(_gdk_selection_property_delete): Don't use a FIFO of GdkSelProps
for a window after all, it breaks testtext. See bug #163844.
(gdk_selection_convert): When converting to the TARGETS format,
i.e. when the caller wants to know what clipboard formats are
available, if PNG is available we report just that and skip
CF_DIB, JPEG and GIF even if advertised.
If CF_UNICODETEXT is available, report only UTF8_STRING.
When converting to the UTF8_STRING format, i.e. when the caller
wants text from the clipboard, try just CF_UNICODETEXT. There is
no point in trying CF_TEXT as Windows will synthesize
CF_UNICODETEXT from CF_TEXT anyway, if some app has stored just
CF_TEXT.
When converting to the image/bmp format, i.e. when the caller
wants an CF_DIB image from the clipboard, we check if the DIB is a
version 3 32-bit BI_RGB one that is likely to actually contain
alpha in the "extra" bytes. Such a DIB is likely to have
premultiplied alpha even, at least in the case of Firefox 3 and
IE7. We then edit the DIB in-place into a version 5 one in
BI_BITFIELDS format and undo the alpha premultiplication.
In any case, prepend a BMP file header before letting go of the
data which will be fed to the gdk-pixbuf bmp loader by upper
levels.
(gdk_win32_selection_add_targets): If some kind of pixmap image
format is being added, actually advertise just PNG and
CF_DIB. Note that alpha won't be stored on the clipboard through
CF_DIB. This is because gdk-pixbuf's bmp loader doesn't save
alpha. Furthermore, few if any non-GTK+ Windows apps seem to
understand a version 5 DIB with proper alpha anyway.
(_gdk_win32_selection_convert_to_dib): Simplified muchly.
svn path=/trunk/; revision=22255
-rw-r--r-- | ChangeLog | 97 | ||||
-rw-r--r-- | gdk/win32/gdkevents-win32.c | 86 | ||||
-rw-r--r-- | gdk/win32/gdkglobals-win32.c | 6 | ||||
-rw-r--r-- | gdk/win32/gdkmain-win32.c | 8 | ||||
-rw-r--r-- | gdk/win32/gdkprivate-win32.h | 12 | ||||
-rw-r--r-- | gdk/win32/gdkproperty-win32.c | 233 | ||||
-rw-r--r-- | gdk/win32/gdkselection-win32.c | 926 |
7 files changed, 782 insertions, 586 deletions
@@ -1,5 +1,102 @@ 2009-01-29 Tor Lillqvist <tml@novell.com> + Bug 559408 - Transparency lost when images are copied between GTK+ + and the clipboard on Windows + + The code in gdkselection-win32.c is simplified quite a lot. When + an image is stored on the clipboard from GTK+, only the "PNG" and + CF_DIB formats are advertised. PNG is our preferred format because + it can losslessly represent any image that gdk-pixbuf can handle, + even with alpha, unambiguously. CF_DIB is also advertised because + of its ubiquitous support in Windows software. + + Delayed rendering is used as before, so for other data than text + nothing is actually stored on the clipboard until some app asks + for it. + + It's pointless to advertise images formats like "image/png" or + "image/x-MS-bmp" that no other Windows application is going to + look for anyway. Likewise it's pointless to store text under + formats like "text/plain" or "UTF8_STRING". Just store + CF_UNICODETEXT. CF_TEXT will be available as a synthesized format + anyways. + + Office 2007 offers and asks for images in PNG format using the + registered clipboard format name "PNG", so we do likewise. If the + "PNG" format is available that is preferred when copying to GTK+ + from the clipboard. + + Unfortunately Word 2007 still uses CF_DIB without handling + alpha. But PowerPoint 2007 uses PNG if available and handles alpha + correctly. Both Word and Powerpoint offer PNG with alpha nicely. + + Firefox and IE7 offer images that contain alpha as 32-bit version + 3 BI_RGB DIBs with the undocumented "extra" bytes actually being + alpha. Also, alpha is premultiplied into the RGB bytes, presumably + because that is how AlphaBlend() wants such DIBs. That is also + taken care of. At least for Firefox it easy to be sure that a + CF_DIB on the clipboard is from Firefox. + + Also some general stylistic cleanup, comment improvements, and + improvements of debugging printout especially in the clipboard + handling. Those are not detailled below. + + * gdk/win32/gdkprivate-win32.h + * gdk/win32/gdkglobals-win32.c + * gdk/win32/gdkgmain-win32.c: Move some globals that were used + only in gdkselection-win32.c to be local to that file. + + * gdk/win32/gdkproperty-win32.c (gdk_property_change): Don't + bother checking if text to be placed on the clipboard consists of + only ASCII. + + * gdk/win32/gdkselection-win32.c: Add static variables for a list + of GdkPixbuf-supported formats, well-known registered clipboard + formats for images, and for GdkAtoms for well-known image and text + formats. + + (_gdk_win32_selection_init): Initialize above static variables. + + (selection_property_store) (gdk_selection_property_get) + (_gdk_selection_property_delete): Don't use a FIFO of GdkSelProps + for a window after all, it breaks testtext. See bug #163844. + + (gdk_selection_convert): When converting to the TARGETS format, + i.e. when the caller wants to know what clipboard formats are + available, if PNG is available we report just that and skip + CF_DIB, JPEG and GIF even if advertised. + + If CF_UNICODETEXT is available, report only UTF8_STRING. + + When converting to the UTF8_STRING format, i.e. when the caller + wants text from the clipboard, try just CF_UNICODETEXT. There is + no point in trying CF_TEXT as Windows will synthesize + CF_UNICODETEXT from CF_TEXT anyway, if some app has stored just + CF_TEXT. + + When converting to the image/bmp format, i.e. when the caller + wants an CF_DIB image from the clipboard, we check if the DIB is a + version 3 32-bit BI_RGB one that is likely to actually contain + alpha in the "extra" bytes. Such a DIB is likely to have + premultiplied alpha even, at least in the case of Firefox 3 and + IE7. We then edit the DIB in-place into a version 5 one in + BI_BITFIELDS format and undo the alpha premultiplication. + + In any case, prepend a BMP file header before letting go of the + data which will be fed to the gdk-pixbuf bmp loader by upper + levels. + + (gdk_win32_selection_add_targets): If some kind of pixmap image + format is being added, actually advertise just PNG and + CF_DIB. Note that alpha won't be stored on the clipboard through + CF_DIB. This is because gdk-pixbuf's bmp loader doesn't save + alpha. Furthermore, few if any non-GTK+ Windows apps seem to + understand a version 5 DIB with proper alpha anyway. + + (_gdk_win32_selection_convert_to_dib): Simplified muchly. + +2009-01-29 Tor Lillqvist <tml@novell.com> + Bug 145058 - Inputting "^^" requires four keystrokes on Win32, differs from platform default behaviour diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 07e68b459..599ff8da2 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -694,12 +694,12 @@ gdk_keyboard_grab (GdkWindow *window, g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0); - GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %p\n", - GDK_WINDOW_HWND (window))); + GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %p%s\n", + GDK_WINDOW_HWND (window), owner_events ? " OWNER_EVENTS" : "")); if (!GDK_WINDOW_DESTROYED (window)) { - k_grab_owner_events = owner_events != 0; + k_grab_owner_events = owner_events; return_val = GDK_GRAB_SUCCESS; } else @@ -746,7 +746,7 @@ gdk_display_keyboard_ungrab (GdkDisplay *display, g_return_if_fail (display == _gdk_display); - GDK_NOTE (EVENTS, g_print ("gdk_keyboard_ungrab\n")); + GDK_NOTE (EVENTS, g_print ("gdk_display_keyboard_ungrab\n")); if (k_grab_window && !k_grab_owner_events) { @@ -955,6 +955,7 @@ static void print_event (GdkEvent *event) { gchar *escaped, *kvname; + gchar *selection_name, *target_name, *property_name; g_print ("%s%*s===> ", (debug_indent > 0 ? "\n" : ""), debug_indent, ""); switch (event->any.type) @@ -1065,6 +1066,18 @@ print_event (GdkEvent *event) case GDK_FOCUS_CHANGE: g_print ("%s", (event->focus_change.in ? "IN" : "OUT")); break; + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + case GDK_SELECTION_CLEAR: + selection_name = gdk_atom_name (event->selection.selection); + target_name = gdk_atom_name (event->selection.target); + property_name = gdk_atom_name (event->selection.property); + g_print ("sel:%s tgt:%s prop:%s", + selection_name, target_name, property_name); + g_free (selection_name); + g_free (target_name); + g_free (property_name); + break; case GDK_CONFIGURE: g_print ("x:%d y:%d w:%d h:%d", event->configure.x, event->configure.y, @@ -1682,7 +1695,8 @@ translate_mouse_coords (GdkWindow *window1, /* The check_extended flag controls whether to check if the windows want * events from extended input devices and if the message should be skipped - * because an extended input device is active */ + * because an extended input device is active + */ static gboolean propagate (GdkWindow **window, MSG *msg, @@ -1693,14 +1707,13 @@ propagate (GdkWindow **window, MSG *msg), gboolean check_extended) { - gboolean in_propagation = FALSE; - if (grab_window != NULL && !grab_owner_events) { /* Event source is grabbed with owner_events FALSE */ - /* See if the event should be ignored because an extended input device - * is used */ + /* See if the event should be ignored because an extended input + * device is used + */ if (check_extended && ((GdkWindowObject *) grab_window)->extension_events != 0 && _gdk_input_ignore_core) @@ -1720,10 +1733,12 @@ propagate (GdkWindow **window, return TRUE; } } + + /* If we come here, we know that if grab_window != NULL then + * grab_owner_events is TRUE + */ while (TRUE) { - /* See if the event should be ignored because an extended input device - * is used */ if (check_extended && ((GdkWindowObject *) *window)->extension_events != 0 && _gdk_input_ignore_core) @@ -1742,8 +1757,6 @@ propagate (GdkWindow **window, { /* Event source is grabbed with owner_events TRUE */ - /* See if the event should be ignored because an extended - * input device is used */ if (check_extended && ((GdkWindowObject *) grab_window)->extension_events != 0 && _gdk_input_ignore_core) @@ -1774,7 +1787,6 @@ propagate (GdkWindow **window, else { assign_object (window, parent); - in_propagation = TRUE; /* The only branch where we actually continue the loop */ } } @@ -2867,7 +2879,7 @@ gdk_event_translate (MSG *msg, break; case WM_MOUSEWHEEL: - GDK_NOTE (EVENTS, g_print (" %d", HIWORD (msg->wParam))); + GDK_NOTE (EVENTS, g_print (" %d", (short) HIWORD (msg->wParam))); /* WM_MOUSEWHEEL is delivered to the focus window. Work around * that. Also, the position is in screen coordinates, not client @@ -2917,6 +2929,42 @@ gdk_event_translate (MSG *msg, return_val = TRUE; break; + case WM_HSCROLL: + GDK_NOTE (EVENTS, + (g_print (" %s", + (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" : + (LOWORD (msg->wParam) == SB_LEFT ? "LEFT" : + (LOWORD (msg->wParam) == SB_RIGHT ? "RIGHT" : + (LOWORD (msg->wParam) == SB_LINELEFT ? "LINELEFT" : + (LOWORD (msg->wParam) == SB_LINERIGHT ? "LINERIGHT" : + (LOWORD (msg->wParam) == SB_PAGELEFT ? "PAGELEFT" : + (LOWORD (msg->wParam) == SB_PAGERIGHT ? "PAGERIGHT" : + (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" : + (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" : + "???")))))))))), + (LOWORD (msg->wParam) == SB_THUMBPOSITION || + LOWORD (msg->wParam) == SB_THUMBTRACK) ? + g_print (" %d", HIWORD (msg->wParam)) : 0)); + break; + + case WM_VSCROLL: + GDK_NOTE (EVENTS, + (g_print (" %s", + (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" : + (LOWORD (msg->wParam) == SB_BOTTOM ? "BOTTOM" : + (LOWORD (msg->wParam) == SB_TOP ? "TOP" : + (LOWORD (msg->wParam) == SB_LINEDOWN ? "LINDOWN" : + (LOWORD (msg->wParam) == SB_LINEUP ? "LINEIP" : + (LOWORD (msg->wParam) == SB_PAGEDOWN ? "PAGEDOWN" : + (LOWORD (msg->wParam) == SB_PAGEUP ? "PAGEUP" : + (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" : + (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" : + "???")))))))))), + (LOWORD (msg->wParam) == SB_THUMBPOSITION || + LOWORD (msg->wParam) == SB_THUMBTRACK) ? + g_print (" %d", HIWORD (msg->wParam)) : 0)); + break; + case WM_QUERYNEWPALETTE: if (gdk_visual_get_system ()->type == GDK_VISUAL_PSEUDO_COLOR) { @@ -3608,7 +3656,7 @@ gdk_event_translate (MSG *msg, event->selection.send_event = FALSE; event->selection.selection = GDK_SELECTION_CLIPBOARD; event->selection.target = target; - event->selection.property = _gdk_selection_property; + event->selection.property = _gdk_selection; event->selection.requestor = msg->hwnd; event->selection.time = msg->time; @@ -3640,6 +3688,11 @@ gdk_event_translate (MSG *msg, /* The requestor is holding the clipboard, no * OpenClipboard() is required/possible */ + GDK_NOTE (DND, + g_print (" SetClipboardData(%s,%p)", + _gdk_win32_cf_to_string (msg->wParam), + _delayed_rendering_data)); + API_CALL (SetClipboardData, (msg->wParam, _delayed_rendering_data)); _delayed_rendering_data = NULL; } @@ -3679,7 +3732,6 @@ gdk_event_translate (MSG *msg, GDK_NOTE (EVENTS, g_print (" %s thread: %I64d", msg->wParam ? "YES" : "NO", (gint64) msg->lParam)); - if (msg->wParam && GDK_WINDOW_IS_MAPPED (window)) ensure_stacking_on_activate_app (msg, window); break; diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c index 3f0f74941..d30ad32e5 100644 --- a/gdk/win32/gdkglobals-win32.c +++ b/gdk/win32/gdkglobals-win32.c @@ -46,10 +46,7 @@ HKL _gdk_input_locale; gboolean _gdk_input_locale_is_ime; UINT _gdk_input_codepage; -WORD _cf_utf8_string; -WORD _cf_image_bmp; - -GdkAtom _gdk_selection_property; +GdkAtom _gdk_selection; GdkAtom _wm_transient_for; GdkAtom _targets; GdkAtom _save_targets; @@ -57,7 +54,6 @@ GdkAtom _utf8_string; GdkAtom _text; GdkAtom _compound_text; GdkAtom _text_uri_list; -GdkAtom _image_bmp; GdkAtom _local_dnd; GdkAtom _gdk_win32_dropfiles; diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c index 498a70926..5be01631a 100644 --- a/gdk/win32/gdkmain-win32.c +++ b/gdk/win32/gdkmain-win32.c @@ -100,10 +100,7 @@ _gdk_windowing_init (void) CoInitialize (NULL); - _cf_utf8_string = RegisterClipboardFormat ("UTF8_STRING"); - _cf_image_bmp = RegisterClipboardFormat ("image/bmp"); - - _gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE); + _gdk_selection = gdk_atom_intern ("GDK_SELECTION", FALSE); _wm_transient_for = gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE); _targets = gdk_atom_intern ("TARGETS", FALSE); _save_targets = gdk_atom_intern ("SAVE_TARGETS", FALSE); @@ -111,7 +108,6 @@ _gdk_windowing_init (void) _text = gdk_atom_intern ("TEXT", FALSE); _compound_text = gdk_atom_intern ("COMPOUND_TEXT", FALSE); _text_uri_list = gdk_atom_intern ("text/uri-list", FALSE); - _image_bmp = gdk_atom_intern ("image/bmp", FALSE); _local_dnd = gdk_atom_intern ("LocalDndSelection", FALSE); _gdk_win32_dropfiles = gdk_atom_intern ("DROPFILES_DND", FALSE); @@ -1039,9 +1035,7 @@ _gdk_win32_cf_to_string (UINT format) #define CASE(x) case CF_##x: return "CF_" #x CASE (BITMAP); CASE (DIB); -#ifdef CF_DIBV5 CASE (DIBV5); -#endif CASE (DIF); CASE (DSPBITMAP); CASE (DSPENHMETAFILE); diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 0d3fe99b9..bc54e00dd 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -93,6 +93,11 @@ #define WM_APPCOMMAND 0x319 #endif +#ifndef CF_DIBV5 +#define CF_DIBV5 17 +#endif + + /* Define some combinations of GdkDebugFlags */ #define GDK_DEBUG_EVENTS_OR_COLORMAP (GDK_DEBUG_EVENTS|GDK_DEBUG_COLORMAP) #define GDK_DEBUG_EVENTS_OR_INPUT (GDK_DEBUG_EVENTS|GDK_DEBUG_INPUT) @@ -400,12 +405,8 @@ extern guint _gdk_keymap_serial; extern gboolean _gdk_keyboard_has_altgr; extern guint _scancode_rshift; -/* Registered clipboard formats */ -extern WORD _cf_utf8_string; -extern WORD _cf_image_bmp; - /* GdkAtoms: properties, targets and types */ -extern GdkAtom _gdk_selection_property; +extern GdkAtom _gdk_selection; extern GdkAtom _wm_transient_for; extern GdkAtom _targets; extern GdkAtom _save_targets; @@ -413,7 +414,6 @@ extern GdkAtom _utf8_string; extern GdkAtom _text; extern GdkAtom _compound_text; extern GdkAtom _text_uri_list; -extern GdkAtom _image_bmp; /* DND selections */ extern GdkAtom _local_dnd; diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c index 0215c47e3..927fd6476 100644 --- a/gdk/win32/gdkproperty-win32.c +++ b/gdk/win32/gdkproperty-win32.c @@ -99,7 +99,8 @@ gdk_atom_name (GdkAtom atom) ATOM win32_atom; gchar name[256]; - if (GDK_SELECTION_PRIMARY == atom) return g_strdup ("PRIMARY"); + if (GDK_NONE == atom) return g_strdup ("<none>"); + else if (GDK_SELECTION_PRIMARY == atom) return g_strdup ("PRIMARY"); else if (GDK_SELECTION_SECONDARY == atom) return g_strdup ("SECONDARY"); else if (GDK_SELECTION_CLIPBOARD == atom) return g_strdup ("CLIPBOARD"); else if (GDK_SELECTION_TYPE_ATOM == atom) return g_strdup ("ATOM"); @@ -153,14 +154,10 @@ gdk_property_change (GdkWindow *window, gint nelements) { HGLOBAL hdata; - UINT cf = 0; - gint i, size, nchars; - gchar *prop_name, *type_name; + gint i, size; guchar *ucptr, *buf = NULL; - wchar_t *wcptr; + wchar_t *wcptr, *p; glong wclen; - enum { SYSTEM_CODEPAGE, UNICODE_TEXT } method; - gboolean ok = TRUE; g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); @@ -168,21 +165,23 @@ gdk_property_change (GdkWindow *window, if (GDK_WINDOW_DESTROYED (window)) return; - GDK_NOTE (DND, - (prop_name = gdk_atom_name (property), - type_name = gdk_atom_name (type), - g_print ("gdk_property_change: %p %p (%s) %p (%s) %s %d*%d bytes: %s\n", - GDK_WINDOW_HWND (window), - property, prop_name, - type, type_name, - (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" : - (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" : - (mode == GDK_PROP_MODE_APPEND ? "APPEND" : - "???"))), - format, nelements, - _gdk_win32_data_to_string (data, MIN (10, format*nelements/8))), - g_free (prop_name), - g_free (type_name))); + GDK_NOTE (DND, { + gchar *prop_name = gdk_atom_name (property); + gchar *type_name = gdk_atom_name (type); + + g_print ("gdk_property_change: %p %s %s %s %d*%d bits: %s\n", + GDK_WINDOW_HWND (window), + prop_name, + type_name, + (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" : + (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" : + (mode == GDK_PROP_MODE_APPEND ? "APPEND" : + "???"))), + format, nelements, + _gdk_win32_data_to_string (data, MIN (10, format*nelements/8))); + g_free (prop_name); + g_free (type_name); + }); /* We should never come here for these types */ g_return_if_fail (type != GDK_TARGET_STRING); @@ -190,9 +189,9 @@ gdk_property_change (GdkWindow *window, g_return_if_fail (type != _compound_text); g_return_if_fail (type != _save_targets); - if (property == _gdk_selection_property - && format == 8 - && mode == GDK_PROP_MODE_REPLACE) + if (property == _gdk_selection && + format == 8 && + mode == GDK_PROP_MODE_REPLACE) { if (type == _utf8_string) { @@ -202,38 +201,13 @@ gdk_property_change (GdkWindow *window, return; } - nchars = g_utf8_strlen ((char*) data, nelements); - - /* Check if only ASCII */ - for (i = 0; i < nelements; i++) - if (data[i] >= 0200) - break; - - if (i == nelements) - { - /* If only ASCII, use CF_TEXT and the data as such */ - method = SYSTEM_CODEPAGE; - size = nelements; - for (i = 0; i < nelements; i++) - if (data[i] == '\n') - size++; - size++; - GDK_NOTE (DND, g_print ("... as text: %.40s\n", data)); - } - else - { - /* Use CF_UNICODETEXT */ - method = UNICODE_TEXT; - - wcptr = g_utf8_to_utf16 ((char *) data, nelements, NULL, &wclen, NULL); + wcptr = g_utf8_to_utf16 ((char *) data, nelements, NULL, &wclen, NULL); - wclen++; /* Terminating 0 */ - size = wclen * 2; - for (i = 0; i < wclen; i++) - if (wcptr[i] == '\n') - size += 2; - GDK_NOTE (DND, g_print ("... as Unicode\n")); - } + wclen++; /* Terminating 0 */ + size = wclen * 2; + for (i = 0; i < wclen; i++) + if (wcptr[i] == '\n') + size += 2; if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size))) { @@ -246,53 +220,32 @@ gdk_property_change (GdkWindow *window, ucptr = GlobalLock (hdata); - switch (method) + p = (wchar_t *) ucptr; + for (i = 0; i < wclen; i++) { - case SYSTEM_CODEPAGE: - cf = CF_TEXT; - for (i = 0; i < nelements; i++) - { - if (data[i] == '\n') - *ucptr++ = '\r'; - *ucptr++ = data[i]; - } - *ucptr++ = '\0'; - break; - - case UNICODE_TEXT: - { - wchar_t *p = (wchar_t *) ucptr; - cf = CF_UNICODETEXT; - for (i = 0; i < wclen; i++) - { - if (wcptr[i] == '\n') - *p++ = '\r'; - *p++ = wcptr[i]; - } - g_free (wcptr); - } - break; - - default: - g_assert_not_reached (); + if (wcptr[i] == '\n') + *p++ = '\r'; + *p++ = wcptr[i]; } + g_free (wcptr); GlobalUnlock (hdata); - GDK_NOTE (DND, g_print ("... SetClipboardData(%s,%p)\n", - _gdk_win32_cf_to_string (cf), hdata)); - if (ok && !SetClipboardData (cf, hdata)) - WIN32_API_FAILED ("SetClipboardData"), ok = FALSE; + GDK_NOTE (DND, g_print ("... SetClipboardData(CF_UNICODETEXT,%p)\n", + hdata)); + if (!SetClipboardData (CF_UNICODETEXT, hdata)) + WIN32_API_FAILED ("SetClipboardData"); if (!CloseClipboard ()) WIN32_API_FAILED ("CloseClipboard"); } else { - GDK_NOTE (DND, g_print ("... delayed rendering\n")); - /* Delayed Rendering. We can't assign hdata to the clipboard - * here as type may be "image/png", "image/jpg", etc. In - * this case there's a further conversion afterwards. + /* We use delayed rendering for everything else than + * text. We can't assign hdata to the clipboard here as type + * may be "image/png", "image/jpg", etc. In this case + * there's a further conversion afterwards. */ + GDK_NOTE (DND, g_print ("... delayed rendering\n")); _delayed_rendering_data = NULL; if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, nelements > 0 ? nelements : 1))) { @@ -318,14 +271,16 @@ gdk_property_delete (GdkWindow *window, g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); - GDK_NOTE (DND, - (prop_name = gdk_atom_name (property), - g_print ("gdk_property_delete: %p %p (%s)\n", - GDK_WINDOW_HWND (window), - property, prop_name), - g_free (prop_name))); + GDK_NOTE (DND, { + prop_name = gdk_atom_name (property); - if (property == _gdk_selection_property) + g_print ("gdk_property_delete: %p %s\n", + GDK_WINDOW_HWND (window), + prop_name); + g_free (prop_name); + }); + + if (property == _gdk_selection) _gdk_selection_property_delete (window); else if (property == _wm_transient_for) gdk_window_set_transient_for (window, _gdk_root); @@ -339,37 +294,56 @@ gdk_property_delete (GdkWindow *window, } /* - for reference copied from gdk/x11/gdkevents-x11.c - - { "Net/DoubleClickTime", "gtk-double-click-time" }, - { "Net/DoubleClickDistance", "gtk-double-click-distance" }, - { "Net/DndDragThreshold", "gtk-dnd-drag-threshold" }, - { "Gtk/CanChangeAccels", "gtk-can-change-accels" }, - { "Gtk/ColorPalette", "gtk-color-palette" }, - { "Gtk/FontName", "gtk-font-name" }, - { "Gtk/IconSizes", "gtk-icon-sizes" }, - { "Gtk/KeyThemeName", "gtk-key-theme-name" }, - { "Gtk/ToolbarStyle", "gtk-toolbar-style" }, - { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" }, - { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" }, - { "Gtk/IMStatusStyle", "gtk-im-status-style" }, - { "Gtk/IMModule", "gtk-im-module" }, - { "Net/CursorBlink", "gtk-cursor-blink" }, - { "Net/CursorBlinkTime", "gtk-cursor-blink-time" }, - { "Net/ThemeName", "gtk-theme-name" }, - { "Net/IconThemeName", "gtk-icon-theme-name" }, - { "Gtk/ButtonImages", "gtk-button-images" }, - { "Gtk/MenuImages", "gtk-menu-images" }, - { "Xft/Antialias", "gtk-xft-antialias" }, - { "Xft/Hinting", "gtk-xft-hinting" }, - { "Xft/HintStyle", "gtk-xft-hintstyle" }, - { "Xft/RGBA", "gtk-xft-rgba" }, - { "Xft/DPI", "gtk-xft-dpi" }, - - // more spread in gtk sources + For reference, from gdk/x11/gdksettings.c: + + "Net/DoubleClickTime\0" "gtk-double-click-time\0" + "Net/DoubleClickDistance\0" "gtk-double-click-distance\0" + "Net/DndDragThreshold\0" "gtk-dnd-drag-threshold\0" + "Net/CursorBlink\0" "gtk-cursor-blink\0" + "Net/CursorBlinkTime\0" "gtk-cursor-blink-time\0" + "Net/ThemeName\0" "gtk-theme-name\0" + "Net/IconThemeName\0" "gtk-icon-theme-name\0" + "Gtk/CanChangeAccels\0" "gtk-can-change-accels\0" + "Gtk/ColorPalette\0" "gtk-color-palette\0" + "Gtk/FontName\0" "gtk-font-name\0" + "Gtk/IconSizes\0" "gtk-icon-sizes\0" + "Gtk/KeyThemeName\0" "gtk-key-theme-name\0" + "Gtk/ToolbarStyle\0" "gtk-toolbar-style\0" + "Gtk/ToolbarIconSize\0" "gtk-toolbar-icon-size\0" + "Gtk/IMPreeditStyle\0" "gtk-im-preedit-style\0" + "Gtk/IMStatusStyle\0" "gtk-im-status-style\0" + "Gtk/Modules\0" "gtk-modules\0" + "Gtk/FileChooserBackend\0" "gtk-file-chooser-backend\0" + "Gtk/ButtonImages\0" "gtk-button-images\0" + "Gtk/MenuImages\0" "gtk-menu-images\0" + "Gtk/MenuBarAccel\0" "gtk-menu-bar-accel\0" + "Gtk/CursorThemeName\0" "gtk-cursor-theme-name\0" + "Gtk/CursorThemeSize\0" "gtk-cursor-theme-size\0" + "Gtk/ShowInputMethodMenu\0" "gtk-show-input-method-menu\0" + "Gtk/ShowUnicodeMenu\0" "gtk-show-unicode-menu\0" + "Gtk/TimeoutInitial\0" "gtk-timeout-initial\0" + "Gtk/TimeoutRepeat\0" "gtk-timeout-repeat\0" + "Gtk/ColorScheme\0" "gtk-color-scheme\0" + "Gtk/EnableAnimations\0" "gtk-enable-animations\0" + "Xft/Antialias\0" "gtk-xft-antialias\0" + "Xft/Hinting\0" "gtk-xft-hinting\0" + "Xft/HintStyle\0" "gtk-xft-hintstyle\0" + "Xft/RGBA\0" "gtk-xft-rgba\0" + "Xft/DPI\0" "gtk-xft-dpi\0" + "Net/FallbackIconTheme\0" "gtk-fallback-icon-theme\0" + "Gtk/TouchscreenMode\0" "gtk-touchscreen-mode\0" + "Gtk/EnableAccels\0" "gtk-enable-accels\0" + "Gtk/EnableMnemonics\0" "gtk-enable-mnemonics\0" + "Gtk/ScrolledWindowPlacement\0" "gtk-scrolled-window-placement\0" + "Gtk/IMModule\0" "gtk-im-module\0" + "Fontconfig/Timestamp\0" "gtk-fontconfig-timestamp\0" + "Net/SoundThemeName\0" "gtk-sound-theme-name\0" + "Net/EnableInputFeedbackSounds\0" "gtk-enable-input-feedback-sounds\0" + "Net/EnableEventSounds\0" "gtk-enable-event-sounds\0"; + + More, from various places in gtk sources: + gtk-entry-select-on-focus - gtk-cursor-blink - gtk-cursor-blink-time gtk-split-cursor */ @@ -463,6 +437,5 @@ gdk_screen_get_setting (GdkScreen *screen, } #endif - GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) not handled\n", name)); return FALSE; } diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c index 5ae442589..73588b8d9 100644 --- a/gdk/win32/gdkselection-win32.c +++ b/gdk/win32/gdkselection-win32.c @@ -35,7 +35,7 @@ #include "gdkprivate-win32.h" /* We emulate the GDK_SELECTION window properties of windows (as used - * in the X11 backend) by using a hash table from GdkWindows to + * in the X11 backend) by using a hash table from window handles to * GdkSelProp structs. */ @@ -55,12 +55,89 @@ static GdkSelProp *dropfiles_prop = NULL; */ static GHashTable *sel_owner_table = NULL; +/* Well-known registered clipboard image formats */ +static UINT cf_png; +static UINT cf_jfif; +static UINT cf_gif; + +/* GdkAtoms for well-known image formats */ +static GdkAtom *known_pixbuf_formats; +static int n_known_pixbuf_formats; +static GdkAtom image_png; +static GdkAtom image_jpeg; +static GdkAtom image_bmp; +static GdkAtom image_gif; + +/* GdkAtoms for well-known text formats */ +static GdkAtom text_plain; +static GdkAtom text_plain_charset_utf_8; +static GdkAtom text_plain_charset_CP1252; + void _gdk_win32_selection_init (void) { + GSList *pixbuf_formats; + GSList *rover; + sel_prop_table = g_hash_table_new (NULL, NULL); sel_owner_table = g_hash_table_new (NULL, NULL); _format_atom_table = g_hash_table_new (NULL, NULL); + + /* 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. + */ + cf_png = RegisterClipboardFormat ("PNG"); + cf_jfif = RegisterClipboardFormat ("JFIF"); + cf_gif = RegisterClipboardFormat ("GIF"); + + pixbuf_formats = gdk_pixbuf_get_formats (); + + 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++) + n_known_pixbuf_formats++; + } + + known_pixbuf_formats = g_new (GdkAtom, n_known_pixbuf_formats); + + 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++) + known_pixbuf_formats[n_known_pixbuf_formats++] = gdk_atom_intern (*mime_type, FALSE); + } + + g_slist_free (pixbuf_formats); + + image_png = gdk_atom_intern ("image/png", FALSE); + image_jpeg = gdk_atom_intern ("image/jpeg", FALSE); + image_bmp = gdk_atom_intern ("image/bmp", FALSE); + image_gif = gdk_atom_intern ("image/gif", FALSE); + + text_plain = gdk_atom_intern ("text/plain", FALSE); + text_plain_charset_utf_8= gdk_atom_intern ("text/plain;charset=utf-8", FALSE); + text_plain_charset_CP1252 = gdk_atom_intern ("text/plain;charset=CP1252", FALSE); + + g_hash_table_replace (_format_atom_table, + GINT_TO_POINTER (cf_png), + image_png); + + g_hash_table_replace (_format_atom_table, + GINT_TO_POINTER (CF_DIB), + image_bmp); } /* The specifications for COMPOUND_TEXT and STRING specify that C0 and @@ -130,42 +207,33 @@ _gdk_utf8_to_string_target_internal (const gchar *str, } static void -_gdk_selection_property_store (GdkWindow *owner, - GdkAtom type, - gint format, - guchar *data, - gint length) +selection_property_store (GdkWindow *owner, + GdkAtom type, + gint format, + guchar *data, + gint length) { GdkSelProp *prop; - GSList *prop_list; - prop = g_new (GdkSelProp, 1); + g_return_if_fail (type != GDK_TARGET_STRING); - if (type == GDK_TARGET_STRING) - { - /* We know that data is UTF-8 */ - prop->data = (guchar *) _gdk_utf8_to_string_target_internal ((char*) data, length); - g_free (data); - - if (!prop->data) - { - g_free (prop); + prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (owner)); - return; - } - else - prop->length = strlen ((char*) prop->data) + 1; - } - else + if (prop != NULL) { - prop->data = data; - prop->length = length; + g_free (prop->data); + g_free (prop); + g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (owner)); } + + prop = g_new (GdkSelProp, 1); + + prop->data = data; + prop->length = length; prop->format = format; prop->type = type; - prop_list = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (owner)); - prop_list = g_slist_append (prop_list, prop); - g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (owner), prop_list); + + g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (owner), prop); } void @@ -192,6 +260,21 @@ _gdk_dropfiles_store (gchar *data) } } +static gchar * +get_mapped_gdk_atom_name (GdkAtom gdk_target) +{ + if (gdk_target == image_png) + return g_strdup ("PNG"); + + if (gdk_target == image_jpeg) + return g_strdup ("JFIF"); + + if (gdk_target == image_gif) + return g_strdup ("GIF"); + + return gdk_atom_name (gdk_target); +} + gboolean gdk_selection_owner_set_for_display (GdkDisplay *display, GdkWindow *owner, @@ -205,18 +288,14 @@ gdk_selection_owner_set_for_display (GdkDisplay *display, g_return_val_if_fail (display == _gdk_display, FALSE); g_return_val_if_fail (selection != GDK_NONE, FALSE); -#ifdef G_ENABLE_DEBUG - { - gchar *sel_name; - - GDK_NOTE (DND, - (sel_name = gdk_atom_name (selection), - g_print ("gdk_selection_owner_set_for_display: %p %p (%s)\n", - (owner ? GDK_WINDOW_HWND (owner) : NULL), - selection, sel_name), - g_free (sel_name))); - } -#endif + GDK_NOTE (DND, { + gchar *sel_name = gdk_atom_name (selection); + + g_print ("gdk_selection_owner_set_for_display: %p %s\n", + (owner ? GDK_WINDOW_HWND (owner) : NULL), + sel_name); + g_free (sel_name); + }); if (selection != GDK_SELECTION_CLIPBOARD) { @@ -266,7 +345,7 @@ gdk_selection_owner_set_for_display (GdkDisplay *display, tmp_event.selection.send_event = FALSE; tmp_event.selection.selection = selection; tmp_event.selection.target = _utf8_string; - tmp_event.selection.property = _gdk_selection_property; + tmp_event.selection.property = _gdk_selection; tmp_event.selection.requestor = hwnd; tmp_event.selection.time = time; @@ -297,18 +376,14 @@ gdk_selection_owner_get_for_display (GdkDisplay *display, window = gdk_window_lookup ((GdkNativeWindow) g_hash_table_lookup (sel_owner_table, selection)); -#ifdef G_ENABLE_DEBUG - { - gchar *sel_name; - - GDK_NOTE (DND, - (sel_name = gdk_atom_name (selection), - g_print ("gdk_selection_owner_get: %p (%s) = %p\n", - selection, sel_name, - (window ? GDK_WINDOW_HWND (window) : NULL)), - g_free (sel_name))); - } -#endif + GDK_NOTE (DND, { + gchar *sel_name = gdk_atom_name (selection); + + g_print ("gdk_selection_owner_get: %s = %p\n", + sel_name, + (window ? GDK_WINDOW_HWND (window) : NULL)); + g_free (sel_name); + }); return window; } @@ -341,7 +416,7 @@ gdk_selection_convert (GdkWindow *requestor, guint32 time) { HGLOBAL hdata; - GdkAtom property = _gdk_selection_property; + GdkAtom property = _gdk_selection; g_return_if_fail (selection != GDK_NONE); g_return_if_fail (requestor != NULL); @@ -349,76 +424,119 @@ gdk_selection_convert (GdkWindow *requestor, if (GDK_WINDOW_DESTROYED (requestor)) return; -#ifdef G_ENABLE_DEBUG - { - gchar *sel_name, *tgt_name; - - GDK_NOTE (DND, - (sel_name = gdk_atom_name (selection), - tgt_name = gdk_atom_name (target), - g_print ("gdk_selection_convert: %p %p (%s) %p (%s)\n", - GDK_WINDOW_HWND (requestor), - selection, sel_name, - target, tgt_name), - g_free (sel_name), - g_free (tgt_name))); - } -#endif + GDK_NOTE (DND, { + gchar *sel_name = gdk_atom_name (selection); + gchar *tgt_name = gdk_atom_name (target); + + g_print ("gdk_selection_convert: %p %s %s\n", + GDK_WINDOW_HWND (requestor), + sel_name, tgt_name); + g_free (sel_name); + g_free (tgt_name); + }); if (selection == GDK_SELECTION_CLIPBOARD && target == _targets) { - gint formats_cnt, i, fmt; - GdkAtom *data; + gint ntargets, fmt; + GdkAtom *targets; + gboolean has_text = FALSE; + gboolean has_png = FALSE; gboolean has_bmp = FALSE; - /* He wants to know what formats are on the clipboard. If there - * is some kind of text, tell him so. - */ if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor)))) return; - formats_cnt = CountClipboardFormats (); - data = g_new (GdkAtom, formats_cnt + 2); - i = 0; + targets = g_new (GdkAtom, CountClipboardFormats ()); + ntargets = 0; - if (IsClipboardFormatAvailable (CF_UNICODETEXT) || - IsClipboardFormatAvailable (_cf_utf8_string) || - IsClipboardFormatAvailable (CF_TEXT)) + for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); ) { - data[i++] = _utf8_string; + if (fmt == cf_png) + { + targets[ntargets++] = image_png; + has_png = TRUE; + } } - if (formats_cnt > 0) - { - /* If there is anything else in the clipboard, enum it all - * although we don't offer special conversion services. - */ - for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); ) - { - gchar sFormat[80]; - if (GetClipboardFormatName (fmt, sFormat, 80) > 0 && - strcmp (sFormat, "UTF8_STRING")) - { - GdkAtom atom; - - if (!has_bmp && - (!strcmp (sFormat, "image/bmp") || - !strcmp (sFormat, "image/x-bmp") || - !strcmp (sFormat, "image/x-MS-bmp"))) - has_bmp = TRUE; - atom = gdk_atom_intern (sFormat, FALSE); - data[i++] = atom; - } + for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); ) + { + gchar sFormat[80]; + + if (fmt == CF_UNICODETEXT || fmt == CF_TEXT) + { + /* Advertise text to GDK always as UTF8_STRING */ + if (!has_text) + targets[ntargets++] = _utf8_string; + has_text = TRUE; + } + else if (fmt == cf_png) + { + /* Already handled above */ + } + else if (fmt == CF_DIB || + fmt == CF_DIBV5) + { + /* Don't bother telling that a bitmap is present if there is + * also PNG, which is much more reliable in transferring + * transparency. + */ + if (!has_bmp && !has_png) + targets[ntargets++] = image_bmp; + has_bmp = TRUE; + } + else if (fmt == cf_jfif) + { + /* Ditto for JPEG */ + if (!has_png) + targets[ntargets++] = image_jpeg; + } + else if (fmt == cf_gif) + { + /* Ditto for GIF. + */ + if (!has_png) + targets[ntargets++] = image_gif; + } + else if (GetClipboardFormatName (fmt, sFormat, 80) > 0) + { + if (strcmp (sFormat, "image/bmp") == 0 || + strcmp (sFormat, "image/x-bmp") == 0 || + strcmp (sFormat, "image/x-MS-bmp") == 0 || + strcmp (sFormat, "image/x-icon") == 0 || + strcmp (sFormat, "image/x-ico") == 0 || + strcmp (sFormat, "image/x-win-bitmap") == 0) + { + /* Ignore these (from older GTK+ versions + * presumably), as the same image in the CF_DIB + * format will also be on the clipboard anyway. + */ + } + else + targets[ntargets++] = gdk_atom_intern (sFormat, FALSE); } } - if (!has_bmp && (IsClipboardFormatAvailable (CF_BITMAP) || - IsClipboardFormatAvailable (CF_DIB))) - data[i++] = _image_bmp; - - if (i > 0) - _gdk_selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM, - 32, (guchar *) data, i * sizeof (GdkAtom)); - else + + GDK_NOTE (DND, { + int i; + + g_print ("... "); + for (i = 0; i < ntargets; i++) + { + gchar *atom_name = gdk_atom_name (targets[i]); + + g_print ("%s", atom_name); + g_free (atom_name); + if (i < ntargets - 1) + g_print (", "); + } + g_print ("\n"); + }); + + if (ntargets > 0) + selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM, + 32, (guchar *) targets, + ntargets * sizeof (GdkAtom)); + else property = GDK_NONE; API_CALL (CloseClipboard, ()); @@ -432,7 +550,6 @@ gdk_selection_convert (GdkWindow *requestor, if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor)))) return; - /* Try various formats. First the simplest, CF_UNICODETEXT. */ if ((hdata = GetClipboardData (CF_UNICODETEXT)) != NULL) { wchar_t *ptr, *wcs, *p, *q; @@ -465,88 +582,8 @@ gdk_selection_convert (GdkWindow *requestor, g_free (wcs); if (data) - _gdk_selection_property_store (requestor, target, 8, - data, strlen (data) + 1); - GlobalUnlock (hdata); - } - } - else if ((hdata = GetClipboardData (_cf_utf8_string)) != NULL) - { - /* UTF8_STRING is a format we store ourselves when necessary */ - guchar *ptr; - gint length; - - if ((ptr = GlobalLock (hdata)) != NULL) - { - length = GlobalSize (hdata); - - GDK_NOTE (DND, g_print ("... UTF8_STRING: %d bytes: %.10s\n", - length, ptr)); - - _gdk_selection_property_store (requestor, target, 8, - g_memdup (ptr, length), length); - GlobalUnlock (hdata); - } - } - else if ((hdata = GetClipboardData (CF_TEXT)) != NULL) - { - /* We must always assume the data can contain non-ASCII - * in either the current code page, or if there is CF_LOCALE - * data, in that locale's default code page. - */ - HGLOBAL hlcid; - UINT cp = CP_ACP; - wchar_t *wcs, *wcs2, *p, *q; - guchar *ptr, *data; - glong length, wclen, wclen2; - - if ((ptr = GlobalLock (hdata)) != NULL) - { - length = GlobalSize (hdata); - - GDK_NOTE (DND, g_print ("... CF_TEXT: %ld bytes: %.10s\n", - length, ptr)); - - if ((hlcid = GetClipboardData (CF_LOCALE)) != NULL) - { - gchar buf[10]; - LCID *lcidptr = GlobalLock (hlcid); - if (GetLocaleInfo (*lcidptr, LOCALE_IDEFAULTANSICODEPAGE, - buf, sizeof (buf))) - { - cp = atoi (buf); - GDK_NOTE (DND, g_print ("... CF_LOCALE: %#lx cp:%d\n", - *lcidptr, cp)); - } - GlobalUnlock (hlcid); - } - - wcs = g_new (wchar_t, length + 1); - wclen = MultiByteToWideChar (cp, 0, ptr, length, - wcs, length + 1); - - /* Strip out \r */ - wcs2 = g_new (wchar_t, wclen); - p = wcs; - q = wcs2; - wclen2 = 0; - while (p < wcs + wclen) - { - if (*p != '\r') - { - *q++ = *p; - wclen2++; - } - p++; - } - g_free (wcs); - - data = g_utf16_to_utf8 (wcs2, wclen2, NULL, &length, NULL); - g_free (wcs2); - - if (data) - _gdk_selection_property_store (requestor, target, 8, - data, length + 1); + selection_property_store (requestor, _utf8_string, 8, + data, strlen (data) + 1); GlobalUnlock (hdata); } } @@ -555,80 +592,180 @@ gdk_selection_convert (GdkWindow *requestor, API_CALL (CloseClipboard, ()); } - else if (selection == GDK_SELECTION_CLIPBOARD && target == _image_bmp) + else if (selection == GDK_SELECTION_CLIPBOARD && target == image_bmp) { - guchar *data; - if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor)))) return; - if ((hdata = GetClipboardData (_cf_image_bmp)) != NULL) - { - /* "image/bmp" is the first choice. */ - guchar *ptr; - if ((ptr = GlobalLock (hdata)) != NULL) - { - gint length = GlobalSize (hdata); - - GDK_NOTE (DND, g_print ("...BITMAP (from \"image/bmp\": %d bytes\n", - length)); - - _gdk_selection_property_store (requestor, target, 8, - g_memdup (ptr, length), length); - GlobalUnlock (hdata); - } - } - else if ((hdata = GetClipboardData (CF_DIB)) != NULL) + if ((hdata = GetClipboardData (CF_DIB)) != NULL) { - /* If there's CF_DIB but not "image/bmp", the clipboard - * owner is probably a native Win32 application. - */ - BITMAPINFOHEADER *ptr; + BITMAPINFOHEADER *bi; - if ((ptr = GlobalLock (hdata)) != NULL) + if ((bi = GlobalLock (hdata)) != NULL) { - BITMAPFILEHEADER *hdr; /* Need to add a file header so gdk-pixbuf can load it */ - gint length = GlobalSize (hdata) + sizeof (BITMAPFILEHEADER); - - GDK_NOTE (DND, g_print ("... BITMAP (from CF_DIB): %d bytes\n", length)); + /* 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 "oldfashioned" 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 + * nitmaps to in fact have alpha, so we have to convince + * it by changint 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. + */ + BITMAPFILEHEADER *bf; + gpointer data; + gint data_length = GlobalSize (hdata); + gint new_length; + gboolean make_dibv5 = FALSE; + + GDK_NOTE (DND, g_print ("... CF_DIB: %d bytes\n", data_length)); + + 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 + (RegisterClipboardFormat ("application/x-moz-nativeimage")) || + IsClipboardFormatAvailable + (RegisterClipboardFormat ("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); + } - data = g_try_malloc (length); + data = g_try_malloc (new_length); + if (data) { - hdr = (BITMAPFILEHEADER *)data; - hdr->bfType = 0x4d42; /* 0x42 = "B" 0x4d = "M" */ - /* Compute the size of the entire file. */ - hdr->bfSize = (DWORD) (sizeof (BITMAPFILEHEADER) - + ptr->biSize + ptr->biClrUsed - * sizeof (RGBQUAD) + ptr->biSizeImage); - hdr->bfReserved1 = 0; - hdr->bfReserved2 = 0; - /* Compute the offset to the array of color indices. */ - hdr->bfOffBits = (DWORD) sizeof (BITMAPFILEHEADER) - + ptr->biSize + ptr->biClrUsed * sizeof (RGBQUAD); - /* Copy the data behind it */ - memcpy (data + sizeof (BITMAPFILEHEADER), ptr, length - sizeof (BITMAPFILEHEADER)); - _gdk_selection_property_store (requestor, target, 8, - data, length); + bf = (BITMAPFILEHEADER *)data; + bf->bfType = 0x4d42; /* "BM" */ + bf->bfSize = new_length; + bf->bfReserved1 = 0; + bf->bfReserved2 = 0; + + if (make_dibv5) + { + BITMAPV5HEADER *bV5 = data + sizeof (BITMAPFILEHEADER); + guchar *p; + int i; + + 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 *) data) + 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; + } + } + else + { + bf->bfOffBits = (sizeof (BITMAPFILEHEADER) + + bi->biSize + + bi->biClrUsed * sizeof (RGBQUAD)); + + memcpy (data + sizeof (BITMAPFILEHEADER), + bi, + data_length); + } + + selection_property_store (requestor, image_bmp, 8, + data, new_length); } GlobalUnlock (hdata); } - } API_CALL (CloseClipboard, ()); } else if (selection == GDK_SELECTION_CLIPBOARD) { - char *target_name; + gchar *mapped_target_name; UINT fmt = 0; if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor)))) return; - target_name = gdk_atom_name (target); + mapped_target_name = get_mapped_gdk_atom_name (target); - /* Check if it's available. In fact, we can simply call + /* Check if it's available. We could simply call * GetClipboardData (RegisterClipboardFormat (targetname)), but * the global custom format ID space is limited, * (0xC000~0xFFFF), and we better not waste an format ID if we @@ -639,7 +776,7 @@ gdk_selection_convert (GdkWindow *requestor, char sFormat[80]; if (GetClipboardFormatName (fmt, sFormat, 80) > 0 && - strcmp (sFormat, target_name) == 0) + strcmp (sFormat, mapped_target_name) == 0) { if ((hdata = GetClipboardData (fmt)) != NULL) { @@ -651,17 +788,17 @@ gdk_selection_convert (GdkWindow *requestor, { length = GlobalSize (hdata); - GDK_NOTE (DND, g_print ("... %s: %d bytes\n", target_name, length)); + GDK_NOTE (DND, g_print ("... %s: %d bytes\n", mapped_target_name, length)); - _gdk_selection_property_store (requestor, target, 8, - g_memdup (ptr, length), length); + selection_property_store (requestor, target, 8, + g_memdup (ptr, length), length); GlobalUnlock (hdata); break; } } } } - g_free (target_name); + g_free (mapped_target_name); API_CALL (CloseClipboard, ()); } else if (selection == _gdk_win32_dropfiles) @@ -672,7 +809,7 @@ gdk_selection_convert (GdkWindow *requestor, */ if (dropfiles_prop != NULL) { - _gdk_selection_property_store + selection_property_store (requestor, selection, dropfiles_prop->format, dropfiles_prop->data, dropfiles_prop->length); g_free (dropfiles_prop); @@ -682,9 +819,9 @@ gdk_selection_convert (GdkWindow *requestor, else property = GDK_NONE; - /* Generate a selection notify message so that we actually fetch - * the data (if property == _gdk_selection_property) or indicating failure - * (if property == GDK_NONE). + /* Generate a selection notify message so that we actually fetch the + * data (if property == _gdk_selection) or indicating failure (if + * property == GDK_NONE). */ generate_selection_notify (requestor, selection, target, property, time); } @@ -696,7 +833,6 @@ gdk_selection_property_get (GdkWindow *requestor, gint *ret_format) { GdkSelProp *prop; - GSList *prop_list; g_return_val_if_fail (requestor != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0); @@ -704,15 +840,16 @@ gdk_selection_property_get (GdkWindow *requestor, if (GDK_WINDOW_DESTROYED (requestor)) return 0; - GDK_NOTE (DND, g_print ("gdk_selection_property_get: %p\n", + GDK_NOTE (DND, g_print ("gdk_selection_property_get: %p", GDK_WINDOW_HWND (requestor))); - prop_list = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (requestor)); - prop = prop_list ? (GdkSelProp *) prop_list->data : NULL; + prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (requestor)); if (prop == NULL) { + GDK_NOTE (DND, g_print (" (nothing)\n")); *data = NULL; + return 0; } @@ -721,6 +858,13 @@ gdk_selection_property_get (GdkWindow *requestor, if (prop->length > 0) memmove (*data, prop->data, prop->length); + GDK_NOTE (DND, { + gchar *type_name = gdk_atom_name (prop->type); + + g_print (" %s format:%d length:%d\n", type_name, prop->format, prop->length); + g_free (type_name); + }); + if (ret_type) *ret_type = prop->type; @@ -734,19 +878,19 @@ void _gdk_selection_property_delete (GdkWindow *window) { GdkSelProp *prop; - GSList *prop_list; - GDK_NOTE (DND, g_print ("_gdk_selection_property_delete: %p\n", + GDK_NOTE (DND, g_print ("_gdk_selection_property_delete: %p (no-op)\n", GDK_WINDOW_HWND (window))); - prop_list = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (window)); - if (prop_list && (prop = (GdkSelProp *) prop_list->data) != NULL) +#if 0 + prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (window)); + if (prop != NULL) { g_free (prop->data); - prop_list = g_slist_remove (prop_list, prop); g_free (prop); - g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (window), prop_list); + g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (window)); } +#endif } void @@ -759,24 +903,17 @@ gdk_selection_send_notify_for_display (GdkDisplay *display, { g_return_if_fail (display == _gdk_display); -#ifdef G_ENABLE_DEBUG - { - gchar *sel_name, *tgt_name, *prop_name; - - GDK_NOTE (DND, - (sel_name = gdk_atom_name (selection), - tgt_name = gdk_atom_name (target), - prop_name = gdk_atom_name (property), - g_print ("gdk_selection_send_notify_for_display: %p %p (%s) %p (%s) %p (%s)\n", - requestor, - selection, sel_name, - target, tgt_name, - property, prop_name), - g_free (sel_name), - g_free (tgt_name), - g_free (prop_name))); - } -#endif + GDK_NOTE (DND, { + gchar *sel_name = gdk_atom_name (selection); + gchar *tgt_name = gdk_atom_name (target); + gchar *prop_name = gdk_atom_name (property); + + g_print ("gdk_selection_send_notify_for_display: %p %s %s %s (no-op)\n", + requestor, sel_name, tgt_name, prop_name); + g_free (sel_name); + g_free (tgt_name); + g_free (prop_name); + }); } /* It's hard to say whether implementing this actually is of any use @@ -797,16 +934,13 @@ gdk_text_property_to_text_list_for_display (GdkDisplay *display, g_return_val_if_fail (display == _gdk_display, 0); -#ifdef G_ENABLE_DEBUG - { - gchar *enc_name; - - GDK_NOTE (DND, (enc_name = gdk_atom_name (encoding), - g_print ("gdk_text_property_to_text_list_for_display: %s %d %.20s %d\n", - enc_name, format, text, length), - g_free (enc_name))); - } -#endif + GDK_NOTE (DND, { + gchar *enc_name = gdk_atom_name (encoding); + + g_print ("gdk_text_property_to_text_list_for_display: %s %d %.20s %d\n", + enc_name, format, text, length); + g_free (enc_name); + }); if (!list) return 0; @@ -1022,6 +1156,13 @@ gdk_free_compound_text (guchar *ctext) g_return_if_fail (ctext == NULL); } +/* 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. Formats copied directly to the clipboard are + * handled in gdk_property_change() in gdkproperty-win32.c. + */ + void gdk_win32_selection_add_targets (GdkWindow *owner, GdkAtom selection, @@ -1029,14 +1170,10 @@ gdk_win32_selection_add_targets (GdkWindow *owner, GdkAtom *targets) { HWND hwnd = NULL; - guint formatid; + gboolean has_image = FALSE; gint i; - GSList *convertable_formats, *format; - gboolean has_set_dib = FALSE, has_real_dib = FALSE; -#ifdef G_ENABLE_DEBUG - if (_gdk_debug_flags & GDK_DEBUG_DND) - { + GDK_NOTE (DND, { gchar *sel_name = gdk_atom_name (selection); g_print ("gdk_win32_selection_add_targets: %p: %s: ", @@ -1048,12 +1185,13 @@ gdk_win32_selection_add_targets (GdkWindow *owner, { gchar *tgt_name = gdk_atom_name (targets[i]); - g_print ("%s ", tgt_name); + g_print ("%s", tgt_name); g_free (tgt_name); + if (i < n_targets - 1) + g_print (", "); } g_print ("\n"); - } -#endif + }); if (selection != GDK_SELECTION_CLIPBOARD) return; @@ -1068,80 +1206,77 @@ gdk_win32_selection_add_targets (GdkWindow *owner, if (!API_CALL (OpenClipboard, (hwnd))) return; - convertable_formats = gdk_pixbuf_get_formats (); - for (i = 0; i < n_targets; ++i) + /* We have a very simple strategy: If some kind of pixmap image + * format is being added, actually advertise just PNG and DIB. PNG + * is our preferred format because it can losslessly represent any + * image that gdk-pixbuf formats in general can, even with alpha, + * unambiguously. CF_DIB is also advertised because of the general + * support for it in Windows software, but note that alpha won't be + * handled. + */ + for (i = 0; !has_image && i < n_targets; ++i) { + UINT cf; gchar *target_name; + int j; + + for (j = 0; j < n_known_pixbuf_formats; j++) + if (targets[i] == known_pixbuf_formats[j]) + { + if (!has_image) + { + GDK_NOTE (DND, g_print ("... SetClipboardData(PNG,NULL)\n")); + SetClipboardData (cf_png, NULL); + + GDK_NOTE (DND, g_print ("... SetClipboardData(CF_DIB,NULL)\n")); + SetClipboardData (CF_DIB, NULL); + + has_image = TRUE; + } + break; + } + + /* If it is one of the pixmap formats, already handled or not + * needed. + */ + if (j < n_known_pixbuf_formats) + continue; - if (targets[i] == _utf8_string || + /* We don't bother registering and advertising clipboard formats + * that are X11 specific or no non-GTK+ apps will have ever + * heard of, and when there are equivalent clipboard formats + * that are commonly used. + */ + if (targets[i] == _save_targets || + targets[i] == _utf8_string || targets[i] == GDK_TARGET_STRING || - targets[i] == _text || targets[i] == _compound_text || - targets[i] == _save_targets) + targets[i] == _text || + targets[i] == text_plain_charset_utf_8 || + targets[i] == text_plain_charset_CP1252 || + targets[i] == text_plain) continue; target_name = gdk_atom_name (targets[i]); - if (!(formatid = RegisterClipboardFormat (target_name))) - { - WIN32_API_FAILED ("RegisterClipboardFormat"); - API_CALL (CloseClipboard, ()); - g_free (target_name); - return; - } - g_hash_table_replace (_format_atom_table, GINT_TO_POINTER (formatid), targets[i]); - - GDK_NOTE (DND, g_print ("... SetClipboardData(%s,NULL)\n", - _gdk_win32_cf_to_string (formatid))); - SetClipboardData (formatid, NULL); - /* We should replace the previous image format associated with - * CF_DIB with "image/bmp" if we find "image/bmp", "image/x-bmp" - * or "image/x-MS-bmp" is available. - */ - if (!has_real_dib && - (!strcmp (target_name, "image/bmp") || - !strcmp (target_name, "image/x-bmp") || - !strcmp (target_name, "image/x-MS-bmp"))) + if (g_str_has_prefix (target_name, "text/plain;charset=")) { - g_hash_table_replace (_format_atom_table, - GINT_TO_POINTER (CF_DIB), - targets[i]); - if (!has_set_dib) - { - GDK_NOTE (DND, g_print ("... SetClipboardData(CF_DIB,NULL)\n")); - SetClipboardData (CF_DIB, NULL); - has_set_dib = TRUE; - } - has_real_dib = TRUE; g_free (target_name); continue; } - for (format = convertable_formats; !has_set_dib && format; format = format->next) - { - gchar **mime_types = - gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) format->data); - gchar **mime_type; + cf = RegisterClipboardFormat (target_name); + + g_hash_table_replace (_format_atom_table, + GINT_TO_POINTER (cf), + targets[i]); + + GDK_NOTE (DND, g_print ("... SetClipboardData(%s,NULL)\n", + _gdk_win32_cf_to_string (cf))); + SetClipboardData (cf, NULL); - for (mime_type = mime_types; *mime_type; ++mime_type) - { - if (!strcmp (target_name, *mime_type)) - { - g_hash_table_replace (_format_atom_table, - GINT_TO_POINTER (CF_DIB), - targets[i]); - GDK_NOTE (DND, g_print ("... SetClipboardData(CF_DIB,NULL)\n")); - SetClipboardData (CF_DIB, NULL); - has_set_dib = TRUE; - break; - } - } - g_strfreev(mime_types); - } g_free (target_name); } - g_slist_free (convertable_formats); - API_CALL (CloseClipboard, ()); } @@ -1153,84 +1288,33 @@ HGLOBAL _gdk_win32_selection_convert_to_dib (HGLOBAL hdata, GdkAtom target) { - GdkPixbufLoader *loader; - GdkPixbuf *pixbuf; - gchar *target_name; - guchar *ptr; - gchar *bmp_buf; - gsize size; - gboolean ok; - - if (!(target_name = gdk_atom_name (target))) - { - GlobalFree (hdata); - return NULL; - } + GDK_NOTE (DND, { + gchar *target_name = gdk_atom_name (target); + + g_print ("_gdk_win32_selection_convert_to_dib: %p %s\n", + hdata, target_name); + g_free (target_name); + }); - if (!strcmp (target_name, "image/bmp") || - !strcmp (target_name, "image/x-bmp") || - !strcmp (target_name, "image/x-MS-bmp")) + if (target == image_bmp) { /* No conversion is needed, just strip the BITMAPFILEHEADER */ HGLOBAL hdatanew; + SIZE_T size = GlobalSize (hdata) - sizeof (BITMAPFILEHEADER); + guchar *ptr = GlobalLock (hdata); - g_free (target_name); - size = GlobalSize (hdata) - sizeof (BITMAPFILEHEADER); - ptr = GlobalLock (hdata); memmove (ptr, ptr + sizeof (BITMAPFILEHEADER), size); GlobalUnlock (hdata); - if (!(hdatanew = GlobalReAlloc (hdata, size, 0))) + + if ((hdatanew = GlobalReAlloc (hdata, size, GMEM_MOVEABLE)) == NULL) { WIN32_API_FAILED ("GlobalReAlloc"); - GlobalFree (hdata); /* the old hdata is not freed if error */ + GlobalFree (hdata); /* The old hdata is not freed if error */ } return hdatanew; } - /* We actually provide image formats -other than- "image/bmp" etc - * and the requestor is either a native Win32 application or a GTK+ - * client that requested "image/bmp". - */ - if (!(loader = gdk_pixbuf_loader_new_with_mime_type (target_name, NULL))) - { - GlobalFree (hdata); - g_free (target_name); - return NULL; - } - g_free (target_name); - - ptr = GlobalLock (hdata); - ok = gdk_pixbuf_loader_write (loader, ptr, GlobalSize (hdata) - 1, NULL) && - gdk_pixbuf_loader_close (loader, NULL); - - GlobalUnlock (hdata); - GlobalFree (hdata); - hdata = NULL; - - if (ok && (pixbuf = gdk_pixbuf_loader_get_pixbuf (loader)) != NULL) - g_object_ref (pixbuf); - - g_object_unref (loader); - - if (ok && gdk_pixbuf_save_to_buffer (pixbuf, &bmp_buf, &size, "bmp", NULL, NULL)) - { - size -= sizeof (BITMAPFILEHEADER); - if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size))) - { - WIN32_API_FAILED ("GlobalAlloc"); - ok = FALSE; - } - - if (ok) - { - ptr = GlobalLock (hdata); - memcpy (ptr, bmp_buf + sizeof (BITMAPFILEHEADER), size); - GlobalUnlock (hdata); - } - - g_free (bmp_buf); - g_object_unref (pixbuf); - } + g_warning ("Should not happen: We provide some image format but not CF_DIB and CF_DIB is requested."); - return hdata; + return NULL; } |