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 "gdkprivate-win32.h"
35 /* We emulate the GDK_SELECTION window properties of windows (as used
36 * in the X11 backend) by using a hash table from GdkWindows to
47 static GHashTable *sel_prop_table = NULL;
49 static GdkSelProp *dropfiles_prop = NULL;
51 /* We store the owner of each selection in this table. Obviously, this only
52 * is valid intra-app, and in fact it is necessary for the intra-app DND to work.
54 static GHashTable *sel_owner_table = NULL;
57 _gdk_win32_selection_init (void)
59 sel_prop_table = g_hash_table_new (NULL, NULL);
60 sel_owner_table = g_hash_table_new (NULL, NULL);
64 _gdk_selection_property_store (GdkWindow *owner,
72 prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (owner));
76 g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (owner));
78 prop = g_new (GdkSelProp, 1);
80 prop->length = length;
81 prop->format = format;
83 g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (owner), prop);
87 _gdk_dropfiles_store (gchar *data)
91 g_assert (dropfiles_prop == NULL);
93 dropfiles_prop = g_new (GdkSelProp, 1);
94 dropfiles_prop->data = data;
95 dropfiles_prop->length = strlen (data);
96 dropfiles_prop->format = 8;
97 dropfiles_prop->type = text_uri_list;
101 if (dropfiles_prop != NULL)
103 g_free (dropfiles_prop->data);
104 g_free (dropfiles_prop);
106 dropfiles_prop = NULL;
111 gdk_selection_owner_set (GdkWindow *owner,
121 (sel_name = gdk_atom_name (selection),
122 g_print ("gdk_selection_owner_set: %#x %#x (%s)\n",
123 (owner ? (guint) GDK_WINDOW_HWND (owner) : 0),
124 (guint) selection, sel_name),
127 if (selection != GDK_SELECTION_CLIPBOARD)
130 g_hash_table_insert (sel_owner_table, selection, GDK_WINDOW_HWND (owner));
132 g_hash_table_remove (sel_owner_table, selection);
136 /* Rest of this function handles the CLIPBOARD selection */
139 if (GDK_WINDOW_DESTROYED (owner))
142 xwindow = GDK_WINDOW_HWND (owner);
147 if (!OpenClipboard (xwindow))
149 WIN32_API_FAILED ("OpenClipboard");
152 if (!EmptyClipboard ())
154 WIN32_API_FAILED ("EmptyClipboard");
159 /* No delayed rendering */
161 SetClipboardData (CF_TEXT, NULL);
163 if (!CloseClipboard ())
165 WIN32_API_FAILED ("CloseClipboard");
171 /* Send ourselves a selection request message so that
172 * gdk_property_change will be called to store the clipboard
175 GDK_NOTE (DND, g_print ("...sending GDK_SELECTION_REQUEST to ourselves\n"));
176 tmp_event.selection.type = GDK_SELECTION_REQUEST;
177 tmp_event.selection.window = owner;
178 tmp_event.selection.send_event = FALSE;
179 tmp_event.selection.selection = selection;
180 tmp_event.selection.target = GDK_TARGET_STRING;
181 tmp_event.selection.property = _gdk_selection_property;
182 tmp_event.selection.requestor = (guint32) xwindow;
183 tmp_event.selection.time = time;
185 gdk_event_put (&tmp_event);
192 gdk_selection_owner_get (GdkAtom selection)
197 /* Return NULL for CLIPBOARD, because otherwise cut&paste
198 * inside the same application doesn't work. We must pretend to gtk
199 * that we don't have the selection, so that we always fetch it from
200 * the Windows clipboard. See also comments in
201 * gdk_selection_send_notify().
203 if (selection == GDK_SELECTION_CLIPBOARD)
206 window = gdk_window_lookup ((GdkNativeWindow) g_hash_table_lookup (sel_owner_table, selection));
209 (sel_name = gdk_atom_name (selection),
210 g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n",
211 (guint) selection, sel_name,
212 (window ? (guint) GDK_WINDOW_HWND (window) : 0)),
219 generate_selection_notify (GdkWindow *requestor,
227 tmp_event.selection.type = GDK_SELECTION_NOTIFY;
228 tmp_event.selection.window = requestor;
229 tmp_event.selection.send_event = FALSE;
230 tmp_event.selection.selection = selection;
231 tmp_event.selection.target = target;
232 tmp_event.selection.property = property;
233 tmp_event.selection.requestor = 0;
234 tmp_event.selection.time = time;
236 gdk_event_put (&tmp_event);
240 gdk_selection_convert (GdkWindow *requestor,
246 GdkAtom property = _gdk_selection_property;
247 gchar *sel_name, *tgt_name;
249 g_return_if_fail (requestor != NULL);
250 if (GDK_WINDOW_DESTROYED (requestor))
254 (sel_name = gdk_atom_name (selection),
255 tgt_name = gdk_atom_name (target),
256 g_print ("gdk_selection_convert: %#x %#x (%s) %#x (%s)\n",
257 (guint) GDK_WINDOW_HWND (requestor),
258 (guint) selection, sel_name,
259 (guint) target, tgt_name),
263 if (selection == GDK_SELECTION_CLIPBOARD &&
264 target == gdk_atom_intern ("TARGETS", FALSE))
266 /* He wants to know what formats are on the clipboard. If there
267 * is some kind of text, tell him so.
269 if (!OpenClipboard (GDK_WINDOW_HWND (requestor)))
271 WIN32_API_FAILED ("OpenClipboard");
275 if (IsClipboardFormatAvailable (CF_UNICODETEXT) ||
276 IsClipboardFormatAvailable (cf_utf8_string) ||
277 IsClipboardFormatAvailable (CF_TEXT))
279 GdkAtom *data = g_new (GdkAtom, 1);
280 *data = GDK_TARGET_STRING;
281 _gdk_selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM,
282 32, (guchar *) data, 1 * sizeof (GdkAtom));
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 (!OpenClipboard (GDK_WINDOW_HWND (requestor)))
297 WIN32_API_FAILED ("OpenClipboard");
301 /* Try various formats. First the simplest, CF_UNICODETEXT. */
302 if ((hdata = GetClipboardData (CF_UNICODETEXT)) != NULL)
304 wchar_t *ptr, *wcs, *p, *q;
308 if ((ptr = GlobalLock (hdata)) != NULL)
310 length = GlobalSize (hdata);
312 GDK_NOTE (DND, g_print ("...CF_UNICODETEXT: %d bytes\n",
316 wcs = g_new (wchar_t, (length + 1) * 2);
330 data = _gdk_ucs2_to_utf8 (wcs, wclen);
333 _gdk_selection_property_store (requestor, target, 8,
334 data, strlen (data) + 1);
335 GlobalUnlock (hdata);
338 else if ((hdata = GetClipboardData (cf_utf8_string)) != NULL)
340 /* UTF8_STRING is a format we store ourselves when necessary */
344 if ((ptr = GlobalLock (hdata)) != NULL)
346 length = GlobalSize (hdata);
348 GDK_NOTE (DND, g_print ("...UTF8_STRING: %d bytes: %.10s\n",
351 _gdk_selection_property_store (requestor, target, 8,
352 g_strdup (ptr), strlen (ptr) + 1);
353 GlobalUnlock (hdata);
356 else if ((hdata = GetClipboardData (CF_TEXT)) != NULL)
358 /* We must always assume the data can contain non-ASCII
359 * in either the current code page, or if there is CF_LOCALE
360 * data, in that locale's default code page.
364 wchar_t *wcs, *wcs2, *p, *q;
368 if ((ptr = GlobalLock (hdata)) != NULL)
370 length = GlobalSize (hdata);
372 GDK_NOTE (DND, g_print ("...CF_TEXT: %d bytes: %.10s\n",
375 if ((hlcid = GetClipboardData (CF_LOCALE)) != NULL)
378 LCID *lcidptr = GlobalLock (hlcid);
379 if (GetLocaleInfo (*lcidptr, LOCALE_IDEFAULTANSICODEPAGE,
383 GDK_NOTE (DND, g_print ("...CF_LOCALE: %#lx cp:%d\n",
386 GlobalUnlock (hlcid);
389 wcs = g_new (wchar_t, length + 1);
390 wclen = MultiByteToWideChar (cp, 0, ptr, length,
394 wcs2 = g_new (wchar_t, wclen);
409 data = _gdk_ucs2_to_utf8 (wcs2, wclen);
412 _gdk_selection_property_store (requestor, target, 8,
413 data, strlen (data) + 1);
414 GlobalUnlock (hdata);
422 else if (selection == gdk_win32_dropfiles)
424 /* This means he wants the names of the dropped files.
425 * gdk_dropfiles_filter already has stored the text/uri-list
426 * data temporarily in dropfiles_prop.
428 if (dropfiles_prop != NULL)
430 _gdk_selection_property_store
431 (requestor, selection, dropfiles_prop->format,
432 dropfiles_prop->data, dropfiles_prop->length);
433 g_free (dropfiles_prop);
434 dropfiles_prop = NULL;
440 /* Generate a selection notify message so that we actually fetch
441 * the data (if property == _gdk_selection_property) or indicating failure
442 * (if property == GDK_NONE).
444 generate_selection_notify (requestor, selection, target, property, time);
448 gdk_selection_property_get (GdkWindow *requestor,
455 g_return_val_if_fail (requestor != NULL, 0);
456 g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
458 if (GDK_WINDOW_DESTROYED (requestor))
461 GDK_NOTE (DND, g_print ("gdk_selection_property_get: %#x\n",
462 (guint) GDK_WINDOW_HWND (requestor)));
464 prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (requestor));
472 *data = g_malloc (prop->length);
473 if (prop->length > 0)
474 memmove (*data, prop->data, prop->length);
477 *ret_type = prop->type;
480 *ret_format = prop->format;
486 _gdk_selection_property_delete (GdkWindow *window)
490 GDK_NOTE (DND, g_print ("_gdk_selection_property_delete: %#x\n",
491 (guint) GDK_WINDOW_HWND (window)));
493 prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (window));
497 g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (window));
502 gdk_selection_send_notify (guint32 requestor,
509 gchar *sel_name, *tgt_name, *prop_name;
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 (GdkAtom encoding,
561 GDK_NOTE (DND, (enc_name = gdk_atom_name (encoding),
562 g_print ("gdk_text_property_to_text_list: %s %d %.20s %d\n",
563 enc_name, format, text, length),
569 *list = g_new (gchar *, 1);
570 **list = g_strdup (text);
576 gdk_free_text_list (gchar **list)
578 g_return_if_fail (list != NULL);
585 gdk_string_to_compound_text (const gchar *str,
591 GDK_NOTE (DND, g_print ("gdk_string_to_compound_text: %.20s\n", str));
594 *encoding = compound_text;
600 *ctext = g_strdup (str);
603 *length = strlen (str);
609 gdk_free_compound_text (guchar *ctext)
614 /* These are lifted from gdkselection-x11.c, just to get GTK+ to build.
615 * These functions probably don't make much sense at all in Windows.
621 make_list (const gchar *text,
626 GSList *strings = NULL;
629 const gchar *p = text;
632 GError *error = NULL;
634 while (p < text + length)
639 while (*q && q < text + length)
644 str = g_convert (p, q - p,
645 "UTF-8", "ISO-8859-1",
650 g_warning ("Error converting selection from STRING: %s",
652 g_error_free (error);
656 str = g_strndup (p, q - p);
660 strings = g_slist_prepend (strings, str);
668 *list = g_new (gchar *, n_strings + 1);
670 (*list)[n_strings] = NULL;
677 (*list)[--i] = tmp_list->data;
679 g_free (tmp_list->data);
681 tmp_list = tmp_list->next;
684 g_slist_free (strings);
690 * gdk_text_property_to_utf8_list:
691 * @encoding: an atom representing the encoding of the text
692 * @format: the format of the property
693 * @text: the text to convert
694 * @length: the length of @text, in bytes
695 * @list: location to store the list of strings or %NULL. The
696 * list should be freed with g_strfreev().
698 * Converts a text property in the giving encoding to
699 * a list of UTF-8 strings.
701 * Return value: the number of strings in the resulting
705 gdk_text_property_to_utf8_list (GdkAtom encoding,
711 g_return_val_if_fail (text != NULL, 0);
712 g_return_val_if_fail (length >= 0, 0);
714 if (encoding == GDK_TARGET_STRING)
716 return make_list ((gchar *)text, length, TRUE, list);
718 else if (encoding == utf8_string)
720 return make_list ((gchar *)text, length, FALSE, list);
727 const gchar *charset = NULL;
728 gboolean need_conversion = g_get_charset (&charset);
730 GError *error = NULL;
732 /* Probably COMPOUND text, we fall back to Xlib routines
734 local_count = gdk_text_property_to_text_list (encoding,
740 *list = g_new (gchar *, local_count + 1);
742 for (i=0; i<local_count; i++)
744 /* list contains stuff in our default encoding
748 gchar *utf = g_convert (local_list[i], -1,
754 (*list)[count++] = utf;
760 g_warning ("Error converting to UTF-8 from '%s': %s",
761 charset, error->message);
762 g_error_free (error);
769 (*list)[count++] = g_strdup (local_list[i]);
773 gdk_free_text_list (local_list);
774 (*list)[count] = NULL;
780 /* The specifications for COMPOUND_TEXT and STRING specify that C0 and
781 * C1 are not allowed except for \n and \t, however the X conversions
782 * routines for COMPOUND_TEXT only enforce this in one direction,
783 * causing cut-and-paste of \r and \r\n separated text to fail.
784 * This routine strips out all non-allowed C0 and C1 characters
785 * from the input string and also canonicalizes \r, \r\n, and \n\r to \n
788 sanitize_utf8 (const gchar *src)
790 gint len = strlen (src);
791 GString *result = g_string_sized_new (len);
792 const gchar *p = src;
796 if (*p == '\r' || *p == '\n')
799 if (*p == '\r' || *p == '\n')
802 g_string_append_c (result, '\n');
806 gunichar ch = g_utf8_get_char (p);
810 if (!((ch < 0x20 && ch != '\t') || (ch >= 0x7f && ch < 0xa0)))
812 buflen = g_unichar_to_utf8 (ch, buf);
813 g_string_append_len (result, buf, buflen);
816 p = g_utf8_next_char (p);
820 return g_string_free (result, FALSE);
824 * gdk_utf8_to_string_target:
825 * @str: a UTF-8 string
827 * Converts an UTF-8 string into the best possible representation
828 * as a STRING. The representation of characters not in STRING
829 * is not specified; it may be as pseudo-escape sequences
830 * \x{ABCD}, or it may be in some other form of approximation.
832 * Return value: the newly allocated string, or %NULL if the
833 * conversion failed. (It should not fail for
834 * any properly formed UTF-8 string.)
837 gdk_utf8_to_string_target (const gchar *str)
839 return sanitize_utf8 (str);
843 * gdk_utf8_to_compound_text:
844 * @str: a UTF-8 string
845 * @encoding: location to store resulting encoding
846 * @format: location to store format of the result
847 * @ctext: location to store the data of the result
848 * @length: location to store the length of the data
851 * Converts from UTF-8 to compound text.
853 * Return value: %TRUE if the conversion succeeded, otherwise
857 gdk_utf8_to_compound_text (const gchar *str,
863 gboolean need_conversion;
864 const gchar *charset;
865 gchar *locale_str, *tmp_str;
866 GError *error = NULL;
869 g_return_val_if_fail (str != NULL, FALSE);
871 need_conversion = !g_get_charset (&charset);
873 tmp_str = sanitize_utf8 (str);
877 locale_str = g_convert_with_fallback (tmp_str, -1,
879 NULL, NULL, NULL, &error);
884 g_warning ("Error converting from UTF-8 to '%s': %s",
885 charset, error->message);
886 g_error_free (error);
889 *encoding = GDK_NONE;
891 *format = GPOINTER_TO_UINT (GDK_ATOM_TO_POINTER (GDK_NONE));
901 locale_str = tmp_str;
903 result = gdk_string_to_compound_text (locale_str,
904 encoding, format, ctext, length);