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 */
47 "\0" /* leave a space for None, even though it is not a predefined atom */
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, 1, 9, 19, 23, 28, 35, 44, 53, 60, 72, 84,
124 96, 108, 120, 132, 144, 156, 165, 170, 178, 185, 189, 201,
125 218, 232, 245, 258, 274, 287, 301, 313, 320, 329, 336, 347,
126 356, 374, 387, 400, 408, 424, 438, 452, 462, 473, 483, 493,
127 507, 521, 533, 545, 564, 584, 601, 619, 632, 641, 652, 659,
128 670, 681, 691, 698, 708, 720, 730, 741, 750, 767
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
176 * @atom: A #GdkAtom, or %GDK_NONE
178 * Converts from a #GdkAtom to the X atom for a #GdkDisplay
179 * with the same string value. The special value %GDK_NONE
180 * is converted to %None.
182 * Return value: the X atom corresponding to @atom, or %None
187 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display,
192 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
194 if (atom == GDK_NONE)
200 xatom = lookup_cached_xatom (display, atom);
206 g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
208 name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
210 xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
211 insert_atom_pair (display, atom, xatom);
218 _gdk_x11_precache_atoms (GdkDisplay *display,
219 const gchar * const *atom_names,
224 const gchar **xatom_names;
228 xatoms = g_new (Atom, n_atoms);
229 xatom_names = g_new (const gchar *, n_atoms);
230 atoms = g_new (GdkAtom, n_atoms);
233 for (i = 0; i < n_atoms; i++)
235 GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
236 if (lookup_cached_xatom (display, atom) == None)
238 atoms[n_xatoms] = atom;
239 xatom_names[n_xatoms] = atom_names[i];
246 #ifdef HAVE_XINTERNATOMS
247 XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
248 (char **)xatom_names, n_xatoms, False, xatoms);
250 for (i = 0; i < n_xatoms; i++)
251 xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
252 xatom_names[i], False);
256 for (i = 0; i < n_xatoms; i++)
257 insert_atom_pair (display, atoms[i], xatoms[i]);
260 g_free (xatom_names);
265 * gdk_x11_atom_to_xatom:
268 * Converts from a #GdkAtom to the X atom for the default GDK display
269 * with the same string value.
271 * Return value: the X atom corresponding to @atom.
274 gdk_x11_atom_to_xatom (GdkAtom atom)
276 return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
280 * gdk_x11_xatom_to_atom_for_display:
281 * @display: A #GdkDisplay
284 * Convert from an X atom for a #GdkDisplay to the corresponding
287 * Return value: the corresponding #GdkAtom.
292 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
295 GdkDisplayX11 *display_x11;
296 GdkAtom virtual_atom = GDK_NONE;
298 g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
299 g_return_val_if_fail (xatom != None, GDK_NONE);
304 display_x11 = GDK_DISPLAY_X11 (display);
306 if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
307 return INDEX_TO_ATOM (xatom);
309 if (display_x11->atom_to_virtual)
310 virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
311 GUINT_TO_POINTER (xatom)));
315 /* If this atom doesn't exist, we'll die with an X error unless
316 * we take precautions
319 gdk_error_trap_push ();
320 name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
321 if (gdk_error_trap_pop ())
323 g_warning (G_STRLOC " invalid X atom: %ld", xatom);
327 virtual_atom = gdk_atom_intern (name, FALSE);
330 insert_atom_pair (display, virtual_atom, xatom);
338 * gdk_x11_xatom_to_atom:
339 * @xatom: an X atom for the default GDK display
341 * Convert from an X atom for the default display to the corresponding
344 * Return value: the corresponding G#dkAtom.
347 gdk_x11_xatom_to_atom (Atom xatom)
349 return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
353 virtual_atom_check_init (void)
355 if (!virtual_atom_hash)
359 virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
360 virtual_atom_array = g_ptr_array_new ();
362 for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
364 g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
365 g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
366 GUINT_TO_POINTER (i));
372 intern_atom (const gchar *atom_name,
377 virtual_atom_check_init ();
379 result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
382 result = INDEX_TO_ATOM (virtual_atom_array->len);
384 g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
385 g_hash_table_insert (virtual_atom_hash,
386 g_ptr_array_index (virtual_atom_array,
387 ATOM_TO_INDEX (result)),
388 GDK_ATOM_TO_POINTER (result));
395 gdk_atom_intern (const gchar *atom_name,
396 gboolean only_if_exists)
398 return intern_atom (atom_name, TRUE);
402 * gdk_atom_intern_static_string:
403 * @atom_name: a static string
405 * Finds or creates an atom corresponding to a given string.
407 * Note that this function is identical to gdk_atom_intern() except
408 * that if a new #GdkAtom is created the string itself is used rather
409 * than a copy. This saves memory, but can only be used if the string
410 * will <emphasis>always</emphasis> exist. It can be used with statically
411 * allocated strings in the main program, but not with statically
412 * allocated memory in dynamically loaded modules, if you expect to
413 * ever unload the module again (e.g. do not use this function in
414 * GTK+ theme engines).
416 * Returns: the atom corresponding to @atom_name
421 gdk_atom_intern_static_string (const gchar *atom_name)
423 return intern_atom (atom_name, FALSE);
426 static G_CONST_RETURN char *
427 get_atom_name (GdkAtom atom)
429 virtual_atom_check_init ();
431 if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
432 return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
438 gdk_atom_name (GdkAtom atom)
440 return g_strdup (get_atom_name (atom));
444 * gdk_x11_get_xatom_by_name_for_display:
445 * @display: a #GdkDisplay
446 * @atom_name: a string
448 * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
449 * This function caches the result, so if called repeatedly it is much
450 * faster than XInternAtom(), which is a round trip to the server each time.
452 * Return value: a X atom for a #GdkDisplay
457 gdk_x11_get_xatom_by_name_for_display (GdkDisplay *display,
458 const gchar *atom_name)
460 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
461 return gdk_x11_atom_to_xatom_for_display (display,
462 gdk_atom_intern (atom_name, FALSE));
466 * gdk_x11_get_xatom_by_name:
467 * @atom_name: a string
469 * Returns the X atom for GDK's default display corresponding to @atom_name.
470 * This function caches the result, so if called repeatedly it is much
471 * faster than XInternAtom(), which is a round trip to the server each time.
473 * Return value: a X atom for GDK's default display.
476 gdk_x11_get_xatom_by_name (const gchar *atom_name)
478 return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
483 * gdk_x11_get_xatom_name_for_display:
484 * @display: the #GdkDisplay where @xatom is defined
487 * Returns the name of an X atom for its display. This
488 * function is meant mainly for debugging, so for convenience, unlike
489 * XAtomName() and gdk_atom_name(), the result doesn't need to
492 * Return value: name of the X atom; this string is owned by GDK,
493 * so it shouldn't be modifed or freed.
497 G_CONST_RETURN gchar *
498 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
501 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
503 return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
507 * gdk_x11_get_xatom_name:
508 * @xatom: an X atom for GDK's default display
510 * Returns the name of an X atom for GDK's default display. This
511 * function is meant mainly for debugging, so for convenience, unlike
512 * <function>XAtomName()</function> and gdk_atom_name(), the result
513 * doesn't need to be freed. Also, this function will never return %NULL,
514 * even if @xatom is invalid.
516 * Return value: name of the X atom; this string is owned by GTK+,
517 * so it shouldn't be modifed or freed.
519 G_CONST_RETURN gchar *
520 gdk_x11_get_xatom_name (Atom xatom)
522 return get_atom_name (gdk_x11_xatom_to_atom (xatom));
526 gdk_property_get (GdkWindow *window,
532 GdkAtom *actual_property_type,
533 gint *actual_format_type,
541 gulong ret_bytes_after;
549 g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
553 GdkScreen *screen = gdk_screen_get_default ();
554 window = gdk_screen_get_root_window (screen);
556 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
558 else if (!GDK_WINDOW_IS_X11 (window))
561 if (GDK_WINDOW_DESTROYED (window))
564 display = gdk_drawable_get_display (window);
565 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
566 if (type == GDK_NONE)
567 xtype = AnyPropertyType;
569 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
574 * Round up length to next 4 byte value. Some code is in the (bad?)
575 * habit of passing G_MAXLONG as the length argument, causing an
576 * overflow to negative on the add. In this case, we clamp the
577 * value to G_MAXLONG.
579 get_length = length + 3;
580 if (get_length > G_MAXLONG)
581 get_length = G_MAXLONG;
583 /* To fail, either the user passed 0 or G_MAXULONG */
584 get_length = get_length / 4;
587 g_warning ("gdk_propery-get(): invalid length 0");
591 res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
592 GDK_WINDOW_XWINDOW (window), xproperty,
593 offset, get_length, pdelete,
594 xtype, &ret_prop_type, &ret_format,
595 &ret_nitems, &ret_bytes_after,
598 if (res != Success || (ret_prop_type == None && ret_format == 0))
603 if (actual_property_type)
604 *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
605 if (actual_format_type)
606 *actual_format_type = ret_format;
608 if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
611 g_warning ("Couldn't match property type %s to %s\n",
612 gdk_x11_get_xatom_name_for_display (display, ret_prop_type),
613 gdk_x11_get_xatom_name_for_display (display, xtype));
617 /* FIXME: ignoring bytes_after could have very bad effects */
621 if (ret_prop_type == XA_ATOM ||
622 ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
625 * data is an array of X atom, we need to convert it
626 * to an array of GDK Atoms
629 GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
630 Atom *xatoms = (Atom *)ret_data;
632 *data = (guchar *)ret_atoms;
634 for (i = 0; i < ret_nitems; i++)
635 ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
638 *actual_length = ret_nitems * sizeof (GdkAtom);
645 ret_length = ret_nitems;
648 ret_length = sizeof(short) * ret_nitems;
651 ret_length = sizeof(long) * ret_nitems;
654 g_warning ("unknown property return format: %d", ret_format);
659 *data = g_new (guchar, ret_length);
660 memcpy (*data, ret_data, ret_length);
662 *actual_length = ret_length;
672 gdk_property_change (GdkWindow *window,
685 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
691 screen = gdk_screen_get_default ();
692 window = gdk_screen_get_root_window (screen);
694 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
696 else if (!GDK_WINDOW_IS_X11 (window))
699 if (GDK_WINDOW_DESTROYED (window))
702 display = gdk_drawable_get_display (window);
704 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
705 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
706 xwindow = GDK_WINDOW_XID (window);
708 if (xtype == XA_ATOM ||
709 xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
712 * data is an array of GdkAtom, we need to convert it
713 * to an array of X Atoms
716 GdkAtom *atoms = (GdkAtom*) data;
719 xatoms = g_new (Atom, nelements);
720 for (i = 0; i < nelements; i++)
721 xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, atoms[i]);
723 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
725 format, mode, (guchar *)xatoms, nelements);
729 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty,
730 xtype, format, mode, (guchar *)data, nelements);
734 gdk_property_delete (GdkWindow *window,
737 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
741 GdkScreen *screen = gdk_screen_get_default ();
742 window = gdk_screen_get_root_window (screen);
745 g_message ("gdk_property_delete(): window is NULL\n"));
747 else if (!GDK_WINDOW_IS_X11 (window))
750 if (GDK_WINDOW_DESTROYED (window))
753 XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XWINDOW (window),
754 gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
758 #define __GDK_PROPERTY_X11_C__
759 #include "gdkaliasdef.c"