]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkproperty-x11.c
wayland: Synthesize fullscreen window state change
[~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, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
23  */
24
25 #include "config.h"
26
27 #include "gdkproperty.h"
28 #include "gdkmain.h"
29 #include "gdkprivate.h"
30 #include "gdkinternals.h"
31 #include "gdkselection.h"
32 #include "gdkprivate-x11.h"
33 #include "gdkdisplay-x11.h"
34 #include "gdkscreen-x11.h"
35
36 #include <X11/Xlib.h>
37 #include <X11/Xatom.h>
38 #include <string.h>
39
40
41 /**
42  * SECTION:properties
43  * @Short_description: Functions to manipulate properties on windows
44  * @Title: Properties and Atoms
45  *
46  * Each window under X can have any number of associated
47  * <firstterm>properties</firstterm> attached to it.
48  * Properties are arbitrary chunks of data identified by
49  * <firstterm>atom</firstterm>s. (An <firstterm>atom</firstterm>
50  * is a numeric index into a string table on the X server. They are used
51  * to transfer strings efficiently between clients without
52  * having to transfer the entire string.) A property
53  * has an associated type, which is also identified
54  * using an atom.
55  *
56  * A property has an associated <firstterm>format</firstterm>,
57  * an integer describing how many bits are in each unit
58  * of data inside the property. It must be 8, 16, or 32.
59  * When data is transferred between the server and client,
60  * if they are of different endianesses it will be byteswapped
61  * as necessary according to the format of the property.
62  * Note that on the client side, properties of format 32
63  * will be stored with one unit per <emphasis>long</emphasis>,
64  * even if a long integer has more than 32 bits on the platform.
65  * (This decision was apparently made for Xlib to maintain
66  * compatibility with programs that assumed longs were 32
67  * bits, at the expense of programs that knew better.)
68  *
69  * The functions in this section are used to add, remove
70  * and change properties on windows, to convert atoms
71  * to and from strings and to manipulate some types of
72  * data commonly stored in X window properties.
73  */
74
75
76 static GPtrArray *virtual_atom_array;
77 static GHashTable *virtual_atom_hash;
78
79 static const gchar xatoms_string[] = 
80   /* These are all the standard predefined X atoms */
81   "\0"  /* leave a space for None, even though it is not a predefined atom */
82   "PRIMARY\0"
83   "SECONDARY\0"
84   "ARC\0"
85   "ATOM\0"
86   "BITMAP\0"
87   "CARDINAL\0"
88   "COLORMAP\0"
89   "CURSOR\0"
90   "CUT_BUFFER0\0"
91   "CUT_BUFFER1\0"
92   "CUT_BUFFER2\0"
93   "CUT_BUFFER3\0"
94   "CUT_BUFFER4\0"
95   "CUT_BUFFER5\0"
96   "CUT_BUFFER6\0"
97   "CUT_BUFFER7\0"
98   "DRAWABLE\0"
99   "FONT\0"
100   "INTEGER\0"
101   "PIXMAP\0"
102   "POINT\0"
103   "RECTANGLE\0"
104   "RESOURCE_MANAGER\0"
105   "RGB_COLOR_MAP\0"
106   "RGB_BEST_MAP\0"
107   "RGB_BLUE_MAP\0"
108   "RGB_DEFAULT_MAP\0"
109   "RGB_GRAY_MAP\0"
110   "RGB_GREEN_MAP\0"
111   "RGB_RED_MAP\0"
112   "STRING\0"
113   "VISUALID\0"
114   "WINDOW\0"
115   "WM_COMMAND\0"
116   "WM_HINTS\0"
117   "WM_CLIENT_MACHINE\0"
118   "WM_ICON_NAME\0"
119   "WM_ICON_SIZE\0"
120   "WM_NAME\0"
121   "WM_NORMAL_HINTS\0"
122   "WM_SIZE_HINTS\0"
123   "WM_ZOOM_HINTS\0"
124   "MIN_SPACE\0"
125   "NORM_SPACE\0"
126   "MAX_SPACE\0"
127   "END_SPACE\0"
128   "SUPERSCRIPT_X\0"
129   "SUPERSCRIPT_Y\0"
130   "SUBSCRIPT_X\0"
131   "SUBSCRIPT_Y\0"
132   "UNDERLINE_POSITION\0"
133   "UNDERLINE_THICKNESS\0"
134   "STRIKEOUT_ASCENT\0"
135   "STRIKEOUT_DESCENT\0"
136   "ITALIC_ANGLE\0"
137   "X_HEIGHT\0"
138   "QUAD_WIDTH\0"
139   "WEIGHT\0"
140   "POINT_SIZE\0"
141   "RESOLUTION\0"
142   "COPYRIGHT\0"
143   "NOTICE\0"
144   "FONT_NAME\0"
145   "FAMILY_NAME\0"
146   "FULL_NAME\0"
147   "CAP_HEIGHT\0"
148   "WM_CLASS\0"
149   "WM_TRANSIENT_FOR\0"
150   /* Below here, these are our additions. Increment N_CUSTOM_PREDEFINED
151    * if you add any.
152    */
153   "CLIPBOARD\0"                 /* = 69 */
154 ;
155
156 static const gint xatoms_offset[] = {
157     0,   1,   9,  19,  23,  28,  35,  44,  53,  60,  72,  84,
158    96, 108, 120, 132, 144, 156, 165, 170, 178, 185, 189, 201,
159   218, 232, 245, 258, 274, 287, 301, 313, 320, 329, 336, 347,
160   356, 374, 387, 400, 408, 424, 438, 452, 462, 473, 483, 493,
161   507, 521, 533, 545, 564, 584, 601, 619, 632, 641, 652, 659,
162   670, 681, 691, 698, 708, 720, 730, 741, 750, 767
163 };
164
165 #define N_CUSTOM_PREDEFINED 1
166
167 #define ATOM_TO_INDEX(atom) (GPOINTER_TO_UINT(atom))
168 #define INDEX_TO_ATOM(atom) ((GdkAtom)GUINT_TO_POINTER(atom))
169
170 static void
171 insert_atom_pair (GdkDisplay *display,
172                   GdkAtom     virtual_atom,
173                   Atom        xatom)
174 {
175   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);  
176   
177   if (!display_x11->atom_from_virtual)
178     {
179       display_x11->atom_from_virtual = g_hash_table_new (g_direct_hash, NULL);
180       display_x11->atom_to_virtual = g_hash_table_new (g_direct_hash, NULL);
181     }
182   
183   g_hash_table_insert (display_x11->atom_from_virtual, 
184                        GDK_ATOM_TO_POINTER (virtual_atom), 
185                        GUINT_TO_POINTER (xatom));
186   g_hash_table_insert (display_x11->atom_to_virtual,
187                        GUINT_TO_POINTER (xatom), 
188                        GDK_ATOM_TO_POINTER (virtual_atom));
189 }
190
191 static Atom
192 lookup_cached_xatom (GdkDisplay *display,
193                      GdkAtom     atom)
194 {
195   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
196
197   if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
198     return ATOM_TO_INDEX (atom);
199   
200   if (display_x11->atom_from_virtual)
201     return GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_virtual,
202                                                   GDK_ATOM_TO_POINTER (atom)));
203
204   return None;
205 }
206
207 /**
208  * gdk_x11_atom_to_xatom_for_display:
209  * @display: A #GdkDisplay
210  * @atom: A #GdkAtom, or %GDK_NONE
211  *
212  * Converts from a #GdkAtom to the X atom for a #GdkDisplay
213  * with the same string value. The special value %GDK_NONE
214  * is converted to %None.
215  *
216  * Return value: the X atom corresponding to @atom, or %None
217  *
218  * Since: 2.2
219  **/
220 Atom
221 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display,
222                                    GdkAtom     atom)
223 {
224   Atom xatom = None;
225
226   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
227
228   if (atom == GDK_NONE)
229     return None;
230
231   if (gdk_display_is_closed (display))
232     return None;
233
234   xatom = lookup_cached_xatom (display, atom);
235
236   if (!xatom)
237     {
238       char *name;
239
240       g_return_val_if_fail (ATOM_TO_INDEX (atom) < virtual_atom_array->len, None);
241
242       name = g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
243
244       xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), name, FALSE);
245       insert_atom_pair (display, atom, xatom);
246     }
247
248   return xatom;
249 }
250
251 void
252 _gdk_x11_precache_atoms (GdkDisplay          *display,
253                          const gchar * const *atom_names,
254                          gint                 n_atoms)
255 {
256   Atom *xatoms;
257   GdkAtom *atoms;
258   const gchar **xatom_names;
259   gint n_xatoms;
260   gint i;
261
262   xatoms = g_new (Atom, n_atoms);
263   xatom_names = g_new (const gchar *, n_atoms);
264   atoms = g_new (GdkAtom, n_atoms);
265
266   n_xatoms = 0;
267   for (i = 0; i < n_atoms; i++)
268     {
269       GdkAtom atom = gdk_atom_intern_static_string (atom_names[i]);
270       if (lookup_cached_xatom (display, atom) == None)
271         {
272           atoms[n_xatoms] = atom;
273           xatom_names[n_xatoms] = atom_names[i];
274           n_xatoms++;
275         }
276     }
277
278   if (n_xatoms)
279     XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
280                   (char **)xatom_names, n_xatoms, False, xatoms);
281
282   for (i = 0; i < n_xatoms; i++)
283     insert_atom_pair (display, atoms[i], xatoms[i]);
284
285   g_free (xatoms);
286   g_free (xatom_names);
287   g_free (atoms);
288 }
289
290 /**
291  * gdk_x11_atom_to_xatom:
292  * @atom: A #GdkAtom 
293  * 
294  * Converts from a #GdkAtom to the X atom for the default GDK display
295  * with the same string value.
296  * 
297  * Return value: the X atom corresponding to @atom.
298  **/
299 Atom
300 gdk_x11_atom_to_xatom (GdkAtom atom)
301 {
302   return gdk_x11_atom_to_xatom_for_display (gdk_display_get_default (), atom);
303 }
304
305 /**
306  * gdk_x11_xatom_to_atom_for_display:
307  * @display: A #GdkDisplay
308  * @xatom: an X atom 
309  * 
310  * Convert from an X atom for a #GdkDisplay to the corresponding
311  * #GdkAtom.
312  * 
313  * Return value: (transfer none): the corresponding #GdkAtom.
314  *
315  * Since: 2.2
316  **/
317 GdkAtom
318 gdk_x11_xatom_to_atom_for_display (GdkDisplay *display,
319                                    Atom        xatom)
320 {
321   GdkX11Display *display_x11;
322   GdkAtom virtual_atom = GDK_NONE;
323   
324   g_return_val_if_fail (GDK_IS_DISPLAY (display), GDK_NONE);
325
326   if (xatom == None)
327     return GDK_NONE;
328
329   if (gdk_display_is_closed (display))
330     return GDK_NONE;
331
332   display_x11 = GDK_X11_DISPLAY (display);
333   
334   if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
335     return INDEX_TO_ATOM (xatom);
336   
337   if (display_x11->atom_to_virtual)
338     virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
339                                                              GUINT_TO_POINTER (xatom)));
340   
341   if (!virtual_atom)
342     {
343       /* If this atom doesn't exist, we'll die with an X error unless
344        * we take precautions
345        */
346       char *name;
347       gdk_x11_display_error_trap_push (display);
348       name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
349       if (gdk_x11_display_error_trap_pop (display))
350         {
351           g_warning (G_STRLOC " invalid X atom: %ld", xatom);
352         }
353       else
354         {
355           virtual_atom = gdk_atom_intern (name, FALSE);
356           XFree (name);
357           
358           insert_atom_pair (display, virtual_atom, xatom);
359         }
360     }
361
362   return virtual_atom;
363 }
364
365 /**
366  * gdk_x11_xatom_to_atom:
367  * @xatom: an X atom for the default GDK display
368  * 
369  * Convert from an X atom for the default display to the corresponding
370  * #GdkAtom.
371  * 
372  * Return value: (transfer none): the corresponding G#dkAtom.
373  **/
374 GdkAtom
375 gdk_x11_xatom_to_atom (Atom xatom)
376 {
377   return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
378 }
379
380 static void
381 virtual_atom_check_init (void)
382 {
383   if (!virtual_atom_hash)
384     {
385       gint i;
386
387       virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
388       virtual_atom_array = g_ptr_array_new ();
389
390       for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
391         {
392           g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
393           g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
394                                GUINT_TO_POINTER (i));
395         }
396     }
397 }
398
399 GdkAtom
400 _gdk_x11_display_manager_atom_intern (GdkDisplayManager *manager,
401                                       const gchar       *atom_name,
402                                       gboolean           dup)
403 {
404   GdkAtom result;
405
406   virtual_atom_check_init ();
407
408   result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
409   if (!result)
410     {
411       result = INDEX_TO_ATOM (virtual_atom_array->len);
412
413       g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
414       g_hash_table_insert (virtual_atom_hash,
415                            g_ptr_array_index (virtual_atom_array,
416                                               ATOM_TO_INDEX (result)),
417                                               GDK_ATOM_TO_POINTER (result));
418     }
419
420   return result;
421 }
422
423 static const gchar *
424 get_atom_name (GdkAtom atom)
425 {
426   virtual_atom_check_init ();
427
428   if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
429     return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
430   else
431     return NULL;
432 }
433
434
435 gchar *
436 _gdk_x11_display_manager_get_atom_name (GdkDisplayManager *manager,
437                                         GdkAtom            atom)
438 {
439   return g_strdup (get_atom_name (atom));
440 }
441
442 /**
443  * gdk_x11_get_xatom_by_name_for_display:
444  * @display: a #GdkDisplay
445  * @atom_name: a string
446  * 
447  * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
448  * This function caches the result, so if called repeatedly it is much
449  * faster than XInternAtom(), which is a round trip to the server each time.
450  * 
451  * Return value: a X atom for a #GdkDisplay
452  *
453  * Since: 2.2
454  **/
455 Atom
456 gdk_x11_get_xatom_by_name_for_display (GdkDisplay  *display,
457                                        const gchar *atom_name)
458 {
459   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
460   return gdk_x11_atom_to_xatom_for_display (display,
461                                             gdk_atom_intern (atom_name, FALSE));
462 }
463
464 /**
465  * gdk_x11_get_xatom_by_name:
466  * @atom_name: a string
467  * 
468  * Returns the X atom for GDK's default display corresponding to @atom_name.
469  * This function caches the result, so if called repeatedly it is much
470  * faster than XInternAtom(), which is a round trip to the server each time.
471  * 
472  * Return value: a X atom for GDK's default display.
473  **/
474 Atom
475 gdk_x11_get_xatom_by_name (const gchar *atom_name)
476 {
477   return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
478                                                 atom_name);
479 }
480
481 /**
482  * gdk_x11_get_xatom_name_for_display:
483  * @display: the #GdkDisplay where @xatom is defined
484  * @xatom: an X atom 
485  * 
486  * Returns the name of an X atom for its display. This
487  * function is meant mainly for debugging, so for convenience, unlike
488  * XAtomName() and gdk_atom_name(), the result doesn't need to
489  * be freed. 
490  *
491  * Return value: name of the X atom; this string is owned by GDK,
492  *   so it shouldn't be modifed or freed. 
493  *
494  * Since: 2.2
495  **/
496 const gchar *
497 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
498                                     Atom        xatom)
499 {
500   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
501
502   return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
503 }
504
505 /**
506  * gdk_x11_get_xatom_name:
507  * @xatom: an X atom for GDK's default display
508  * 
509  * Returns the name of an X atom for GDK's default display. This
510  * function is meant mainly for debugging, so for convenience, unlike
511  * <function>XAtomName()</function> and gdk_atom_name(), the result 
512  * doesn't need to be freed. Also, this function will never return %NULL, 
513  * even if @xatom is invalid.
514  * 
515  * Return value: name of the X atom; this string is owned by GTK+,
516  *   so it shouldn't be modifed or freed. 
517  **/
518 const gchar *
519 gdk_x11_get_xatom_name (Atom xatom)
520 {
521   return get_atom_name (gdk_x11_xatom_to_atom (xatom));
522 }
523
524 gboolean
525 _gdk_x11_window_get_property (GdkWindow   *window,
526                               GdkAtom      property,
527                               GdkAtom      type,
528                               gulong       offset,
529                               gulong       length,
530                               gint         pdelete,
531                               GdkAtom     *actual_property_type,
532                               gint        *actual_format_type,
533                               gint        *actual_length,
534                               guchar     **data)
535 {
536   GdkDisplay *display;
537   Atom ret_prop_type;
538   gint ret_format;
539   gulong ret_nitems;
540   gulong ret_bytes_after;
541   gulong get_length;
542   gulong ret_length;
543   guchar *ret_data;
544   Atom xproperty;
545   Atom xtype;
546   int res;
547
548   g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
549
550   if (!window)
551     {
552       GdkScreen *screen = gdk_screen_get_default ();
553       window = gdk_screen_get_root_window (screen);
554       
555       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
556     }
557   else if (!GDK_WINDOW_IS_X11 (window))
558     return FALSE;
559
560   if (GDK_WINDOW_DESTROYED (window))
561     return FALSE;
562
563   display = gdk_window_get_display (window);
564   xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
565   if (type == GDK_NONE)
566     xtype = AnyPropertyType;
567   else
568     xtype = gdk_x11_atom_to_xatom_for_display (display, type);
569
570   ret_data = NULL;
571   
572   /* 
573    * Round up length to next 4 byte value.  Some code is in the (bad?)
574    * habit of passing G_MAXLONG as the length argument, causing an
575    * overflow to negative on the add.  In this case, we clamp the
576    * value to G_MAXLONG.
577    */
578   get_length = length + 3;
579   if (get_length > G_MAXLONG)
580     get_length = G_MAXLONG;
581
582   /* To fail, either the user passed 0 or G_MAXULONG */
583   get_length = get_length / 4;
584   if (get_length == 0)
585     {
586       g_warning ("gdk_propery-get(): invalid length 0");
587       return FALSE;
588     }
589
590   res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
591                             GDK_WINDOW_XID (window), xproperty,
592                             offset, get_length, pdelete,
593                             xtype, &ret_prop_type, &ret_format,
594                             &ret_nitems, &ret_bytes_after,
595                             &ret_data);
596
597   if (res != Success || (ret_prop_type == None && ret_format == 0))
598     {
599       return FALSE;
600     }
601
602   if (actual_property_type)
603     *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
604   if (actual_format_type)
605     *actual_format_type = ret_format;
606
607   if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
608     {
609       XFree (ret_data);
610       g_warning ("Couldn't match property type %s to %s\n", 
611                  gdk_x11_get_xatom_name_for_display (display, ret_prop_type), 
612                  gdk_x11_get_xatom_name_for_display (display, xtype));
613       return FALSE;
614     }
615
616   /* FIXME: ignoring bytes_after could have very bad effects */
617
618   if (data)
619     {
620       if (ret_prop_type == XA_ATOM ||
621           ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
622         {
623           /*
624            * data is an array of X atom, we need to convert it
625            * to an array of GDK Atoms
626            */
627           gint i;
628           GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
629           Atom *xatoms = (Atom *)ret_data;
630
631           *data = (guchar *)ret_atoms;
632
633           for (i = 0; i < ret_nitems; i++)
634             ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
635           
636           if (actual_length)
637             *actual_length = ret_nitems * sizeof (GdkAtom);
638         }
639       else
640         {
641           switch (ret_format)
642             {
643             case 8:
644               ret_length = ret_nitems;
645               break;
646             case 16:
647               ret_length = sizeof(short) * ret_nitems;
648               break;
649             case 32:
650               ret_length = sizeof(long) * ret_nitems;
651               break;
652             default:
653               g_warning ("unknown property return format: %d", ret_format);
654               XFree (ret_data);
655               return FALSE;
656             }
657           
658           *data = g_new (guchar, ret_length);
659           memcpy (*data, ret_data, ret_length);
660           if (actual_length)
661             *actual_length = ret_length;
662         }
663     }
664
665   XFree (ret_data);
666
667   return TRUE;
668 }
669
670 void
671 _gdk_x11_window_change_property (GdkWindow    *window,
672                                  GdkAtom       property,
673                                  GdkAtom       type,
674                                  gint          format,
675                                  GdkPropMode   mode,
676                                  const guchar *data,
677                                  gint          nelements)
678 {
679   GdkDisplay *display;
680   Window xwindow;
681   Atom xproperty;
682   Atom xtype;
683
684   g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
685
686   if (!window)
687     {
688       GdkScreen *screen;
689       
690       screen = gdk_screen_get_default ();
691       window = gdk_screen_get_root_window (screen);
692       
693       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
694     }
695   else if (!GDK_WINDOW_IS_X11 (window))
696     return;
697
698   if (GDK_WINDOW_DESTROYED (window))
699     return;
700
701   gdk_window_ensure_native (window);
702
703   display = gdk_window_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);
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_x11_window_delete_property (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_XID (window),
754                    gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
755                                                       property));
756 }