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 <X11/Xatom.h>
32 #include "gdk.h" /* For gdk_error_trap_push/pop() */
34 #include "gdkproperty.h"
35 #include "gdkprivate.h"
36 #include "gdkinternals.h"
37 #include "gdkdisplay-x11.h"
38 #include "gdkscreen-x11.h"
39 #include "gdkselection.h" /* only from predefined atom */
42 static GPtrArray *virtual_atom_array;
43 static GHashTable *virtual_atom_hash;
45 static const gchar xatoms_string[] =
46 /* These are all the standard predefined X atoms */
98 "UNDERLINE_POSITION\0"
99 "UNDERLINE_THICKNESS\0"
101 "STRIKEOUT_DESCENT\0"
116 /* Below here, these are our additions. Increment N_CUSTOM_PREDEFINED
119 "CLIPBOARD\0" /* = 69 */
122 static const gint xatoms_offset[] = {
123 0, 5, 13, 23, 27, 32, 39, 48, 57, 64, 76, 88,
124 100, 112, 124, 136, 148, 160, 169, 174, 182, 189, 195, 205,
125 222, 236, 249, 262, 278, 291, 305, 317, 324, 333, 340, 351,
126 360, 378, 391, 404, 412, 428, 442, 456, 466, 477, 487, 497,
127 511, 525, 537, 549, 568, 588, 605, 623, 636, 645, 656, 663,
128 674, 685, 695, 702, 712, 724, 734, 745, 754, 771
131 #define N_CUSTOM_PREDEFINED 1
133 #define ATOM_TO_INDEX(atom) (GPOINTER_TO_UINT(atom))
134 #define INDEX_TO_ATOM(atom) ((GdkAtom)GUINT_TO_POINTER(atom))
137 insert_atom_pair (GdkDisplay *display,
138 GdkAtom virtual_atom,
141 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
143 if (!display_x11->atom_from_virtual)
145 display_x11->atom_from_virtual = g_hash_table_new (g_direct_hash, NULL);
146 display_x11->atom_to_virtual = g_hash_table_new (g_direct_hash, NULL);
149 g_hash_table_insert (display_x11->atom_from_virtual,
150 GDK_ATOM_TO_POINTER (virtual_atom),
151 GUINT_TO_POINTER (xatom));
152 g_hash_table_insert (display_x11->atom_to_virtual,
153 GUINT_TO_POINTER (xatom),
154 GDK_ATOM_TO_POINTER (virtual_atom));
158 lookup_cached_xatom (GdkDisplay *display,
161 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
163 if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
164 return ATOM_TO_INDEX (atom);
166 if (display_x11->atom_from_virtual)
167 return GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_virtual,
168 GDK_ATOM_TO_POINTER (atom)));
174 * gdk_x11_atom_to_xatom_for_display:
175 * @display: A #GdkDisplay
178 * Converts from a #GdkAtom to the X atom for a #GdkDisplay
179 * with the same string value.
181 * Return value: the X atom corresponding to @atom.
186 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display,
191 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
196 xatom = lookup_cached_xatom (display, atom);
202 g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
204 name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
206 xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
207 insert_atom_pair (display, atom, xatom);
214 _gdk_x11_precache_atoms (GdkDisplay *display,
215 const gchar * const *atom_names,
220 const gchar **xatom_names;
224 xatoms = g_new (Atom, n_atoms);
225 xatom_names = g_new (const gchar *, n_atoms);
226 atoms = g_new (GdkAtom, n_atoms);
229 for (i = 0; i < n_atoms; i++)
231 GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
232 if (lookup_cached_xatom (display, atom) == None)
234 atoms[n_xatoms] = atom;
235 xatom_names[n_xatoms] = atom_names[i];
242 #ifdef HAVE_XINTERNATOMS
243 XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
244 (char **)xatom_names, n_xatoms, False, xatoms);
246 for (i = 0; i < n_xatoms; i++)
247 xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
248 xatom_names[i], False);
252 for (i = 0; i < n_xatoms; i++)
253 insert_atom_pair (display, atoms[i], xatoms[i]);
256 g_free (xatom_names);
261 * gdk_x11_atom_to_xatom:
264 * Converts from a #GdkAtom to the X atom for the default GDK display
265 * with the same string value.
267 * Return value: the X atom corresponding to @atom.
270 gdk_x11_atom_to_xatom (GdkAtom atom)
272 return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
276 * gdk_x11_xatom_to_atom_for_display:
277 * @display: A #GdkDisplay
280 * Convert from an X atom for a #GdkDisplay to the corresponding
283 * Return value: the corresponding #GdkAtom.
288 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
291 GdkDisplayX11 *display_x11;
292 GdkAtom virtual_atom = GDK_NONE;
294 g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
299 display_x11 = GDK_DISPLAY_X11 (display);
301 if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
302 return INDEX_TO_ATOM (xatom);
304 if (display_x11->atom_to_virtual)
305 virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
306 GUINT_TO_POINTER (xatom)));
310 /* If this atom doesn't exist, we'll die with an X error unless
311 * we take precautions
314 gdk_error_trap_push ();
315 name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
316 if (gdk_error_trap_pop ())
318 g_warning (G_STRLOC " invalid X atom: %ld", xatom);
322 virtual_atom = gdk_atom_intern (name, FALSE);
325 insert_atom_pair (display, virtual_atom, xatom);
333 * gdk_x11_xatom_to_atom:
334 * @xatom: an X atom for the default GDK display
336 * Convert from an X atom for the default display to the corresponding
339 * Return value: the corresponding G#dkAtom.
342 gdk_x11_xatom_to_atom (Atom xatom)
344 return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
348 virtual_atom_check_init (void)
350 if (!virtual_atom_hash)
354 virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
355 virtual_atom_array = g_ptr_array_new ();
357 for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
359 g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
360 g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
361 GUINT_TO_POINTER (i));
367 intern_atom (const gchar *atom_name,
372 virtual_atom_check_init ();
374 result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
377 result = INDEX_TO_ATOM (virtual_atom_array->len);
379 g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
380 g_hash_table_insert (virtual_atom_hash,
381 g_ptr_array_index (virtual_atom_array,
382 ATOM_TO_INDEX (result)),
383 GDK_ATOM_TO_POINTER (result));
390 gdk_atom_intern (const gchar *atom_name,
391 gboolean only_if_exists)
393 return intern_atom (atom_name, TRUE);
397 * gdk_atom_intern_static_string:
398 * @atom_name: a static string
400 * Finds or creates an atom corresponding to a given string.
402 * Note that this function is identical to gdk_atom_intern() except
403 * that if a new #GdkAtom is created the string itself is used rather
404 * than a copy. This saves memory, but can only be used if the string
405 * will <emphasis>always</emphasis> exist. It can be used with statically
406 * allocated strings in the main program, but not with statically
407 * allocated memory in dynamically loaded modules, if you expect to
408 * ever unload the module again (e.g. do not use this function in
409 * GTK+ theme engines).
411 * Returns: the atom corresponding to @atom_name
416 gdk_atom_intern_static_string (const gchar *atom_name)
418 return intern_atom (atom_name, FALSE);
421 static G_CONST_RETURN char *
422 get_atom_name (GdkAtom atom)
424 virtual_atom_check_init ();
426 if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
427 return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
433 gdk_atom_name (GdkAtom atom)
435 return g_strdup (get_atom_name (atom));
439 * gdk_x11_get_xatom_by_name_for_display:
440 * @display: a #GdkDisplay
441 * @atom_name: a string
443 * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
444 * This function caches the result, so if called repeatedly it is much
445 * faster than XInternAtom(), which is a round trip to the server each time.
447 * Return value: a X atom for a #GdkDisplay
452 gdk_x11_get_xatom_by_name_for_display (GdkDisplay *display,
453 const gchar *atom_name)
455 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
456 return gdk_x11_atom_to_xatom_for_display (display,
457 gdk_atom_intern (atom_name, FALSE));
461 * gdk_x11_get_xatom_by_name:
462 * @atom_name: a string
464 * Returns the X atom for GDK's default display corresponding to @atom_name.
465 * This function caches the result, so if called repeatedly it is much
466 * faster than XInternAtom(), which is a round trip to the server each time.
468 * Return value: a X atom for GDK's default display.
471 gdk_x11_get_xatom_by_name (const gchar *atom_name)
473 return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
478 * gdk_x11_get_xatom_name_for_display:
479 * @display: the #GdkDisplay where @xatom is defined
482 * Returns the name of an X atom for its display. This
483 * function is meant mainly for debugging, so for convenience, unlike
484 * XAtomName() and gdk_atom_name(), the result doesn't need to
487 * Return value: name of the X atom; this string is owned by GDK,
488 * so it shouldn't be modifed or freed.
492 G_CONST_RETURN gchar *
493 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
496 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
498 return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
502 * gdk_x11_get_xatom_name:
503 * @xatom: an X atom for GDK's default display
505 * Returns the name of an X atom for GDK's default display. This
506 * function is meant mainly for debugging, so for convenience, unlike
507 * <function>XAtomName()</function> and gdk_atom_name(), the result
508 * doesn't need to be freed. Also, this function will never return %NULL,
509 * even if @xatom is invalid.
511 * Return value: name of the X atom; this string is owned by GTK+,
512 * so it shouldn't be modifed or freed.
514 G_CONST_RETURN gchar *
515 gdk_x11_get_xatom_name (Atom xatom)
517 return get_atom_name (gdk_x11_xatom_to_atom (xatom));
521 gdk_property_get (GdkWindow *window,
527 GdkAtom *actual_property_type,
528 gint *actual_format_type,
536 gulong ret_bytes_after;
544 g_return_val_if_fail (!window || GDK_IS_WINDOW (window), FALSE);
548 GdkScreen *screen = gdk_screen_get_default ();
549 window = gdk_screen_get_root_window (screen);
551 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
554 if (GDK_WINDOW_DESTROYED (window))
557 display = gdk_drawable_get_display (window);
558 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
559 if (type == GDK_NONE)
560 xtype = AnyPropertyType;
562 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
567 * Round up length to next 4 byte value. Some code is in the (bad?)
568 * habit of passing G_MAXLONG as the length argument, causing an
569 * overflow to negative on the add. In this case, we clamp the
570 * value to G_MAXLONG.
572 get_length = length + 3;
573 if (get_length > G_MAXLONG)
574 get_length = G_MAXLONG;
576 /* To fail, either the user passed 0 or G_MAXULONG */
577 get_length = get_length / 4;
580 g_warning ("gdk_propery-get(): invalid length 0");
584 res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
585 GDK_WINDOW_XWINDOW (window), xproperty,
586 offset, get_length, pdelete,
587 xtype, &ret_prop_type, &ret_format,
588 &ret_nitems, &ret_bytes_after,
591 if (res != Success || (ret_prop_type == None && ret_format == 0))
596 if (actual_property_type)
597 *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
598 if (actual_format_type)
599 *actual_format_type = ret_format;
601 if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
604 g_warning ("Couldn't match property type %s to %s\n",
605 gdk_x11_get_xatom_name_for_display (display, ret_prop_type),
606 gdk_x11_get_xatom_name_for_display (display, xtype));
610 /* FIXME: ignoring bytes_after could have very bad effects */
614 if (ret_prop_type == XA_ATOM ||
615 ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
618 * data is an array of X atom, we need to convert it
619 * to an array of GDK Atoms
622 GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
623 Atom *xatoms = (Atom *)ret_data;
625 *data = (guchar *)ret_atoms;
627 for (i = 0; i < ret_nitems; i++)
628 ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
631 *actual_length = ret_nitems * sizeof (GdkAtom);
638 ret_length = ret_nitems;
641 ret_length = sizeof(short) * ret_nitems;
644 ret_length = sizeof(long) * ret_nitems;
647 g_warning ("unknown property return format: %d", ret_format);
652 *data = g_new (guchar, ret_length);
653 memcpy (*data, ret_data, ret_length);
655 *actual_length = ret_length;
665 gdk_property_change (GdkWindow *window,
678 g_return_if_fail (!window || GDK_IS_WINDOW (window));
684 screen = gdk_screen_get_default ();
685 window = gdk_screen_get_root_window (screen);
687 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
691 if (GDK_WINDOW_DESTROYED (window))
694 display = gdk_drawable_get_display (window);
696 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
697 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
698 xwindow = GDK_WINDOW_XID (window);
700 if (xtype == XA_ATOM ||
701 xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
704 * data is an array of GdkAtom, we need to convert it
705 * to an array of X Atoms
708 GdkAtom *atoms = (GdkAtom*) data;
711 xatoms = g_new (Atom, nelements);
712 for (i = 0; i < nelements; i++)
713 xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, atoms[i]);
715 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
717 format, mode, (guchar *)xatoms, nelements);
721 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty,
722 xtype, format, mode, (guchar *)data, nelements);
726 gdk_property_delete (GdkWindow *window,
729 g_return_if_fail (!window || GDK_IS_WINDOW (window));
733 GdkScreen *screen = gdk_screen_get_default ();
734 window = gdk_screen_get_root_window (screen);
737 g_message ("gdk_property_delete(): window is NULL\n"));
740 if (GDK_WINDOW_DESTROYED (window))
743 XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XWINDOW (window),
744 gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
748 #define __GDK_PROPERTY_X11_C__
749 #include "gdkaliasdef.c"