1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-2002 Tor Lillqvist
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
32 #include "gdkproperty.h"
33 #include "gdkselection.h"
34 #include "gdkdisplay.h"
35 #include "gdkprivate-win32.h"
37 /* We emulate the GDK_SELECTION window properties of windows (as used
38 * in the X11 backend) by using a hash table from GdkWindows to
49 static GHashTable *sel_prop_table = NULL;
51 static GdkSelProp *dropfiles_prop = NULL;
53 /* We store the owner of each selection in this table. Obviously, this only
54 * is valid intra-app, and in fact it is necessary for the intra-app DND to work.
56 static GHashTable *sel_owner_table = NULL;
59 _gdk_win32_selection_init (void)
61 sel_prop_table = g_hash_table_new (NULL, NULL);
62 sel_owner_table = g_hash_table_new (NULL, NULL);
63 _format_atom_table = g_hash_table_new (NULL, NULL);
66 /* The specifications for COMPOUND_TEXT and STRING specify that C0 and
67 * C1 are not allowed except for \n and \t, however the X conversions
68 * routines for COMPOUND_TEXT only enforce this in one direction,
69 * causing cut-and-paste of \r and \r\n separated text to fail.
70 * This routine strips out all non-allowed C0 and C1 characters
71 * from the input string and also canonicalizes \r, and \r\n to \n
74 sanitize_utf8 (const gchar *src,
77 GString *result = g_string_sized_new (length + 1);
79 const gchar *endp = src + length;
89 g_string_append_c (result, '\n');
93 gunichar ch = g_utf8_get_char (p);
97 if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
99 buflen = g_unichar_to_utf8 (ch, buf);
100 g_string_append_len (result, buf, buflen);
103 p = g_utf8_next_char (p);
106 g_string_append_c (result, '\0');
108 return g_string_free (result, FALSE);
112 _gdk_utf8_to_string_target_internal (const gchar *str,
115 GError *error = NULL;
117 gchar *tmp_str = sanitize_utf8 (str, length);
118 gchar *result = g_convert_with_fallback (tmp_str, -1,
119 "ISO-8859-1", "UTF-8",
120 NULL, NULL, NULL, &error);
123 g_warning ("Error converting from UTF-8 to STRING: %s",
125 g_error_free (error);
133 _gdk_selection_property_store (GdkWindow *owner,
142 prop = g_new (GdkSelProp, 1);
144 if (type == GDK_TARGET_STRING)
146 /* We know that data is UTF-8 */
147 prop->data = _gdk_utf8_to_string_target_internal (data, length);
157 prop->length = strlen (prop->data) + 1;
162 prop->length = length;
164 prop->format = format;
166 prop_list = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (owner));
167 prop_list = g_slist_append (prop_list, prop);
168 g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (owner), prop_list);
172 _gdk_dropfiles_store (gchar *data)
176 g_assert (dropfiles_prop == NULL);
178 dropfiles_prop = g_new (GdkSelProp, 1);
179 dropfiles_prop->data = data;
180 dropfiles_prop->length = strlen (data) + 1;
181 dropfiles_prop->format = 8;
182 dropfiles_prop->type = _text_uri_list;
186 if (dropfiles_prop != NULL)
188 g_free (dropfiles_prop->data);
189 g_free (dropfiles_prop);
191 dropfiles_prop = NULL;
196 gdk_selection_owner_set_for_display (GdkDisplay *display,
205 g_return_val_if_fail (display == _gdk_display, FALSE);
206 g_return_val_if_fail (selection != GDK_NONE, FALSE);
208 #ifdef G_ENABLE_DEBUG
213 (sel_name = gdk_atom_name (selection),
214 g_print ("gdk_selection_owner_set_for_display: %p %#x (%s)\n",
215 (owner ? GDK_WINDOW_HWND (owner) : NULL),
216 (guint) selection, sel_name),
221 if (selection != GDK_SELECTION_CLIPBOARD)
224 g_hash_table_insert (sel_owner_table, selection, GDK_WINDOW_HWND (owner));
226 g_hash_table_remove (sel_owner_table, selection);
230 /* Rest of this function handles the CLIPBOARD selection */
233 if (GDK_WINDOW_DESTROYED (owner))
236 hwnd = GDK_WINDOW_HWND (owner);
241 if (!API_CALL (OpenClipboard, (hwnd)))
244 _ignore_destroy_clipboard = TRUE;
245 GDK_NOTE (DND, g_print ("... EmptyClipboard()\n"));
246 if (!API_CALL (EmptyClipboard, ()))
248 _ignore_destroy_clipboard = FALSE;
249 API_CALL (CloseClipboard, ());
252 _ignore_destroy_clipboard = FALSE;
254 if (!API_CALL (CloseClipboard, ()))
259 /* Send ourselves a selection request message so that
260 * gdk_property_change will be called to store the clipboard
263 GDK_NOTE (DND, g_print ("... sending GDK_SELECTION_REQUEST to ourselves\n"));
264 tmp_event.selection.type = GDK_SELECTION_REQUEST;
265 tmp_event.selection.window = owner;
266 tmp_event.selection.send_event = FALSE;
267 tmp_event.selection.selection = selection;
268 tmp_event.selection.target = _utf8_string;
269 tmp_event.selection.property = _gdk_selection_property;
270 tmp_event.selection.requestor = (guint32) hwnd;
271 tmp_event.selection.time = time;
273 gdk_event_put (&tmp_event);
280 gdk_selection_owner_get_for_display (GdkDisplay *display,
285 g_return_val_if_fail (display == _gdk_display, NULL);
286 g_return_val_if_fail (selection != GDK_NONE, NULL);
288 if (selection == GDK_SELECTION_CLIPBOARD)
290 HWND owner = GetClipboardOwner ();
295 return gdk_win32_handle_table_lookup ((GdkNativeWindow) owner);
298 window = gdk_window_lookup ((GdkNativeWindow) g_hash_table_lookup (sel_owner_table, selection));
300 #ifdef G_ENABLE_DEBUG
305 (sel_name = gdk_atom_name (selection),
306 g_print ("gdk_selection_owner_get: %#x (%s) = %p\n",
307 (guint) selection, sel_name,
308 (window ? GDK_WINDOW_HWND (window) : NULL)),
317 generate_selection_notify (GdkWindow *requestor,
325 tmp_event.selection.type = GDK_SELECTION_NOTIFY;
326 tmp_event.selection.window = requestor;
327 tmp_event.selection.send_event = FALSE;
328 tmp_event.selection.selection = selection;
329 tmp_event.selection.target = target;
330 tmp_event.selection.property = property;
331 tmp_event.selection.requestor = 0;
332 tmp_event.selection.time = time;
334 gdk_event_put (&tmp_event);
338 gdk_selection_convert (GdkWindow *requestor,
344 GdkAtom property = _gdk_selection_property;
346 g_return_if_fail (selection != GDK_NONE);
347 g_return_if_fail (requestor != NULL);
349 if (GDK_WINDOW_DESTROYED (requestor))
352 #ifdef G_ENABLE_DEBUG
354 gchar *sel_name, *tgt_name;
357 (sel_name = gdk_atom_name (selection),
358 tgt_name = gdk_atom_name (target),
359 g_print ("gdk_selection_convert: %p %#x (%s) %#x (%s)\n",
360 GDK_WINDOW_HWND (requestor),
361 (guint) selection, sel_name,
362 (guint) target, tgt_name),
368 if (selection == GDK_SELECTION_CLIPBOARD && target == _targets)
370 gint formats_cnt, i, fmt;
372 gboolean has_bmp = FALSE;
374 /* He wants to know what formats are on the clipboard. If there
375 * is some kind of text, tell him so.
377 if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
380 formats_cnt = CountClipboardFormats ();
381 data = g_new (GdkAtom, formats_cnt + 2);
384 if (IsClipboardFormatAvailable (CF_UNICODETEXT) ||
385 IsClipboardFormatAvailable (_cf_utf8_string) ||
386 IsClipboardFormatAvailable (CF_TEXT))
388 data[i++] = _utf8_string;
392 /* If there is anything else in the clipboard, enum it all
393 * although we don't offer special conversion services.
395 for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); )
399 if (GetClipboardFormatName (fmt, sFormat, 80) > 0 &&
400 strcmp (sFormat, "UTF8_STRING"))
405 (!strcmp (sFormat, "image/bmp") ||
406 !strcmp (sFormat, "image/x-bmp") ||
407 !strcmp (sFormat, "image/x-MS-bmp")))
409 atom = gdk_atom_intern (sFormat, FALSE);
414 if (!has_bmp && (IsClipboardFormatAvailable (CF_BITMAP) ||
415 IsClipboardFormatAvailable (CF_DIB)))
416 data[i++] = _image_bmp;
419 _gdk_selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM,
420 32, (guchar *) data, i * sizeof (GdkAtom));
424 API_CALL (CloseClipboard, ());
426 else if (selection == GDK_SELECTION_CLIPBOARD && target == _utf8_string)
428 /* Converting the CLIPBOARD selection means he wants the
429 * contents of the clipboard. Get the clipboard data, and store
432 if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
435 /* Try various formats. First the simplest, CF_UNICODETEXT. */
436 if ((hdata = GetClipboardData (CF_UNICODETEXT)) != NULL)
438 wchar_t *ptr, *wcs, *p, *q;
442 if ((ptr = GlobalLock (hdata)) != NULL)
444 length = GlobalSize (hdata);
446 GDK_NOTE (DND, g_print ("... CF_UNICODETEXT: %ld bytes\n",
450 wcs = g_new (wchar_t, length / 2 + 1);
454 while (p < ptr + length / 2)
464 data = g_utf16_to_utf8 (wcs, wclen, NULL, NULL, NULL);
468 _gdk_selection_property_store (requestor, target, 8,
469 data, strlen (data) + 1);
470 GlobalUnlock (hdata);
473 else if ((hdata = GetClipboardData (_cf_utf8_string)) != NULL)
475 /* UTF8_STRING is a format we store ourselves when necessary */
479 if ((ptr = GlobalLock (hdata)) != NULL)
481 length = GlobalSize (hdata);
483 GDK_NOTE (DND, g_print ("... UTF8_STRING: %d bytes: %.10s\n",
486 _gdk_selection_property_store (requestor, target, 8,
487 g_memdup (ptr, length), length);
488 GlobalUnlock (hdata);
491 else if ((hdata = GetClipboardData (CF_TEXT)) != NULL)
493 /* We must always assume the data can contain non-ASCII
494 * in either the current code page, or if there is CF_LOCALE
495 * data, in that locale's default code page.
499 wchar_t *wcs, *wcs2, *p, *q;
501 glong length, wclen, wclen2;
503 if ((ptr = GlobalLock (hdata)) != NULL)
505 length = GlobalSize (hdata);
507 GDK_NOTE (DND, g_print ("... CF_TEXT: %ld bytes: %.10s\n",
510 if ((hlcid = GetClipboardData (CF_LOCALE)) != NULL)
513 LCID *lcidptr = GlobalLock (hlcid);
514 if (GetLocaleInfo (*lcidptr, LOCALE_IDEFAULTANSICODEPAGE,
518 GDK_NOTE (DND, g_print ("... CF_LOCALE: %#lx cp:%d\n",
521 GlobalUnlock (hlcid);
524 wcs = g_new (wchar_t, length + 1);
525 wclen = MultiByteToWideChar (cp, 0, ptr, length,
529 wcs2 = g_new (wchar_t, wclen);
533 while (p < wcs + wclen)
544 data = g_utf16_to_utf8 (wcs2, wclen2, NULL, &length, NULL);
548 _gdk_selection_property_store (requestor, target, 8,
550 GlobalUnlock (hdata);
556 API_CALL (CloseClipboard, ());
558 else if (selection == GDK_SELECTION_CLIPBOARD && target == _image_bmp)
562 if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
564 if ((hdata = GetClipboardData (_cf_image_bmp)) != NULL)
566 /* "image/bmp" is the first choice. */
569 if ((ptr = GlobalLock (hdata)) != NULL)
571 gint length = GlobalSize (hdata);
573 GDK_NOTE (DND, g_print ("...BITMAP (from \"image/bmp\": %d bytes\n",
576 _gdk_selection_property_store (requestor, target, 8,
577 g_memdup (ptr, length), length);
578 GlobalUnlock (hdata);
581 else if ((hdata = GetClipboardData (CF_DIB)) != NULL)
583 /* If there's CF_DIB but not "image/bmp", the clipboard
584 * owner is probably a native Win32 application.
586 BITMAPINFOHEADER *ptr;
588 if ((ptr = GlobalLock (hdata)) != NULL)
590 BITMAPFILEHEADER *hdr; /* Need to add a file header so gdk-pixbuf can load it */
591 gint length = GlobalSize (hdata) + sizeof (BITMAPFILEHEADER);
593 GDK_NOTE (DND, g_print ("... BITMAP (from CF_DIB): %d bytes\n", length));
595 data = g_try_malloc (length);
598 hdr = (BITMAPFILEHEADER *)data;
599 hdr->bfType = 0x4d42; /* 0x42 = "B" 0x4d = "M" */
600 /* Compute the size of the entire file. */
601 hdr->bfSize = (DWORD) (sizeof (BITMAPFILEHEADER)
602 + ptr->biSize + ptr->biClrUsed
603 * sizeof (RGBQUAD) + ptr->biSizeImage);
604 hdr->bfReserved1 = 0;
605 hdr->bfReserved2 = 0;
606 /* Compute the offset to the array of color indices. */
607 hdr->bfOffBits = (DWORD) sizeof (BITMAPFILEHEADER)
608 + ptr->biSize + ptr->biClrUsed * sizeof (RGBQUAD);
609 /* Copy the data behind it */
610 memcpy (data + sizeof (BITMAPFILEHEADER), ptr, length - sizeof (BITMAPFILEHEADER));
611 _gdk_selection_property_store (requestor, target, 8,
614 GlobalUnlock (hdata);
619 API_CALL (CloseClipboard, ());
621 else if (selection == GDK_SELECTION_CLIPBOARD)
626 if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
629 target_name = gdk_atom_name (target);
631 /* Check if it's available. In fact, we can simply call
632 * GetClipboardData (RegisterClipboardFormat (targetname)), but
633 * the global custom format ID space is limited,
634 * (0xC000~0xFFFF), and we better not waste an format ID if we
635 * are just a requestor.
637 for ( ; 0 != (fmt = EnumClipboardFormats (fmt)); )
641 if (GetClipboardFormatName (fmt, sFormat, 80) > 0 &&
642 strcmp (sFormat, target_name) == 0)
644 if ((hdata = GetClipboardData (fmt)) != NULL)
646 /* Simply get it without conversion */
650 if ((ptr = GlobalLock (hdata)) != NULL)
652 length = GlobalSize (hdata);
654 GDK_NOTE (DND, g_print ("... %s: %d bytes\n", target_name, length));
656 _gdk_selection_property_store (requestor, target, 8,
657 g_memdup (ptr, length), length);
658 GlobalUnlock (hdata);
664 g_free (target_name);
665 API_CALL (CloseClipboard, ());
667 else if (selection == _gdk_win32_dropfiles)
669 /* This means he wants the names of the dropped files.
670 * gdk_dropfiles_filter already has stored the text/uri-list
671 * data temporarily in dropfiles_prop.
673 if (dropfiles_prop != NULL)
675 _gdk_selection_property_store
676 (requestor, selection, dropfiles_prop->format,
677 dropfiles_prop->data, dropfiles_prop->length);
678 g_free (dropfiles_prop);
679 dropfiles_prop = NULL;
685 /* Generate a selection notify message so that we actually fetch
686 * the data (if property == _gdk_selection_property) or indicating failure
687 * (if property == GDK_NONE).
689 generate_selection_notify (requestor, selection, target, property, time);
693 gdk_selection_property_get (GdkWindow *requestor,
701 g_return_val_if_fail (requestor != NULL, 0);
702 g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
704 if (GDK_WINDOW_DESTROYED (requestor))
707 GDK_NOTE (DND, g_print ("gdk_selection_property_get: %p\n",
708 GDK_WINDOW_HWND (requestor)));
710 prop_list = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (requestor));
711 prop = prop_list ? (GdkSelProp *) prop_list->data : NULL;
719 *data = g_malloc (prop->length + 1);
720 (*data)[prop->length] = '\0';
721 if (prop->length > 0)
722 memmove (*data, prop->data, prop->length);
725 *ret_type = prop->type;
728 *ret_format = prop->format;
734 _gdk_selection_property_delete (GdkWindow *window)
739 GDK_NOTE (DND, g_print ("_gdk_selection_property_delete: %p\n",
740 GDK_WINDOW_HWND (window)));
742 prop_list = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (window));
743 if (prop_list && (prop = (GdkSelProp *) prop_list->data) != NULL)
746 prop_list = g_slist_remove (prop_list, prop);
748 g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (window), prop_list);
753 gdk_selection_send_notify_for_display (GdkDisplay *display,
760 g_return_if_fail (display == _gdk_display);
762 #ifdef G_ENABLE_DEBUG
764 gchar *sel_name, *tgt_name, *prop_name;
767 (sel_name = gdk_atom_name (selection),
768 tgt_name = gdk_atom_name (target),
769 prop_name = gdk_atom_name (property),
770 g_print ("gdk_selection_send_notify_for_display: %p %#x (%s) %#x (%s) %#x (%s)\n",
771 (gpointer) requestor,
772 (guint) selection, sel_name,
773 (guint) target, tgt_name,
774 (guint) property, prop_name),
777 g_free (prop_name)));
782 /* It's hard to say whether implementing this actually is of any use
783 * on the Win32 platform? gtk calls only
784 * gdk_text_property_to_utf8_list_for_display().
787 gdk_text_property_to_text_list_for_display (GdkDisplay *display,
795 const gchar *charset;
796 gchar *source_charset;
798 g_return_val_if_fail (display == _gdk_display, 0);
800 #ifdef G_ENABLE_DEBUG
804 GDK_NOTE (DND, (enc_name = gdk_atom_name (encoding),
805 g_print ("gdk_text_property_to_text_list_for_display: %s %d %.20s %d\n",
806 enc_name, format, text, length),
814 if (encoding == GDK_TARGET_STRING)
815 source_charset = g_strdup ("ISO-8859-1");
816 else if (encoding == _utf8_string)
817 source_charset = g_strdup ("UTF-8");
819 source_charset = gdk_atom_name (encoding);
821 g_get_charset (&charset);
823 result = g_convert (text, length, charset, source_charset,
825 g_free (source_charset);
830 *list = g_new (gchar *, 1);
837 gdk_free_text_list (gchar **list)
839 g_return_if_fail (list != NULL);
846 make_list (const gchar *text,
851 GSList *strings = NULL;
854 const gchar *p = text;
857 GError *error = NULL;
859 while (p < text + length)
864 while (*q && q < text + length)
869 str = g_convert (p, q - p,
870 "UTF-8", "ISO-8859-1",
875 g_warning ("Error converting selection from STRING: %s",
877 g_error_free (error);
881 str = g_strndup (p, q - p);
885 strings = g_slist_prepend (strings, str);
893 *list = g_new (gchar *, n_strings + 1);
895 (*list)[n_strings] = NULL;
902 (*list)[--i] = tmp_list->data;
904 g_free (tmp_list->data);
906 tmp_list = tmp_list->next;
909 g_slist_free (strings);
915 gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
922 g_return_val_if_fail (text != NULL, 0);
923 g_return_val_if_fail (length >= 0, 0);
924 g_return_val_if_fail (display == _gdk_display, 0);
926 if (encoding == GDK_TARGET_STRING)
928 return make_list ((gchar *)text, length, TRUE, list);
930 else if (encoding == _utf8_string)
932 return make_list ((gchar *)text, length, FALSE, list);
936 gchar *enc_name = gdk_atom_name (encoding);
938 g_warning ("gdk_text_property_to_utf8_list_for_display: encoding %s not handled\n", enc_name);
949 gdk_string_to_compound_text_for_display (GdkDisplay *display,
956 g_return_val_if_fail (str != NULL, 0);
957 g_return_val_if_fail (length >= 0, 0);
958 g_return_val_if_fail (display == _gdk_display, 0);
960 GDK_NOTE (DND, g_print ("gdk_string_to_compound_text_for_display: %.20s\n", str));
962 /* Always fail on Win32. No COMPOUND_TEXT support. */
965 *encoding = GDK_NONE;
980 gdk_utf8_to_string_target (const gchar *str)
982 return _gdk_utf8_to_string_target_internal (str, strlen (str));
986 gdk_utf8_to_compound_text_for_display (GdkDisplay *display,
993 g_return_val_if_fail (str != NULL, FALSE);
994 g_return_val_if_fail (display == _gdk_display, FALSE);
996 GDK_NOTE (DND, g_print ("gdk_utf8_to_compound_text_for_display: %.20s\n", str));
998 /* Always fail on Win32. No COMPOUND_TEXT support. */
1001 *encoding = GDK_NONE;
1016 gdk_free_compound_text (guchar *ctext)
1018 /* As we never generate anything claimed to be COMPOUND_TEXT, this
1019 * should never be called. Or if it is called, ctext should be the
1020 * NULL returned for conversions to COMPOUND_TEXT above.
1022 g_return_if_fail (ctext == NULL);
1026 gdk_win32_selection_add_targets (GdkWindow *owner,
1034 GSList *convertable_formats, *format;
1035 gboolean has_set_dib = FALSE, has_real_dib = FALSE;
1037 #ifdef G_ENABLE_DEBUG
1038 if (_gdk_debug_flags & GDK_DEBUG_DND)
1040 gchar *sel_name = gdk_atom_name (selection);
1042 g_print ("gdk_win32_selection_add_targets: %p: %s: ",
1043 owner ? GDK_WINDOW_HWND (owner) : NULL,
1047 for (i = 0; i < n_targets; i++)
1049 gchar *tgt_name = gdk_atom_name (targets[i]);
1051 g_print ("%s ", tgt_name);
1058 if (selection != GDK_SELECTION_CLIPBOARD)
1063 if (GDK_WINDOW_DESTROYED (owner))
1065 hwnd = GDK_WINDOW_HWND (owner);
1068 if (!API_CALL (OpenClipboard, (hwnd)))
1071 convertable_formats = gdk_pixbuf_get_formats ();
1072 for (i = 0; i < n_targets; ++i)
1076 if (targets[i] == _utf8_string ||
1077 targets[i] == GDK_TARGET_STRING ||
1078 targets[i] == _text ||
1079 targets[i] == _compound_text ||
1080 targets[i] == _save_targets)
1083 target_name = gdk_atom_name (targets[i]);
1084 if (!(formatid = RegisterClipboardFormat (target_name)))
1086 WIN32_API_FAILED ("RegisterClipboardFormat");
1087 API_CALL (CloseClipboard, ());
1088 g_free (target_name);
1091 g_hash_table_replace (_format_atom_table, GINT_TO_POINTER (formatid), targets[i]);
1093 GDK_NOTE (DND, g_print ("... SetClipboardData(%s,NULL)\n",
1094 _gdk_win32_cf_to_string (formatid)));
1095 SetClipboardData (formatid, NULL);
1097 /* We should replace the previous image format associated with
1098 * CF_DIB with "image/bmp" if we find "image/bmp", "image/x-bmp"
1099 * or "image/x-MS-bmp" is available.
1101 if (!has_real_dib &&
1102 (!strcmp (target_name, "image/bmp") ||
1103 !strcmp (target_name, "image/x-bmp") ||
1104 !strcmp (target_name, "image/x-MS-bmp")))
1106 g_hash_table_replace (_format_atom_table,
1107 GINT_TO_POINTER (CF_DIB),
1111 GDK_NOTE (DND, g_print ("... SetClipboardData(CF_DIB,NULL)\n"));
1112 SetClipboardData (CF_DIB, NULL);
1115 has_real_dib = TRUE;
1116 g_free (target_name);
1120 for (format = convertable_formats; !has_set_dib && format; format = format->next)
1122 gchar **mime_types =
1123 gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) format->data);
1126 for (mime_type = mime_types; *mime_type; ++mime_type)
1128 if (!strcmp (target_name, *mime_type))
1130 g_hash_table_replace (_format_atom_table,
1131 GINT_TO_POINTER (CF_DIB),
1133 GDK_NOTE (DND, g_print ("... SetClipboardData(CF_DIB,NULL)\n"));
1134 SetClipboardData (CF_DIB, NULL);
1139 g_strfreev(mime_types);
1141 g_free (target_name);
1143 g_slist_free (convertable_formats);
1145 API_CALL (CloseClipboard, ());
1148 /* Convert from types such as "image/jpg" or "image/png" to DIB using
1149 * gdk-pixbuf so that image copied from GTK+ apps can be pasted in
1150 * native apps like mspaint.exe
1153 _gdk_win32_selection_convert_to_dib (HGLOBAL hdata,
1156 GdkPixbufLoader *loader;
1164 if (!(target_name = gdk_atom_name (target)))
1170 if (!strcmp (target_name, "image/bmp") ||
1171 !strcmp (target_name, "image/x-bmp") ||
1172 !strcmp (target_name, "image/x-MS-bmp"))
1174 /* No conversion is needed, just strip the BITMAPFILEHEADER */
1177 g_free (target_name);
1178 size = GlobalSize (hdata) - 1 - sizeof (BITMAPFILEHEADER);
1179 ptr = GlobalLock (hdata);
1180 memmove (ptr, ptr + sizeof (BITMAPFILEHEADER), size);
1181 GlobalUnlock (hdata);
1182 if (!(hdatanew = GlobalReAlloc (hdata, size, 0)))
1184 WIN32_API_FAILED ("GlobalReAlloc");
1185 GlobalFree (hdata); /* the old hdata is not freed if error */
1190 /* We actually provide image formats -other than- "image/bmp" etc
1191 * and the requestor is either a native Win32 application or a GTK+
1192 * client that requested "image/bmp".
1194 if (!(loader = gdk_pixbuf_loader_new_with_mime_type (target_name, NULL)))
1197 g_free (target_name);
1200 g_free (target_name);
1202 ptr = GlobalLock (hdata);
1203 ok = gdk_pixbuf_loader_write (loader, ptr, GlobalSize (hdata) - 1, NULL) &&
1204 gdk_pixbuf_loader_close (loader, NULL);
1206 GlobalUnlock (hdata);
1210 if (ok && (pixbuf = gdk_pixbuf_loader_get_pixbuf (loader)) != NULL)
1211 g_object_ref (pixbuf);
1213 g_object_unref (loader);
1215 if (ok && gdk_pixbuf_save_to_buffer (pixbuf, &bmp_buf, &size, "bmp", NULL, NULL))
1217 size -= sizeof (BITMAPFILEHEADER);
1218 if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size)))
1220 WIN32_API_FAILED ("GlobalAlloc");
1226 ptr = GlobalLock (hdata);
1227 memcpy (ptr, bmp_buf + sizeof (BITMAPFILEHEADER), size);
1228 GlobalUnlock (hdata);
1232 g_object_unref (pixbuf);