]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkproperty-x11.c
Set the property as type ATOM_PAIR, not ATOM. (#72074, Gregory Merchan.)
[~andy/gtk] / gdk / x11 / gdkproperty-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include <X11/Xlib.h>
28 #include <X11/Xatom.h>
29 #include <string.h>
30
31 #include "gdk.h"          /* For gdk_error_trap_push/pop() */
32 #include "gdkx.h"
33 #include "gdkproperty.h"
34 #include "gdkprivate.h"
35
36 static GPtrArray *virtual_atom_array;
37 static GHashTable *virtual_atom_hash;
38 static GHashTable *atom_to_virtual;
39 static GHashTable *atom_from_virtual;
40
41 static gchar *XAtomsStrings[] = {
42   /* These are all the standard predefined X atoms */
43   "NONE",
44   "PRIMARY",
45   "SECONDARY",
46   "ARC",
47   "ATOM",
48   "BITMAP",
49   "CARDINAL",
50   "COLORMAP",
51   "CURSOR",
52   "CUT_BUFFER0",
53   "CUT_BUFFER1",
54   "CUT_BUFFER2",
55   "CUT_BUFFER3",
56   "CUT_BUFFER4",
57   "CUT_BUFFER5",
58   "CUT_BUFFER6",
59   "CUT_BUFFER7",
60   "DRAWABLE",
61   "FONT",
62   "INTEGER",
63   "PIXMAP",
64   "POINT",
65   "RECTANGLE",
66   "RESOURCE_MANAGER",
67   "RGB_COLOR_MAP",
68   "RGB_BEST_MAP",
69   "RGB_BLUE_MAP",
70   "RGB_DEFAULT_MAP",
71   "RGB_GRAY_MAP",
72   "RGB_GREEN_MAP",
73   "RGB_RED_MAP",
74   "STRING",
75   "VISUALID",
76   "WINDOW",
77   "WM_COMMAND",
78   "WM_HINTS",
79   "WM_CLIENT_MACHINE",
80   "WM_ICON_NAME",
81   "WM_ICON_SIZE",
82   "WM_NAME",
83   "WM_NORMAL_HINTS",
84   "WM_SIZE_HINTS",
85   "WM_ZOOM_HINTS",
86   "MIN_SPACE",
87   "NORM_SPACE",
88   "MAX_SPACE",  "END_SPACE",
89   "SUPERSCRIPT_X",
90   "SUPERSCRIPT_Y",
91   "SUBSCRIPT_X",
92   "SUBSCRIPT_Y",
93   "UNDERLINE_POSITION",
94   "UNDERLINE_THICKNESS",
95   "STRIKEOUT_ASCENT",
96   "STRIKEOUT_DESCENT",
97   "ITALIC_ANGLE",
98   "X_HEIGHT",
99   "QUAD_WIDTH",
100   "WEIGHT",
101   "POINT_SIZE",
102   "RESOLUTION",
103   "COPYRIGHT",
104   "NOTICE",
105   "FONT_NAME",
106   "FAMILY_NAME",
107   "FULL_NAME",
108   "CAP_HEIGHT",
109   "WM_CLASS",
110   "WM_TRANSIENT_FOR",
111   /* Below here, these our our additions. Increment N_CUSTOM_PREDEFINED
112    * if you add any.
113    */
114   "CLIPBOARD"                   /* = 69 */
115 };
116
117 #define N_CUSTOM_PREDEFINED 1
118
119 #define ATOM_TO_INDEX(atom) (GPOINTER_TO_UINT(atom))
120 #define INDEX_TO_ATOM(atom) ((GdkAtom)GUINT_TO_POINTER(atom))
121
122 static void
123 insert_atom_pair (GdkAtom     virtual_atom,
124                   Atom        xatom)
125 {
126   if (!atom_from_virtual)
127     {
128       atom_from_virtual = g_hash_table_new (g_direct_hash, NULL);
129       atom_to_virtual = g_hash_table_new (g_direct_hash, NULL);
130     }
131   
132   g_hash_table_insert (atom_from_virtual, 
133                        GDK_ATOM_TO_POINTER (virtual_atom), GUINT_TO_POINTER (xatom));
134   g_hash_table_insert (atom_to_virtual,
135                        GUINT_TO_POINTER (xatom), GDK_ATOM_TO_POINTER (virtual_atom));
136 }
137
138 /**
139  * gdk_x11_atom_to_xatom:
140  * @atom: A #GdkAtom 
141  * 
142  * Converts from a #GdkAtom to the X atom for the default GDK display
143  * with the same string value.
144  * 
145  * Return value: the X atom corresponding to @atom.
146  **/
147 Atom
148 gdk_x11_atom_to_xatom (GdkAtom atom)
149 {
150   Atom xatom = None;
151   
152   if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (XAtomsStrings) - N_CUSTOM_PREDEFINED)
153     return ATOM_TO_INDEX (atom);
154   
155   if (atom_from_virtual)
156     xatom = GPOINTER_TO_UINT (g_hash_table_lookup (atom_from_virtual,
157                                                    GDK_ATOM_TO_POINTER (atom)));
158   if (!xatom)
159     {
160       char *name;
161       
162       g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
163
164       name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
165       
166       xatom = XInternAtom (gdk_display, name, FALSE);
167       insert_atom_pair (atom, xatom);
168     }
169
170   return xatom;
171 }
172
173 /**
174  * gdk_x11_xatom_to_atom:
175  * @xatom: an X atom for the default GDK display
176  * 
177  * Converts from an X atom for the default display to the corresponding
178  * #GdkAtom.
179  * 
180  * Return value: the corresponding #GdkAtom.
181  **/
182 GdkAtom
183 gdk_x11_xatom_to_atom (Atom xatom)
184 {
185   GdkAtom virtual_atom = GDK_NONE;
186   
187   if (xatom < G_N_ELEMENTS (XAtomsStrings) - N_CUSTOM_PREDEFINED)
188     return INDEX_TO_ATOM (xatom);
189   
190   if (atom_to_virtual)
191     virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (atom_to_virtual,
192                                                              GUINT_TO_POINTER (xatom)));
193   
194   if (!virtual_atom)
195     {
196       /* If this atom doesn't exist, we'll die with an X error unless
197        * we take precautions
198        */
199       char *name;
200       gdk_error_trap_push ();
201       name = XGetAtomName (gdk_display, xatom);
202       if (gdk_error_trap_pop ())
203         {
204           g_warning (G_STRLOC " invalid X atom: %ld", xatom);
205         }
206       else
207         {
208           virtual_atom = gdk_atom_intern (name, FALSE);
209           XFree (name);
210           
211           insert_atom_pair (virtual_atom, xatom);
212         }
213     }
214
215   return virtual_atom;
216 }
217
218 static void
219 virtual_atom_check_init (void)
220 {
221   if (!virtual_atom_hash)
222     {
223       gint i;
224       
225       virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
226       virtual_atom_array = g_ptr_array_new ();
227       
228       for (i = 0; i < G_N_ELEMENTS (XAtomsStrings); i++)
229         {
230           g_ptr_array_add (virtual_atom_array, XAtomsStrings[i]);
231           g_hash_table_insert (virtual_atom_hash, XAtomsStrings[i],
232                                GUINT_TO_POINTER (i));
233         }
234     }
235 }
236
237 GdkAtom
238 gdk_atom_intern (const gchar *atom_name, 
239                  gboolean     only_if_exists)
240 {
241   GdkAtom result;
242
243   virtual_atom_check_init ();
244   
245   result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
246   if (!result)
247     {
248       result = INDEX_TO_ATOM (virtual_atom_array->len);
249       
250       g_ptr_array_add (virtual_atom_array, g_strdup (atom_name));
251       g_hash_table_insert (virtual_atom_hash, 
252                            g_ptr_array_index (virtual_atom_array,
253                                               ATOM_TO_INDEX (result)),
254                            GDK_ATOM_TO_POINTER (result));
255     }
256
257   return result;
258 }
259
260 static G_CONST_RETURN char *
261 get_atom_name (GdkAtom atom)
262 {
263   virtual_atom_check_init ();
264
265   if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
266     return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
267   else
268     return NULL;
269 }
270
271 gchar *
272 gdk_atom_name (GdkAtom atom)
273 {
274   return g_strdup (get_atom_name (atom));
275 }
276
277 /**
278  * gdk_x11_get_xatom_by_name:
279  * @atom_name: a string
280  * 
281  * Returns the X atom for GDK's default display corresponding to @atom_name.
282  * This function caches the result, so if called repeatedly it is much
283  * faster than <function>XInternAtom()</function>, which is a round trip to 
284  * the server each time.
285  * 
286  * Return value: a X atom for GDK's default display.
287  **/
288 Atom
289 gdk_x11_get_xatom_by_name (const gchar *atom_name)
290 {
291   return gdk_x11_atom_to_xatom (gdk_atom_intern (atom_name, FALSE));
292 }
293
294 /**
295  * gdk_x11_get_xatom_name:
296  * @xatom: an X atom for GDK's default display
297  * 
298  * Returns the name of an X atom for GDK's default display. This
299  * function is meant mainly for debugging, so for convenience, unlike
300  * <function>XAtomName()</function> and gdk_atom_name(), the result 
301  * doesn't need to be freed. Also, this function will never return %NULL, 
302  * even if @xatom is invalid.
303  * 
304  * Return value: name of the X atom; this string is owned by GTK+,
305  *   so it shouldn't be modifed or freed. 
306  **/
307 G_CONST_RETURN gchar *
308 gdk_x11_get_xatom_name (Atom xatom)
309 {
310   return get_atom_name (gdk_x11_xatom_to_atom (xatom));
311 }
312
313 gboolean
314 gdk_property_get (GdkWindow   *window,
315                   GdkAtom      property,
316                   GdkAtom      type,
317                   gulong       offset,
318                   gulong       length,
319                   gint         pdelete,
320                   GdkAtom     *actual_property_type,
321                   gint        *actual_format_type,
322                   gint        *actual_length,
323                   guchar     **data)
324 {
325   Display *xdisplay;
326   Window xwindow;
327   Atom xproperty;
328   Atom xtype;
329   Atom ret_prop_type;
330   gint ret_format;
331   gulong ret_nitems;
332   gulong ret_bytes_after;
333   gulong ret_length;
334   guchar *ret_data;
335
336   g_return_val_if_fail (!window || GDK_IS_WINDOW (window), FALSE);
337
338   xproperty = gdk_x11_atom_to_xatom (property);
339   xtype = gdk_x11_atom_to_xatom (type);
340
341   if (window)
342     {
343       if (GDK_WINDOW_DESTROYED (window))
344         return FALSE;
345
346       xdisplay = GDK_WINDOW_XDISPLAY (window);
347       xwindow = GDK_WINDOW_XID (window);
348     }
349   else
350     {
351       xdisplay = gdk_display;
352       xwindow = _gdk_root_window;
353     }
354
355   ret_data = NULL;
356   XGetWindowProperty (xdisplay, xwindow, xproperty,
357                       offset, (length + 3) / 4, pdelete,
358                       xtype, &ret_prop_type, &ret_format,
359                       &ret_nitems, &ret_bytes_after,
360                       &ret_data);
361
362   if ((ret_prop_type == None) && (ret_format == 0)) {
363     return FALSE;
364   }
365
366   if (actual_property_type)
367     *actual_property_type = gdk_x11_xatom_to_atom (ret_prop_type);
368   if (actual_format_type)
369     *actual_format_type = ret_format;
370
371   if ((type != AnyPropertyType) && (ret_prop_type != xtype))
372     {
373       XFree (ret_data);
374       
375       g_warning("Couldn't match property type %s to %s\n", 
376                 gdk_x11_get_xatom_name (ret_prop_type),
377                 gdk_x11_get_xatom_name (xtype));
378       return FALSE;
379     }
380
381   /* FIXME: ignoring bytes_after could have very bad effects */
382
383   if (data)
384     {
385       if (ret_prop_type == XA_ATOM ||
386           ret_prop_type == gdk_x11_get_xatom_by_name ("ATOM_PAIR"))
387         {
388           /*
389            * data is an array of X atom, we need to convert it
390            * to an array of GDK Atoms
391            */
392           gint i;
393           GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
394           Atom *xatoms = (Atom *)ret_data;
395
396           *data = (guchar *)ret_atoms;
397
398           for (i = 0; i < ret_nitems; i++)
399             ret_atoms[i] = gdk_x11_xatom_to_atom (xatoms[i]);
400         }
401       else
402         {
403           switch (ret_format)
404             {
405             case 8:
406               ret_length = ret_nitems;
407               break;
408             case 16:
409               ret_length = sizeof(short) * ret_nitems;
410               break;
411             case 32:
412               ret_length = sizeof(long) * ret_nitems;
413               break;
414             default:
415               g_warning ("unknown property return format: %d", ret_format);
416               XFree (ret_data);
417               return FALSE;
418             }
419           
420           *data = g_new (guchar, ret_length);
421           memcpy (*data, ret_data, ret_length);
422           if (actual_length)
423             *actual_length = ret_length;
424         }
425     }
426
427   XFree (ret_data);
428
429   return TRUE;
430 }
431
432 void
433 gdk_property_change (GdkWindow    *window,
434                      GdkAtom       property,
435                      GdkAtom       type,
436                      gint          format,
437                      GdkPropMode   mode,
438                      const guchar *data,
439                      gint          nelements)
440 {
441   Display *xdisplay;
442   Window xwindow;
443   Atom xproperty;
444   Atom xtype;
445
446   g_return_if_fail (!window || GDK_IS_WINDOW (window));
447
448   xproperty = gdk_x11_atom_to_xatom (property);
449   xtype = gdk_x11_atom_to_xatom (type);
450
451   if (window)
452     {
453       if (GDK_WINDOW_DESTROYED (window))
454         return;
455
456       xdisplay = GDK_WINDOW_XDISPLAY (window);
457       xwindow = GDK_WINDOW_XID (window);
458     }
459   else
460     {
461       xdisplay = gdk_display;
462       xwindow = _gdk_root_window;
463     }
464
465   if (xtype == XA_ATOM || xtype == gdk_x11_get_xatom_by_name ("ATOM_PAIR"))
466     {
467       /*
468        * data is an array of GdkAtom, we need to convert it
469        * to an array of X Atoms
470        */
471       gint i;
472       GdkAtom *atoms = (GdkAtom*) data;
473       Atom *xatoms;
474
475       xatoms = g_new (Atom, nelements);
476       for (i = 0; i < nelements; i++)
477         xatoms[i] = gdk_x11_atom_to_xatom (atoms[i]);
478
479       XChangeProperty (xdisplay, xwindow, xproperty, xtype,
480                       format, mode, (guchar *)xatoms, nelements);
481       g_free (xatoms);
482     }
483   else
484     XChangeProperty (xdisplay, xwindow, xproperty, xtype,
485                     format, mode, (guchar *)data, nelements);
486 }
487
488 void
489 gdk_property_delete (GdkWindow *window,
490                      GdkAtom    property)
491 {
492   Display *xdisplay;
493   Window xwindow;
494
495   g_return_if_fail (!window || GDK_IS_WINDOW (window));
496
497   if (window)
498     {
499       if (GDK_WINDOW_DESTROYED (window))
500         return;
501
502       xdisplay = GDK_WINDOW_XDISPLAY (window);
503       xwindow = GDK_WINDOW_XID (window);
504     }
505   else
506     {
507       xdisplay = gdk_display;
508       xwindow = _gdk_root_window;
509     }
510
511   XDeleteProperty (xdisplay, xwindow, gdk_x11_atom_to_xatom (property));
512 }