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/.
31 #include "gdkproperty.h"
32 #include "gdkselection.h"
33 #include "gdkdisplay.h"
34 #include "gdkprivate-win32.h"
36 /* We emulate the GDK_SELECTION window properties of windows (as used
37 * in the X11 backend) by using a hash table from GdkWindows to
48 static GHashTable *sel_prop_table = NULL;
50 static GdkSelProp *dropfiles_prop = NULL;
52 /* We store the owner of each selection in this table. Obviously, this only
53 * is valid intra-app, and in fact it is necessary for the intra-app DND to work.
55 static GHashTable *sel_owner_table = NULL;
58 _gdk_win32_selection_init (void)
60 sel_prop_table = g_hash_table_new (NULL, NULL);
61 sel_owner_table = g_hash_table_new (NULL, NULL);
65 _gdk_selection_property_store (GdkWindow *owner,
73 prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (owner));
77 g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (owner));
79 prop = g_new (GdkSelProp, 1);
81 prop->length = length;
82 prop->format = format;
84 g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (owner), prop);
88 _gdk_dropfiles_store (gchar *data)
92 g_assert (dropfiles_prop == NULL);
94 dropfiles_prop = g_new (GdkSelProp, 1);
95 dropfiles_prop->data = data;
96 dropfiles_prop->length = strlen (data);
97 dropfiles_prop->format = 8;
98 dropfiles_prop->type = _text_uri_list;
102 if (dropfiles_prop != NULL)
104 g_free (dropfiles_prop->data);
105 g_free (dropfiles_prop);
107 dropfiles_prop = NULL;
112 gdk_selection_owner_set_for_display (GdkDisplay *display,
122 g_return_val_if_fail (display == gdk_display_get_default (), FALSE);
125 (sel_name = gdk_atom_name (selection),
126 g_print ("gdk_selection_owner_set: %p %#x (%s)\n",
127 (owner ? GDK_WINDOW_HWND (owner) : NULL),
128 (guint) selection, sel_name),
131 if (selection != GDK_SELECTION_CLIPBOARD)
134 g_hash_table_insert (sel_owner_table, selection, GDK_WINDOW_HWND (owner));
136 g_hash_table_remove (sel_owner_table, selection);
140 /* Rest of this function handles the CLIPBOARD selection */
143 if (GDK_WINDOW_DESTROYED (owner))
146 hwnd = GDK_WINDOW_HWND (owner);
151 if (!API_CALL (OpenClipboard, (hwnd)))
154 if (!API_CALL (EmptyClipboard, ()))
156 API_CALL (CloseClipboard, ());
160 /* No delayed rendering */
162 SetClipboardData (CF_TEXT, NULL);
164 if (!API_CALL (CloseClipboard, ()))
169 /* Send ourselves a selection request message so that
170 * gdk_property_change will be called to store the clipboard
173 GDK_NOTE (DND, g_print ("...sending GDK_SELECTION_REQUEST to ourselves\n"));
174 tmp_event.selection.type = GDK_SELECTION_REQUEST;
175 tmp_event.selection.window = owner;
176 tmp_event.selection.send_event = FALSE;
177 tmp_event.selection.selection = selection;
178 tmp_event.selection.target = GDK_TARGET_STRING;
179 tmp_event.selection.property = _gdk_selection_property;
180 tmp_event.selection.requestor = (guint32) hwnd;
181 tmp_event.selection.time = time;
183 gdk_event_put (&tmp_event);
190 gdk_selection_owner_get_for_display (GdkDisplay *display,
196 g_return_val_if_fail (display == gdk_display_get_default (), NULL);
198 /* Return NULL for CLIPBOARD, because otherwise cut&paste
199 * inside the same application doesn't work. We must pretend to gtk
200 * that we don't have the selection, so that we always fetch it from
201 * the Windows clipboard. See also comments in
202 * gdk_selection_send_notify().
204 if (selection == GDK_SELECTION_CLIPBOARD)
207 window = gdk_window_lookup ((GdkNativeWindow) g_hash_table_lookup (sel_owner_table, selection));
210 (sel_name = gdk_atom_name (selection),
211 g_print ("gdk_selection_owner_get: %#x (%s) = %p\n",
212 (guint) selection, sel_name,
213 (window ? GDK_WINDOW_HWND (window) : NULL)),
220 generate_selection_notify (GdkWindow *requestor,
228 tmp_event.selection.type = GDK_SELECTION_NOTIFY;
229 tmp_event.selection.window = requestor;
230 tmp_event.selection.send_event = FALSE;
231 tmp_event.selection.selection = selection;
232 tmp_event.selection.target = target;
233 tmp_event.selection.property = property;
234 tmp_event.selection.requestor = 0;
235 tmp_event.selection.time = time;
237 gdk_event_put (&tmp_event);
241 gdk_selection_convert (GdkWindow *requestor,
247 GdkAtom property = _gdk_selection_property;
248 gchar *sel_name, *tgt_name;
250 g_return_if_fail (requestor != NULL);
251 if (GDK_WINDOW_DESTROYED (requestor))
255 (sel_name = gdk_atom_name (selection),
256 tgt_name = gdk_atom_name (target),
257 g_print ("gdk_selection_convert: %p %#x (%s) %#x (%s)\n",
258 GDK_WINDOW_HWND (requestor),
259 (guint) selection, sel_name,
260 (guint) target, tgt_name),
264 if (selection == GDK_SELECTION_CLIPBOARD &&
265 target == gdk_atom_intern ("TARGETS", FALSE))
267 /* He wants to know what formats are on the clipboard. If there
268 * is some kind of text, tell him so.
270 if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
273 if (IsClipboardFormatAvailable (CF_UNICODETEXT) ||
274 IsClipboardFormatAvailable (_cf_utf8_string) ||
275 IsClipboardFormatAvailable (CF_TEXT))
277 GdkAtom *data = g_new (GdkAtom, 1);
278 *data = GDK_TARGET_STRING;
279 _gdk_selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM,
280 32, (guchar *) data, 1 * sizeof (GdkAtom));
285 API_CALL (CloseClipboard, ());
287 else if (selection == GDK_SELECTION_CLIPBOARD &&
288 (target == _compound_text ||
289 target == GDK_TARGET_STRING))
291 /* Converting the CLIPBOARD selection means he wants the
292 * contents of the clipboard. Get the clipboard data,
293 * and store it for later.
295 if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
298 /* Try various formats. First the simplest, CF_UNICODETEXT. */
299 if ((hdata = GetClipboardData (CF_UNICODETEXT)) != NULL)
301 wchar_t *ptr, *wcs, *p, *q;
305 if ((ptr = GlobalLock (hdata)) != NULL)
307 length = GlobalSize (hdata);
309 GDK_NOTE (DND, g_print ("...CF_UNICODETEXT: %d bytes\n",
313 wcs = g_new (wchar_t, (length + 1) * 2);
327 data = _gdk_ucs2_to_utf8 (wcs, wclen);
330 _gdk_selection_property_store (requestor, target, 8,
331 data, strlen (data) + 1);
332 GlobalUnlock (hdata);
335 else if ((hdata = GetClipboardData (_cf_utf8_string)) != NULL)
337 /* UTF8_STRING is a format we store ourselves when necessary */
341 if ((ptr = GlobalLock (hdata)) != NULL)
343 length = GlobalSize (hdata);
345 GDK_NOTE (DND, g_print ("...UTF8_STRING: %d bytes: %.10s\n",
348 _gdk_selection_property_store (requestor, target, 8,
349 g_strdup (ptr), strlen (ptr) + 1);
350 GlobalUnlock (hdata);
353 else if ((hdata = GetClipboardData (CF_TEXT)) != NULL)
355 /* We must always assume the data can contain non-ASCII
356 * in either the current code page, or if there is CF_LOCALE
357 * data, in that locale's default code page.
361 wchar_t *wcs, *wcs2, *p, *q;
365 if ((ptr = GlobalLock (hdata)) != NULL)
367 length = GlobalSize (hdata);
369 GDK_NOTE (DND, g_print ("...CF_TEXT: %d bytes: %.10s\n",
372 if ((hlcid = GetClipboardData (CF_LOCALE)) != NULL)
375 LCID *lcidptr = GlobalLock (hlcid);
376 if (GetLocaleInfo (*lcidptr, LOCALE_IDEFAULTANSICODEPAGE,
380 GDK_NOTE (DND, g_print ("...CF_LOCALE: %#lx cp:%d\n",
383 GlobalUnlock (hlcid);
386 wcs = g_new (wchar_t, length + 1);
387 wclen = MultiByteToWideChar (cp, 0, ptr, -1,
391 wcs2 = g_new (wchar_t, wclen);
406 data = _gdk_ucs2_to_utf8 (wcs2, wclen);
409 _gdk_selection_property_store (requestor, target, 8,
410 data, strlen (data) + 1);
411 GlobalUnlock (hdata);
417 API_CALL (CloseClipboard, ());
419 else if (selection == _gdk_win32_dropfiles)
421 /* This means he wants the names of the dropped files.
422 * gdk_dropfiles_filter already has stored the text/uri-list
423 * data temporarily in dropfiles_prop.
425 if (dropfiles_prop != NULL)
427 _gdk_selection_property_store
428 (requestor, selection, dropfiles_prop->format,
429 dropfiles_prop->data, dropfiles_prop->length);
430 g_free (dropfiles_prop);
431 dropfiles_prop = NULL;
437 /* Generate a selection notify message so that we actually fetch
438 * the data (if property == _gdk_selection_property) or indicating failure
439 * (if property == GDK_NONE).
441 generate_selection_notify (requestor, selection, target, property, time);
445 gdk_selection_property_get (GdkWindow *requestor,
452 g_return_val_if_fail (requestor != NULL, 0);
453 g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
455 if (GDK_WINDOW_DESTROYED (requestor))
458 GDK_NOTE (DND, g_print ("gdk_selection_property_get: %p\n",
459 GDK_WINDOW_HWND (requestor)));
461 prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (requestor));
469 *data = g_malloc (prop->length);
470 if (prop->length > 0)
471 memmove (*data, prop->data, prop->length);
474 *ret_type = prop->type;
477 *ret_format = prop->format;
483 _gdk_selection_property_delete (GdkWindow *window)
487 GDK_NOTE (DND, g_print ("_gdk_selection_property_delete: %p\n",
488 GDK_WINDOW_HWND (window)));
490 prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (window));
494 g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (window));
499 gdk_selection_send_notify_for_display (GdkDisplay *display,
507 gchar *sel_name, *tgt_name, *prop_name;
509 g_return_if_fail (display == gdk_display_get_default ());
512 (sel_name = gdk_atom_name (selection),
513 tgt_name = gdk_atom_name (target),
514 prop_name = gdk_atom_name (property),
515 g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n",
517 (guint) selection, sel_name,
518 (guint) target, tgt_name,
519 (guint) property, prop_name),
522 g_free (prop_name)));
524 /* Send ourselves a selection clear message so that gtk thinks we don't
525 * have the selection, and will claim it anew when needed, and
526 * we thus get a chance to store data in the Windows clipboard.
527 * Otherwise, if a gtkeditable does a copy to CLIPBOARD several times
528 * only the first one actually gets copied to the Windows clipboard,
529 * as only the first one causes a call to gdk_property_change().
531 * Hmm, there is something fishy with this. Cut and paste inside the
532 * same app didn't work, the gtkeditable immediately forgot the
533 * clipboard contents in gtk_editable_selection_clear() as a result
534 * of this message. OTOH, when I changed gdk_selection_owner_get to
535 * return NULL for CLIPBOARD, it works. Sigh.
538 tmp_event.selection.type = GDK_SELECTION_CLEAR;
539 tmp_event.selection.window = gdk_window_lookup (requestor);
540 tmp_event.selection.send_event = FALSE;
541 tmp_event.selection.selection = selection;
542 tmp_event.selection.target = 0;
543 tmp_event.selection.property = 0;
544 tmp_event.selection.requestor = 0;
545 tmp_event.selection.time = time;
547 gdk_event_put (&tmp_event);
550 /* Simplistic implementations of text list and compound text functions */
553 gdk_text_property_to_text_list_for_display (GdkDisplay *display,
562 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
564 GDK_NOTE (DND, (enc_name = gdk_atom_name (encoding),
565 g_print ("gdk_text_property_to_text_list: %s %d %.20s %d\n",
566 enc_name, format, text, length),
572 *list = g_new (gchar *, 1);
573 **list = g_strdup (text);
579 gdk_free_text_list (gchar **list)
581 g_return_if_fail (list != NULL);
588 gdk_string_to_compound_text_for_display (GdkDisplay *display,
595 g_return_val_if_fail (str != NULL, 0);
596 g_return_val_if_fail (length >= 0, 0);
597 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
599 GDK_NOTE (DND, g_print ("gdk_string_to_compound_text: %.20s\n", str));
602 *encoding = _compound_text;
608 *ctext = g_strdup (str);
611 *length = strlen (str);
617 gdk_free_compound_text (guchar *ctext)
622 /* These are lifted from gdkselection-x11.c, just to get GTK+ to build.
623 * These functions probably don't make much sense at all in Windows.
629 make_list (const gchar *text,
634 GSList *strings = NULL;
637 const gchar *p = text;
640 GError *error = NULL;
642 while (p < text + length)
647 while (*q && q < text + length)
652 str = g_convert (p, q - p,
653 "UTF-8", "ISO-8859-1",
658 g_warning ("Error converting selection from STRING: %s",
660 g_error_free (error);
664 str = g_strndup (p, q - p);
668 strings = g_slist_prepend (strings, str);
676 *list = g_new (gchar *, n_strings + 1);
678 (*list)[n_strings] = NULL;
685 (*list)[--i] = tmp_list->data;
687 g_free (tmp_list->data);
689 tmp_list = tmp_list->next;
692 g_slist_free (strings);
698 gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
705 g_return_val_if_fail (text != NULL, 0);
706 g_return_val_if_fail (length >= 0, 0);
707 g_return_val_if_fail (display == gdk_display_get_default (), 0);
709 if (encoding == GDK_TARGET_STRING)
711 return make_list ((gchar *)text, length, TRUE, list);
713 else if (encoding == _utf8_string)
715 return make_list ((gchar *)text, length, FALSE, list);
722 const gchar *charset = NULL;
723 gboolean need_conversion = g_get_charset (&charset);
725 GError *error = NULL;
727 /* Probably COMPOUND text, we fall back to Xlib routines
729 local_count = gdk_text_property_to_text_list (encoding,
735 *list = g_new (gchar *, local_count + 1);
737 for (i=0; i<local_count; i++)
739 /* list contains stuff in our default encoding
743 gchar *utf = g_convert (local_list[i], -1,
749 (*list)[count++] = utf;
755 g_warning ("Error converting to UTF-8 from '%s': %s",
756 charset, error->message);
757 g_error_free (error);
764 (*list)[count++] = g_strdup (local_list[i]);
768 gdk_free_text_list (local_list);
769 (*list)[count] = NULL;
775 /* The specifications for COMPOUND_TEXT and STRING specify that C0 and
776 * C1 are not allowed except for \n and \t, however the X conversions
777 * routines for COMPOUND_TEXT only enforce this in one direction,
778 * causing cut-and-paste of \r and \r\n separated text to fail.
779 * This routine strips out all non-allowed C0 and C1 characters
780 * from the input string and also canonicalizes \r, and \r\n to \n
783 sanitize_utf8 (const gchar *src)
785 gint len = strlen (src);
786 GString *result = g_string_sized_new (len);
787 const gchar *p = src;
797 g_string_append_c (result, '\n');
801 gunichar ch = g_utf8_get_char (p);
805 if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
807 buflen = g_unichar_to_utf8 (ch, buf);
808 g_string_append_len (result, buf, buflen);
811 p = g_utf8_next_char (p);
815 return g_string_free (result, FALSE);
819 gdk_utf8_to_string_target (const gchar *str)
821 return sanitize_utf8 (str);
825 gdk_utf8_to_compound_text_for_display (GdkDisplay *display,
832 gboolean need_conversion;
833 const gchar *charset;
834 gchar *locale_str, *tmp_str;
835 GError *error = NULL;
838 g_return_val_if_fail (str != NULL, FALSE);
839 g_return_val_if_fail (display == gdk_display_get_default (), FALSE);
841 need_conversion = !g_get_charset (&charset);
843 tmp_str = sanitize_utf8 (str);
847 locale_str = g_convert_with_fallback (tmp_str, -1,
849 NULL, NULL, NULL, &error);
854 g_warning ("Error converting from UTF-8 to '%s': %s",
855 charset, error->message);
856 g_error_free (error);
859 *encoding = GDK_NONE;
861 *format = GPOINTER_TO_UINT (GDK_ATOM_TO_POINTER (GDK_NONE));
871 locale_str = tmp_str;
873 result = gdk_string_to_compound_text (locale_str,
874 encoding, format, ctext, length);