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/.
29 #include "gdkproperty.h"
31 #include "gdkprivate.h"
32 #include "gdkinternals.h"
33 #include "gdkselection.h"
34 #include "gdkprivate-x11.h"
35 #include "gdkdisplay-x11.h"
36 #include "gdkscreen-x11.h"
39 #include <X11/Xatom.h>
45 * @Short_description: Functions to manipulate properties on windows
46 * @Title: Properties and Atoms
48 * Each window under X can have any number of associated
49 * <firstterm>properties</firstterm> attached to it.
50 * Properties are arbitrary chunks of data identified by
51 * <firstterm>atom</firstterm>s. (An <firstterm>atom</firstterm>
52 * is a numeric index into a string table on the X server. They are used
53 * to transfer strings efficiently between clients without
54 * having to transfer the entire string.) A property
55 * has an associated type, which is also identified
58 * A property has an associated <firstterm>format</firstterm>,
59 * an integer describing how many bits are in each unit
60 * of data inside the property. It must be 8, 16, or 32.
61 * When data is transferred between the server and client,
62 * if they are of different endianesses it will be byteswapped
63 * as necessary according to the format of the property.
64 * Note that on the client side, properties of format 32
65 * will be stored with one unit per <emphasis>long</emphasis>,
66 * even if a long integer has more than 32 bits on the platform.
67 * (This decision was apparently made for Xlib to maintain
68 * compatibility with programs that assumed longs were 32
69 * bits, at the expense of programs that knew better.)
71 * The functions in this section are used to add, remove
72 * and change properties on windows, to convert atoms
73 * to and from strings and to manipulate some types of
74 * data commonly stored in X window properties.
78 static GPtrArray *virtual_atom_array;
79 static GHashTable *virtual_atom_hash;
81 static const gchar xatoms_string[] =
82 /* These are all the standard predefined X atoms */
83 "\0" /* leave a space for None, even though it is not a predefined atom */
119 "WM_CLIENT_MACHINE\0"
134 "UNDERLINE_POSITION\0"
135 "UNDERLINE_THICKNESS\0"
137 "STRIKEOUT_DESCENT\0"
152 /* Below here, these are our additions. Increment N_CUSTOM_PREDEFINED
155 "CLIPBOARD\0" /* = 69 */
158 static const gint xatoms_offset[] = {
159 0, 1, 9, 19, 23, 28, 35, 44, 53, 60, 72, 84,
160 96, 108, 120, 132, 144, 156, 165, 170, 178, 185, 189, 201,
161 218, 232, 245, 258, 274, 287, 301, 313, 320, 329, 336, 347,
162 356, 374, 387, 400, 408, 424, 438, 452, 462, 473, 483, 493,
163 507, 521, 533, 545, 564, 584, 601, 619, 632, 641, 652, 659,
164 670, 681, 691, 698, 708, 720, 730, 741, 750, 767
167 #define N_CUSTOM_PREDEFINED 1
169 #define ATOM_TO_INDEX(atom) (GPOINTER_TO_UINT(atom))
170 #define INDEX_TO_ATOM(atom) ((GdkAtom)GUINT_TO_POINTER(atom))
173 insert_atom_pair (GdkDisplay *display,
174 GdkAtom virtual_atom,
177 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
179 if (!display_x11->atom_from_virtual)
181 display_x11->atom_from_virtual = g_hash_table_new (g_direct_hash, NULL);
182 display_x11->atom_to_virtual = g_hash_table_new (g_direct_hash, NULL);
185 g_hash_table_insert (display_x11->atom_from_virtual,
186 GDK_ATOM_TO_POINTER (virtual_atom),
187 GUINT_TO_POINTER (xatom));
188 g_hash_table_insert (display_x11->atom_to_virtual,
189 GUINT_TO_POINTER (xatom),
190 GDK_ATOM_TO_POINTER (virtual_atom));
194 lookup_cached_xatom (GdkDisplay *display,
197 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
199 if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
200 return ATOM_TO_INDEX (atom);
202 if (display_x11->atom_from_virtual)
203 return GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_virtual,
204 GDK_ATOM_TO_POINTER (atom)));
210 * gdk_x11_atom_to_xatom_for_display:
211 * @display: A #GdkDisplay
212 * @atom: A #GdkAtom, or %GDK_NONE
214 * Converts from a #GdkAtom to the X atom for a #GdkDisplay
215 * with the same string value. The special value %GDK_NONE
216 * is converted to %None.
218 * Return value: the X atom corresponding to @atom, or %None
223 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display,
228 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
230 if (atom == GDK_NONE)
233 if (gdk_display_is_closed (display))
236 xatom = lookup_cached_xatom (display, atom);
242 g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
244 name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
246 xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
247 insert_atom_pair (display, atom, xatom);
254 _gdk_x11_precache_atoms (GdkDisplay *display,
255 const gchar * const *atom_names,
260 const gchar **xatom_names;
264 xatoms = g_new (Atom, n_atoms);
265 xatom_names = g_new (const gchar *, n_atoms);
266 atoms = g_new (GdkAtom, n_atoms);
269 for (i = 0; i < n_atoms; i++)
271 GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
272 if (lookup_cached_xatom (display, atom) == None)
274 atoms[n_xatoms] = atom;
275 xatom_names[n_xatoms] = atom_names[i];
282 #ifdef HAVE_XINTERNATOMS
283 XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
284 (char **)xatom_names, n_xatoms, False, xatoms);
286 for (i = 0; i < n_xatoms; i++)
287 xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
288 xatom_names[i], False);
292 for (i = 0; i < n_xatoms; i++)
293 insert_atom_pair (display, atoms[i], xatoms[i]);
296 g_free (xatom_names);
301 * gdk_x11_atom_to_xatom:
304 * Converts from a #GdkAtom to the X atom for the default GDK display
305 * with the same string value.
307 * Return value: the X atom corresponding to @atom.
310 gdk_x11_atom_to_xatom (GdkAtom atom)
312 return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
316 * gdk_x11_xatom_to_atom_for_display:
317 * @display: A #GdkDisplay
320 * Convert from an X atom for a #GdkDisplay to the corresponding
323 * Return value: the corresponding #GdkAtom.
328 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
331 GdkDisplayX11 *display_x11;
332 GdkAtom virtual_atom = GDK_NONE;
334 g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
339 if (gdk_display_is_closed (display))
342 display_x11 = GDK_DISPLAY_X11 (display);
344 if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
345 return INDEX_TO_ATOM (xatom);
347 if (display_x11->atom_to_virtual)
348 virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
349 GUINT_TO_POINTER (xatom)));
353 /* If this atom doesn't exist, we'll die with an X error unless
354 * we take precautions
357 gdk_x11_display_error_trap_push (display);
358 name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
359 if (gdk_x11_display_error_trap_pop (display))
361 g_warning (G_STRLOC " invalid X atom: %ld", xatom);
365 virtual_atom = gdk_atom_intern (name, FALSE);
368 insert_atom_pair (display, virtual_atom, xatom);
376 * gdk_x11_xatom_to_atom:
377 * @xatom: an X atom for the default GDK display
379 * Convert from an X atom for the default display to the corresponding
382 * Return value: the corresponding G#dkAtom.
385 gdk_x11_xatom_to_atom (Atom xatom)
387 return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
391 virtual_atom_check_init (void)
393 if (!virtual_atom_hash)
397 virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
398 virtual_atom_array = g_ptr_array_new ();
400 for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
402 g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
403 g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
404 GUINT_TO_POINTER (i));
410 intern_atom (const gchar *atom_name,
415 virtual_atom_check_init ();
417 result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
420 result = INDEX_TO_ATOM (virtual_atom_array->len);
422 g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
423 g_hash_table_insert (virtual_atom_hash,
424 g_ptr_array_index (virtual_atom_array,
425 ATOM_TO_INDEX (result)),
426 GDK_ATOM_TO_POINTER (result));
434 * @atom_name: a string.
435 * @only_if_exists: if %TRUE, GDK is allowed to not create a new atom, but
436 * just return %GDK_NONE if the requested atom doesn't already
437 * exists. Currently, the flag is ignored, since checking the
438 * existance of an atom is as expensive as creating it.
440 * Finds or creates an atom corresponding to a given string.
442 * Returns: the atom corresponding to @atom_name.
445 gdk_atom_intern (const gchar *atom_name,
446 gboolean only_if_exists)
448 return intern_atom (atom_name, TRUE);
452 * gdk_atom_intern_static_string:
453 * @atom_name: a static string
455 * Finds or creates an atom corresponding to a given string.
457 * Note that this function is identical to gdk_atom_intern() except
458 * that if a new #GdkAtom is created the string itself is used rather
459 * than a copy. This saves memory, but can only be used if the string
460 * will <emphasis>always</emphasis> exist. It can be used with statically
461 * allocated strings in the main program, but not with statically
462 * allocated memory in dynamically loaded modules, if you expect to
463 * ever unload the module again (e.g. do not use this function in
464 * GTK+ theme engines).
466 * Returns: the atom corresponding to @atom_name
471 gdk_atom_intern_static_string (const gchar *atom_name)
473 return intern_atom (atom_name, FALSE);
476 static G_CONST_RETURN char *
477 get_atom_name (GdkAtom atom)
479 virtual_atom_check_init ();
481 if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
482 return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
491 * Determines the string corresponding to an atom.
493 * Returns: a newly-allocated string containing the string
494 * corresponding to @atom. When you are done with the
495 * return value, you should free it using g_free().
498 gdk_atom_name (GdkAtom atom)
500 return g_strdup (get_atom_name (atom));
504 * gdk_x11_get_xatom_by_name_for_display:
505 * @display: a #GdkDisplay
506 * @atom_name: a string
508 * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
509 * This function caches the result, so if called repeatedly it is much
510 * faster than XInternAtom(), which is a round trip to the server each time.
512 * Return value: a X atom for a #GdkDisplay
517 gdk_x11_get_xatom_by_name_for_display (GdkDisplay *display,
518 const gchar *atom_name)
520 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
521 return gdk_x11_atom_to_xatom_for_display (display,
522 gdk_atom_intern (atom_name, FALSE));
526 * gdk_x11_get_xatom_by_name:
527 * @atom_name: a string
529 * Returns the X atom for GDK's default display corresponding to @atom_name.
530 * This function caches the result, so if called repeatedly it is much
531 * faster than XInternAtom(), which is a round trip to the server each time.
533 * Return value: a X atom for GDK's default display.
536 gdk_x11_get_xatom_by_name (const gchar *atom_name)
538 return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
543 * gdk_x11_get_xatom_name_for_display:
544 * @display: the #GdkDisplay where @xatom is defined
547 * Returns the name of an X atom for its display. This
548 * function is meant mainly for debugging, so for convenience, unlike
549 * XAtomName() and gdk_atom_name(), the result doesn't need to
552 * Return value: name of the X atom; this string is owned by GDK,
553 * so it shouldn't be modifed or freed.
557 G_CONST_RETURN gchar *
558 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
561 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
563 return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
567 * gdk_x11_get_xatom_name:
568 * @xatom: an X atom for GDK's default display
570 * Returns the name of an X atom for GDK's default display. This
571 * function is meant mainly for debugging, so for convenience, unlike
572 * <function>XAtomName()</function> and gdk_atom_name(), the result
573 * doesn't need to be freed. Also, this function will never return %NULL,
574 * even if @xatom is invalid.
576 * Return value: name of the X atom; this string is owned by GTK+,
577 * so it shouldn't be modifed or freed.
579 G_CONST_RETURN gchar *
580 gdk_x11_get_xatom_name (Atom xatom)
582 return get_atom_name (gdk_x11_xatom_to_atom (xatom));
587 * @window: a #GdkWindow.
588 * @property: the property to retrieve.
589 * @type: the desired property type, or %GDK_NONE, if any type of data
590 * is acceptable. If this does not match the actual
591 * type, then @actual_format and @actual_length will
592 * be filled in, a warning will be printed to stderr
593 * and no data will be returned.
594 * @offset: the offset into the property at which to begin
595 * retrieving data, in 4 byte units.
596 * @length: the length of the data to retrieve in bytes. Data is
597 * considered to be retrieved in 4 byte chunks, so @length
598 * will be rounded up to the next highest 4 byte boundary
599 * (so be careful not to pass a value that might overflow
601 * @pdelete: if %TRUE, delete the property after retrieving the
603 * @actual_property_type: location to store the actual type of
605 * @actual_format: location to store the actual return format of the
606 * data; either 8, 16 or 32 bits.
607 * @actual_length: location to store the length of the retrieved data, in
608 * bytes. Data returned in the 32 bit format is stored
609 * in a long variable, so the actual number of 32 bit
610 * elements should be be calculated via
611 * @actual_length / sizeof(glong) to ensure portability to
613 * @data: location to store a pointer to the data. The retrieved
614 * data should be freed with g_free() when you are finished
617 * Retrieves a portion of the contents of a property. If the
618 * property does not exist, then the function returns %FALSE,
619 * and %GDK_NONE will be stored in @actual_property_type.
623 * The XGetWindowProperty() function that gdk_property_get()
624 * uses has a very confusing and complicated set of semantics.
625 * Unfortunately, gdk_property_get() makes the situation
626 * worse instead of better (the semantics should be considered
627 * undefined), and also prints warnings to stderr in cases where it
628 * should return a useful error to the program. You are advised to use
629 * XGetWindowProperty() directly until a replacement function for
635 * Returns: %TRUE if data was successfully received and stored
636 * in @data, otherwise %FALSE.
639 gdk_property_get (GdkWindow *window,
645 GdkAtom *actual_property_type,
646 gint *actual_format_type,
654 gulong ret_bytes_after;
662 g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
666 GdkScreen *screen = gdk_screen_get_default ();
667 window = gdk_screen_get_root_window (screen);
669 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
671 else if (!GDK_WINDOW_IS_X11 (window))
674 if (GDK_WINDOW_DESTROYED (window))
677 display = gdk_window_get_display (window);
678 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
679 if (type == GDK_NONE)
680 xtype = AnyPropertyType;
682 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
687 * Round up length to next 4 byte value. Some code is in the (bad?)
688 * habit of passing G_MAXLONG as the length argument, causing an
689 * overflow to negative on the add. In this case, we clamp the
690 * value to G_MAXLONG.
692 get_length = length + 3;
693 if (get_length > G_MAXLONG)
694 get_length = G_MAXLONG;
696 /* To fail, either the user passed 0 or G_MAXULONG */
697 get_length = get_length / 4;
700 g_warning ("gdk_propery-get(): invalid length 0");
704 res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
705 GDK_WINDOW_XID (window), xproperty,
706 offset, get_length, pdelete,
707 xtype, &ret_prop_type, &ret_format,
708 &ret_nitems, &ret_bytes_after,
711 if (res != Success || (ret_prop_type == None && ret_format == 0))
716 if (actual_property_type)
717 *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
718 if (actual_format_type)
719 *actual_format_type = ret_format;
721 if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
724 g_warning ("Couldn't match property type %s to %s\n",
725 gdk_x11_get_xatom_name_for_display (display, ret_prop_type),
726 gdk_x11_get_xatom_name_for_display (display, xtype));
730 /* FIXME: ignoring bytes_after could have very bad effects */
734 if (ret_prop_type == XA_ATOM ||
735 ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
738 * data is an array of X atom, we need to convert it
739 * to an array of GDK Atoms
742 GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
743 Atom *xatoms = (Atom *)ret_data;
745 *data = (guchar *)ret_atoms;
747 for (i = 0; i < ret_nitems; i++)
748 ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
751 *actual_length = ret_nitems * sizeof (GdkAtom);
758 ret_length = ret_nitems;
761 ret_length = sizeof(short) * ret_nitems;
764 ret_length = sizeof(long) * ret_nitems;
767 g_warning ("unknown property return format: %d", ret_format);
772 *data = g_new (guchar, ret_length);
773 memcpy (*data, ret_data, ret_length);
775 *actual_length = ret_length;
785 * gdk_property_change:
786 * @window: a #GdkWindow.
787 * @property: the property to change.
788 * @type: the new type for the property. If @mode is
789 * %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
790 * must match the existing type or an error will occur.
791 * @format: the new format for the property. If @mode is
792 * %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
793 * must match the existing format or an error will occur.
794 * @mode: a value describing how the new data is to be combined
795 * with the current data.
796 * @data: the data (a <literal>guchar *</literal>
797 * <literal>gushort *</literal>, or <literal>gulong *</literal>,
798 * depending on @format), cast to a <literal>guchar *</literal>.
799 * @nelements: the number of elements of size determined by the format,
800 * contained in @data.
802 * Changes the contents of a property on a window.
805 gdk_property_change (GdkWindow *window,
818 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
824 screen = gdk_screen_get_default ();
825 window = gdk_screen_get_root_window (screen);
827 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
829 else if (!GDK_WINDOW_IS_X11 (window))
832 if (GDK_WINDOW_DESTROYED (window))
835 gdk_window_ensure_native (window);
837 display = gdk_window_get_display (window);
838 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
839 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
840 xwindow = GDK_WINDOW_XID (window);
842 if (xtype == XA_ATOM ||
843 xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
846 * data is an array of GdkAtom, we need to convert it
847 * to an array of X Atoms
850 GdkAtom *atoms = (GdkAtom*) data;
853 xatoms = g_new (Atom, nelements);
854 for (i = 0; i < nelements; i++)
855 xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, atoms[i]);
857 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
859 format, mode, (guchar *)xatoms, nelements);
863 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty,
864 xtype, format, mode, (guchar *)data, nelements);
868 * gdk_property_delete:
869 * @window: a #GdkWindow.
870 * @property: the property to delete.
872 * Deletes a property from a window.
875 gdk_property_delete (GdkWindow *window,
878 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
882 GdkScreen *screen = gdk_screen_get_default ();
883 window = gdk_screen_get_root_window (screen);
886 g_message ("gdk_property_delete(): window is NULL\n"));
888 else if (!GDK_WINDOW_IS_X11 (window))
891 if (GDK_WINDOW_DESTROYED (window))
894 XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
895 gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),