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"
33 #include "gdkprivate.h"
34 #include "gdkinternals.h"
35 #include "gdkdisplay-x11.h"
36 #include "gdkscreen-x11.h"
37 #include "gdkselection.h"
40 #include <X11/Xatom.h>
46 * @Short_description: Functions to manipulate properties on windows
47 * @Title: Properties and Atoms
49 * Each window under X can have any number of associated
50 * <firstterm>properties</firstterm> attached to it.
51 * Properties are arbitrary chunks of data identified by
52 * <firstterm>atom</firstterm>s. (An <firstterm>atom</firstterm>
53 * is a numeric index into a string table on the X server. They are used
54 * to transfer strings efficiently between clients without
55 * having to transfer the entire string.) A property
56 * has an associated type, which is also identified
59 * A property has an associated <firstterm>format</firstterm>,
60 * an integer describing how many bits are in each unit
61 * of data inside the property. It must be 8, 16, or 32.
62 * When data is transferred between the server and client,
63 * if they are of different endianesses it will be byteswapped
64 * as necessary according to the format of the property.
65 * Note that on the client side, properties of format 32
66 * will be stored with one unit per <emphasis>long</emphasis>,
67 * even if a long integer has more than 32 bits on the platform.
68 * (This decision was apparently made for Xlib to maintain
69 * compatibility with programs that assumed longs were 32
70 * bits, at the expense of programs that knew better.)
72 * The functions in this section are used to add, remove
73 * and change properties on windows, to convert atoms
74 * to and from strings and to manipulate some types of
75 * data commonly stored in X window properties.
79 static GPtrArray *virtual_atom_array;
80 static GHashTable *virtual_atom_hash;
82 static const gchar xatoms_string[] =
83 /* These are all the standard predefined X atoms */
84 "\0" /* leave a space for None, even though it is not a predefined atom */
120 "WM_CLIENT_MACHINE\0"
135 "UNDERLINE_POSITION\0"
136 "UNDERLINE_THICKNESS\0"
138 "STRIKEOUT_DESCENT\0"
153 /* Below here, these are our additions. Increment N_CUSTOM_PREDEFINED
156 "CLIPBOARD\0" /* = 69 */
159 static const gint xatoms_offset[] = {
160 0, 1, 9, 19, 23, 28, 35, 44, 53, 60, 72, 84,
161 96, 108, 120, 132, 144, 156, 165, 170, 178, 185, 189, 201,
162 218, 232, 245, 258, 274, 287, 301, 313, 320, 329, 336, 347,
163 356, 374, 387, 400, 408, 424, 438, 452, 462, 473, 483, 493,
164 507, 521, 533, 545, 564, 584, 601, 619, 632, 641, 652, 659,
165 670, 681, 691, 698, 708, 720, 730, 741, 750, 767
168 #define N_CUSTOM_PREDEFINED 1
170 #define ATOM_TO_INDEX(atom) (GPOINTER_TO_UINT(atom))
171 #define INDEX_TO_ATOM(atom) ((GdkAtom)GUINT_TO_POINTER(atom))
174 insert_atom_pair (GdkDisplay *display,
175 GdkAtom virtual_atom,
178 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
180 if (!display_x11->atom_from_virtual)
182 display_x11->atom_from_virtual = g_hash_table_new (g_direct_hash, NULL);
183 display_x11->atom_to_virtual = g_hash_table_new (g_direct_hash, NULL);
186 g_hash_table_insert (display_x11->atom_from_virtual,
187 GDK_ATOM_TO_POINTER (virtual_atom),
188 GUINT_TO_POINTER (xatom));
189 g_hash_table_insert (display_x11->atom_to_virtual,
190 GUINT_TO_POINTER (xatom),
191 GDK_ATOM_TO_POINTER (virtual_atom));
195 lookup_cached_xatom (GdkDisplay *display,
198 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
200 if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
201 return ATOM_TO_INDEX (atom);
203 if (display_x11->atom_from_virtual)
204 return GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_virtual,
205 GDK_ATOM_TO_POINTER (atom)));
211 * gdk_x11_atom_to_xatom_for_display:
212 * @display: A #GdkDisplay
213 * @atom: A #GdkAtom, or %GDK_NONE
215 * Converts from a #GdkAtom to the X atom for a #GdkDisplay
216 * with the same string value. The special value %GDK_NONE
217 * is converted to %None.
219 * Return value: the X atom corresponding to @atom, or %None
224 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display,
229 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
231 if (atom == GDK_NONE)
237 xatom = lookup_cached_xatom (display, atom);
243 g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
245 name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
247 xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
248 insert_atom_pair (display, atom, xatom);
255 _gdk_x11_precache_atoms (GdkDisplay *display,
256 const gchar * const *atom_names,
261 const gchar **xatom_names;
265 xatoms = g_new (Atom, n_atoms);
266 xatom_names = g_new (const gchar *, n_atoms);
267 atoms = g_new (GdkAtom, n_atoms);
270 for (i = 0; i < n_atoms; i++)
272 GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
273 if (lookup_cached_xatom (display, atom) == None)
275 atoms[n_xatoms] = atom;
276 xatom_names[n_xatoms] = atom_names[i];
283 #ifdef HAVE_XINTERNATOMS
284 XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
285 (char **)xatom_names, n_xatoms, False, xatoms);
287 for (i = 0; i < n_xatoms; i++)
288 xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
289 xatom_names[i], False);
293 for (i = 0; i < n_xatoms; i++)
294 insert_atom_pair (display, atoms[i], xatoms[i]);
297 g_free (xatom_names);
302 * gdk_x11_atom_to_xatom:
305 * Converts from a #GdkAtom to the X atom for the default GDK display
306 * with the same string value.
308 * Return value: the X atom corresponding to @atom.
311 gdk_x11_atom_to_xatom (GdkAtom atom)
313 return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
317 * gdk_x11_xatom_to_atom_for_display:
318 * @display: A #GdkDisplay
321 * Convert from an X atom for a #GdkDisplay to the corresponding
324 * Return value: the corresponding #GdkAtom.
329 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
332 GdkDisplayX11 *display_x11;
333 GdkAtom virtual_atom = GDK_NONE;
335 g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
343 display_x11 = GDK_DISPLAY_X11 (display);
345 if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
346 return INDEX_TO_ATOM (xatom);
348 if (display_x11->atom_to_virtual)
349 virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
350 GUINT_TO_POINTER (xatom)));
354 /* If this atom doesn't exist, we'll die with an X error unless
355 * we take precautions
358 gdk_error_trap_push ();
359 name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
360 if (gdk_error_trap_pop ())
362 g_warning (G_STRLOC " invalid X atom: %ld", xatom);
366 virtual_atom = gdk_atom_intern (name, FALSE);
369 insert_atom_pair (display, virtual_atom, xatom);
377 * gdk_x11_xatom_to_atom:
378 * @xatom: an X atom for the default GDK display
380 * Convert from an X atom for the default display to the corresponding
383 * Return value: the corresponding G#dkAtom.
386 gdk_x11_xatom_to_atom (Atom xatom)
388 return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
392 virtual_atom_check_init (void)
394 if (!virtual_atom_hash)
398 virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
399 virtual_atom_array = g_ptr_array_new ();
401 for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
403 g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
404 g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
405 GUINT_TO_POINTER (i));
411 intern_atom (const gchar *atom_name,
416 virtual_atom_check_init ();
418 result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
421 result = INDEX_TO_ATOM (virtual_atom_array->len);
423 g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
424 g_hash_table_insert (virtual_atom_hash,
425 g_ptr_array_index (virtual_atom_array,
426 ATOM_TO_INDEX (result)),
427 GDK_ATOM_TO_POINTER (result));
435 * @atom_name: a string.
436 * @only_if_exists: if %TRUE, GDK is allowed to not create a new atom, but
437 * just return %GDK_NONE if the requested atom doesn't already
438 * exists. Currently, the flag is ignored, since checking the
439 * existance of an atom is as expensive as creating it.
441 * Finds or creates an atom corresponding to a given string.
443 * Returns: the atom corresponding to @atom_name.
446 gdk_atom_intern (const gchar *atom_name,
447 gboolean only_if_exists)
449 return intern_atom (atom_name, TRUE);
453 * gdk_atom_intern_static_string:
454 * @atom_name: a static string
456 * Finds or creates an atom corresponding to a given string.
458 * Note that this function is identical to gdk_atom_intern() except
459 * that if a new #GdkAtom is created the string itself is used rather
460 * than a copy. This saves memory, but can only be used if the string
461 * will <emphasis>always</emphasis> exist. It can be used with statically
462 * allocated strings in the main program, but not with statically
463 * allocated memory in dynamically loaded modules, if you expect to
464 * ever unload the module again (e.g. do not use this function in
465 * GTK+ theme engines).
467 * Returns: the atom corresponding to @atom_name
472 gdk_atom_intern_static_string (const gchar *atom_name)
474 return intern_atom (atom_name, FALSE);
477 static G_CONST_RETURN char *
478 get_atom_name (GdkAtom atom)
480 virtual_atom_check_init ();
482 if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
483 return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
492 * Determines the string corresponding to an atom.
494 * Returns: a newly-allocated string containing the string
495 * corresponding to @atom. When you are done with the
496 * return value, you should free it using g_free().
499 gdk_atom_name (GdkAtom atom)
501 return g_strdup (get_atom_name (atom));
505 * gdk_x11_get_xatom_by_name_for_display:
506 * @display: a #GdkDisplay
507 * @atom_name: a string
509 * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
510 * This function caches the result, so if called repeatedly it is much
511 * faster than XInternAtom(), which is a round trip to the server each time.
513 * Return value: a X atom for a #GdkDisplay
518 gdk_x11_get_xatom_by_name_for_display (GdkDisplay *display,
519 const gchar *atom_name)
521 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
522 return gdk_x11_atom_to_xatom_for_display (display,
523 gdk_atom_intern (atom_name, FALSE));
527 * gdk_x11_get_xatom_by_name:
528 * @atom_name: a string
530 * Returns the X atom for GDK's default display corresponding to @atom_name.
531 * This function caches the result, so if called repeatedly it is much
532 * faster than XInternAtom(), which is a round trip to the server each time.
534 * Return value: a X atom for GDK's default display.
537 gdk_x11_get_xatom_by_name (const gchar *atom_name)
539 return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
544 * gdk_x11_get_xatom_name_for_display:
545 * @display: the #GdkDisplay where @xatom is defined
548 * Returns the name of an X atom for its display. This
549 * function is meant mainly for debugging, so for convenience, unlike
550 * XAtomName() and gdk_atom_name(), the result doesn't need to
553 * Return value: name of the X atom; this string is owned by GDK,
554 * so it shouldn't be modifed or freed.
558 G_CONST_RETURN gchar *
559 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
562 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
564 return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
568 * gdk_x11_get_xatom_name:
569 * @xatom: an X atom for GDK's default display
571 * Returns the name of an X atom for GDK's default display. This
572 * function is meant mainly for debugging, so for convenience, unlike
573 * <function>XAtomName()</function> and gdk_atom_name(), the result
574 * doesn't need to be freed. Also, this function will never return %NULL,
575 * even if @xatom is invalid.
577 * Return value: name of the X atom; this string is owned by GTK+,
578 * so it shouldn't be modifed or freed.
580 G_CONST_RETURN gchar *
581 gdk_x11_get_xatom_name (Atom xatom)
583 return get_atom_name (gdk_x11_xatom_to_atom (xatom));
588 * @window: a #GdkWindow.
589 * @property: the property to retrieve.
590 * @type: the desired property type, or %GDK_NONE, if any type of data
591 * is acceptable. If this does not match the actual
592 * type, then @actual_format and @actual_length will
593 * be filled in, a warning will be printed to stderr
594 * and no data will be returned.
595 * @offset: the offset into the property at which to begin
596 * retrieving data, in 4 byte units.
597 * @length: the length of the data to retrieve in bytes. Data is
598 * considered to be retrieved in 4 byte chunks, so @length
599 * will be rounded up to the next highest 4 byte boundary
600 * (so be careful not to pass a value that might overflow
602 * @pdelete: if %TRUE, delete the property after retrieving the
604 * @actual_property_type: location to store the actual type of
606 * @actual_format: location to store the actual return format of the
607 * data; either 8, 16 or 32 bits.
608 * @actual_length: location to store the length of the retrieved data, in
609 * bytes. Data returned in the 32 bit format is stored
610 * in a long variable, so the actual number of 32 bit
611 * elements should be be calculated via
612 * @actual_length / sizeof(glong) to ensure portability to
614 * @data: location to store a pointer to the data. The retrieved
615 * data should be freed with g_free() when you are finished
618 * Retrieves a portion of the contents of a property. If the
619 * property does not exist, then the function returns %FALSE,
620 * and %GDK_NONE will be stored in @actual_property_type.
624 * The XGetWindowProperty() function that gdk_property_get()
625 * uses has a very confusing and complicated set of semantics.
626 * Unfortunately, gdk_property_get() makes the situation
627 * worse instead of better (the semantics should be considered
628 * undefined), and also prints warnings to stderr in cases where it
629 * should return a useful error to the program. You are advised to use
630 * XGetWindowProperty() directly until a replacement function for
636 * Returns: %TRUE if data was successfully received and stored
637 * in @data, otherwise %FALSE.
640 gdk_property_get (GdkWindow *window,
646 GdkAtom *actual_property_type,
647 gint *actual_format_type,
655 gulong ret_bytes_after;
663 g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
667 GdkScreen *screen = gdk_screen_get_default ();
668 window = gdk_screen_get_root_window (screen);
670 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
672 else if (!GDK_WINDOW_IS_X11 (window))
675 if (GDK_WINDOW_DESTROYED (window))
678 display = gdk_window_get_display (window);
679 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
680 if (type == GDK_NONE)
681 xtype = AnyPropertyType;
683 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
688 * Round up length to next 4 byte value. Some code is in the (bad?)
689 * habit of passing G_MAXLONG as the length argument, causing an
690 * overflow to negative on the add. In this case, we clamp the
691 * value to G_MAXLONG.
693 get_length = length + 3;
694 if (get_length > G_MAXLONG)
695 get_length = G_MAXLONG;
697 /* To fail, either the user passed 0 or G_MAXULONG */
698 get_length = get_length / 4;
701 g_warning ("gdk_propery-get(): invalid length 0");
705 res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
706 GDK_WINDOW_XID (window), xproperty,
707 offset, get_length, pdelete,
708 xtype, &ret_prop_type, &ret_format,
709 &ret_nitems, &ret_bytes_after,
712 if (res != Success || (ret_prop_type == None && ret_format == 0))
717 if (actual_property_type)
718 *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
719 if (actual_format_type)
720 *actual_format_type = ret_format;
722 if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
725 g_warning ("Couldn't match property type %s to %s\n",
726 gdk_x11_get_xatom_name_for_display (display, ret_prop_type),
727 gdk_x11_get_xatom_name_for_display (display, xtype));
731 /* FIXME: ignoring bytes_after could have very bad effects */
735 if (ret_prop_type == XA_ATOM ||
736 ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
739 * data is an array of X atom, we need to convert it
740 * to an array of GDK Atoms
743 GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
744 Atom *xatoms = (Atom *)ret_data;
746 *data = (guchar *)ret_atoms;
748 for (i = 0; i < ret_nitems; i++)
749 ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
752 *actual_length = ret_nitems * sizeof (GdkAtom);
759 ret_length = ret_nitems;
762 ret_length = sizeof(short) * ret_nitems;
765 ret_length = sizeof(long) * ret_nitems;
768 g_warning ("unknown property return format: %d", ret_format);
773 *data = g_new (guchar, ret_length);
774 memcpy (*data, ret_data, ret_length);
776 *actual_length = ret_length;
786 * gdk_property_change:
787 * @window: a #GdkWindow.
788 * @property: the property to change.
789 * @type: the new type for the property. If @mode is
790 * %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
791 * must match the existing type or an error will occur.
792 * @format: the new format for the property. If @mode is
793 * %GDK_PROP_MODE_PREPEND or %GDK_PROP_MODE_APPEND, then this
794 * must match the existing format or an error will occur.
795 * @mode: a value describing how the new data is to be combined
796 * with the current data.
797 * @data: the data (a <literal>guchar *</literal>
798 * <literal>gushort *</literal>, or <literal>gulong *</literal>,
799 * depending on @format), cast to a <literal>guchar *</literal>.
800 * @nelements: the number of elements of size determined by the format,
801 * contained in @data.
803 * Changes the contents of a property on a window.
806 gdk_property_change (GdkWindow *window,
819 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
825 screen = gdk_screen_get_default ();
826 window = gdk_screen_get_root_window (screen);
828 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
830 else if (!GDK_WINDOW_IS_X11 (window))
833 if (GDK_WINDOW_DESTROYED (window))
836 gdk_window_ensure_native (window);
838 display = gdk_window_get_display (window);
839 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
840 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
841 xwindow = GDK_WINDOW_XID (window);
843 if (xtype == XA_ATOM ||
844 xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
847 * data is an array of GdkAtom, we need to convert it
848 * to an array of X Atoms
851 GdkAtom *atoms = (GdkAtom*) data;
854 xatoms = g_new (Atom, nelements);
855 for (i = 0; i < nelements; i++)
856 xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, atoms[i]);
858 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
860 format, mode, (guchar *)xatoms, nelements);
864 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty,
865 xtype, format, mode, (guchar *)data, nelements);
869 * gdk_property_delete:
870 * @window: a #GdkWindow.
871 * @property: the property to delete.
873 * Deletes a property from a window.
876 gdk_property_delete (GdkWindow *window,
879 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
883 GdkScreen *screen = gdk_screen_get_default ();
884 window = gdk_screen_get_root_window (screen);
887 g_message ("gdk_property_delete(): window is NULL\n"));
889 else if (!GDK_WINDOW_IS_X11 (window))
892 if (GDK_WINDOW_DESTROYED (window))
895 XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
896 gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),