]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkproperty-x11.c
gdk/: fully remove gdkalias hacks
[~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
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
300   if (xatom == None)
301     return GDK_NONE;
302
303   if (display->closed)
304     return GDK_NONE;
305
306   display_x11 = GDK_DISPLAY_X11 (display);
307   
308   if (xatom < G_N_ELEMENTS (xatoms_offset) - N_CUSTOM_PREDEFINED)
309     return INDEX_TO_ATOM (xatom);
310   
311   if (display_x11->atom_to_virtual)
312     virtual_atom = GDK_POINTER_TO_ATOM (g_hash_table_lookup (display_x11->atom_to_virtual,
313                                                              GUINT_TO_POINTER (xatom)));
314   
315   if (!virtual_atom)
316     {
317       /* If this atom doesn't exist, we'll die with an X error unless
318        * we take precautions
319        */
320       char *name;
321       gdk_error_trap_push ();
322       name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
323       if (gdk_error_trap_pop ())
324         {
325           g_warning (G_STRLOC " invalid X atom: %ld", xatom);
326         }
327       else
328         {
329           virtual_atom = gdk_atom_intern (name, FALSE);
330           XFree (name);
331           
332           insert_atom_pair (display, virtual_atom, xatom);
333         }
334     }
335
336   return virtual_atom;
337 }
338
339 /**
340  * gdk_x11_xatom_to_atom:
341  * @xatom: an X atom for the default GDK display
342  * 
343  * Convert from an X atom for the default display to the corresponding
344  * #GdkAtom.
345  * 
346  * Return value: the corresponding G#dkAtom.
347  **/
348 GdkAtom
349 gdk_x11_xatom_to_atom (Atom xatom)
350 {
351   return gdk_x11_xatom_to_atom_for_display (gdk_display_get_default (), xatom);
352 }
353
354 static void
355 virtual_atom_check_init (void)
356 {
357   if (!virtual_atom_hash)
358     {
359       gint i;
360       
361       virtual_atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
362       virtual_atom_array = g_ptr_array_new ();
363       
364       for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
365         {
366           g_ptr_array_add (virtual_atom_array, (gchar *)(xatoms_string + xatoms_offset[i]));
367           g_hash_table_insert (virtual_atom_hash, (gchar *)(xatoms_string + xatoms_offset[i]),
368                                GUINT_TO_POINTER (i));
369         }
370     }
371 }
372
373 static GdkAtom
374 intern_atom (const gchar *atom_name, 
375              gboolean     dup)
376 {
377   GdkAtom result;
378
379   virtual_atom_check_init ();
380   
381   result = GDK_POINTER_TO_ATOM (g_hash_table_lookup (virtual_atom_hash, atom_name));
382   if (!result)
383     {
384       result = INDEX_TO_ATOM (virtual_atom_array->len);
385       
386       g_ptr_array_add (virtual_atom_array, dup ? g_strdup (atom_name) : (gchar *)atom_name);
387       g_hash_table_insert (virtual_atom_hash, 
388                            g_ptr_array_index (virtual_atom_array,
389                                               ATOM_TO_INDEX (result)),
390                            GDK_ATOM_TO_POINTER (result));
391     }
392
393   return result;
394 }
395
396 GdkAtom
397 gdk_atom_intern (const gchar *atom_name, 
398                  gboolean     only_if_exists)
399 {
400   return intern_atom (atom_name, TRUE);
401 }
402
403 /**
404  * gdk_atom_intern_static_string:
405  * @atom_name: a static string
406  *
407  * Finds or creates an atom corresponding to a given string.
408  *
409  * Note that this function is identical to gdk_atom_intern() except
410  * that if a new #GdkAtom is created the string itself is used rather 
411  * than a copy. This saves memory, but can only be used if the string 
412  * will <emphasis>always</emphasis> exist. It can be used with statically
413  * allocated strings in the main program, but not with statically 
414  * allocated memory in dynamically loaded modules, if you expect to
415  * ever unload the module again (e.g. do not use this function in
416  * GTK+ theme engines).
417  *
418  * Returns: the atom corresponding to @atom_name
419  * 
420  * Since: 2.10
421  */
422 GdkAtom
423 gdk_atom_intern_static_string (const gchar *atom_name)
424 {
425   return intern_atom (atom_name, FALSE);
426 }
427
428 static G_CONST_RETURN char *
429 get_atom_name (GdkAtom atom)
430 {
431   virtual_atom_check_init ();
432
433   if (ATOM_TO_INDEX (atom) < virtual_atom_array->len)
434     return g_ptr_array_index (virtual_atom_array, ATOM_TO_INDEX (atom));
435   else
436     return NULL;
437 }
438
439 gchar *
440 gdk_atom_name (GdkAtom atom)
441 {
442   return g_strdup (get_atom_name (atom));
443 }
444
445 /**
446  * gdk_x11_get_xatom_by_name_for_display:
447  * @display: a #GdkDisplay
448  * @atom_name: a string
449  * 
450  * Returns the X atom for a #GdkDisplay corresponding to @atom_name.
451  * This function caches the result, so if called repeatedly it is much
452  * faster than XInternAtom(), which is a round trip to the server each time.
453  * 
454  * Return value: a X atom for a #GdkDisplay
455  *
456  * Since: 2.2
457  **/
458 Atom
459 gdk_x11_get_xatom_by_name_for_display (GdkDisplay  *display,
460                                        const gchar *atom_name)
461 {
462   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
463   return gdk_x11_atom_to_xatom_for_display (display,
464                                             gdk_atom_intern (atom_name, FALSE));
465 }
466
467 /**
468  * gdk_x11_get_xatom_by_name:
469  * @atom_name: a string
470  * 
471  * Returns the X atom for GDK's default display corresponding to @atom_name.
472  * This function caches the result, so if called repeatedly it is much
473  * faster than XInternAtom(), which is a round trip to the server each time.
474  * 
475  * Return value: a X atom for GDK's default display.
476  **/
477 Atom
478 gdk_x11_get_xatom_by_name (const gchar *atom_name)
479 {
480   return gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (),
481                                                 atom_name);
482 }
483
484 /**
485  * gdk_x11_get_xatom_name_for_display:
486  * @display: the #GdkDisplay where @xatom is defined
487  * @xatom: an X atom 
488  * 
489  * Returns the name of an X atom for its display. This
490  * function is meant mainly for debugging, so for convenience, unlike
491  * XAtomName() and gdk_atom_name(), the result doesn't need to
492  * be freed. 
493  *
494  * Return value: name of the X atom; this string is owned by GDK,
495  *   so it shouldn't be modifed or freed. 
496  *
497  * Since: 2.2
498  **/
499 G_CONST_RETURN gchar *
500 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
501                                     Atom        xatom)
502 {
503   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
504
505   return get_atom_name (gdk_x11_xatom_to_atom_for_display (display, xatom));
506 }
507
508 /**
509  * gdk_x11_get_xatom_name:
510  * @xatom: an X atom for GDK's default display
511  * 
512  * Returns the name of an X atom for GDK's default display. This
513  * function is meant mainly for debugging, so for convenience, unlike
514  * <function>XAtomName()</function> and gdk_atom_name(), the result 
515  * doesn't need to be freed. Also, this function will never return %NULL, 
516  * even if @xatom is invalid.
517  * 
518  * Return value: name of the X atom; this string is owned by GTK+,
519  *   so it shouldn't be modifed or freed. 
520  **/
521 G_CONST_RETURN gchar *
522 gdk_x11_get_xatom_name (Atom xatom)
523 {
524   return get_atom_name (gdk_x11_xatom_to_atom (xatom));
525 }
526
527 gboolean
528 gdk_property_get (GdkWindow   *window,
529                   GdkAtom      property,
530                   GdkAtom      type,
531                   gulong       offset,
532                   gulong       length,
533                   gint         pdelete,
534                   GdkAtom     *actual_property_type,
535                   gint        *actual_format_type,
536                   gint        *actual_length,
537                   guchar     **data)
538 {
539   GdkDisplay *display;
540   Atom ret_prop_type;
541   gint ret_format;
542   gulong ret_nitems;
543   gulong ret_bytes_after;
544   gulong get_length;
545   gulong ret_length;
546   guchar *ret_data;
547   Atom xproperty;
548   Atom xtype;
549   int res;
550
551   g_return_val_if_fail (!window || GDK_WINDOW_IS_X11 (window), FALSE);
552
553   if (!window)
554     {
555       GdkScreen *screen = gdk_screen_get_default ();
556       window = gdk_screen_get_root_window (screen);
557       
558       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
559     }
560   else if (!GDK_WINDOW_IS_X11 (window))
561     return FALSE;
562
563   if (GDK_WINDOW_DESTROYED (window))
564     return FALSE;
565
566   display = gdk_drawable_get_display (window);
567   xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
568   if (type == GDK_NONE)
569     xtype = AnyPropertyType;
570   else
571     xtype = gdk_x11_atom_to_xatom_for_display (display, type);
572
573   ret_data = NULL;
574   
575   /* 
576    * Round up length to next 4 byte value.  Some code is in the (bad?)
577    * habit of passing G_MAXLONG as the length argument, causing an
578    * overflow to negative on the add.  In this case, we clamp the
579    * value to G_MAXLONG.
580    */
581   get_length = length + 3;
582   if (get_length > G_MAXLONG)
583     get_length = G_MAXLONG;
584
585   /* To fail, either the user passed 0 or G_MAXULONG */
586   get_length = get_length / 4;
587   if (get_length == 0)
588     {
589       g_warning ("gdk_propery-get(): invalid length 0");
590       return FALSE;
591     }
592
593   res = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
594                             GDK_WINDOW_XWINDOW (window), xproperty,
595                             offset, get_length, pdelete,
596                             xtype, &ret_prop_type, &ret_format,
597                             &ret_nitems, &ret_bytes_after,
598                             &ret_data);
599
600   if (res != Success || (ret_prop_type == None && ret_format == 0))
601     {
602       return FALSE;
603     }
604
605   if (actual_property_type)
606     *actual_property_type = gdk_x11_xatom_to_atom_for_display (display, ret_prop_type);
607   if (actual_format_type)
608     *actual_format_type = ret_format;
609
610   if ((xtype != AnyPropertyType) && (ret_prop_type != xtype))
611     {
612       XFree (ret_data);
613       g_warning ("Couldn't match property type %s to %s\n", 
614                  gdk_x11_get_xatom_name_for_display (display, ret_prop_type), 
615                  gdk_x11_get_xatom_name_for_display (display, xtype));
616       return FALSE;
617     }
618
619   /* FIXME: ignoring bytes_after could have very bad effects */
620
621   if (data)
622     {
623       if (ret_prop_type == XA_ATOM ||
624           ret_prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
625         {
626           /*
627            * data is an array of X atom, we need to convert it
628            * to an array of GDK Atoms
629            */
630           gint i;
631           GdkAtom *ret_atoms = g_new (GdkAtom, ret_nitems);
632           Atom *xatoms = (Atom *)ret_data;
633
634           *data = (guchar *)ret_atoms;
635
636           for (i = 0; i < ret_nitems; i++)
637             ret_atoms[i] = gdk_x11_xatom_to_atom_for_display (display, xatoms[i]);
638           
639           if (actual_length)
640             *actual_length = ret_nitems * sizeof (GdkAtom);
641         }
642       else
643         {
644           switch (ret_format)
645             {
646             case 8:
647               ret_length = ret_nitems;
648               break;
649             case 16:
650               ret_length = sizeof(short) * ret_nitems;
651               break;
652             case 32:
653               ret_length = sizeof(long) * ret_nitems;
654               break;
655             default:
656               g_warning ("unknown property return format: %d", ret_format);
657               XFree (ret_data);
658               return FALSE;
659             }
660           
661           *data = g_new (guchar, ret_length);
662           memcpy (*data, ret_data, ret_length);
663           if (actual_length)
664             *actual_length = ret_length;
665         }
666     }
667
668   XFree (ret_data);
669
670   return TRUE;
671 }
672
673 void
674 gdk_property_change (GdkWindow    *window,
675                      GdkAtom       property,
676                      GdkAtom       type,
677                      gint          format,
678                      GdkPropMode   mode,
679                      const guchar *data,
680                      gint          nelements)
681 {
682   GdkDisplay *display;
683   Window xwindow;
684   Atom xproperty;
685   Atom xtype;
686
687   g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
688
689   if (!window)
690     {
691       GdkScreen *screen;
692       
693       screen = gdk_screen_get_default ();
694       window = gdk_screen_get_root_window (screen);
695       
696       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
697     }
698   else if (!GDK_WINDOW_IS_X11 (window))
699     return;
700
701   if (GDK_WINDOW_DESTROYED (window))
702     return;
703
704   gdk_window_ensure_native (window);
705
706   display = gdk_drawable_get_display (window);
707   xproperty = gdk_x11_atom_to_xatom_for_display (display, property);
708   xtype = gdk_x11_atom_to_xatom_for_display (display, type);
709   xwindow = GDK_WINDOW_XID (window);
710
711   if (xtype == XA_ATOM ||
712       xtype == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
713     {
714       /*
715        * data is an array of GdkAtom, we need to convert it
716        * to an array of X Atoms
717        */
718       gint i;
719       GdkAtom *atoms = (GdkAtom*) data;
720       Atom *xatoms;
721
722       xatoms = g_new (Atom, nelements);
723       for (i = 0; i < nelements; i++)
724         xatoms[i] = gdk_x11_atom_to_xatom_for_display (display, atoms[i]);
725
726       XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
727                        xproperty, xtype,
728                        format, mode, (guchar *)xatoms, nelements);
729       g_free (xatoms);
730     }
731   else
732     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, xproperty, 
733                      xtype, format, mode, (guchar *)data, nelements);
734 }
735
736 void
737 gdk_property_delete (GdkWindow *window,
738                      GdkAtom    property)
739 {
740   g_return_if_fail (!window || GDK_WINDOW_IS_X11 (window));
741
742   if (!window)
743     {
744       GdkScreen *screen = gdk_screen_get_default ();
745       window = gdk_screen_get_root_window (screen);
746       
747       GDK_NOTE (MULTIHEAD, 
748                 g_message ("gdk_property_delete(): window is NULL\n"));
749     }
750   else if (!GDK_WINDOW_IS_X11 (window))
751     return;
752
753   if (GDK_WINDOW_DESTROYED (window))
754     return;
755
756   XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XWINDOW (window),
757                    gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (window),
758                                                       property));
759 }