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