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
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);
192 g_return_val_if_fail (atom != GDK_NONE, None);
197 xatom = lookup_cached_xatom (display, atom);
203 g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
205 name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
207 xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
208 insert_atom_pair (display, atom, xatom);
215 _gdk_x11_precache_atoms (GdkDisplay *display,
216 const gchar * const *atom_names,
221 const gchar **xatom_names;
225 xatoms = g_new (Atom, n_atoms);
226 xatom_names = g_new (const gchar *, n_atoms);
227 atoms = g_new (GdkAtom, n_atoms);
230 for (i = 0; i < n_atoms; i++)
232 GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
233 if (lookup_cached_xatom (display, atom) == None)
235 atoms[n_xatoms] = atom;
236 xatom_names[n_xatoms] = atom_names[i];
243 #ifdef HAVE_XINTERNATOMS
244 XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
245 (char **)xatom_names, n_xatoms, False, xatoms);
247 for (i = 0; i < n_xatoms; i++)
248 xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
249 xatom_names[i], False);
253 for (i = 0; i < n_xatoms; i++)
254 insert_atom_pair (display, atoms[i], xatoms[i]);
257 g_free (xatom_names);
262 * gdk_x11_atom_to_xatom:
265 * Converts from a #GdkAtom to the X atom for the default GDK display
266 * with the same string value.
268 * Return value: the X atom corresponding to @atom.
271 gdk_x11_atom_to_xatom (GdkAtom atom)
273 return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
277 * gdk_x11_xatom_to_atom_for_display:
278 * @display: A #GdkDisplay
281 * Convert from an X atom for a #GdkDisplay to the corresponding
284 * Return value: the corresponding #GdkAtom.
289 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
292 GdkDisplayX11 *display_x11;
293 GdkAtom virtual_atom = GDK_NONE;
295 g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
296 g_return_val_if_fail (xatom != None, GDK_NONE);
301 display_x11 = GDK_DISPLAY_X11 (display);
303 if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
304 return INDEX_TO_ATOM (xatom);
306 if (display_x11->atom_to_virtual)
307 virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
308 GUINT_TO_POINTER (xatom)));
312 /* If this atom doesn't exist, we'll die with an X error unless
313 * we take precautions
316 gdk_error_trap_push ();
317 name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
318 if (gdk_error_trap_pop ())
320 g_warning (G_STRLOC " invalid X atom: %ld", xatom);
324 virtual_atom = gdk_atom_intern (name, FALSE);
327 insert_atom_pair (display, virtual_atom, xatom);
335 * gdk_x11_xatom_to_atom:
336 * @xatom: an X atom for the default GDK display
338 * Convert from an X atom for the default display to the corresponding
341 * Return value: the corresponding G#dkAtom.
344 gdk_x11_xatom_to_atom (Atom xatom)
346 return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
350 virtual_atom_check_init (void)
352 if (!virtual_atom_hash)
356 virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
357 virtual_atom_array = g_ptr_array_new ();
359 for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
361 g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
362 g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
363 GUINT_TO_POINTER (i));
369 intern_atom (const gchar *atom_name,
374 virtual_atom_check_init ();
376 result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
379 result = INDEX_TO_ATOM (virtual_atom_array->len);
381 g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
382 g_hash_table_insert (virtual_atom_hash,
383 g_ptr_array_index (virtual_atom_array,
384 ATOM_TO_INDEX (result)),
385 GDK_ATOM_TO_POINTER (result));
392 gdk_atom_intern (const gchar *atom_name,
393 gboolean only_if_exists)
395 return intern_atom (atom_name, TRUE);
399 * gdk_atom_intern_static_string:
400 * @atom_name: a static string
402 * Finds or creates an atom corresponding to a given string.
404 * Note that this function is identical to gdk_atom_intern() except
405 * that if a new #GdkAtom is created the string itself is used rather
406 * than a copy. This saves memory, but can only be used if the string
407 * will <emphasis>always</emphasis> exist. It can be used with statically
408 * allocated strings in the main program, but not with statically
409 * allocated memory in dynamically loaded modules, if you expect to
410 * ever unload the module again (e.g. do not use this function in
411 * GTK+ theme engines).
413 * Returns: the atom corresponding to @atom_name
418 gdk_atom_intern_static_string (const gchar *atom_name)
420 return intern_atom (atom_name, FALSE);
423 static G_CONST_RETURN char *
424 get_atom_name (GdkAtom atom)
426 virtual_atom_check_init ();
428 if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
429 return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
435 gdk_atom_name (GdkAtom atom)
437 return g_strdup (get_atom_name (atom));
441 * gdk_x11_get_xatom_by_name_for_display:
442 * @display: a #GdkDisplay
443 * @atom_name: a string
445 * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
446 * This function caches the result, so if called repeatedly it is much
447 * faster than XInternAtom(), which is a round trip to the server each time.
449 * Return value: a X atom for a #GdkDisplay
454 gdk_x11_get_xatom_by_name_for_display (GdkDisplay *display,
455 const gchar *atom_name)
457 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
458 return gdk_x11_atom_to_xatom_for_display (display,
459 gdk_atom_intern (atom_name, FALSE));
463 * gdk_x11_get_xatom_by_name:
464 * @atom_name: a string
466 * Returns the X atom for GDK's default display corresponding to @atom_name.
467 * This function caches the result, so if called repeatedly it is much
468 * faster than XInternAtom(), which is a round trip to the server each time.
470 * Return value: a X atom for GDK's default display.
473 gdk_x11_get_xatom_by_name (const gchar *atom_name)
475 return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
480 * gdk_x11_get_xatom_name_for_display:
481 * @display: the #GdkDisplay where @xatom is defined
484 * Returns the name of an X atom for its display. This
485 * function is meant mainly for debugging, so for convenience, unlike
486 * XAtomName() and gdk_atom_name(), the result doesn't need to
489 * Return value: name of the X atom; this string is owned by GDK,
490 * so it shouldn't be modifed or freed.
494 G_CONST_RETURN gchar *
495 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
498 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
500 return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
504 * gdk_x11_get_xatom_name:
505 * @xatom: an X atom for GDK's default display
507 * Returns the name of an X atom for GDK's default display. This
508 * function is meant mainly for debugging, so for convenience, unlike
509 * <function>XAtomName()</function> and gdk_atom_name(), the result
510 * doesn't need to be freed. Also, this function will never return %NULL,
511 * even if @xatom is invalid.
513 * Return value: name of the X atom; this string is owned by GTK+,
514 * so it shouldn't be modifed or freed.
516 G_CONST_RETURN gchar *
517 gdk_x11_get_xatom_name (Atom xatom)
519 return get_atom_name (gdk_x11_xatom_to_atom (xatom));
523 gdk_property_get (GdkWindow *window,
529 GdkAtom *actual_property_type,
530 gint *actual_format_type,
538 gulong ret_bytes_after;
546 g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
550 GdkScreen *screen = gdk_screen_get_default ();
551 window = gdk_screen_get_root_window (screen);
553 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
555 else if (!GDK_WINDOW_IS_X11 (window))
558 if (GDK_WINDOW_DESTROYED (window))
561 display = gdk_drawable_get_display (window);
562 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
563 if (type == GDK_NONE)
564 xtype = AnyPropertyType;
566 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
571 * Round up length to next 4 byte value. Some code is in the (bad?)
572 * habit of passing G_MAXLONG as the length argument, causing an
573 * overflow to negative on the add. In this case, we clamp the
574 * value to G_MAXLONG.
576 get_length = length + 3;
577 if (get_length > G_MAXLONG)
578 get_length = G_MAXLONG;
580 /* To fail, either the user passed 0 or G_MAXULONG */
581 get_length = get_length / 4;
584 g_warning ("gdk_propery-get(): invalid length 0");
588 res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
589 GDK_WINDOW_XWINDOW (window), xproperty,
590 offset, get_length, pdelete,
591 xtype, &ret_prop_type, &ret_format,
592 &ret_nitems, &ret_bytes_after,
595 if (res != Success || (ret_prop_type == None && ret_format == 0))
600 if (actual_property_type)
601 *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
602 if (actual_format_type)
603 *actual_format_type = ret_format;
605 if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
608 g_warning ("Couldn't match property type %s to %s\n",
609 gdk_x11_get_xatom_name_for_display (display, ret_prop_type),
610 gdk_x11_get_xatom_name_for_display (display, xtype));
614 /* FIXME: ignoring bytes_after could have very bad effects */
618 if (ret_prop_type == XA_ATOM ||
619 ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
622 * data is an array of X atom, we need to convert it
623 * to an array of GDK Atoms
626 GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
627 Atom *xatoms = (Atom *)ret_data;
629 *data = (guchar *)ret_atoms;
631 for (i = 0; i < ret_nitems; i++)
632 ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
635 *actual_length = ret_nitems * sizeof (GdkAtom);
642 ret_length = ret_nitems;
645 ret_length = sizeof(short) * ret_nitems;
648 ret_length = sizeof(long) * ret_nitems;
651 g_warning ("unknown property return format: %d", ret_format);
656 *data = g_new (guchar, ret_length);
657 memcpy (*data, ret_data, ret_length);
659 *actual_length = ret_length;
669 gdk_property_change (GdkWindow *window,
682 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
688 screen = gdk_screen_get_default ();
689 window = gdk_screen_get_root_window (screen);
691 GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
693 else if (!GDK_WINDOW_IS_X11 (window))
696 if (GDK_WINDOW_DESTROYED (window))
699 display = gdk_drawable_get_display (window);
701 xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
702 xtype = gdk_x11_atom_to_xatom_for_display (display, type);
703 xwindow = GDK_WINDOW_XID (window);
705 if (xtype == XA_ATOM ||
706 xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
709 * data is an array of GdkAtom, we need to convert it
710 * to an array of X Atoms
713 GdkAtom *atoms = (GdkAtom*) data;
716 xatoms = g_new (Atom, nelements);
717 for (i = 0; i < nelements; i++)
718 xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, atoms[i]);
720 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
722 format, mode, (guchar *)xatoms, nelements);
726 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty,
727 xtype, format, mode, (guchar *)data, nelements);
731 gdk_property_delete (GdkWindow *window,
734 g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
738 GdkScreen *screen = gdk_screen_get_default ();
739 window = gdk_screen_get_root_window (screen);
742 g_message ("gdk_property_delete(): window is NULL\n"));
744 else if (!GDK_WINDOW_IS_X11 (window))
747 if (GDK_WINDOW_DESTROYED (window))
750 XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XWINDOW (window),
751 gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
755 #define __GDK_PROPERTY_X11_C__
756 #include "gdkaliasdef.c"