]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkproperty-x11.c
Merge branch 'master' into client-side-windows
[~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   "\0"  /* leave a space for None, even though it is not a predefined atom */
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,   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
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, or %GDK_NONE
177  *
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.
181  *
182  * Return value: the X atom corresponding to @atom, or %None
183  *
184  * Since: 2.2
185  **/
186 Atom
187 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display,
188                                    GdkAtom     atom)
189 {
190   Atom xatom = None;
191
192   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
193
194   if (atom == GDK_NONE)
195     return None;
196
197   if (display->closed)
198     return None;
199
200   xatom = lookup_cached_xatom (display, atom);
201
202   if (!xatom)
203     {
204       char *name;
205
206       g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
207
208       name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
209
210       xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
211       insert_atom_pair (display, atom, xatom);
212     }
213
214   return xatom;
215 }
216
217 void
218 _gdk_x11_precache_atoms (GdkDisplay          *display,
219                          const gchar * const *atom_names,
220                          gint                 n_atoms)
221 {
222   Atom *xatoms;
223   GdkAtom *atoms;
224   const gchar **xatom_names;
225   gint n_xatoms;
226   gint i;
227
228   xatoms = g_new (Atom, n_atoms);
229   xatom_names = g_new (const gchar *, n_atoms);
230   atoms = g_new (GdkAtom, n_atoms);
231
232   n_xatoms = 0;
233   for (i = 0; i < n_atoms; i++)
234     {
235       GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
236       if (lookup_cached_xatom (display, atom) == None)
237         {
238           atoms[n_xatoms] = atom;
239           xatom_names[n_xatoms] = atom_names[i];
240           n_xatoms++;
241         }
242     }
243
244   if (n_xatoms)
245     {
246 #ifdef HAVE_XINTERNATOMS
247       XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
248                     (char **)xatom_names, n_xatoms, False, xatoms);
249 #else
250       for (i = 0; i < n_xatoms; i++)
251         xatoms[i] = XInternAtom (GDK_DISPLAY_XDISPLAY (display),
252                                  xatom_names[i], False);
253 #endif
254     }
255
256   for (i = 0; i < n_xatoms; i++)
257     insert_atom_pair (display, atoms[i], xatoms[i]);
258
259   g_free (xatoms);
260   g_free (xatom_names);
261   g_free (atoms);
262 }
263
264 /**
265  * gdk_x11_atom_to_xatom:
266  * @atom: A #GdkAtom 
267  * 
268  * Converts from a #GdkAtom to the X atom for the default GDK display
269  * with the same string value.
270  * 
271  * Return value: the X atom corresponding to @atom.
272  **/
273 Atom
274 gdk_x11_atom_to_xatom (GdkAtom atom)
275 {
276   return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
277 }
278
279 /**
280  * gdk_x11_xatom_to_atom_for_display:
281  * @display: A #GdkDisplay
282  * @xatom: an X atom 
283  * 
284  * Convert from an X atom for a #GdkDisplay to the corresponding
285  * #GdkAtom.
286  * 
287  * Return value: the corresponding #GdkAtom.
288  *
289  * Since: 2.2
290  **/
291 GdkAtom
292 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
293                                    Atom        xatom)
294 {
295   GdkDisplayX11 *display_x11;
296   GdkAtom virtual_atom = GDK_NONE;
297   
298   g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
299   g_return_val_if_fail (xatom != None, GDK_NONE);
300
301   if (display->closed)
302     return GDK_NONE;
303
304   display_x11 = GDK_DISPLAY_X11 (display);
305   
306   if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
307     return INDEX_TO_ATOM (xatom);
308   
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)));
312   
313   if (!virtual_atom)
314     {
315       /* If this atom doesn't exist, we'll die with an X error unless
316        * we take precautions
317        */
318       char *name;
319       gdk_error_trap_push ();
320       name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
321       if (gdk_error_trap_pop ())
322         {
323           g_warning (G_STRLOC " invalid X atom: %ld", xatom);
324         }
325       else
326         {
327           virtual_atom = gdk_atom_intern (name, FALSE);
328           XFree (name);
329           
330           insert_atom_pair (display, virtual_atom, xatom);
331         }
332     }
333
334   return virtual_atom;
335 }
336
337 /**
338  * gdk_x11_xatom_to_atom:
339  * @xatom: an X atom for the default GDK display
340  * 
341  * Convert from an X atom for the default display to the corresponding
342  * #GdkAtom.
343  * 
344  * Return value: the corresponding G#dkAtom.
345  **/
346 GdkAtom
347 gdk_x11_xatom_to_atom (Atom xatom)
348 {
349   return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
350 }
351
352 static void
353 virtual_atom_check_init (void)
354 {
355   if (!virtual_atom_hash)
356     {
357       gint i;
358       
359       virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
360       virtual_atom_array = g_ptr_array_new ();
361       
362       for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
363         {
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));
367         }
368     }
369 }
370
371 static GdkAtom
372 intern_atom (const gchar *atom_name, 
373              gboolean     dup)
374 {
375   GdkAtom result;
376
377   virtual_atom_check_init ();
378   
379   result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
380   if (!result)
381     {
382       result = INDEX_TO_ATOM (virtual_atom_array->len);
383       
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));
389     }
390
391   return result;
392 }
393
394 GdkAtom
395 gdk_atom_intern (const gchar *atom_name, 
396                  gboolean     only_if_exists)
397 {
398   return intern_atom (atom_name, TRUE);
399 }
400
401 /**
402  * gdk_atom_intern_static_string:
403  * @atom_name: a static string
404  *
405  * Finds or creates an atom corresponding to a given string.
406  *
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).
415  *
416  * Returns: the atom corresponding to @atom_name
417  * 
418  * Since: 2.10
419  */
420 GdkAtom
421 gdk_atom_intern_static_string (const gchar *atom_name)
422 {
423   return intern_atom (atom_name, FALSE);
424 }
425
426 static G_CONST_RETURN char *
427 get_atom_name (GdkAtom atom)
428 {
429   virtual_atom_check_init ();
430
431   if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
432     return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
433   else
434     return NULL;
435 }
436
437 gchar *
438 gdk_atom_name (GdkAtom atom)
439 {
440   return g_strdup (get_atom_name (atom));
441 }
442
443 /**
444  * gdk_x11_get_xatom_by_name_for_display:
445  * @display: a #GdkDisplay
446  * @atom_name: a string
447  * 
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.
451  * 
452  * Return value: a X atom for a #GdkDisplay
453  *
454  * Since: 2.2
455  **/
456 Atom
457 gdk_x11_get_xatom_by_name_for_display (GdkDisplay  *display,
458                                        const gchar *atom_name)
459 {
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));
463 }
464
465 /**
466  * gdk_x11_get_xatom_by_name:
467  * @atom_name: a string
468  * 
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.
472  * 
473  * Return value: a X atom for GDK's default display.
474  **/
475 Atom
476 gdk_x11_get_xatom_by_name (const gchar *atom_name)
477 {
478   return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
479                                                 atom_name);
480 }
481
482 /**
483  * gdk_x11_get_xatom_name_for_display:
484  * @display: the #GdkDisplay where @xatom is defined
485  * @xatom: an X atom 
486  * 
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
490  * be freed. 
491  *
492  * Return value: name of the X atom; this string is owned by GDK,
493  *   so it shouldn't be modifed or freed. 
494  *
495  * Since: 2.2
496  **/
497 G_CONST_RETURN gchar *
498 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
499                                     Atom        xatom)
500 {
501   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
502
503   return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
504 }
505
506 /**
507  * gdk_x11_get_xatom_name:
508  * @xatom: an X atom for GDK's default display
509  * 
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.
515  * 
516  * Return value: name of the X atom; this string is owned by GTK+,
517  *   so it shouldn't be modifed or freed. 
518  **/
519 G_CONST_RETURN gchar *
520 gdk_x11_get_xatom_name (Atom xatom)
521 {
522   return get_atom_name (gdk_x11_xatom_to_atom (xatom));
523 }
524
525 gboolean
526 gdk_property_get (GdkWindow   *window,
527                   GdkAtom      property,
528                   GdkAtom      type,
529                   gulong       offset,
530                   gulong       length,
531                   gint         pdelete,
532                   GdkAtom     *actual_property_type,
533                   gint        *actual_format_type,
534                   gint        *actual_length,
535                   guchar     **data)
536 {
537   GdkDisplay *display;
538   Atom ret_prop_type;
539   gint ret_format;
540   gulong ret_nitems;
541   gulong ret_bytes_after;
542   gulong get_length;
543   gulong ret_length;
544   guchar *ret_data;
545   Atom xproperty;
546   Atom xtype;
547   int res;
548
549   g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
550
551   if (!window)
552     {
553       GdkScreen *screen = gdk_screen_get_default ();
554       window = gdk_screen_get_root_window (screen);
555       
556       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
557     }
558   else if (!GDK_WINDOW_IS_X11 (window))
559     return FALSE;
560
561   if (GDK_WINDOW_DESTROYED (window))
562     return FALSE;
563
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;
568   else
569     xtype = gdk_x11_atom_to_xatom_for_display (display, type);
570
571   ret_data = NULL;
572   
573   /* 
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.
578    */
579   get_length = length + 3;
580   if (get_length > G_MAXLONG)
581     get_length = G_MAXLONG;
582
583   /* To fail, either the user passed 0 or G_MAXULONG */
584   get_length = get_length / 4;
585   if (get_length == 0)
586     {
587       g_warning ("gdk_propery-get(): invalid length 0");
588       return FALSE;
589     }
590
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,
596                             &ret_data);
597
598   if (res != Success || (ret_prop_type == None && ret_format == 0))
599     {
600       return FALSE;
601     }
602
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;
607
608   if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
609     {
610       XFree (ret_data);
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));
614       return FALSE;
615     }
616
617   /* FIXME: ignoring bytes_after could have very bad effects */
618
619   if (data)
620     {
621       if (ret_prop_type == XA_ATOM ||
622           ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
623         {
624           /*
625            * data is an array of X atom, we need to convert it
626            * to an array of GDK Atoms
627            */
628           gint i;
629           GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
630           Atom *xatoms = (Atom *)ret_data;
631
632           *data = (guchar *)ret_atoms;
633
634           for (i = 0; i < ret_nitems; i++)
635             ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
636           
637           if (actual_length)
638             *actual_length = ret_nitems * sizeof (GdkAtom);
639         }
640       else
641         {
642           switch (ret_format)
643             {
644             case 8:
645               ret_length = ret_nitems;
646               break;
647             case 16:
648               ret_length = sizeof(short) * ret_nitems;
649               break;
650             case 32:
651               ret_length = sizeof(long) * ret_nitems;
652               break;
653             default:
654               g_warning ("unknown property return format: %d", ret_format);
655               XFree (ret_data);
656               return FALSE;
657             }
658           
659           *data = g_new (guchar, ret_length);
660           memcpy (*data, ret_data, ret_length);
661           if (actual_length)
662             *actual_length = ret_length;
663         }
664     }
665
666   XFree (ret_data);
667
668   return TRUE;
669 }
670
671 void
672 gdk_property_change (GdkWindow    *window,
673                      GdkAtom       property,
674                      GdkAtom       type,
675                      gint          format,
676                      GdkPropMode   mode,
677                      const guchar *data,
678                      gint          nelements)
679 {
680   GdkDisplay *display;
681   Window xwindow;
682   Atom xproperty;
683   Atom xtype;
684
685   g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
686
687   if (!window)
688     {
689       GdkScreen *screen;
690       
691       screen = gdk_screen_get_default ();
692       window = gdk_screen_get_root_window (screen);
693       
694       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
695     }
696   else if (!GDK_WINDOW_IS_X11 (window))
697     return;
698
699   if (GDK_WINDOW_DESTROYED (window))
700     return;
701
702   display = gdk_drawable_get_display (window);
703   
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);
707
708   if (xtype == XA_ATOM ||
709       xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
710     {
711       /*
712        * data is an array of GdkAtom, we need to convert it
713        * to an array of X Atoms
714        */
715       gint i;
716       GdkAtom *atoms = (GdkAtom*) data;
717       Atom *xatoms;
718
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]);
722
723       XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
724                        xproperty, xtype,
725                        format, mode, (guchar *)xatoms, nelements);
726       g_free (xatoms);
727     }
728   else
729     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty, 
730                      xtype, format, mode, (guchar *)data, nelements);
731 }
732
733 void
734 gdk_property_delete (GdkWindow *window,
735                      GdkAtom    property)
736 {
737   g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
738
739   if (!window)
740     {
741       GdkScreen *screen = gdk_screen_get_default ();
742       window = gdk_screen_get_root_window (screen);
743       
744       GDK_NOTE (MULTIHEAD, 
745                 g_message ("gdk_property_delete(): window is NULL\n"));
746     }
747   else if (!GDK_WINDOW_IS_X11 (window))
748     return;
749
750   if (GDK_WINDOW_DESTROYED (window))
751     return;
752
753   XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XWINDOW (window),
754                    gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
755                                                       property));
756 }
757
758 #define __GDK_PROPERTY_X11_C__
759 #include "gdkaliasdef.c"