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