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