1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 #include <X11/Xatom.h>
32 #include "gdkproperty.h"
33 #include "gdkselection.h"
34 #include "gdkprivate.h"
35 #include "gdkprivate-x11.h"
36 #include "gdkdisplay-x11.h"
38 typedef struct _OwnerInfo OwnerInfo;
47 static GSList *owner_list;
49 /* When a window is destroyed we check if it is the owner
50 * of any selections. This is somewhat inefficient, but
51 * owner_list is typically short, and it is a low memory,
55 _gdk_selection_window_destroyed (GdkWindow *window)
57 GSList *tmp_list = owner_list;
60 OwnerInfo *info = tmp_list->data;
61 tmp_list = tmp_list->next;
63 if (info->owner == window)
65 owner_list = g_slist_remove (owner_list, info);
71 /* We only pass through those SelectionClear events that actually
72 * reflect changes to the selection owner that we didn't make ourself.
75 _gdk_selection_filter_clear_event (XSelectionClearEvent *event)
77 GSList *tmp_list = owner_list;
78 GdkDisplay *display = gdk_x11_lookup_xdisplay (event->display);
82 OwnerInfo *info = tmp_list->data;
84 if (gdk_drawable_get_display (info->owner) == display &&
85 info->selection == gdk_x11_xatom_to_atom_for_display (display, event->selection))
87 if ((GDK_DRAWABLE_XID (info->owner) == event->window &&
88 event->serial >= info->serial))
90 owner_list = g_slist_remove (owner_list, info);
97 tmp_list = tmp_list->next;
103 * gdk_selection_owner_set_for_display:
104 * @display: the #GdkDisplay.
105 * @owner: a #GdkWindow or %NULL to indicate that the the owner for
106 * the given should be unset.
107 * @selection: an atom identifying a selection.
108 * @time_: timestamp to use when setting the selection.
109 * If this is older than the timestamp given last time the owner was
110 * set for the given selection, the request will be ignored.
111 * @send_event: if %TRUE, and the new owner is different from the current
112 * owner, the current owner will be sent a SelectionClear event.
114 * Sets the #GdkWindow @owner as the current owner of the selection @selection.
116 * Returns: %TRUE if the selection owner was successfully changed to owner,
122 gdk_selection_owner_set_for_display (GdkDisplay *display,
134 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
141 if (GDK_WINDOW_DESTROYED (owner))
144 xdisplay = GDK_WINDOW_XDISPLAY (owner);
145 xwindow = GDK_WINDOW_XID (owner);
149 xdisplay = GDK_DISPLAY_XDISPLAY (display);
153 xselection = gdk_x11_atom_to_xatom_for_display (display, selection);
155 tmp_list = owner_list;
158 info = tmp_list->data;
159 if (info->selection == selection)
161 owner_list = g_slist_remove (owner_list, info);
165 tmp_list = tmp_list->next;
170 info = g_new (OwnerInfo, 1);
172 info->serial = NextRequest (GDK_WINDOW_XDISPLAY (owner));
173 info->selection = selection;
175 owner_list = g_slist_prepend (owner_list, info);
178 XSetSelectionOwner (xdisplay, xselection, xwindow, time);
180 return (XGetSelectionOwner (xdisplay, xselection) == xwindow);
184 * gdk_selection_owner_get_for_display:
185 * @display: a #GdkDisplay.
186 * @selection: an atom indentifying a selection.
188 * Determine the owner of the given selection.
190 * Note that the return value may be owned by a different
191 * process if a foreign window was previously created for that
192 * window, but a new foreign window will never be created by this call.
194 * Returns: if there is a selection owner for this window, and it is a
195 * window known to the current process, the #GdkWindow that owns the
196 * selection, otherwise %NULL.
201 gdk_selection_owner_get_for_display (GdkDisplay *display,
205 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
210 xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
211 gdk_x11_atom_to_xatom_for_display (display,
216 return gdk_window_lookup_for_display (display, xwindow);
220 gdk_selection_convert (GdkWindow *requestor,
227 if (GDK_WINDOW_DESTROYED (requestor))
230 display = GDK_WINDOW_DISPLAY (requestor);
232 XConvertSelection (GDK_WINDOW_XDISPLAY (requestor),
233 gdk_x11_atom_to_xatom_for_display (display, selection),
234 gdk_x11_atom_to_xatom_for_display (display, target),
235 gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property),
236 GDK_WINDOW_XID (requestor), time);
240 * gdk_selection_property_get:
241 * @requestor: the window on which the data is stored
242 * @data: location to store a pointer to the retrieved data.
243 If the retrieval failed, %NULL we be stored here, otherwise, it
244 will be non-%NULL and the returned data should be freed with g_free()
245 when you are finished using it. The length of the
246 allocated memory is one more than the the length
247 of the returned data, and the final byte will always
248 be zero, to ensure nul-termination of strings.
249 * @prop_type: location to store the type of the property.
250 * @prop_format: location to store the format of the property.
252 * Retrieves selection data that was stored by the selection
253 * data in response to a call to gdk_selection_convert(). This function
254 * will not be used by applications, who should use the #GtkClipboard
257 * Return value: the length of the retrieved data.
260 gdk_selection_property_get (GdkWindow *requestor,
267 gulong length = 0; /* Quiet GCC */
273 g_return_val_if_fail (requestor != NULL, 0);
274 g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
276 display = GDK_WINDOW_DISPLAY (requestor);
278 if (GDK_WINDOW_DESTROYED (requestor))
283 /* We can't delete the selection here, because it might be the INCR
284 protocol, in which case the client has to make sure they'll be
285 notified of PropertyChange events _before_ the property is deleted.
286 Otherwise there's no guarantee we'll win the race ... */
287 if (XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (requestor),
288 GDK_DRAWABLE_XID (requestor),
289 gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property),
290 0, 0x1FFFFFFF /* MAXINT32 / 4 */, False,
291 AnyPropertyType, &prop_type, &prop_format,
292 &nitems, &nbytes, &t) != Success)
295 if (prop_type != None)
298 *ret_type = gdk_x11_xatom_to_atom_for_display (display, prop_type);
300 *ret_format = prop_format;
302 if (prop_type == XA_ATOM ||
303 prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
305 Atom* atoms = (Atom*) t;
309 if (prop_format != 32)
313 length = sizeof (GdkAtom) * num_atom + 1;
317 *data = g_malloc (length);
318 (*data)[length - 1] = '\0';
319 atoms_dest = (GdkAtom *)(*data);
321 for (i=0; i < num_atom; i++)
322 atoms_dest[i] = gdk_x11_xatom_to_atom_for_display (display, atoms[i]);
333 length = sizeof(short) * nitems;
336 length = sizeof(long) * nitems;
339 g_assert_not_reached ();
343 /* Add on an extra byte to handle null termination. X guarantees
344 that t will be 1 longer than nitems and null terminated */
348 *data = g_memdup (t, length);
359 *ret_type = GDK_NONE;
369 * gdk_selection_send_notify_for_display:
370 * @display: the #GdkDisplay where @requestor is realized
371 * @requestor: window to which to deliver response.
372 * @selection: selection that was requested.
373 * @target: target that was selected.
374 * @property: property in which the selection owner stored the data,
375 * or %GDK_NONE to indicate that the request was rejected.
378 * Send a response to SelectionRequest event.
383 gdk_selection_send_notify_for_display (GdkDisplay *display,
390 XSelectionEvent xevent;
392 g_return_if_fail (GDK_IS_DISPLAY (display));
394 xevent.type = SelectionNotify;
396 xevent.send_event = True;
397 xevent.requestor = requestor;
398 xevent.selection = gdk_x11_atom_to_xatom_for_display (display, selection);
399 xevent.target = gdk_x11_atom_to_xatom_for_display (display, target);
400 xevent.property = gdk_x11_atom_to_xatom_for_display (display, property);
403 _gdk_send_xevent (display, requestor, False, NoEventMask, (XEvent*) & xevent);
407 * gdk_text_property_to_text_list_for_display:
408 * @display: The #GdkDisplay where the encoding is defined.
409 * @encoding: an atom representing the encoding. The most
410 * common values for this are STRING, or COMPOUND_TEXT.
411 * This is value used as the type for the property.
412 * @format: the format of the property.
413 * @text: The text data.
414 * @length: The number of items to transform.
415 * @list: location to store a terminated array of strings in
416 * the encoding of the current locale. This array should be
417 * freed using gdk_free_text_list().
419 * Convert a text string from the encoding as it is stored
420 * in a property into an array of strings in the encoding of
421 * the current locale. (The elements of the array represent the
422 * nul-separated elements of the original text string.)
424 * Returns: the number of strings stored in list, or 0,
425 * if the conversion failed.
430 gdk_text_property_to_text_list_for_display (GdkDisplay *display,
437 XTextProperty property;
441 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
449 property.value = (guchar *)text;
450 property.encoding = gdk_x11_atom_to_xatom_for_display (display, encoding);
451 property.format = format;
452 property.nitems = length;
453 res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), &property,
454 &local_list, &count);
455 if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound)
462 XFreeStringList (local_list);
469 gdk_free_text_list (gchar **list)
471 g_return_if_fail (list != NULL);
473 XFreeStringList (list);
477 make_list (const gchar *text,
482 GSList *strings = NULL;
485 const gchar *p = text;
488 GError *error = NULL;
490 while (p < text + length)
495 while (*q && q < text + length)
500 str = g_convert (p, q - p,
501 "UTF-8", "ISO-8859-1",
506 g_warning ("Error converting selection from STRING: %s",
508 g_error_free (error);
512 str = g_strndup (p, q - p);
516 strings = g_slist_prepend (strings, str);
524 *list = g_new (gchar *, n_strings + 1);
526 (*list)[n_strings] = NULL;
533 (*list)[--i] = tmp_list->data;
535 g_free (tmp_list->data);
537 tmp_list = tmp_list->next;
540 g_slist_free (strings);
546 * gdk_text_property_to_utf8_list_for_display:
547 * @display: a #GdkDisplay
548 * @encoding: an atom representing the encoding of the text
549 * @format: the format of the property
550 * @text: the text to convert
551 * @length: the length of @text, in bytes
552 * @list: location to store the list of strings or %NULL. The
553 * list should be freed with g_strfreev().
555 * Converts a text property in the given encoding to
556 * a list of UTF-8 strings.
558 * Return value: the number of strings in the resulting
564 gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
571 g_return_val_if_fail (text != NULL, 0);
572 g_return_val_if_fail (length >= 0, 0);
573 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
575 if (encoding == GDK_TARGET_STRING)
577 return make_list ((gchar *)text, length, TRUE, list);
579 else if (encoding == gdk_atom_intern ("UTF8_STRING", FALSE))
581 return make_list ((gchar *)text, length, FALSE, list);
588 const gchar *charset = NULL;
589 gboolean need_conversion = !g_get_charset (&charset);
591 GError *error = NULL;
593 /* Probably COMPOUND text, we fall back to Xlib routines
595 local_count = gdk_text_property_to_text_list_for_display (display,
602 *list = g_new (gchar *, local_count + 1);
604 for (i=0; i<local_count; i++)
606 /* list contains stuff in our default encoding
610 gchar *utf = g_convert (local_list[i], -1,
616 (*list)[count++] = utf;
622 g_warning ("Error converting to UTF-8 from '%s': %s",
623 charset, error->message);
624 g_error_free (error);
631 (*list)[count++] = g_strdup (local_list[i]);
636 gdk_free_text_list (local_list);
638 (*list)[count] = NULL;
645 * gdk_string_to_compound_text_for_display:
646 * @display: the #GdkDisplay where the encoding is defined.
647 * @str: a nul-terminated string.
648 * @encoding: location to store the encoding atom
649 * (to be used as the type for the property).
650 * @format: location to store the format of the property
651 * @ctext: location to store newly allocated data for the property.
652 * @length: the length of @text, in bytes
654 * Convert a string from the encoding of the current
655 * locale into a form suitable for storing in a window property.
657 * Returns: 0 upon sucess, non-zero upon failure.
662 gdk_string_to_compound_text_for_display (GdkDisplay *display,
670 XTextProperty property;
672 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
675 res = XLocaleNotSupported;
677 res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display),
678 (char **)&str, 1, XCompoundTextStyle,
682 property.encoding = None;
683 property.format = None;
684 property.value = NULL;
689 *encoding = gdk_x11_xatom_to_atom_for_display (display, property.encoding);
691 *format = property.format;
693 *ctext = property.value;
695 *length = property.nitems;
700 /* The specifications for COMPOUND_TEXT and STRING specify that C0 and
701 * C1 are not allowed except for \n and \t, however the X conversions
702 * routines for COMPOUND_TEXT only enforce this in one direction,
703 * causing cut-and-paste of \r and \r\n separated text to fail.
704 * This routine strips out all non-allowed C0 and C1 characters
705 * from the input string and also canonicalizes \r, and \r\n to \n
708 sanitize_utf8 (const gchar *src)
710 gint len = strlen (src);
711 GString *result = g_string_sized_new (len);
712 const gchar *p = src;
722 g_string_append_c (result, '\n');
726 gunichar ch = g_utf8_get_char (p);
730 if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
732 buflen = g_unichar_to_utf8 (ch, buf);
733 g_string_append_len (result, buf, buflen);
736 p = g_utf8_next_char (p);
740 return g_string_free (result, FALSE);
744 * gdk_utf8_to_string_target:
745 * @str: a UTF-8 string
747 * Converts an UTF-8 string into the best possible representation
748 * as a STRING. The representation of characters not in STRING
749 * is not specified; it may be as pseudo-escape sequences
750 * \x{ABCD}, or it may be in some other form of approximation.
752 * Return value: the newly-allocated string, or %NULL if the
753 * conversion failed. (It should not fail for
754 * any properly formed UTF-8 string unless system
755 * limits like memory or file descriptors are exceeded.)
758 gdk_utf8_to_string_target (const gchar *str)
760 GError *error = NULL;
762 gchar *tmp_str = sanitize_utf8 (str);
763 gchar *result = g_convert_with_fallback (tmp_str, -1,
764 "ISO-8859-1", "UTF-8",
765 NULL, NULL, NULL, &error);
768 g_warning ("Error converting from UTF-8 to STRING: %s",
770 g_error_free (error);
778 * gdk_utf8_to_compound_text_for_display:
779 * @display: a #GdkDisplay
780 * @str: a UTF-8 string
781 * @encoding: location to store resulting encoding
782 * @format: location to store format of the result
783 * @ctext: location to store the data of the result
784 * @length: location to store the length of the data
787 * Converts from UTF-8 to compound text.
789 * Return value: %TRUE if the conversion succeeded, otherwise
795 gdk_utf8_to_compound_text_for_display (GdkDisplay *display,
802 gboolean need_conversion;
803 const gchar *charset;
804 gchar *locale_str, *tmp_str;
805 GError *error = NULL;
808 g_return_val_if_fail (str != NULL, FALSE);
809 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
811 need_conversion = !g_get_charset (&charset);
813 tmp_str = sanitize_utf8 (str);
817 locale_str = g_convert_with_fallback (tmp_str, -1,
819 NULL, NULL, NULL, &error);
824 g_warning ("Error converting from UTF-8 to '%s': %s",
825 charset, error->message);
826 g_error_free (error);
841 locale_str = tmp_str;
843 result = gdk_string_to_compound_text_for_display (display, locale_str,
846 result = (result == Success? TRUE : FALSE);
853 void gdk_free_compound_text (guchar *ctext)