]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkproperty-x11.c
Include "config.h" instead of <config.h> Command used: find -name
[~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 "config.h"
28 #include <X11/Xlib.h>
29 #include <X11/Xatom.h>
30 #include <string.h>
31
32 #include "gdk.h"          /* For gdk_error_trap_push/pop() */
33 #include "gdkx.h"
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 */
40 #include "gdkalias.h"
41
42 static GPtrArray *virtual_atom_array;
43 static GHashTable *virtual_atom_hash;
44
45 static const gchar xatoms_string[] = 
46   /* These are all the standard predefined X atoms */
47   "NONE\0"
48   "PRIMARY\0"
49   "SECONDARY\0"
50   "ARC\0"
51   "ATOM\0"
52   "BITMAP\0"
53   "CARDINAL\0"
54   "COLORMAP\0"
55   "CURSOR\0"
56   "CUT_BUFFER0\0"
57   "CUT_BUFFER1\0"
58   "CUT_BUFFER2\0"
59   "CUT_BUFFER3\0"
60   "CUT_BUFFER4\0"
61   "CUT_BUFFER5\0"
62   "CUT_BUFFER6\0"
63   "CUT_BUFFER7\0"
64   "DRAWABLE\0"
65   "FONT\0"
66   "INTEGER\0"
67   "PIXMAP\0"
68   "POINT\0"
69   "RECTANGLE\0"
70   "RESOURCE_MANAGER\0"
71   "RGB_COLOR_MAP\0"
72   "RGB_BEST_MAP\0"
73   "RGB_BLUE_MAP\0"
74   "RGB_DEFAULT_MAP\0"
75   "RGB_GRAY_MAP\0"
76   "RGB_GREEN_MAP\0"
77   "RGB_RED_MAP\0"
78   "STRING\0"
79   "VISUALID\0"
80   "WINDOW\0"
81   "WM_COMMAND\0"
82   "WM_HINTS\0"
83   "WM_CLIENT_MACHINE\0"
84   "WM_ICON_NAME\0"
85   "WM_ICON_SIZE\0"
86   "WM_NAME\0"
87   "WM_NORMAL_HINTS\0"
88   "WM_SIZE_HINTS\0"
89   "WM_ZOOM_HINTS\0"
90   "MIN_SPACE\0"
91   "NORM_SPACE\0"
92   "MAX_SPACE\0"
93   "END_SPACE\0"
94   "SUPERSCRIPT_X\0"
95   "SUPERSCRIPT_Y\0"
96   "SUBSCRIPT_X\0"
97   "SUBSCRIPT_Y\0"
98   "UNDERLINE_POSITION\0"
99   "UNDERLINE_THICKNESS\0"
100   "STRIKEOUT_ASCENT\0"
101   "STRIKEOUT_DESCENT\0"
102   "ITALIC_ANGLE\0"
103   "X_HEIGHT\0"
104   "QUAD_WIDTH\0"
105   "WEIGHT\0"
106   "POINT_SIZE\0"
107   "RESOLUTION\0"
108   "COPYRIGHT\0"
109   "NOTICE\0"
110   "FONT_NAME\0"
111   "FAMILY_NAME\0"
112   "FULL_NAME\0"
113   "CAP_HEIGHT\0"
114   "WM_CLASS\0"
115   "WM_TRANSIENT_FOR\0"
116   /* Below here, these are our additions. Increment N_CUSTOM_PREDEFINED
117    * if you add any.
118    */
119   "CLIPBOARD\0"                 /* = 69 */
120 ;
121
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
129 };
130
131 #define N_CUSTOM_PREDEFINED 1
132
133 #define ATOM_TO_INDEX(atom) (GPOINTER_TO_UINT(atom))
134 #define INDEX_TO_ATOM(atom) ((GdkAtom)GUINT_TO_POINTER(atom))
135
136 static void
137 insert_atom_pair (GdkDisplay *display,
138                   GdkAtom     virtual_atom,
139                   Atom        xatom)
140 {
141   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);  
142   
143   if (!display_x11->atom_from_virtual)
144     {
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);
147     }
148   
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));
155 }
156
157 static Atom
158 lookup_cached_xatom (GdkDisplay *display,
159                      GdkAtom     atom)
160 {
161   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
162
163   if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
164     return ATOM_TO_INDEX (atom);
165   
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)));
169
170   return None;
171 }
172
173 /**
174  * gdk_x11_atom_to_xatom_for_display:
175  * @display: A #GdkDisplay
176  * @atom: A #GdkAtom 
177  * 
178  * Converts from a #GdkAtom to the X atom for a #GdkDisplay
179  * with the same string value.
180  * 
181  * Return value: the X atom corresponding to @atom.
182  *
183  * Since: 2.2
184  **/
185 Atom
186 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display, 
187                                    GdkAtom atom)
188 {
189   Atom xatom = None;
190   
191   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
192
193   if (display->closed)
194     return None;
195   
196   xatom = lookup_cached_xatom (display, atom);
197   
198   if (!xatom)
199     {
200       char *name;
201       
202       g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
203
204       name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
205       
206       xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
207       insert_atom_pair (display, atom, xatom);
208     }
209
210   return xatom;
211 }
212
213 void
214 _gdk_x11_precache_atoms (GdkDisplay          *display,
215                          const gchar * const *atom_names,
216                          gint                 n_atoms)
217 {
218   Atom *xatoms;
219   GdkAtom *atoms;
220   const gchar **xatom_names;
221   gint n_xatoms;
222   gint i;
223
224   xatoms = g_new (Atom, n_atoms);
225   xatom_names = g_new (const gchar *, n_atoms);
226   atoms = g_new (GdkAtom, n_atoms);
227
228   n_xatoms = 0;
229   for (i = 0; i < n_atoms; i++)
230     {
231       GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
232       if (lookup_cached_xatom (display, atom) == None)
233         {
234           atoms[n_xatoms] = atom;
235           xatom_names[n_xatoms] = atom_names[i];
236           n_xatoms++;
237         }
238     }
239
240   if (n_xatoms)
241     {
242 #ifdef HAVE_XINTERNATOMS
243       XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
244                     (char **)xatom_names, n_xatoms, False, xatoms);
245 #else
246       for (i = 0; i < n_xatoms; i++)
247         xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
248                                  xatom_names[i], False);
249 #endif
250     }
251
252   for (i = 0; i < n_xatoms; i++)
253     insert_atom_pair (display, atoms[i], xatoms[i]);
254
255   g_free (xatoms);
256   g_free (xatom_names);
257   g_free (atoms);
258 }
259
260 /**
261  * gdk_x11_atom_to_xatom:
262  * @atom: A #GdkAtom 
263  * 
264  * Converts from a #GdkAtom to the X atom for the default GDK display
265  * with the same string value.
266  * 
267  * Return value: the X atom corresponding to @atom.
268  **/
269 Atom
270 gdk_x11_atom_to_xatom (GdkAtom atom)
271 {
272   return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
273 }
274
275 /**
276  * gdk_x11_xatom_to_atom_for_display:
277  * @display: A #GdkDisplay
278  * @xatom: an X atom 
279  * 
280  * Convert from an X atom for a #GdkDisplay to the corresponding
281  * #GdkAtom.
282  * 
283  * Return value: the corresponding #GdkAtom.
284  *
285  * Since: 2.2
286  **/
287 GdkAtom
288 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
289                                    Atom        xatom)
290 {
291   GdkDisplayX11 *display_x11;
292   GdkAtom virtual_atom = GDK_NONE;
293   
294   g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
295
296   if (display->closed)
297     return GDK_NONE;
298
299   display_x11 = GDK_DISPLAY_X11 (display);
300   
301   if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
302     return INDEX_TO_ATOM (xatom);
303   
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)));
307   
308   if (!virtual_atom)
309     {
310       /* If this atom doesn't exist, we'll die with an X error unless
311        * we take precautions
312        */
313       char *name;
314       gdk_error_trap_push ();
315       name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
316       if (gdk_error_trap_pop ())
317         {
318           g_warning (G_STRLOC " invalid X atom: %ld", xatom);
319         }
320       else
321         {
322           virtual_atom = gdk_atom_intern (name, FALSE);
323           XFree (name);
324           
325           insert_atom_pair (display, virtual_atom, xatom);
326         }
327     }
328
329   return virtual_atom;
330 }
331
332 /**
333  * gdk_x11_xatom_to_atom:
334  * @xatom: an X atom for the default GDK display
335  * 
336  * Convert from an X atom for the default display to the corresponding
337  * #GdkAtom.
338  * 
339  * Return value: the corresponding G#dkAtom.
340  **/
341 GdkAtom
342 gdk_x11_xatom_to_atom (Atom xatom)
343 {
344   return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
345 }
346
347 static void
348 virtual_atom_check_init (void)
349 {
350   if (!virtual_atom_hash)
351     {
352       gint i;
353       
354       virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
355       virtual_atom_array = g_ptr_array_new ();
356       
357       for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
358         {
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));
362         }
363     }
364 }
365
366 static GdkAtom
367 intern_atom (const gchar *atom_name, 
368              gboolean     dup)
369 {
370   GdkAtom result;
371
372   virtual_atom_check_init ();
373   
374   result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
375   if (!result)
376     {
377       result = INDEX_TO_ATOM (virtual_atom_array->len);
378       
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));
384     }
385
386   return result;
387 }
388
389 GdkAtom
390 gdk_atom_intern (const gchar *atom_name, 
391                  gboolean     only_if_exists)
392 {
393   return intern_atom (atom_name, TRUE);
394 }
395
396 /**
397  * gdk_atom_intern_static_string:
398  * @atom_name: a static string
399  *
400  * Finds or creates an atom corresponding to a given string.
401  *
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).
410  *
411  * Returns: the atom corresponding to @atom_name
412  * 
413  * Since: 2.10
414  */
415 GdkAtom
416 gdk_atom_intern_static_string (const gchar *atom_name)
417 {
418   return intern_atom (atom_name, FALSE);
419 }
420
421 static G_CONST_RETURN char *
422 get_atom_name (GdkAtom atom)
423 {
424   virtual_atom_check_init ();
425
426   if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
427     return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
428   else
429     return NULL;
430 }
431
432 gchar *
433 gdk_atom_name (GdkAtom atom)
434 {
435   return g_strdup (get_atom_name (atom));
436 }
437
438 /**
439  * gdk_x11_get_xatom_by_name_for_display:
440  * @display: a #GdkDisplay
441  * @atom_name: a string
442  * 
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.
446  * 
447  * Return value: a X atom for a #GdkDisplay
448  *
449  * Since: 2.2
450  **/
451 Atom
452 gdk_x11_get_xatom_by_name_for_display (GdkDisplay  *display,
453                                        const gchar *atom_name)
454 {
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));
458 }
459
460 /**
461  * gdk_x11_get_xatom_by_name:
462  * @atom_name: a string
463  * 
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.
467  * 
468  * Return value: a X atom for GDK's default display.
469  **/
470 Atom
471 gdk_x11_get_xatom_by_name (const gchar *atom_name)
472 {
473   return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
474                                                 atom_name);
475 }
476
477 /**
478  * gdk_x11_get_xatom_name_for_display:
479  * @display: the #GdkDisplay where @xatom is defined
480  * @xatom: an X atom 
481  * 
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
485  * be freed. 
486  *
487  * Return value: name of the X atom; this string is owned by GDK,
488  *   so it shouldn't be modifed or freed. 
489  *
490  * Since: 2.2
491  **/
492 G_CONST_RETURN gchar *
493 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
494                                     Atom        xatom)
495 {
496   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
497
498   return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
499 }
500
501 /**
502  * gdk_x11_get_xatom_name:
503  * @xatom: an X atom for GDK's default display
504  * 
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.
510  * 
511  * Return value: name of the X atom; this string is owned by GTK+,
512  *   so it shouldn't be modifed or freed. 
513  **/
514 G_CONST_RETURN gchar *
515 gdk_x11_get_xatom_name (Atom xatom)
516 {
517   return get_atom_name (gdk_x11_xatom_to_atom (xatom));
518 }
519
520 gboolean
521 gdk_property_get (GdkWindow   *window,
522                   GdkAtom      property,
523                   GdkAtom      type,
524                   gulong       offset,
525                   gulong       length,
526                   gint         pdelete,
527                   GdkAtom     *actual_property_type,
528                   gint        *actual_format_type,
529                   gint        *actual_length,
530                   guchar     **data)
531 {
532   GdkDisplay *display;
533   Atom ret_prop_type;
534   gint ret_format;
535   gulong ret_nitems;
536   gulong ret_bytes_after;
537   gulong get_length;
538   gulong ret_length;
539   guchar *ret_data;
540   Atom xproperty;
541   Atom xtype;
542   int res;
543
544   g_return_val_if_fail (!window || GDK_IS_WINDOW (window), FALSE);
545
546   if (!window)
547     {
548       GdkScreen *screen = gdk_screen_get_default ();
549       window = gdk_screen_get_root_window (screen);
550       
551       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
552     }
553
554   if (GDK_WINDOW_DESTROYED (window))
555     return FALSE;
556
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;
561   else
562     xtype = gdk_x11_atom_to_xatom_for_display (display, type);
563
564   ret_data = NULL;
565   
566   /* 
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.
571    */
572   get_length = length + 3;
573   if (get_length > G_MAXLONG)
574     get_length = G_MAXLONG;
575
576   /* To fail, either the user passed 0 or G_MAXULONG */
577   get_length = get_length / 4;
578   if (get_length == 0)
579     {
580       g_warning ("gdk_propery-get(): invalid length 0");
581       return FALSE;
582     }
583
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,
589                             &ret_data);
590
591   if (res != Success || (ret_prop_type == None && ret_format == 0))
592     {
593       return FALSE;
594     }
595
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;
600
601   if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
602     {
603       XFree (ret_data);
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));
607       return FALSE;
608     }
609
610   /* FIXME: ignoring bytes_after could have very bad effects */
611
612   if (data)
613     {
614       if (ret_prop_type == XA_ATOM ||
615           ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
616         {
617           /*
618            * data is an array of X atom, we need to convert it
619            * to an array of GDK Atoms
620            */
621           gint i;
622           GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
623           Atom *xatoms = (Atom *)ret_data;
624
625           *data = (guchar *)ret_atoms;
626
627           for (i = 0; i < ret_nitems; i++)
628             ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
629           
630           if (actual_length)
631             *actual_length = ret_nitems * sizeof (GdkAtom);
632         }
633       else
634         {
635           switch (ret_format)
636             {
637             case 8:
638               ret_length = ret_nitems;
639               break;
640             case 16:
641               ret_length = sizeof(short) * ret_nitems;
642               break;
643             case 32:
644               ret_length = sizeof(long) * ret_nitems;
645               break;
646             default:
647               g_warning ("unknown property return format: %d", ret_format);
648               XFree (ret_data);
649               return FALSE;
650             }
651           
652           *data = g_new (guchar, ret_length);
653           memcpy (*data, ret_data, ret_length);
654           if (actual_length)
655             *actual_length = ret_length;
656         }
657     }
658
659   XFree (ret_data);
660
661   return TRUE;
662 }
663
664 void
665 gdk_property_change (GdkWindow    *window,
666                      GdkAtom       property,
667                      GdkAtom       type,
668                      gint          format,
669                      GdkPropMode   mode,
670                      const guchar *data,
671                      gint          nelements)
672 {
673   GdkDisplay *display;
674   Window xwindow;
675   Atom xproperty;
676   Atom xtype;
677
678   g_return_if_fail (!window || GDK_IS_WINDOW (window));
679
680   if (!window)
681     {
682       GdkScreen *screen;
683       
684       screen = gdk_screen_get_default ();
685       window = gdk_screen_get_root_window (screen);
686       
687       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
688     }
689
690
691   if (GDK_WINDOW_DESTROYED (window))
692     return;
693
694   display = gdk_drawable_get_display (window);
695   
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);
699
700   if (xtype == XA_ATOM ||
701       xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
702     {
703       /*
704        * data is an array of GdkAtom, we need to convert it
705        * to an array of X Atoms
706        */
707       gint i;
708       GdkAtom *atoms = (GdkAtom*) data;
709       Atom *xatoms;
710
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]);
714
715       XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
716                        xproperty, xtype,
717                        format, mode, (guchar *)xatoms, nelements);
718       g_free (xatoms);
719     }
720   else
721     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty, 
722                      xtype, format, mode, (guchar *)data, nelements);
723 }
724
725 void
726 gdk_property_delete (GdkWindow *window,
727                      GdkAtom    property)
728 {
729   g_return_if_fail (!window || GDK_IS_WINDOW (window));
730
731   if (!window)
732     {
733       GdkScreen *screen = gdk_screen_get_default ();
734       window = gdk_screen_get_root_window (screen);
735       
736       GDK_NOTE (MULTIHEAD, 
737                 g_message ("gdk_property_delete(): window is NULL\n"));
738     }
739
740   if (GDK_WINDOW_DESTROYED (window))
741     return;
742
743   XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XWINDOW (window),
744                    gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
745                                                       property));
746 }
747
748 #define __GDK_PROPERTY_X11_C__
749 #include "gdkaliasdef.c"