]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkwindow-x11.c
Robustify tracking of pointer grab window.
[~andy/gtk] / gdk / x11 / gdkwindow-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 <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <netinet/in.h>
31 #include <unistd.h>
32 #include "gdk.h"
33 #include "config.h"
34
35 #include "gdkwindow.h"
36 #include "gdkinputprivate.h"
37 #include "gdkprivate-x11.h"
38 #include "gdkregion.h"
39 #include "gdkinternals.h"
40 #include "MwmUtil.h"
41 #include "gdkwindow-x11.h"
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46
47
48 #ifdef HAVE_SHAPE_EXT
49 #include <X11/extensions/shape.h>
50 #endif
51
52 const int _gdk_event_mask_table[21] =
53 {
54   ExposureMask,
55   PointerMotionMask,
56   PointerMotionHintMask,
57   ButtonMotionMask,
58   Button1MotionMask,
59   Button2MotionMask,
60   Button3MotionMask,
61   ButtonPressMask,
62   ButtonReleaseMask,
63   KeyPressMask,
64   KeyReleaseMask,
65   EnterWindowMask,
66   LeaveWindowMask,
67   FocusChangeMask,
68   StructureNotifyMask,
69   PropertyChangeMask,
70   VisibilityChangeMask,
71   0,                            /* PROXIMITY_IN */
72   0,                            /* PROXIMTY_OUT */
73   SubstructureNotifyMask,
74   ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
75 };
76 const int _gdk_nenvent_masks = sizeof (_gdk_event_mask_table) / sizeof (int);
77
78 /* Forward declarations */
79 static gboolean gdk_window_gravity_works          (void);
80 static void     gdk_window_set_static_win_gravity (GdkWindow *window,
81                                                    gboolean   on);
82 static gboolean gdk_window_have_shape_ext         (void);
83 static gboolean gdk_window_icon_name_set          (GdkWindow *window);
84
85 static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable);
86 static void         gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
87                                                       GdkColormap *cmap);
88 static void         gdk_window_impl_x11_get_size    (GdkDrawable *drawable,
89                                                      gint *width,
90                                                      gint *height);
91 static GdkRegion*  gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable);
92 static void gdk_window_impl_x11_init       (GdkWindowImplX11      *window);
93 static void gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass);
94 static void gdk_window_impl_x11_finalize   (GObject            *object);
95
96 static gpointer parent_class = NULL;
97
98 GType
99 gdk_window_impl_x11_get_type (void)
100 {
101   static GType object_type = 0;
102
103   if (!object_type)
104     {
105       static const GTypeInfo object_info =
106       {
107         sizeof (GdkWindowImplX11Class),
108         (GBaseInitFunc) NULL,
109         (GBaseFinalizeFunc) NULL,
110         (GClassInitFunc) gdk_window_impl_x11_class_init,
111         NULL,           /* class_finalize */
112         NULL,           /* class_data */
113         sizeof (GdkWindowImplX11),
114         0,              /* n_preallocs */
115         (GInstanceInitFunc) gdk_window_impl_x11_init,
116       };
117       
118       object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_X11,
119                                             "GdkWindowImplX11",
120                                             &object_info, 0);
121     }
122   
123   return object_type;
124 }
125
126 GType
127 _gdk_window_impl_get_type (void)
128 {
129   return gdk_window_impl_x11_get_type ();
130 }
131
132 static void
133 gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
134 {
135   impl->width = 1;
136   impl->height = 1;
137 }
138
139 static void
140 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
141 {
142   GObjectClass *object_class = G_OBJECT_CLASS (klass);
143   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
144   
145   parent_class = g_type_class_peek_parent (klass);
146
147   object_class->finalize = gdk_window_impl_x11_finalize;
148
149   drawable_class->set_colormap = gdk_window_impl_x11_set_colormap;
150   drawable_class->get_colormap = gdk_window_impl_x11_get_colormap;
151   drawable_class->get_size = gdk_window_impl_x11_get_size;
152
153   /* Visible and clip regions are the same */
154   drawable_class->get_clip_region = gdk_window_impl_x11_get_visible_region;
155   drawable_class->get_visible_region = gdk_window_impl_x11_get_visible_region;
156 }
157
158 static void
159 gdk_window_impl_x11_finalize (GObject *object)
160 {
161   GdkWindowObject *wrapper;
162   GdkDrawableImplX11 *draw_impl;
163   GdkWindowImplX11 *window_impl;
164   
165   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));
166
167   draw_impl = GDK_DRAWABLE_IMPL_X11 (object);
168   window_impl = GDK_WINDOW_IMPL_X11 (object);
169   
170   wrapper = (GdkWindowObject*) draw_impl->wrapper;
171
172   _gdk_xgrab_check_destroy (GDK_WINDOW (wrapper));
173
174   if (!GDK_WINDOW_DESTROYED (wrapper))
175     {
176       gdk_xid_table_remove (draw_impl->xid);
177       if (window_impl->focus_window)
178         gdk_xid_table_remove (window_impl->focus_window);
179     }
180
181   G_OBJECT_CLASS (parent_class)->finalize (object);
182 }
183
184 static GdkColormap*
185 gdk_window_impl_x11_get_colormap (GdkDrawable *drawable)
186 {
187   GdkDrawableImplX11 *drawable_impl;
188   GdkWindowImplX11 *window_impl;
189   
190   g_return_val_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable), NULL);
191
192   drawable_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
193   window_impl = GDK_WINDOW_IMPL_X11 (drawable);
194
195   if (!((GdkWindowObject *) drawable_impl->wrapper)->input_only && 
196       drawable_impl->colormap == NULL)
197     {
198       XWindowAttributes window_attributes;
199
200       XGetWindowAttributes (drawable_impl->xdisplay,
201                             drawable_impl->xid,
202                             &window_attributes);
203       drawable_impl->colormap =
204         gdk_colormap_lookup (window_attributes.colormap);
205     }
206   
207   return drawable_impl->colormap;
208 }
209
210 static void
211 gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
212                                   GdkColormap *cmap)
213 {
214   GdkWindowImplX11 *impl;
215   GdkDrawableImplX11 *draw_impl;
216   
217   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
218
219   impl = GDK_WINDOW_IMPL_X11 (drawable);
220   draw_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
221
222   /* chain up */
223   GDK_DRAWABLE_CLASS (parent_class)->set_colormap (drawable, cmap);
224
225   if (cmap)
226     {
227       XSetWindowColormap (draw_impl->xdisplay,
228                           draw_impl->xid,
229                           GDK_COLORMAP_XCOLORMAP (cmap));
230       
231       if (((GdkWindowObject*)draw_impl->wrapper)->window_type !=
232           GDK_WINDOW_TOPLEVEL)
233         gdk_window_add_colormap_windows (GDK_WINDOW (draw_impl->wrapper));
234     }
235 }
236
237
238 static void
239 gdk_window_impl_x11_get_size (GdkDrawable *drawable,
240                               gint        *width,
241                               gint        *height)
242 {
243   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
244
245   if (width)
246     *width = GDK_WINDOW_IMPL_X11 (drawable)->width;
247   if (height)
248     *height = GDK_WINDOW_IMPL_X11 (drawable)->height;
249 }
250
251 static GdkRegion*
252 gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable)
253 {
254   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (drawable);
255   GdkRectangle result_rect;
256
257   result_rect.x = 0;
258   result_rect.y = 0;
259   result_rect.width = impl->width;
260   result_rect.height = impl->height;
261
262   gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect);
263
264   return gdk_region_rectangle (&result_rect);
265 }
266
267 void
268 _gdk_windowing_window_init (void)
269 {
270   GdkWindowObject *private;
271   GdkWindowImplX11 *impl;
272   GdkDrawableImplX11 *draw_impl;
273   XWindowAttributes xattributes;
274   unsigned int width;
275   unsigned int height;
276   unsigned int border_width;
277   unsigned int depth;
278   int x, y;
279
280   g_assert (_gdk_parent_root == NULL);
281   
282   XGetGeometry (gdk_display, _gdk_root_window, &_gdk_root_window,
283                 &x, &y, &width, &height, &border_width, &depth);
284   XGetWindowAttributes (gdk_display, _gdk_root_window, &xattributes);
285
286   _gdk_parent_root = g_object_new (GDK_TYPE_WINDOW, NULL);
287   private = (GdkWindowObject *)_gdk_parent_root;
288   impl = GDK_WINDOW_IMPL_X11 (private->impl);
289   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
290   
291   draw_impl->xdisplay = gdk_display;
292   draw_impl->xid = _gdk_root_window;
293   draw_impl->wrapper = GDK_DRAWABLE (private);
294   
295   private->window_type = GDK_WINDOW_ROOT;
296   private->depth = depth;
297   impl->width = width;
298   impl->height = height;
299   
300   gdk_xid_table_insert (&_gdk_root_window, _gdk_parent_root);
301 }
302
303 static Atom wm_client_leader_atom = None;
304
305 /**
306  * gdk_window_new:
307  * @parent: a #GdkWindow
308  * @attributes: attributes of the new window
309  * @attributes_mask: mask indicating which fields in @attributes are valid
310  * 
311  * Creates a new #GdkWindow using the attributes from @attributes. See
312  * #GdkWindowAttr and #GdkWindowAttributesType for more details.
313  * 
314  * Return value: the new #GdkWindow
315  **/
316 GdkWindow*
317 gdk_window_new (GdkWindow     *parent,
318                 GdkWindowAttr *attributes,
319                 gint           attributes_mask)
320 {
321   GdkWindow *window;
322   GdkWindowObject *private;
323   GdkWindowImplX11 *impl;
324   GdkDrawableImplX11 *draw_impl;
325   
326   GdkVisual *visual;
327   Window xparent;
328   Visual *xvisual;
329   Display *xdisplay;
330   Window xid;
331
332   XSetWindowAttributes xattributes;
333   long xattributes_mask;
334   XSizeHints size_hints;
335   XWMHints wm_hints;
336   XClassHint *class_hint;
337   int x, y, depth;
338   
339   unsigned int class;
340   char *title;
341   int i;
342   long pid;
343   
344   g_return_val_if_fail (attributes != NULL, NULL);
345   
346   if (!parent)
347     parent = _gdk_parent_root;
348
349   g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
350   
351   if (GDK_WINDOW_DESTROYED (parent))
352     return NULL;
353   
354   xparent = GDK_WINDOW_XID (parent);
355   
356   window = g_object_new (GDK_TYPE_WINDOW, NULL);
357   private = (GdkWindowObject *)window;
358   impl = GDK_WINDOW_IMPL_X11 (private->impl);
359   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
360   draw_impl->wrapper = GDK_DRAWABLE (window);
361
362   xdisplay = draw_impl->xdisplay = GDK_WINDOW_XDISPLAY (parent); 
363
364   /* Windows with a foreign parent are treated as if they are children
365    * of the root window, except for actual creation.
366    */
367   if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
368     parent = _gdk_parent_root;
369   
370   private->parent = (GdkWindowObject *)parent;
371
372   xattributes_mask = 0;
373   
374   if (attributes_mask & GDK_WA_X)
375     x = attributes->x;
376   else
377     x = 0;
378   
379   if (attributes_mask & GDK_WA_Y)
380     y = attributes->y;
381   else
382     y = 0;
383   
384   private->x = x;
385   private->y = y;
386   impl->width = (attributes->width > 1) ? (attributes->width) : (1);
387   impl->height = (attributes->height > 1) ? (attributes->height) : (1);
388
389   if (attributes->wclass == GDK_INPUT_ONLY)
390     {
391       /* Backwards compatiblity - we've always ignored
392        * attributes->window_type for input-only windows
393        * before
394        */
395       if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT)
396         private->window_type = GDK_WINDOW_TEMP;
397       else
398         private->window_type = GDK_WINDOW_CHILD;
399     }
400   else
401     private->window_type = attributes->window_type;
402
403   _gdk_window_init_position (GDK_WINDOW (private));
404   if (impl->position_info.big)
405     private->guffaw_gravity = TRUE;
406   
407   if (attributes_mask & GDK_WA_VISUAL)
408     visual = attributes->visual;
409   else
410     visual = gdk_visual_get_system ();
411   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
412   
413   xattributes.event_mask = StructureNotifyMask;
414   for (i = 0; i < _gdk_nenvent_masks; i++)
415     {
416       if (attributes->event_mask & (1 << (i + 1)))
417         xattributes.event_mask |= _gdk_event_mask_table[i];
418     }
419   private->event_mask = attributes->event_mask;
420   
421   if (xattributes.event_mask)
422     xattributes_mask |= CWEventMask;
423   
424   if (attributes_mask & GDK_WA_NOREDIR)
425     {
426       xattributes.override_redirect =
427         (attributes->override_redirect == FALSE)?False:True;
428       xattributes_mask |= CWOverrideRedirect;
429     } 
430   else
431     xattributes.override_redirect = False;
432
433   if (private->parent && private->parent->guffaw_gravity)
434     {
435       xattributes.win_gravity = StaticGravity;
436       xattributes_mask |= CWWinGravity;
437     }
438   
439   /* Sanity checks */
440   switch (private->window_type)
441     {
442     case GDK_WINDOW_TOPLEVEL:
443     case GDK_WINDOW_DIALOG:
444     case GDK_WINDOW_TEMP:
445       if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT)
446         {
447           g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
448                      "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
449           xparent = _gdk_root_window;
450         }
451     case GDK_WINDOW_CHILD:
452       break;
453     default:
454       g_warning (G_STRLOC "cannot make windows of type %d", private->window_type);
455       return NULL;
456     }
457           
458   if (attributes->wclass == GDK_INPUT_OUTPUT)
459     {
460       class = InputOutput;
461       depth = visual->depth;
462
463       private->input_only = FALSE;
464       private->depth = depth;
465       
466       if (attributes_mask & GDK_WA_COLORMAP)
467         {
468           draw_impl->colormap = attributes->colormap;
469           gdk_colormap_ref (attributes->colormap);
470         }
471       else
472         {
473           if ((((GdkVisualPrivate*)gdk_visual_get_system ())->xvisual) == xvisual)
474             {
475               draw_impl->colormap =
476                 gdk_colormap_get_system ();
477               gdk_colormap_ref (draw_impl->colormap);
478             }
479           else
480             {
481               draw_impl->colormap =
482                 gdk_colormap_new (visual, FALSE);
483             }
484         }
485       
486       private->bg_color.pixel = BlackPixel (gdk_display, _gdk_screen);
487       xattributes.background_pixel = private->bg_color.pixel;
488
489       private->bg_pixmap = NULL;
490       
491       xattributes.border_pixel = BlackPixel (gdk_display, _gdk_screen);
492       xattributes_mask |= CWBorderPixel | CWBackPixel;
493
494       if (private->guffaw_gravity)
495         xattributes.bit_gravity = StaticGravity;
496       else
497         xattributes.bit_gravity = NorthWestGravity;
498       
499       xattributes_mask |= CWBitGravity;
500
501       xattributes.colormap = GDK_COLORMAP_XCOLORMAP (draw_impl->colormap);
502       xattributes_mask |= CWColormap;
503
504       if (private->window_type == GDK_WINDOW_TEMP)
505         {
506           xattributes.save_under = True;
507           xattributes.override_redirect = True;
508           xattributes.cursor = None;
509           xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
510         }
511     }
512   else
513     {
514       depth = 0;
515       private->depth = 0;
516       class = InputOnly;
517       private->input_only = TRUE;
518       draw_impl->colormap = gdk_colormap_get_system ();
519       gdk_colormap_ref (draw_impl->colormap);
520     }
521
522   xid = draw_impl->xid = XCreateWindow (xdisplay, xparent,
523                                         impl->position_info.x, impl->position_info.y,
524                                         impl->position_info.width, impl->position_info.height,
525                                         0, depth, class, xvisual,
526                                         xattributes_mask, &xattributes);
527
528   gdk_drawable_ref (window);
529   gdk_xid_table_insert (&draw_impl->xid, window);
530   
531   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
532                                   (attributes->cursor) :
533                                   NULL));
534   
535   if (private->parent)
536     private->parent->children = g_list_prepend (private->parent->children, window);
537   
538   switch (GDK_WINDOW_TYPE (private))
539     {
540     case GDK_WINDOW_DIALOG:
541       XSetTransientForHint (xdisplay, xid, xparent);
542     case GDK_WINDOW_TOPLEVEL:
543     case GDK_WINDOW_TEMP:
544       XSetWMProtocols (xdisplay, xid,
545                        _gdk_wm_window_protocols, 3);
546       break;
547     case GDK_WINDOW_CHILD:
548       if ((attributes->wclass == GDK_INPUT_OUTPUT) &&
549           (draw_impl->colormap != gdk_colormap_get_system ()) &&
550           (draw_impl->colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window))))
551         {
552           GDK_NOTE (MISC, g_message ("adding colormap window\n"));
553           gdk_window_add_colormap_windows (window);
554         }
555       
556       return window;
557     default:
558       
559       return window;
560     }
561
562   if (class != InputOnly)
563     {
564       /* The focus window is off the visible area, and serves to receive key
565        * press events so they don't get sent to child windows.
566        */
567       impl->focus_window = XCreateSimpleWindow (xdisplay, xid,
568                                                 -1, -1, 1, 1, 0,
569                                                 xattributes.background_pixel,
570                                                 xattributes.background_pixel);
571       /* FIXME: probably better to actually track the requested event mask for the toplevel
572        */
573       XSelectInput (xdisplay, impl->focus_window,
574                     KeyPressMask | KeyReleaseMask | FocusChangeMask);
575       
576       XMapWindow (xdisplay, impl->focus_window);
577       gdk_xid_table_insert (&impl->focus_window, window);
578     }
579
580   size_hints.flags = PSize;
581   size_hints.width = impl->width;
582   size_hints.height = impl->height;
583   
584   wm_hints.flags = StateHint | WindowGroupHint;
585   wm_hints.window_group = _gdk_leader_window;
586   wm_hints.input = True;
587   wm_hints.initial_state = NormalState;
588   
589   /* FIXME: Is there any point in doing this? Do any WM's pay
590    * attention to PSize, and even if they do, is this the
591    * correct value???
592    */
593   XSetWMNormalHints (xdisplay, xid, &size_hints);
594   
595   XSetWMHints (xdisplay, xid, &wm_hints);
596   
597   if (!wm_client_leader_atom)
598     wm_client_leader_atom = gdk_x11_get_xatom_by_name ("WM_CLIENT_LEADER");
599
600   /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
601   XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
602
603   pid = getpid ();
604   XChangeProperty (xdisplay, xid,
605                    gdk_x11_get_xatom_by_name ("_NET_WM_PID"),
606                    XA_CARDINAL, 32,
607                    PropModeReplace,
608                    (guchar *)&pid, 1);
609   
610   XChangeProperty (xdisplay, xid,
611                    wm_client_leader_atom,
612                    XA_WINDOW, 32, PropModeReplace,
613                    (guchar*) &_gdk_leader_window, 1);
614   
615   if (attributes_mask & GDK_WA_TITLE)
616     title = attributes->title;
617   else
618     title = g_get_prgname ();
619
620   gdk_window_set_title (window, title);
621   
622   if (attributes_mask & GDK_WA_WMCLASS)
623     {
624       class_hint = XAllocClassHint ();
625       class_hint->res_name = attributes->wmclass_name;
626       class_hint->res_class = attributes->wmclass_class;
627       XSetClassHint (xdisplay, xid, class_hint);
628       XFree (class_hint);
629     }
630   
631   return window;
632 }
633
634 static GdkEventMask
635 x_event_mask_to_gdk_event_mask (long mask)
636 {
637   GdkEventMask event_mask = 0;
638   int i;
639
640   for (i = 0; i < _gdk_nenvent_masks; i++)
641     {
642       if (mask & _gdk_event_mask_table[i])
643         event_mask |= 1 << (i + 1);
644     }
645
646   return event_mask;
647 }
648
649 /**
650  * gdk_window_foreign_new:
651  * @anid: a native window handle.
652  * 
653  * Wraps a native window in a #GdkWindow.
654  * This may fail if the window has been destroyed.
655  *
656  * For example in the X backend, a native window handle is an Xlib
657  * <type>XID</type>.
658  * 
659  * Return value: the newly-created #GdkWindow wrapper for the 
660  *    native window or %NULL if the window has been destroyed.
661  **/
662 GdkWindow *
663 gdk_window_foreign_new (GdkNativeWindow anid)
664 {
665   GdkWindow *window;
666   GdkWindowObject *private;
667   GdkWindowImplX11 *impl;
668   GdkDrawableImplX11 *draw_impl;
669   XWindowAttributes attrs;
670   Window root, parent;
671   Window *children = NULL;
672   guint nchildren;
673   gboolean result;
674
675   gdk_error_trap_push ();
676   result = XGetWindowAttributes (gdk_display, anid, &attrs);
677   if (gdk_error_trap_pop () || !result)
678     return NULL;
679
680   /* FIXME: This is pretty expensive. Maybe the caller should supply
681    *        the parent */
682   gdk_error_trap_push ();
683   result = XQueryTree (gdk_display, anid, &root, &parent, &children, &nchildren);
684   if (gdk_error_trap_pop () || !result)
685     return NULL;
686
687   if (children)
688     XFree (children);
689   
690   window = g_object_new (GDK_TYPE_WINDOW, NULL);
691   private = (GdkWindowObject *)window;
692   impl = GDK_WINDOW_IMPL_X11 (private->impl);
693   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
694   draw_impl->wrapper = GDK_DRAWABLE (window);
695   
696   private->parent = gdk_xid_table_lookup (parent);
697   if (!private->parent || GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_FOREIGN)
698     private->parent = (GdkWindowObject *)_gdk_parent_root;
699   
700   private->parent->children = g_list_prepend (private->parent->children, window);
701
702   draw_impl->xid = anid;
703   draw_impl->xdisplay = gdk_display;
704
705   private->x = attrs.x;
706   private->y = attrs.y;
707   impl->width = attrs.width;
708   impl->height = attrs.height;
709   private->window_type = GDK_WINDOW_FOREIGN;
710   private->destroyed = FALSE;
711
712   private->event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
713
714   if (attrs.map_state == IsUnmapped)
715     private->state = GDK_WINDOW_STATE_WITHDRAWN;
716   else
717     private->state = 0;
718
719   private->depth = attrs.depth;
720   
721   _gdk_window_init_position (GDK_WINDOW (private));
722
723   gdk_drawable_ref (window);
724   gdk_xid_table_insert (&GDK_WINDOW_XID (window), window);
725   
726   return window;
727 }
728
729 /**
730  * gdk_window_lookup:
731  * @anid: a native window handle.
732  *
733  * Looks up the #GdkWindow that wraps the given native window handle. 
734  *
735  * For example in the X backend, a native window handle is an Xlib
736  * <type>XID</type>.
737  *
738  * Return value: the #GdkWindow wrapper for the native window, 
739  *    or %NULL if there is none.
740  **/
741 GdkWindow *
742 gdk_window_lookup (GdkNativeWindow anid)
743 {
744   return (GdkWindow*) gdk_xid_table_lookup (anid);
745 }
746
747 void
748 _gdk_windowing_window_destroy (GdkWindow *window,
749                                gboolean   recursing,
750                                gboolean   foreign_destroy)
751 {
752   GdkWindowObject *private = (GdkWindowObject *)window;
753
754   g_return_if_fail (GDK_IS_WINDOW (window));
755
756   _gdk_selection_window_destroyed (window);
757   
758   if (private->extension_events != 0)
759     gdk_input_window_destroy (window);
760
761 #ifdef HAVE_XFT  
762   {
763     GdkDrawableImplX11 *draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
764
765     if (draw_impl->picture)
766       XRenderFreePicture (draw_impl->xdisplay, draw_impl->picture);
767   }
768 #endif /* HAVE_XFT */  
769
770   if (private->window_type == GDK_WINDOW_FOREIGN)
771     {
772       if (!foreign_destroy && (private->parent != NULL))
773         {
774           /* It's somebody else's window, but in our heirarchy,
775            * so reparent it to the root window, and then send
776            * it a delete event, as if we were a WM
777            */
778           XClientMessageEvent xevent;
779           
780           gdk_error_trap_push ();
781           gdk_window_hide (window);
782           gdk_window_reparent (window, NULL, 0, 0);
783           
784           xevent.type = ClientMessage;
785           xevent.window = GDK_WINDOW_XID (window);
786           xevent.message_type = gdk_x11_get_xatom_by_name ("WM_PROTOCOLS");
787           xevent.format = 32;
788           xevent.data.l[0] = gdk_x11_get_xatom_by_name ("WM_DELETE_WINDOW");
789           xevent.data.l[1] = CurrentTime;
790           
791           XSendEvent (GDK_WINDOW_XDISPLAY (window),
792                       GDK_WINDOW_XID (window),
793                       False, 0, (XEvent *)&xevent);
794           gdk_flush ();
795           gdk_error_trap_pop ();
796         }
797     }
798   else if (!recursing && !foreign_destroy)
799     {
800       XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
801     }
802 }
803
804 /* This function is called when the XWindow is really gone.
805  */
806 void
807 gdk_window_destroy_notify (GdkWindow *window)
808 {
809   GdkWindowImplX11 *window_impl;
810
811   g_return_if_fail (window != NULL);
812   
813   window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
814
815   if (!GDK_WINDOW_DESTROYED (window))
816     {
817       if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN)
818         g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_WINDOW_XID (window));
819
820       _gdk_window_destroy (window, TRUE);
821     }
822   
823   gdk_xid_table_remove (GDK_WINDOW_XID (window));
824   if (window_impl->focus_window)
825     gdk_xid_table_remove (window_impl->focus_window);
826
827   _gdk_xgrab_check_destroy (window);
828   
829   gdk_drawable_unref (window);
830 }
831
832 static void
833 set_initial_hints (GdkWindow *window)
834 {
835   GdkWindowObject *private;
836   Atom atoms[5];
837   gint i;
838   
839   private = (GdkWindowObject*) window;
840
841   if (private->state & GDK_WINDOW_STATE_ICONIFIED)
842     {
843       XWMHints *wm_hints;
844       
845       wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
846                               GDK_WINDOW_XID (window));
847       if (!wm_hints)
848         wm_hints = XAllocWMHints ();
849
850       wm_hints->flags |= StateHint;
851       wm_hints->initial_state = IconicState;
852       
853       XSetWMHints (GDK_WINDOW_XDISPLAY (window),
854                    GDK_WINDOW_XID (window), wm_hints);
855       XFree (wm_hints);
856     }
857
858   /* We set the spec hints regardless of whether the spec is supported,
859    * since it can't hurt and it's kind of expensive to check whether
860    * it's supported.
861    */
862   
863   i = 0;
864
865   if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
866     {
867       atoms[i] = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_MAXIMIZED_VERT");
868       ++i;
869       atoms[i] = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_MAXIMIZED_HORZ");
870       ++i;
871     }
872
873   if (private->state & GDK_WINDOW_STATE_STICKY)
874     {
875       atoms[i] = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_STICKY");
876       ++i;
877     }
878
879   if (private->modal_hint)
880     {
881       atoms[i] = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_MODAL");
882       ++i;
883     }
884
885   if (i > 0)
886     {
887       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
888                        GDK_WINDOW_XID (window),
889                        gdk_x11_get_xatom_by_name ("_NET_WM_STATE"),
890                        XA_ATOM, 32, PropModeReplace,
891                        (guchar*) atoms, i);
892     }
893
894   if (private->state & GDK_WINDOW_STATE_STICKY)
895     {
896       atoms[0] = 0xFFFFFFFF;
897       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
898                        GDK_WINDOW_XID (window),
899                        gdk_x11_get_xatom_by_name ("_NET_WM_DESKTOP"),
900                        XA_CARDINAL, 32, PropModeReplace,
901                        (guchar*) atoms, 1);
902     }
903 }
904
905 static void
906 show_window_internal (GdkWindow *window,
907                       gboolean   raise)
908 {
909   GdkWindowObject *private;
910   
911   g_return_if_fail (GDK_IS_WINDOW (window));
912   
913   private = (GdkWindowObject*) window;
914   if (!private->destroyed)
915     {
916       if (raise)
917         XRaiseWindow (GDK_WINDOW_XDISPLAY (window),
918                       GDK_WINDOW_XID (window));
919
920       if (!GDK_WINDOW_IS_MAPPED (window))
921         {
922           set_initial_hints (window);
923           
924           gdk_synthesize_window_state (window,
925                                        GDK_WINDOW_STATE_WITHDRAWN,
926                                        0);
927         }
928       
929       g_assert (GDK_WINDOW_IS_MAPPED (window));
930       
931       if (GDK_WINDOW_IMPL_X11 (private->impl)->position_info.mapped)
932         XMapWindow (GDK_WINDOW_XDISPLAY (window),
933                     GDK_WINDOW_XID (window));
934     }
935 }
936
937 /**
938  * gdk_window_show_unraised:
939  * @window: a #GdkWindow
940  *
941  * Shows a #GdkWindow onscreen, but does not modify its stacking
942  * order. In contrast, gdk_window_show() will raise the window
943  * to the top of the window stack.
944  *
945  * On the X11 platform, in Xlib terms, this function calls
946  * XMapWindow() (it also updates some internal GDK state, which means
947  * that you can't really use XMapWindow() directly on a GDK window).
948  * 
949  **/
950 void
951 gdk_window_show_unraised (GdkWindow *window)
952 {
953   g_return_if_fail (GDK_IS_WINDOW (window));
954   
955   show_window_internal (window, FALSE);
956 }
957
958 /**
959  * gdk_window_show:
960  * @window: a #GdkWindow
961  *
962  * Like gdk_window_show_unraised(), but also raises the window to the
963  * top of the window stack (moves the window to the front of the
964  * Z-order).
965  *
966  * This function maps a window so it's visible onscreen. Its opposite
967  * is gdk_window_hide().
968  *
969  * When implementing a #GtkWidget, you should call this function on the widget's
970  * #GdkWindow as part of the "map" method.
971  * 
972  **/
973 void
974 gdk_window_show (GdkWindow *window)
975 {
976   g_return_if_fail (GDK_IS_WINDOW (window));
977
978   show_window_internal (window, TRUE);
979 }
980
981 /**
982  * gdk_window_hide:
983  * @window: a #GdkWindow
984  *
985  * For toplevel windows, withdraws them, so they will no longer be
986  * known to the window manager; for all windows, unmaps them, so
987  * they won't be displayed. Normally done automatically as
988  * part of gtk_widget_hide().
989  * 
990  **/
991 void
992 gdk_window_hide (GdkWindow *window)
993 {
994   GdkWindowObject *private;
995   
996   g_return_if_fail (window != NULL);
997
998   private = (GdkWindowObject*) window;
999
1000   /* We'll get the unmap notify eventually, and handle it then,
1001    * but checking here makes things more consistent if we are
1002    * just doing stuff ourself.
1003    */
1004   _gdk_xgrab_check_unmap (window,
1005                           NextRequest (GDK_WINDOW_XDISPLAY (window)));
1006
1007   /* You can't simply unmap toplevel windows. */
1008   switch (private->window_type)
1009     {
1010     case GDK_WINDOW_TOPLEVEL:
1011     case GDK_WINDOW_DIALOG:
1012     case GDK_WINDOW_TEMP: /* ? */
1013       gdk_window_withdraw (window);
1014       return;
1015       break;
1016       
1017     case GDK_WINDOW_FOREIGN:
1018     case GDK_WINDOW_ROOT:
1019     case GDK_WINDOW_CHILD:
1020       break;
1021     }
1022   
1023   if (!private->destroyed)
1024     {
1025       if (GDK_WINDOW_IS_MAPPED (window))
1026         gdk_synthesize_window_state (window,
1027                                      0,
1028                                      GDK_WINDOW_STATE_WITHDRAWN);
1029
1030       g_assert (!GDK_WINDOW_IS_MAPPED (window));
1031       
1032       _gdk_window_clear_update_area (window);
1033       
1034       XUnmapWindow (GDK_WINDOW_XDISPLAY (window),
1035                     GDK_WINDOW_XID (window));
1036     }
1037 }
1038
1039 /**
1040  * gdk_window_withdraw:
1041  * @window: a toplevel #GdkWindow
1042  * 
1043  * Withdraws a window (unmaps it and asks the window manager to forget about it).
1044  * Normally done automatically by gtk_widget_hide() called on a #GtkWindow.
1045  * 
1046  **/
1047 void
1048 gdk_window_withdraw (GdkWindow *window)
1049 {
1050   GdkWindowObject *private;
1051   
1052   g_return_if_fail (window != NULL);
1053   
1054   private = (GdkWindowObject*) window;
1055   if (!private->destroyed)
1056     {
1057       if (GDK_WINDOW_IS_MAPPED (window))
1058         gdk_synthesize_window_state (window,
1059                                      0,
1060                                      GDK_WINDOW_STATE_WITHDRAWN);
1061
1062       g_assert (!GDK_WINDOW_IS_MAPPED (window));
1063       
1064       XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
1065                        GDK_WINDOW_XID (window), 0);
1066     }
1067 }
1068
1069 /**
1070  * gdk_window_move:
1071  * @window: a #GdkWindow
1072  * @x: X coordinate relative to window's parent
1073  * @y: Y coordinate relative to window's parent
1074  *
1075  * Repositions a window relative to its parent window.
1076  * For toplevel windows, window managers may ignore or modify the move;
1077  * you should probably use gtk_window_move() on a #GtkWindow widget
1078  * anyway, instead of using GDK functions. For child windows,
1079  * the move will reliably succeed.
1080  *
1081  * If you're also planning to resize the window, use gdk_window_move_resize()
1082  * to both move and resize simultaneously, for a nicer visual effect.
1083  * 
1084  **/
1085 void
1086 gdk_window_move (GdkWindow *window,
1087                  gint       x,
1088                  gint       y)
1089 {
1090   GdkWindowObject *private = (GdkWindowObject *)window;
1091   GdkWindowImplX11 *impl;
1092
1093   g_return_if_fail (window != NULL);
1094   g_return_if_fail (GDK_IS_WINDOW (window));
1095
1096   impl = GDK_WINDOW_IMPL_X11 (private->impl);
1097
1098   if (!GDK_WINDOW_DESTROYED (window))
1099     {
1100       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1101         _gdk_window_move_resize_child (window, x, y,
1102                                        impl->width, impl->height);
1103       else
1104         {
1105           XMoveWindow (GDK_WINDOW_XDISPLAY (window),
1106                        GDK_WINDOW_XID (window),
1107                        x, y);
1108         }
1109     }
1110 }
1111
1112 /**
1113  * gdk_window_resize:
1114  * @window: a #GdkWindow
1115  * @width: new width of the window
1116  * @height: new height of the window
1117  *
1118  * Resizes @window; for toplevel windows, asks the window manager to resize
1119  * the window. The window manager may not allow the resize. When using GTK+,
1120  * use gtk_window_resize() instead of this low-level GDK function.
1121  *
1122  * Windows may not be resized below 1x1.
1123  * 
1124  * If you're also planning to move the window, use gdk_window_move_resize()
1125  * to both move and resize simultaneously, for a nicer visual effect.
1126  * 
1127  **/
1128 void
1129 gdk_window_resize (GdkWindow *window,
1130                    gint       width,
1131                    gint       height)
1132 {
1133   GdkWindowObject *private;
1134   
1135   g_return_if_fail (window != NULL);
1136   g_return_if_fail (GDK_IS_WINDOW (window));
1137   
1138   if (width < 1)
1139     width = 1;
1140   if (height < 1)
1141     height = 1;
1142
1143   private = (GdkWindowObject*) window;
1144   
1145   if (!GDK_WINDOW_DESTROYED (window))
1146     {
1147       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1148         _gdk_window_move_resize_child (window, private->x, private->y,
1149                                        width, height);
1150       else
1151         {
1152           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
1153           
1154           if (width != impl->width || height != impl->height)
1155             private->resize_count += 1;
1156
1157           XResizeWindow (GDK_WINDOW_XDISPLAY (window),
1158                          GDK_WINDOW_XID (window),
1159                          width, height);
1160         }
1161     }
1162 }
1163
1164 /**
1165  * gdk_window_move_resize:
1166  * @window: a #GdkWindow
1167  * @x: new X position relative to window's parent
1168  * @y: new Y position relative to window's parent
1169  * @width: new width
1170  * @height: new height
1171  *
1172  * Equivalent to calling gdk_window_move() and gdk_window_resize(),
1173  * except that both operations are performed at once, avoiding strange
1174  * visual effects. (i.e. the user may be able to see the window first
1175  * move, then resize, if youu don't use gdk_window_move_resize().)
1176  * 
1177  **/
1178 void
1179 gdk_window_move_resize (GdkWindow *window,
1180                         gint       x,
1181                         gint       y,
1182                         gint       width,
1183                         gint       height)
1184 {
1185   GdkWindowObject *private;
1186   
1187   g_return_if_fail (window != NULL);
1188   g_return_if_fail (GDK_IS_WINDOW (window));
1189
1190   if (width < 1)
1191     width = 1;
1192   if (height < 1)
1193     height = 1;
1194   
1195   private = (GdkWindowObject*) window;
1196
1197   if (!GDK_WINDOW_DESTROYED (window))
1198     {
1199       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1200         _gdk_window_move_resize_child (window, x, y, width, height);
1201       else
1202         {
1203           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
1204           
1205           if (width != impl->width || height != impl->height)
1206             private->resize_count += 1;
1207           
1208           XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
1209                              GDK_WINDOW_XID (window),
1210                              x, y, width, height);
1211         }
1212     }
1213 }
1214
1215 /**
1216  * gdk_window_reparent:
1217  * @window: a #GdkWindow
1218  * @new_parent: new parent to move @window into
1219  * @x: X location inside the new parent
1220  * @y: Y location inside the new parent
1221  *
1222  * Reparents @window into the given @new_parent. The window being
1223  * reparented will be unmapped as a side effect.
1224  * 
1225  **/
1226 void
1227 gdk_window_reparent (GdkWindow *window,
1228                      GdkWindow *new_parent,
1229                      gint       x,
1230                      gint       y)
1231 {
1232   GdkWindowObject *window_private;
1233   GdkWindowObject *parent_private;
1234   GdkWindowObject *old_parent_private;
1235   
1236   g_return_if_fail (window != NULL);
1237   g_return_if_fail (GDK_IS_WINDOW (window));
1238   g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
1239   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
1240   
1241   if (!new_parent)
1242     new_parent = _gdk_parent_root;
1243   
1244   window_private = (GdkWindowObject*) window;
1245   old_parent_private = (GdkWindowObject*)window_private->parent;
1246   parent_private = (GdkWindowObject*) new_parent;
1247   
1248   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (new_parent))
1249     XReparentWindow (GDK_WINDOW_XDISPLAY (window),
1250                      GDK_WINDOW_XID (window),
1251                      GDK_WINDOW_XID (new_parent),
1252                      x, y);
1253
1254   /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
1255    * the root window
1256    */
1257   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
1258     new_parent = _gdk_parent_root;
1259   
1260   window_private->parent = (GdkWindowObject *)new_parent;
1261
1262   /* Switch the window type as appropriate */
1263
1264   switch (GDK_WINDOW_TYPE (new_parent))
1265     {
1266     case GDK_WINDOW_ROOT:
1267     case GDK_WINDOW_FOREIGN:
1268       /* Now a toplevel */
1269       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1270         {
1271           GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
1272           XSetWMProtocols (GDK_WINDOW_XDISPLAY (window),
1273                            GDK_WINDOW_XID (window),
1274                            _gdk_wm_window_protocols, 3);
1275         }
1276     case GDK_WINDOW_TOPLEVEL:
1277     case GDK_WINDOW_CHILD:
1278     case GDK_WINDOW_DIALOG:
1279     case GDK_WINDOW_TEMP:
1280       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
1281           GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
1282         {
1283           /* If we were being sophisticated, we'd save the old window type
1284            * here, and restore it if we were reparented back to the
1285            * toplevel. However, the difference between different types
1286            * of toplevels only really matters on creation anyways.
1287            */
1288           GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
1289         }
1290     }
1291
1292   if (old_parent_private)
1293     old_parent_private->children = g_list_remove (old_parent_private->children, window);
1294   
1295   if ((old_parent_private &&
1296        (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
1297       (!old_parent_private && parent_private->guffaw_gravity))
1298     gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
1299   
1300   parent_private->children = g_list_prepend (parent_private->children, window);
1301   _gdk_window_init_position (GDK_WINDOW (window_private));
1302 }
1303
1304 void
1305 _gdk_windowing_window_clear_area (GdkWindow *window,
1306                                   gint       x,
1307                                   gint       y,
1308                                   gint       width,
1309                                   gint       height)
1310 {
1311   g_return_if_fail (window != NULL);
1312   g_return_if_fail (GDK_IS_WINDOW (window));
1313   
1314   if (!GDK_WINDOW_DESTROYED (window))
1315     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1316                 x, y, width, height, False);
1317 }
1318
1319 void
1320 _gdk_windowing_window_clear_area_e (GdkWindow *window,
1321                                     gint       x,
1322                                     gint       y,
1323                                     gint       width,
1324                                     gint       height)
1325 {
1326   g_return_if_fail (window != NULL);
1327   g_return_if_fail (GDK_IS_WINDOW (window));
1328   
1329   if (!GDK_WINDOW_DESTROYED (window))
1330     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1331                 x, y, width, height, True);
1332 }
1333
1334
1335 /**
1336  * gdk_window_raise:
1337  * @window: a #GdkWindow
1338  * 
1339  * Raises @window to the top of the Z-order (stacking order), so that
1340  * other windows with the same parent window appear below @window.
1341  * If @window is a toplevel, the window manager may choose to deny the
1342  * request to move the window in the Z-order, gdk_window_raise() only
1343  * requests the restack, does not guarantee it.
1344  * 
1345  **/
1346 void
1347 gdk_window_raise (GdkWindow *window)
1348 {
1349   g_return_if_fail (window != NULL);
1350   g_return_if_fail (GDK_IS_WINDOW (window));
1351   
1352   if (!GDK_WINDOW_DESTROYED (window))
1353     XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1354 }
1355
1356 /**
1357  * gdk_window_lower:
1358  * @window: a #GdkWindow
1359  * 
1360  * Lowers @window to the bottom of the Z-order (stacking order), so that
1361  * other windows with the same parent window appear above @window.
1362  * If @window is a toplevel, the window manager may choose to deny the
1363  * request to move the window in the Z-order, gdk_window_lower() only
1364  * requests the restack, does not guarantee it.
1365  *
1366  * Note that gdk_window_show() raises the window again, so don't call this
1367  * function before gdk_window_show(). (Try gdk_window_show_unraised().)
1368  * 
1369  **/
1370 void
1371 gdk_window_lower (GdkWindow *window)
1372 {
1373   g_return_if_fail (window != NULL);
1374   g_return_if_fail (GDK_IS_WINDOW (window));
1375   
1376   if (!GDK_WINDOW_DESTROYED (window))
1377     XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1378 }
1379
1380 /**
1381  * gdk_window_focus:
1382  * @window: a #GdkWindow
1383  * @timestamp: timestamp of the event triggering the window focus
1384  *
1385  * Sets keyboard focus to @window. If @window is not onscreen this
1386  * will not work. In most cases, gtk_window_present() should be used on
1387  * a #GtkWindow, rather than calling this function.
1388  * 
1389  **/
1390 void
1391 gdk_window_focus (GdkWindow *window,
1392                   guint32    timestamp)
1393 {
1394   g_return_if_fail (GDK_IS_WINDOW (window));
1395
1396   if (GDK_WINDOW_DESTROYED (window))
1397     return;
1398   
1399   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE)))
1400     {
1401       XEvent xev;
1402
1403       xev.xclient.type = ClientMessage;
1404       xev.xclient.serial = 0;
1405       xev.xclient.send_event = True;
1406       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
1407       xev.xclient.display = gdk_display;
1408       xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_ACTIVE_WINDOW");
1409       xev.xclient.format = 32;
1410       xev.xclient.data.l[0] = 0;
1411       
1412       XSendEvent (gdk_display, _gdk_root_window, False,
1413                   SubstructureRedirectMask | SubstructureNotifyMask,
1414                   &xev);
1415     }
1416   else
1417     {
1418       XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1419
1420       /* There is no way of knowing reliably whether we are viewable so we need
1421        * to trap errors so we don't cause a BadMatch.
1422        */
1423       gdk_error_trap_push ();
1424       XSetInputFocus (GDK_WINDOW_XDISPLAY (window),
1425                       GDK_WINDOW_XWINDOW (window),
1426                       RevertToParent,
1427                       timestamp);
1428       XSync (GDK_WINDOW_XDISPLAY (window), False);
1429       gdk_error_trap_pop ();
1430     }
1431 }
1432
1433 /**
1434  * gdk_window_set_hints:
1435  * @window: a #GdkWindow
1436  * @x: ignored field, does not matter
1437  * @y: ignored field, does not matter
1438  * @min_width: minimum width hint
1439  * @min_height: minimum height hint
1440  * @max_width: max width hint
1441  * @max_height: max height hint
1442  * @flags: logical OR of GDK_HINT_POS, GDK_HINT_MIN_SIZE, and/or GDK_HINT_MAX_SIZE
1443  *
1444  * This function is broken and useless and you should ignore it.
1445  * If using GTK+, use functions such as gtk_window_resize(), gtk_window_set_size_request(),
1446  * gtk_window_move(), gtk_window_parse_geometry(), and gtk_window_set_geometry_hints(),
1447  * depending on what you're trying to do.
1448  *
1449  * If using GDK directly, use gdk_window_set_geometry_hints().
1450  * 
1451  **/
1452 void
1453 gdk_window_set_hints (GdkWindow *window,
1454                       gint       x,
1455                       gint       y,
1456                       gint       min_width,
1457                       gint       min_height,
1458                       gint       max_width,
1459                       gint       max_height,
1460                       gint       flags)
1461 {
1462   XSizeHints size_hints;
1463   
1464   g_return_if_fail (window != NULL);
1465   g_return_if_fail (GDK_IS_WINDOW (window));
1466   
1467   if (GDK_WINDOW_DESTROYED (window))
1468     return;
1469   
1470   size_hints.flags = 0;
1471   
1472   if (flags & GDK_HINT_POS)
1473     {
1474       size_hints.flags |= PPosition;
1475       size_hints.x = x;
1476       size_hints.y = y;
1477     }
1478   
1479   if (flags & GDK_HINT_MIN_SIZE)
1480     {
1481       size_hints.flags |= PMinSize;
1482       size_hints.min_width = min_width;
1483       size_hints.min_height = min_height;
1484     }
1485   
1486   if (flags & GDK_HINT_MAX_SIZE)
1487     {
1488       size_hints.flags |= PMaxSize;
1489       size_hints.max_width = max_width;
1490       size_hints.max_height = max_height;
1491     }
1492   
1493   /* FIXME: Would it be better to delete this property if
1494    *        flags == 0? It would save space on the server
1495    */
1496   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1497                      GDK_WINDOW_XID (window),
1498                      &size_hints);
1499 }
1500
1501 /**
1502  * gdk_window_set_type_hint:
1503  * @window: A #GdkWindow
1504  * @hint: A hint of the function this window will have
1505  *
1506  * The application can use this call to provide a hint to the window
1507  * manager about the functionality of a window. The window manager
1508  * can use this information when determining the decoration and behaviour
1509  * of the window.
1510  *
1511  * The hint must be set before the window is mapped.
1512  **/
1513 void
1514 gdk_window_set_type_hint (GdkWindow        *window,
1515                           GdkWindowTypeHint hint)
1516 {
1517   Atom atom;
1518   
1519   g_return_if_fail (window != NULL);
1520   g_return_if_fail (GDK_IS_WINDOW (window));
1521   
1522   if (GDK_WINDOW_DESTROYED (window))
1523     return;
1524
1525   switch (hint)
1526     {
1527     case GDK_WINDOW_TYPE_HINT_DIALOG:
1528       atom = gdk_x11_get_xatom_by_name ("_NET_WM_WINDOW_TYPE_DIALOG");
1529       break;
1530     case GDK_WINDOW_TYPE_HINT_MENU:
1531       atom = gdk_x11_get_xatom_by_name ("_NET_WM_WINDOW_TYPE_MENU");
1532       break;
1533     case GDK_WINDOW_TYPE_HINT_TOOLBAR:
1534       atom = gdk_x11_get_xatom_by_name ("_NET_WM_WINDOW_TYPE_TOOLBAR");
1535       break;
1536     default:
1537       g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint);
1538       /* Fall thru */
1539     case GDK_WINDOW_TYPE_HINT_NORMAL:
1540       atom = gdk_x11_get_xatom_by_name ("_NET_WM_WINDOW_TYPE_NORMAL");
1541       break;
1542     }
1543
1544   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1545                    GDK_WINDOW_XID (window),
1546                    gdk_x11_get_xatom_by_name ("_NET_WM_WINDOW_TYPE"),
1547                    XA_ATOM, 32, PropModeReplace,
1548                    (guchar *)&atom, 1);
1549 }
1550
1551
1552 static void
1553 gdk_wmspec_change_state (gboolean   add,
1554                          GdkWindow *window,
1555                          GdkAtom    state1,
1556                          GdkAtom    state2)
1557 {
1558   XEvent xev;
1559
1560 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
1561 #define _NET_WM_STATE_ADD           1    /* add/set property */
1562 #define _NET_WM_STATE_TOGGLE        2    /* toggle property  */  
1563   
1564   xev.xclient.type = ClientMessage;
1565   xev.xclient.serial = 0;
1566   xev.xclient.send_event = True;
1567   xev.xclient.display = gdk_display;
1568   xev.xclient.window = GDK_WINDOW_XID (window);
1569   xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
1570   xev.xclient.format = 32;
1571   xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1572   xev.xclient.data.l[1] = gdk_x11_atom_to_xatom (state1);
1573   xev.xclient.data.l[2] = gdk_x11_atom_to_xatom (state2);
1574   
1575   XSendEvent (gdk_display, _gdk_root_window, False,
1576               SubstructureRedirectMask | SubstructureNotifyMask,
1577               &xev);
1578 }
1579 /**
1580  * gdk_window_set_modal_hint:
1581  * @window: A #GdkWindow
1582  * @modal: TRUE if the window is modal, FALSE otherwise.
1583  *
1584  * The application can use this hint to tell the window manager
1585  * that a certain window has modal behaviour. The window manager
1586  * can use this information to handle modal windows in a special
1587  * way.
1588  *
1589  * You should only use this on windows for which you have
1590  * previously called #gdk_window_set_transient_for()
1591  **/
1592 void
1593 gdk_window_set_modal_hint (GdkWindow *window,
1594                            gboolean   modal)
1595 {
1596   GdkWindowObject *private;
1597
1598   g_return_if_fail (window != NULL);
1599   g_return_if_fail (GDK_IS_WINDOW (window));
1600   
1601   if (GDK_WINDOW_DESTROYED (window))
1602     return;
1603
1604   private = (GdkWindowObject*) window;
1605
1606   private->modal_hint = modal;
1607
1608   if (GDK_WINDOW_IS_MAPPED (window))
1609     gdk_wmspec_change_state (modal, window,
1610                              gdk_atom_intern ("_NET_WM_STATE_MODAL", FALSE),
1611                              0);
1612 }
1613
1614 /**
1615  * gdk_window_set_geometry_hints:
1616  * @window: a #GdkWindow
1617  * @geometry: geometry hints
1618  * @geom_mask: bitmask indicating fields of @geometry to pay attention to
1619  *
1620  * Sets the geometry hints for @window. Hints flagged in @geom_mask
1621  * are set, hints not flagged in @geom_mask are unset.
1622  * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
1623  * 
1624  **/
1625 void 
1626 gdk_window_set_geometry_hints (GdkWindow      *window,
1627                                GdkGeometry    *geometry,
1628                                GdkWindowHints  geom_mask)
1629 {
1630   XSizeHints size_hints;
1631   
1632   g_return_if_fail (window != NULL);
1633   g_return_if_fail (GDK_IS_WINDOW (window));
1634   
1635   if (GDK_WINDOW_DESTROYED (window))
1636     return;
1637   
1638   size_hints.flags = 0;
1639   
1640   if (geom_mask & GDK_HINT_POS)
1641     {
1642       size_hints.flags |= PPosition;
1643       /* We need to initialize the following obsolete fields because KWM 
1644        * apparently uses these fields if they are non-zero.
1645        * #@#!#!$!.
1646        */
1647       size_hints.x = 0;
1648       size_hints.y = 0;
1649     }
1650
1651   if (geom_mask & GDK_HINT_USER_POS)
1652     {
1653       size_hints.flags |= USPosition;
1654     }
1655
1656   if (geom_mask & GDK_HINT_USER_SIZE)
1657     {
1658       size_hints.flags |= USSize;
1659     }
1660   
1661   if (geom_mask & GDK_HINT_MIN_SIZE)
1662     {
1663       size_hints.flags |= PMinSize;
1664       size_hints.min_width = geometry->min_width;
1665       size_hints.min_height = geometry->min_height;
1666     }
1667   
1668   if (geom_mask & GDK_HINT_MAX_SIZE)
1669     {
1670       size_hints.flags |= PMaxSize;
1671       size_hints.max_width = MAX (geometry->max_width, 1);
1672       size_hints.max_height = MAX (geometry->max_height, 1);
1673     }
1674   
1675   if (geom_mask & GDK_HINT_BASE_SIZE)
1676     {
1677       size_hints.flags |= PBaseSize;
1678       size_hints.base_width = geometry->base_width;
1679       size_hints.base_height = geometry->base_height;
1680     }
1681   
1682   if (geom_mask & GDK_HINT_RESIZE_INC)
1683     {
1684       size_hints.flags |= PResizeInc;
1685       size_hints.width_inc = geometry->width_inc;
1686       size_hints.height_inc = geometry->height_inc;
1687     }
1688   
1689   if (geom_mask & GDK_HINT_ASPECT)
1690     {
1691       size_hints.flags |= PAspect;
1692       if (geometry->min_aspect <= 1)
1693         {
1694           size_hints.min_aspect.x = 65536 * geometry->min_aspect;
1695           size_hints.min_aspect.y = 65536;
1696         }
1697       else
1698         {
1699           size_hints.min_aspect.x = 65536;
1700           size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
1701         }
1702       if (geometry->max_aspect <= 1)
1703         {
1704           size_hints.max_aspect.x = 65536 * geometry->max_aspect;
1705           size_hints.max_aspect.y = 65536;
1706         }
1707       else
1708         {
1709           size_hints.max_aspect.x = 65536;
1710           size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
1711         }
1712     }
1713
1714   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1715     {
1716       size_hints.flags |= PWinGravity;
1717       size_hints.win_gravity = geometry->win_gravity;
1718     }
1719   
1720   /* FIXME: Would it be better to delete this property if
1721    *        geom_mask == 0? It would save space on the server
1722    */
1723   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1724                      GDK_WINDOW_XID (window),
1725                      &size_hints);
1726 }
1727
1728 static void
1729 gdk_window_get_geometry_hints (GdkWindow      *window,
1730                                GdkGeometry    *geometry,
1731                                GdkWindowHints *geom_mask)
1732 {
1733   XSizeHints size_hints;  
1734   glong junk_size_mask = 0;
1735
1736   g_return_if_fail (GDK_IS_WINDOW (window));
1737   g_return_if_fail (geometry != NULL);
1738   g_return_if_fail (geom_mask != NULL);
1739
1740   *geom_mask = 0;
1741   
1742   if (GDK_WINDOW_DESTROYED (window))
1743     return;
1744   
1745   if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1746                           GDK_WINDOW_XID (window),
1747                           &size_hints,
1748                           &junk_size_mask))
1749     return;                   
1750
1751   if (size_hints.flags & PMinSize)
1752     {
1753       *geom_mask |= GDK_HINT_MIN_SIZE;
1754       geometry->min_width = size_hints.min_width;
1755       geometry->min_height = size_hints.min_height;
1756     }
1757
1758   if (size_hints.flags & PMaxSize)
1759     {
1760       *geom_mask |= GDK_HINT_MAX_SIZE;
1761       geometry->max_width = MAX (size_hints.max_width, 1);
1762       geometry->max_height = MAX (size_hints.max_height, 1);
1763     }
1764
1765   if (size_hints.flags & PResizeInc)
1766     {
1767       *geom_mask |= GDK_HINT_RESIZE_INC;
1768       geometry->width_inc = size_hints.width_inc;
1769       geometry->height_inc = size_hints.height_inc;
1770     }
1771
1772   if (size_hints.flags & PAspect)
1773     {
1774       *geom_mask |= GDK_HINT_ASPECT;
1775
1776       geometry->min_aspect = (gdouble) size_hints.min_aspect.x / (gdouble) size_hints.min_aspect.y;
1777       geometry->max_aspect = (gdouble) size_hints.max_aspect.x / (gdouble) size_hints.max_aspect.y;
1778     }
1779
1780   if (size_hints.flags & PWinGravity)
1781     {
1782       *geom_mask |= GDK_HINT_WIN_GRAVITY;
1783       geometry->win_gravity = size_hints.win_gravity;
1784     }
1785 }
1786
1787 static gboolean
1788 utf8_is_latin1 (const gchar *str)
1789 {
1790   const char *p = str;
1791
1792   while (*p)
1793     {
1794       gunichar ch = g_utf8_get_char (p);
1795
1796       if (ch > 0xff)
1797         return FALSE;
1798       
1799       p = g_utf8_next_char (p);
1800     }
1801
1802   return TRUE;
1803 }
1804
1805 /* Set the property to @utf8_str as STRING if the @utf8_str is fully
1806  * convertable to STRING, otherwise, set it as compound text
1807  */
1808 static void
1809 set_text_property (GdkWindow   *window,
1810                    Atom         property,
1811                    const gchar *utf8_str)
1812 {
1813   guchar *prop_text = NULL;
1814   Atom prop_type;
1815   gint prop_length;
1816   gint prop_format;
1817   
1818   if (utf8_is_latin1 (utf8_str))
1819     {
1820       prop_type = XA_STRING;
1821       prop_text = gdk_utf8_to_string_target (utf8_str);
1822       prop_length = strlen (prop_text);
1823       prop_format = 8;
1824     }
1825   else
1826     {
1827       GdkAtom gdk_type;
1828       
1829       gdk_utf8_to_compound_text (utf8_str, &gdk_type, &prop_format,
1830                                  &prop_text, &prop_length);
1831       prop_type = gdk_x11_atom_to_xatom (gdk_type);
1832     }
1833
1834   if (prop_text)
1835     {
1836       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1837                        GDK_WINDOW_XID (window),
1838                        property,
1839                        prop_type, prop_format,
1840                        PropModeReplace, prop_text,
1841                        prop_length);
1842
1843       g_free (prop_text);
1844     }
1845 }
1846
1847 /**
1848  * gdk_window_set_title:
1849  * @window: a #GdkWindow
1850  * @title: title of @window
1851  *
1852  * Sets the title of a toplevel window, to be displayed in the titlebar.
1853  * If you haven't explicitly set the icon name for the window
1854  * (using gdk_window_set_icon_name()), the icon name will be set to
1855  * @title as well. @title must be in UTF-8 encoding (as with all
1856  * user-readable strings in GDK/GTK+). @title may not be %NULL.
1857  * 
1858  **/
1859 void
1860 gdk_window_set_title (GdkWindow   *window,
1861                       const gchar *title)
1862 {
1863   g_return_if_fail (window != NULL);
1864   g_return_if_fail (GDK_IS_WINDOW (window));
1865   g_return_if_fail (title != NULL);
1866
1867   if (GDK_WINDOW_DESTROYED (window))
1868     return;
1869   
1870   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1871                    GDK_WINDOW_XID (window),
1872                    gdk_x11_get_xatom_by_name ("_NET_WM_NAME"),
1873                    gdk_x11_get_xatom_by_name ("UTF8_STRING"), 8,
1874                    PropModeReplace, title,
1875                    strlen (title));
1876
1877   set_text_property (window, gdk_x11_get_xatom_by_name ("WM_NAME"), title);
1878   if (!gdk_window_icon_name_set (window))
1879     {
1880       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1881                        GDK_WINDOW_XID (window),
1882                        gdk_x11_get_xatom_by_name ("_NET_WM_ICON_NAME"),
1883                        gdk_x11_get_xatom_by_name ("UTF8_STRING"), 8,
1884                        PropModeReplace, title,
1885                        strlen (title));
1886       set_text_property (window, gdk_x11_get_xatom_by_name ("WM_ICON_NAME"), title);
1887     }
1888 }
1889
1890 /**
1891  * gdk_window_set_role:
1892  * @window: a #GdkWindow
1893  * @role: a string indicating its role
1894  *
1895  * When using GTK+, typically you should use gtk_window_set_role() instead
1896  * of this low-level function.
1897  * 
1898  * The window manager and session manager use a window's role to
1899  * distinguish it from other kinds of window in the same application.
1900  * When an application is restarted after being saved in a previous
1901  * session, all windows with the same title and role are treated as
1902  * interchangeable.  So if you have two windows with the same title
1903  * that should be distinguished for session management purposes, you
1904  * should set the role on those windows. It doesn't matter what string
1905  * you use for the role, as long as you have a different role for each
1906  * non-interchangeable kind of window.
1907  * 
1908  **/
1909 void          
1910 gdk_window_set_role (GdkWindow   *window,
1911                      const gchar *role)
1912 {
1913   g_return_if_fail (window != NULL);
1914   g_return_if_fail (GDK_IS_WINDOW (window));
1915
1916   if (!GDK_WINDOW_DESTROYED (window))
1917     {
1918       if (role)
1919         XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1920                          gdk_x11_get_xatom_by_name ("WM_WINDOW_ROLE"), XA_STRING,
1921                          8, PropModeReplace, role, strlen (role));
1922       else
1923         XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1924                          gdk_x11_get_xatom_by_name ("WM_WINDOW_ROLE"));
1925     }
1926 }
1927
1928 /**
1929  * gdk_window_set_transient_for:
1930  * @window: a toplevel #GdkWindow
1931  * @parent: another toplevel #GdkWindow
1932  *
1933  * Indicates to the window manager that @window is a transient dialog
1934  * associated with the application window @parent. This allows the
1935  * window manager to do things like center @window on @parent and
1936  * keep @window above @parent.
1937  *
1938  * See gtk_window_set_transient_for() if you're using #GtkWindow or
1939  * #GtkDialog.
1940  * 
1941  **/
1942 void          
1943 gdk_window_set_transient_for (GdkWindow *window, 
1944                               GdkWindow *parent)
1945 {
1946   GdkWindowObject *private;
1947   GdkWindowObject *parent_private;
1948   
1949   g_return_if_fail (window != NULL);
1950   g_return_if_fail (GDK_IS_WINDOW (window));
1951   
1952   private = (GdkWindowObject*) window;
1953   parent_private = (GdkWindowObject*) parent;
1954   
1955   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent))
1956     XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
1957                           GDK_WINDOW_XID (window),
1958                           GDK_WINDOW_XID (parent));
1959 }
1960
1961 /**
1962  * gdk_window_set_background:
1963  * @window: a #GdkWindow
1964  * @color: an allocated #GdkColor
1965  *
1966  * Sets the background color of @window. (However, when using GTK+,
1967  * set the background of a widget with gtk_widget_modify_bg() - if
1968  * you're an application - or gtk_style_set_background() - if you're
1969  * implementing a custom widget.)
1970  *
1971  * The @color must be allocated; gdk_rgb_find_color() is the best way
1972  * to allocate a color.
1973  *
1974  * See also gdk_window_set_back_pixmap().
1975  * 
1976  **/
1977 void
1978 gdk_window_set_background (GdkWindow *window,
1979                            GdkColor  *color)
1980 {
1981   GdkWindowObject *private = (GdkWindowObject *)window;
1982   
1983   g_return_if_fail (window != NULL);
1984   g_return_if_fail (GDK_IS_WINDOW (window));
1985   
1986   if (!GDK_WINDOW_DESTROYED (window))
1987     XSetWindowBackground (GDK_WINDOW_XDISPLAY (window),
1988                           GDK_WINDOW_XID (window), color->pixel);
1989
1990   private->bg_color = *color;
1991
1992   if (private->bg_pixmap &&
1993       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1994       private->bg_pixmap != GDK_NO_BG)
1995     gdk_pixmap_unref (private->bg_pixmap);
1996   
1997   private->bg_pixmap = NULL;
1998 }
1999
2000 /**
2001  * gdk_window_set_back_pixmap:
2002  * @window: a #GdkWindow
2003  * @pixmap: a #GdkPixmap, or %NULL
2004  * @parent_relative: whether the tiling origin is at the origin of @window's parent
2005  *
2006  * Sets the background pixmap of @window. May also be used to set a background of
2007  * "None" on @window, by setting a background pixmap of %NULL.
2008  * A background pixmap will be tiled, positioning the first tile at the origin of
2009  * @window, or if @parent_relative is %TRUE, the tiling will be done based on the
2010  * origin of the parent window (useful to align tiles in a parent with tiles
2011  * in a child).
2012  *
2013  * A background pixmap of %NULL means that the window will have no
2014  * background.  A window with no background will never have its
2015  * background filled by the windowing system, instead the window will
2016  * contain whatever pixels were already in the corresponding area of
2017  * the display.
2018  *
2019  * The windowing system will normally fill a window with its background
2020  * when the window is obscured then exposed, and when you call
2021  * gdk_window_clear().
2022  * 
2023  **/
2024 void
2025 gdk_window_set_back_pixmap (GdkWindow *window,
2026                             GdkPixmap *pixmap,
2027                             gboolean   parent_relative)
2028 {
2029   GdkWindowObject *private = (GdkWindowObject *)window;
2030   Pixmap xpixmap;
2031   
2032   g_return_if_fail (window != NULL);
2033   g_return_if_fail (GDK_IS_WINDOW (window));
2034   g_return_if_fail (pixmap == NULL || !parent_relative);
2035
2036   if (private->bg_pixmap &&
2037       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
2038       private->bg_pixmap != GDK_NO_BG)
2039     gdk_pixmap_unref (private->bg_pixmap);
2040
2041   if (parent_relative)
2042     {
2043       xpixmap = ParentRelative;
2044       private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
2045     }
2046   else
2047     {
2048       if (pixmap)
2049         {
2050           gdk_pixmap_ref (pixmap);
2051           private->bg_pixmap = pixmap;
2052           xpixmap = GDK_PIXMAP_XID (pixmap);
2053         }
2054       else
2055         {
2056           xpixmap = None;
2057           private->bg_pixmap = GDK_NO_BG;
2058         }
2059     }
2060   
2061   if (!GDK_WINDOW_DESTROYED (window))
2062     XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
2063                                 GDK_WINDOW_XID (window), xpixmap);
2064 }
2065
2066 /**
2067  * gdk_window_set_cursor:
2068  * @window: a #GdkWindow
2069  * @cursor: a cursor
2070  *
2071  * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or
2072  * gdk_cursor_new_from_pixmap() to create the cursor.
2073  * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
2074  * a cursor with no pixels in it. Passing %NULL for the @cursor argument
2075  * to gdk_window_set_cursor() means that @window will use the cursor of
2076  * its parent window. Most windows should use this default.
2077  * 
2078  **/
2079 void
2080 gdk_window_set_cursor (GdkWindow *window,
2081                        GdkCursor *cursor)
2082 {
2083   GdkCursorPrivate *cursor_private;
2084   Cursor xcursor;
2085   
2086   g_return_if_fail (window != NULL);
2087   g_return_if_fail (GDK_IS_WINDOW (window));
2088   
2089   cursor_private = (GdkCursorPrivate*) cursor;
2090   
2091   if (!cursor)
2092     xcursor = None;
2093   else
2094     xcursor = cursor_private->xcursor;
2095   
2096   if (!GDK_WINDOW_DESTROYED (window))
2097     XDefineCursor (GDK_WINDOW_XDISPLAY (window),
2098                    GDK_WINDOW_XID (window),
2099                    xcursor);
2100 }
2101
2102 /**
2103  * gdk_window_get_geometry:
2104  * @window: a #GdkWindow
2105  * @x: return location for X coordinate of window (relative to its parent)
2106  * @y: return location for Y coordinate of window (relative to its parent)
2107  * @width: return location for width of window
2108  * @height: return location for height of window
2109  * @depth: return location for bit depth of window
2110  *
2111  * Any of the return location arguments to this function may be %NULL,
2112  * if you aren't interested in getting the value of that field.
2113  *
2114  * The X and Y coordinates returned are relative to the parent window
2115  * of @window, which for toplevels usually means relative to the
2116  * window decorations (titlebar, etc.) rather than relative to the
2117  * root window (screen-size background window).
2118  *
2119  * On the X11 platform, the geometry is obtained from the X server,
2120  * so reflects the latest position of @window; this may be out-of-sync
2121  * with the position of @window delivered in the most-recently-processed
2122  * #GdkEventConfigure. gdk_window_get_position() in contrast gets the
2123  * position from the most recent configure event.
2124  * 
2125  **/
2126 void
2127 gdk_window_get_geometry (GdkWindow *window,
2128                          gint      *x,
2129                          gint      *y,
2130                          gint      *width,
2131                          gint      *height,
2132                          gint      *depth)
2133 {
2134   Window root;
2135   gint tx;
2136   gint ty;
2137   guint twidth;
2138   guint theight;
2139   guint tborder_width;
2140   guint tdepth;
2141   
2142   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
2143   
2144   if (!window)
2145     window = _gdk_parent_root;
2146   
2147   if (!GDK_WINDOW_DESTROYED (window))
2148     {
2149       XGetGeometry (GDK_WINDOW_XDISPLAY (window),
2150                     GDK_WINDOW_XID (window),
2151                     &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
2152       
2153       if (x)
2154         *x = tx;
2155       if (y)
2156         *y = ty;
2157       if (width)
2158         *width = twidth;
2159       if (height)
2160         *height = theight;
2161       if (depth)
2162         *depth = tdepth;
2163     }
2164 }
2165
2166 /**
2167  * gdk_window_get_origin:
2168  * @window: a #GdkWindow
2169  * @x: return location for X coordinate
2170  * @y: return location for Y coordinate
2171  * 
2172  * Obtains the position of a window in root window coordinates.
2173  * (Compare with gdk_window_get_position() and
2174  * gdk_window_get_geometry() which return the position of a window
2175  * relative to its parent window.)
2176  * 
2177  * Return value: not meaningful, ignore
2178  **/
2179 gint
2180 gdk_window_get_origin (GdkWindow *window,
2181                        gint      *x,
2182                        gint      *y)
2183 {
2184   gint return_val;
2185   Window child;
2186   gint tx = 0;
2187   gint ty = 0;
2188   
2189   g_return_val_if_fail (window != NULL, 0);
2190   
2191   if (!GDK_WINDOW_DESTROYED (window))
2192     {
2193       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
2194                                           GDK_WINDOW_XID (window),
2195                                           _gdk_root_window,
2196                                           0, 0, &tx, &ty,
2197                                           &child);
2198       
2199     }
2200   else
2201     return_val = 0;
2202   
2203   if (x)
2204     *x = tx;
2205   if (y)
2206     *y = ty;
2207   
2208   return return_val;
2209 }
2210
2211 /**
2212  * gdk_window_get_deskrelative_origin:
2213  * @window: a #GdkWindow
2214  * @x: return location for X coordinate
2215  * @y: return location for Y coordinate
2216  * 
2217  * This gets the origin of a #GdkWindow relative to
2218  * an Enlightenment-window-manager desktop. As long as you don't
2219  * assume that the user's desktop/workspace covers the entire
2220  * root window (i.e. you don't assume that the desktop begins
2221  * at root window coordinate 0,0) this function is not necessary.
2222  * It's deprecated for that reason.
2223  * 
2224  * Return value: not meaningful
2225  **/
2226 gboolean
2227 gdk_window_get_deskrelative_origin (GdkWindow *window,
2228                                     gint      *x,
2229                                     gint      *y)
2230 {
2231   gboolean return_val = FALSE;
2232   gint num_children, format_return;
2233   Window win, *child, parent, root;
2234   gint tx = 0;
2235   gint ty = 0;
2236   Atom type_return;
2237   static Atom atom = 0;
2238   gulong number_return, bytes_after_return;
2239   guchar *data_return;
2240   
2241   g_return_val_if_fail (window != NULL, 0);
2242   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2243   
2244   if (!GDK_WINDOW_DESTROYED (window))
2245     {
2246       if (!atom)
2247         atom = gdk_x11_get_xatom_by_name ("ENLIGHTENMENT_DESKTOP");
2248       win = GDK_WINDOW_XID (window);
2249       
2250       while (XQueryTree (GDK_WINDOW_XDISPLAY (window), win, &root, &parent,
2251                          &child, (unsigned int *)&num_children))
2252         {
2253           if ((child) && (num_children > 0))
2254             XFree (child);
2255           
2256           if (!parent)
2257             break;
2258           else
2259             win = parent;
2260           
2261           if (win == root)
2262             break;
2263           
2264           data_return = NULL;
2265           XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), win, atom, 0, 0,
2266                               False, XA_CARDINAL, &type_return, &format_return,
2267                               &number_return, &bytes_after_return, &data_return);
2268           if (type_return == XA_CARDINAL)
2269             {
2270               XFree (data_return);
2271               break;
2272             }
2273         }
2274       
2275       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
2276                                           GDK_WINDOW_XID (window),
2277                                           win,
2278                                           0, 0, &tx, &ty,
2279                                           &root);
2280       if (x)
2281         *x = tx;
2282       if (y)
2283         *y = ty;
2284     }
2285   
2286   
2287   return return_val;
2288 }
2289
2290 /**
2291  * gdk_window_get_root_origin:
2292  * @window: a #GdkWindow
2293  * @x: return location for X position of window frame
2294  * @y: return location for Y position of window frame
2295  *
2296  * Obtains the top-left corner of the window manager frame in root
2297  * window coordinates.
2298  * 
2299  **/
2300 void
2301 gdk_window_get_root_origin (GdkWindow *window,
2302                             gint      *x,
2303                             gint      *y)
2304 {
2305   GdkRectangle rect;
2306
2307   g_return_if_fail (GDK_IS_WINDOW (window));
2308
2309   gdk_window_get_frame_extents (window, &rect);
2310
2311   if (x)
2312     *x = rect.x;
2313
2314   if (y)
2315     *y = rect.y;
2316 }
2317
2318 /**
2319  * gdk_window_get_frame_extents:
2320  * @window: a #GdkWindow
2321  * @rect: rectangle to fill with bounding box of the window frame
2322  *
2323  * Obtains the bounding box of the window, including window manager
2324  * titlebar/borders if any. The frame position is given in root window
2325  * coordinates. To get the position of the window itself (rather than
2326  * the frame) in root window coordinates, use gdk_window_get_origin().
2327  * 
2328  **/
2329 void
2330 gdk_window_get_frame_extents (GdkWindow    *window,
2331                               GdkRectangle *rect)
2332 {
2333   GdkWindowObject *private;
2334   Window xwindow;
2335   Window xparent;
2336   Window root;
2337   Window *children;
2338   unsigned int nchildren;
2339   
2340   g_return_if_fail (GDK_IS_WINDOW (window));
2341   g_return_if_fail (rect != NULL);
2342   
2343   private = (GdkWindowObject*) window;
2344   
2345   rect->x = 0;
2346   rect->y = 0;
2347   rect->width = 1;
2348   rect->height = 1;
2349   
2350   if (GDK_WINDOW_DESTROYED (window))
2351     return;
2352   
2353   while (private->parent && ((GdkWindowObject*) private->parent)->parent)
2354     private = (GdkWindowObject*) private->parent;
2355   if (GDK_WINDOW_DESTROYED (window))
2356     return;
2357   
2358   xparent = GDK_WINDOW_XID (window);
2359   do
2360     {
2361       xwindow = xparent;
2362       if (!XQueryTree (GDK_WINDOW_XDISPLAY (window), xwindow,
2363                        &root, &xparent,
2364                        &children, &nchildren))
2365         return;
2366       
2367       if (children)
2368         XFree (children);
2369     }
2370   while (xparent != root);
2371   
2372   if (xparent == root)
2373     {
2374       unsigned int ww, wh, wb, wd;
2375       int wx, wy;
2376       
2377       if (XGetGeometry (GDK_WINDOW_XDISPLAY (window), xwindow, &root, &wx, &wy, &ww, &wh, &wb, &wd))
2378         {
2379           rect->x = wx;
2380           rect->y = wy;
2381           rect->width = ww;
2382           rect->height = wh;
2383         }
2384     }
2385 }
2386
2387 GdkWindow*
2388 _gdk_windowing_window_get_pointer (GdkWindow       *window,
2389                                    gint            *x,
2390                                    gint            *y,
2391                                    GdkModifierType *mask)
2392 {
2393   GdkWindow *return_val;
2394   Window root;
2395   Window child;
2396   int rootx, rooty;
2397   int winx = 0;
2398   int winy = 0;
2399   unsigned int xmask = 0;
2400   gint xoffset, yoffset;
2401
2402   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
2403   
2404   if (!window)
2405     window = _gdk_parent_root;
2406   
2407   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2408
2409   return_val = NULL;
2410   if (!GDK_WINDOW_DESTROYED (window) &&
2411       XQueryPointer (GDK_WINDOW_XDISPLAY (window),
2412                      GDK_WINDOW_XID (window),
2413                      &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
2414     {
2415       if (child)
2416         return_val = gdk_window_lookup (child);
2417     }
2418   
2419   if (x)
2420     *x = winx + xoffset;
2421   if (y)
2422     *y = winy + yoffset;
2423   if (mask)
2424     *mask = xmask;
2425   
2426   return return_val;
2427 }
2428
2429 GdkWindow*
2430 _gdk_windowing_window_at_pointer (GdkScreen *screen,
2431                                   gint      *win_x,
2432                                   gint      *win_y)
2433 {
2434   GdkWindow *window;
2435   Window root;
2436   Window xwindow;
2437   Window xwindow_last = 0;
2438   Display *xdisplay;
2439   int rootx = -1, rooty = -1;
2440   int winx, winy;
2441   unsigned int xmask;
2442   
2443   xwindow = GDK_ROOT_WINDOW ();
2444   xdisplay = GDK_DISPLAY ();
2445
2446   gdk_x11_grab_server ();
2447   while (xwindow)
2448     {
2449       xwindow_last = xwindow;
2450       XQueryPointer (xdisplay, xwindow,
2451                      &root, &xwindow,
2452                      &rootx, &rooty,
2453                      &winx, &winy,
2454                      &xmask);
2455     }
2456   gdk_x11_ungrab_server ();
2457   
2458   window = gdk_window_lookup (xwindow_last);
2459   
2460   if (win_x)
2461     *win_x = window ? winx : -1;
2462   if (win_y)
2463     *win_y = window ? winy : -1;
2464   
2465   return window;
2466 }
2467
2468 /**
2469  * gdk_window_get_events:
2470  * @window: a #GdkWindow
2471  * 
2472  * Gets the event mask for @window. See gdk_window_set_events().
2473  * 
2474  * Return value: event mask for @window
2475  **/
2476 GdkEventMask  
2477 gdk_window_get_events (GdkWindow *window)
2478 {
2479   XWindowAttributes attrs;
2480   GdkEventMask event_mask;
2481   
2482   g_return_val_if_fail (window != NULL, 0);
2483   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2484
2485   if (GDK_WINDOW_DESTROYED (window))
2486     return 0;
2487   else
2488     {
2489       XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2490                             GDK_WINDOW_XID (window), 
2491                             &attrs);
2492       
2493       event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
2494       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
2495   
2496       return event_mask;
2497     }
2498 }
2499
2500 /**
2501  * gdk_window_set_events:
2502  * @window: a #GdkWindow
2503  * @event_mask: event mask for @window
2504  *
2505  * The event mask for a window determines which events will be reported
2506  * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK
2507  * means the window should report button press events. The event mask
2508  * is the bitwise OR of values from the #GdkEventMask enumeration.
2509  * 
2510  **/
2511 void          
2512 gdk_window_set_events (GdkWindow       *window,
2513                        GdkEventMask     event_mask)
2514 {
2515   long xevent_mask;
2516   int i;
2517   
2518   g_return_if_fail (window != NULL);
2519   g_return_if_fail (GDK_IS_WINDOW (window));
2520   
2521   if (!GDK_WINDOW_DESTROYED (window))
2522     {
2523       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
2524       xevent_mask = StructureNotifyMask;
2525       for (i = 0; i < _gdk_nenvent_masks; i++)
2526         {
2527           if (event_mask & (1 << (i + 1)))
2528             xevent_mask |= _gdk_event_mask_table[i];
2529         }
2530       
2531       XSelectInput (GDK_WINDOW_XDISPLAY (window),
2532                     GDK_WINDOW_XID (window),
2533                     xevent_mask);
2534     }
2535 }
2536
2537 void
2538 gdk_window_add_colormap_windows (GdkWindow *window)
2539 {
2540   GdkWindow *toplevel;
2541   Window *old_windows;
2542   Window *new_windows;
2543   int i, count;
2544   
2545   g_return_if_fail (window != NULL);
2546   g_return_if_fail (GDK_IS_WINDOW (window));
2547   
2548   toplevel = gdk_window_get_toplevel (window);
2549   if (GDK_WINDOW_DESTROYED (toplevel))
2550     return;
2551   
2552   old_windows = NULL;
2553   if (!XGetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2554                               GDK_WINDOW_XID (toplevel),
2555                               &old_windows, &count))
2556     {
2557       count = 0;
2558     }
2559   
2560   for (i = 0; i < count; i++)
2561     if (old_windows[i] == GDK_WINDOW_XID (window))
2562       {
2563         XFree (old_windows);
2564         return;
2565       }
2566   
2567   new_windows = g_new (Window, count + 1);
2568   
2569   for (i = 0; i < count; i++)
2570     new_windows[i] = old_windows[i];
2571   new_windows[count] = GDK_WINDOW_XID (window);
2572   
2573   XSetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2574                          GDK_WINDOW_XID (toplevel),
2575                          new_windows, count + 1);
2576   
2577   g_free (new_windows);
2578   if (old_windows)
2579     XFree (old_windows);
2580 }
2581
2582 static gboolean
2583 gdk_window_have_shape_ext (void)
2584 {
2585   enum { UNKNOWN, NO, YES };
2586   static gint have_shape = UNKNOWN;
2587   
2588   if (have_shape == UNKNOWN)
2589     {
2590       int ignore;
2591       if (XQueryExtension (gdk_display, "SHAPE", &ignore, &ignore, &ignore))
2592         have_shape = YES;
2593       else
2594         have_shape = NO;
2595     }
2596   
2597   return (have_shape == YES);
2598 }
2599
2600 #define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.")
2601
2602 /*
2603  * This needs the X11 shape extension.
2604  * If not available, shaped windows will look
2605  * ugly, but programs still work.    Stefan Wille
2606  */
2607 /**
2608  * gdk_window_shape_combine_mask:
2609  * @window: a #GdkWindow
2610  * @mask: shape mask
2611  * @x: X position of shape mask with respect to @window
2612  * @y: Y position of shape mask with respect to @window
2613  *
2614  * Applies a shape mask to @window. Pixels in @window corresponding to
2615  * set bits in the @mask will be visible; pixels in @window
2616  * corresponding to unset bits in the @mask will be transparent. This
2617  * gives a non-rectangular window.
2618  *
2619  * If @mask is %NULL, the shape mask will be unset, and the @x/@y
2620  * parameters are not used.
2621  *
2622  * On the X11 platform, this uses an X server extension which is
2623  * widely available on most common platforms, but not available on
2624  * very old X servers, and occasionally the implementation will be
2625  * buggy. On servers without the shape extension, this function
2626  * will do nothing.
2627  * 
2628  **/
2629 void
2630 gdk_window_shape_combine_mask (GdkWindow *window,
2631                                GdkBitmap *mask,
2632                                gint x, gint y)
2633 {
2634   Pixmap pixmap;
2635   gint xoffset, yoffset;
2636   
2637   g_return_if_fail (window != NULL);
2638   g_return_if_fail (GDK_IS_WINDOW (window));
2639   
2640 #ifdef HAVE_SHAPE_EXT
2641   if (GDK_WINDOW_DESTROYED (window))
2642     return;
2643
2644   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2645
2646   if (xoffset != 0 || yoffset != 0)
2647     {
2648       WARN_SHAPE_TOO_BIG ();
2649       return;
2650     }
2651   
2652   if (gdk_window_have_shape_ext ())
2653     {
2654       if (mask)
2655         {
2656           pixmap = GDK_PIXMAP_XID (mask);
2657         }
2658       else
2659         {
2660           x = 0;
2661           y = 0;
2662           pixmap = None;
2663         }
2664       
2665       XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
2666                          GDK_WINDOW_XID (window),
2667                          ShapeBounding,
2668                          x, y,
2669                          pixmap,
2670                          ShapeSet);
2671     }
2672 #endif /* HAVE_SHAPE_EXT */
2673 }
2674
2675 /**
2676  * gdk_window_shape_combine_region:
2677  * @window: a #GdkWindow
2678  * @shape_region: region of window to be non-transparent
2679  * @offset_x: X position of @shape_region in @window coordinates
2680  * @offset_y: Y position of @shape_region in @window coordinates
2681  *
2682  * Makes pixels in @window outside @shape_region be transparent,
2683  * so that the window may be nonrectangular. See also
2684  * gdk_window_shape_combine_mask() to use a bitmap as the mask.
2685  *
2686  * If @shape_region is %NULL, the shape will be unset, so the whole
2687  * window will be opaque again. @offset_x and @offset_y are ignored
2688  * if @shape_region is %NULL.
2689  * 
2690  * On the X11 platform, this uses an X server extension which is
2691  * widely available on most common platforms, but not available on
2692  * very old X servers, and occasionally the implementation will be
2693  * buggy. On servers without the shape extension, this function
2694  * will do nothing.
2695  * 
2696  **/
2697 void
2698 gdk_window_shape_combine_region (GdkWindow *window,
2699                                  GdkRegion *shape_region,
2700                                  gint       offset_x,
2701                                  gint       offset_y)
2702 {
2703   gint xoffset, yoffset;
2704   
2705   g_return_if_fail (GDK_IS_WINDOW (window));
2706   
2707 #ifdef HAVE_SHAPE_EXT
2708   if (GDK_WINDOW_DESTROYED (window))
2709     return;
2710
2711   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2712
2713   if (xoffset != 0 || yoffset != 0)
2714     {
2715       WARN_SHAPE_TOO_BIG ();
2716       return;
2717     }
2718   
2719   if (shape_region == NULL)
2720     {
2721       /* Use NULL mask to unset the shape */
2722       gdk_window_shape_combine_mask (window, NULL, 0, 0);
2723       return;
2724     }
2725   
2726   if (gdk_window_have_shape_ext ())
2727     {
2728       gint n_rects = 0;
2729       XRectangle *xrects = NULL;
2730
2731       _gdk_region_get_xrectangles (shape_region,
2732                                    0, 0,
2733                                    &xrects, &n_rects);
2734       
2735       XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
2736                                GDK_WINDOW_XID (window),
2737                                ShapeBounding,
2738                                offset_x, offset_y,
2739                                xrects, n_rects,
2740                                ShapeSet,
2741                                YXBanded);
2742
2743       g_free (xrects);
2744     }
2745 #endif /* HAVE_SHAPE_EXT */
2746 }
2747
2748
2749 /**
2750  * gdk_window_set_override_redirect:
2751  * @window: a #GdkWindow
2752  * @override_redirect: %TRUE if window should be override redirect
2753  *
2754  * An override redirect window is not under the control of the window manager.
2755  * This means it won't have a titlebar, won't be minimizable, etc. - it will
2756  * be entirely under the control of the application. The window manager
2757  * can't see the override redirect window at all.
2758  *
2759  * Override redirect should only be used for short-lived temporary
2760  * windows, such as popup menus. #GtkMenu uses an override redirect
2761  * window in its implementation, for example.
2762  * 
2763  **/
2764 void
2765 gdk_window_set_override_redirect (GdkWindow *window,
2766                                   gboolean override_redirect)
2767 {
2768   XSetWindowAttributes attr;
2769   
2770   g_return_if_fail (window != NULL);
2771   g_return_if_fail (GDK_IS_WINDOW (window));
2772
2773   if (GDK_WINDOW_DESTROYED (window))
2774     {
2775       attr.override_redirect = (override_redirect == FALSE)?False:True;
2776       XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2777                                GDK_WINDOW_XID (window),
2778                                CWOverrideRedirect,
2779                                &attr);
2780     }
2781 }
2782
2783
2784 /**
2785  * gdk_window_set_icon_list:
2786  * @window: The #GdkWindow toplevel window to set the icon of.
2787  * @pixbufs: A list of pixbufs, of different sizes.
2788  *
2789  * Sets a list of icons for the window. One of these will be used
2790  * to represent the window when it has been iconified. The icon is
2791  * usually shown in an icon box or some sort of task bar. Which icon
2792  * size is shown depends on the window manager. The window manager
2793  * can scale the icon  but setting several size icons can give better
2794  * image quality since the window manager may only need to scale the
2795  * icon by a small amount or not at all.
2796  *
2797  **/
2798 void
2799 gdk_window_set_icon_list (GdkWindow *window,
2800                           GList     *pixbufs)
2801 {
2802   gulong *data;
2803   guchar *pixels;
2804   gulong *p;
2805   gint size;
2806   GList *l;
2807   GdkPixbuf *pixbuf;
2808   gint width, height, stride;
2809   gint x, y;
2810   gint n_channels;
2811   
2812   g_return_if_fail (GDK_IS_WINDOW (window));
2813
2814   if (GDK_WINDOW_DESTROYED (window))
2815     return;
2816   
2817   l = pixbufs;
2818   size = 0;
2819   
2820   while (l)
2821     {
2822       pixbuf = l->data;
2823       g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
2824
2825       width = gdk_pixbuf_get_width (pixbuf);
2826       height = gdk_pixbuf_get_height (pixbuf);
2827       
2828       size += 2 + width * height;
2829
2830       l = g_list_next (l);
2831     }
2832
2833   data = g_malloc (size * sizeof (gulong));
2834
2835   l = pixbufs;
2836   p = data;
2837   while (l)
2838     {
2839       pixbuf = l->data;
2840       
2841       width = gdk_pixbuf_get_width (pixbuf);
2842       height = gdk_pixbuf_get_height (pixbuf);
2843       stride = gdk_pixbuf_get_rowstride (pixbuf);
2844       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
2845       
2846       *p++ = width;
2847       *p++ = height;
2848
2849       pixels = gdk_pixbuf_get_pixels (pixbuf);
2850
2851       for (y = 0; y < height; y++)
2852         {
2853           for (x = 0; x < width; x++)
2854             {
2855               guchar r, g, b, a;
2856               
2857               r = pixels[y*stride + x*n_channels + 0];
2858               g = pixels[y*stride + x*n_channels + 1];
2859               b = pixels[y*stride + x*n_channels + 2];
2860               if (n_channels >= 4)
2861                 a = pixels[y*stride + x*n_channels + 3];
2862               else
2863                 a = 255;
2864               
2865               *p++ = a << 24 | r << 16 | g << 8 | b ;
2866             }
2867         }
2868
2869       l = g_list_next (l);
2870     }
2871
2872   if (size > 0)
2873     {
2874       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
2875                        GDK_WINDOW_XID (window),
2876                        gdk_x11_get_xatom_by_name ("_NET_WM_ICON"),
2877                        XA_CARDINAL, 32,
2878                        PropModeReplace,
2879                        (guchar*) data, size);
2880     }
2881   else
2882     {
2883       XDeleteProperty (GDK_WINDOW_XDISPLAY (window),
2884                        GDK_WINDOW_XID (window),
2885                        gdk_x11_get_xatom_by_name ("_NET_WM_ICON"));
2886     }
2887   
2888   g_free (data);
2889 }
2890
2891 /**
2892  * gdk_window_set_icon:
2893  * @window: a #GdkWindow
2894  * @icon_window: a #GdkWindow to use for the icon, or %NULL to unset
2895  * @pixmap: a #GdkPixmap to use as the icon, or %NULL to unset
2896  * @mask: a 1-bit pixmap (#GdkBitmap) to use as mask for @pixmap, or %NULL to have none
2897  *
2898  * Sets the icon of @window as a pixmap or window. If using GTK+, investigate
2899  * gtk_window_set_default_icon_list() first, and then gtk_window_set_icon_list()
2900  * and gtk_window_set_icon(). If those don't meet your needs, look at
2901  * gdk_window_set_icon_list(). Only if all those are too high-level do you
2902  * want to fall back to gdk_window_set_icon().
2903  * 
2904  **/
2905 void          
2906 gdk_window_set_icon (GdkWindow *window, 
2907                      GdkWindow *icon_window,
2908                      GdkPixmap *pixmap,
2909                      GdkBitmap *mask)
2910 {
2911   XWMHints *wm_hints;
2912   
2913   g_return_if_fail (window != NULL);
2914   g_return_if_fail (GDK_IS_WINDOW (window));
2915
2916   if (GDK_WINDOW_DESTROYED (window))
2917     return;
2918
2919   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
2920                           GDK_WINDOW_XID (window));
2921   if (!wm_hints)
2922     wm_hints = XAllocWMHints ();
2923
2924   if (icon_window != NULL)
2925     {
2926       wm_hints->flags |= IconWindowHint;
2927       wm_hints->icon_window = GDK_WINDOW_XID (icon_window);
2928     }
2929   
2930   if (pixmap != NULL)
2931     {
2932       wm_hints->flags |= IconPixmapHint;
2933       wm_hints->icon_pixmap = GDK_PIXMAP_XID (pixmap);
2934     }
2935   
2936   if (mask != NULL)
2937     {
2938       wm_hints->flags |= IconMaskHint;
2939       wm_hints->icon_mask = GDK_PIXMAP_XID (mask);
2940     }
2941
2942   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
2943                GDK_WINDOW_XID (window), wm_hints);
2944   XFree (wm_hints);
2945 }
2946
2947 static gboolean
2948 gdk_window_icon_name_set (GdkWindow *window)
2949 {
2950   return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
2951                                                g_quark_from_static_string ("gdk-icon-name-set")));
2952 }
2953
2954 /**
2955  * gdk_window_set_icon_name:
2956  * @window: a #GdkWindow
2957  * @name: name of window while iconified (minimized)
2958  *
2959  * Windows may have a name used while minimized, distinct from the
2960  * name they display in their titlebar. Most of the time this is a bad
2961  * idea from a user interface standpoint. But you can set such a name
2962  * with this function, if you like.
2963  * 
2964  **/
2965 void          
2966 gdk_window_set_icon_name (GdkWindow   *window, 
2967                           const gchar *name)
2968 {
2969   g_return_if_fail (window != NULL);
2970   g_return_if_fail (GDK_IS_WINDOW (window));
2971
2972   if (GDK_WINDOW_DESTROYED (window))
2973     return;
2974
2975   g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
2976                       GUINT_TO_POINTER (TRUE));
2977
2978   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
2979                    GDK_WINDOW_XID (window),
2980                    gdk_x11_get_xatom_by_name ("_NET_WM_ICON_NAME"),
2981                    gdk_x11_get_xatom_by_name ("UTF8_STRING"), 8,
2982                    PropModeReplace, name,
2983                    strlen (name));
2984   set_text_property (window, gdk_x11_get_xatom_by_name ("WM_ICON_NAME"), name);
2985 }
2986
2987 /**
2988  * gdk_window_iconify:
2989  * @window: a #GdkWindow
2990  * 
2991  * Asks to iconify (minimize) @window. The window manager may choose
2992  * to ignore the request, but normally will honor it. Using
2993  * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
2994  * 
2995  **/
2996 void
2997 gdk_window_iconify (GdkWindow *window)
2998 {
2999   Display *display;
3000   GdkWindowObject *private;
3001   
3002   g_return_if_fail (window != NULL);
3003   g_return_if_fail (GDK_IS_WINDOW (window));
3004
3005   if (GDK_WINDOW_DESTROYED (window))
3006     return;
3007
3008   display = GDK_WINDOW_XDISPLAY (window);
3009
3010   private = (GdkWindowObject*) window;
3011
3012   if (GDK_WINDOW_IS_MAPPED (window))
3013     {  
3014       XIconifyWindow (display, GDK_WINDOW_XWINDOW (window), DefaultScreen (display));
3015
3016     }
3017   else
3018     {
3019       /* Flip our client side flag, the real work happens on map. */
3020       gdk_synthesize_window_state (window,
3021                                    0,
3022                                    GDK_WINDOW_STATE_ICONIFIED);
3023     }
3024 }
3025
3026 /**
3027  * gdk_window_deiconify:
3028  * @window: a #GdkWindow
3029  *
3030  * Attempt to deiconify (unminimize) @window. On X11 the window manager may
3031  * choose to ignore the request to deiconify. When using GTK+,
3032  * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet,
3033  * you probably want to use gtk_window_present(), which raises the window, focuses it,
3034  * unminimizes it, and puts it on the current desktop.
3035  * 
3036  **/
3037 void
3038 gdk_window_deiconify (GdkWindow *window)
3039 {
3040   Display *display;
3041   GdkWindowObject *private;
3042   
3043   g_return_if_fail (window != NULL);
3044   g_return_if_fail (GDK_IS_WINDOW (window));
3045
3046   if (GDK_WINDOW_DESTROYED (window))
3047     return;
3048
3049   display = GDK_WINDOW_XDISPLAY (window);
3050
3051   private = (GdkWindowObject*) window;
3052
3053   if (GDK_WINDOW_IS_MAPPED (window))
3054     {  
3055       gdk_window_show (window);
3056     }
3057   else
3058     {
3059       /* Flip our client side flag, the real work happens on map. */
3060       gdk_synthesize_window_state (window,
3061                                    GDK_WINDOW_STATE_ICONIFIED,
3062                                    0);
3063     }
3064 }
3065
3066 /**
3067  * gdk_window_stick:
3068  * @window: a toplevel #GdkWindow
3069  *
3070  * "Pins" a window such that it's on all workspaces and does not scroll
3071  * with viewports, for window managers that have scrollable viewports.
3072  * (When using #GtkWindow, gtk_window_stick() may be more useful.)
3073  *
3074  * On the X11 platform, this function depends on window manager
3075  * support, so may have no effect with many window managers. However,
3076  * GDK will do the best it can to convince the window manager to stick
3077  * the window. For window managers that don't support this operation,
3078  * there's nothing you can do to force it to happen.
3079  * 
3080  **/
3081 void
3082 gdk_window_stick (GdkWindow *window)
3083 {
3084   g_return_if_fail (GDK_IS_WINDOW (window));
3085
3086   if (GDK_WINDOW_DESTROYED (window))
3087     return;
3088
3089   if (GDK_WINDOW_IS_MAPPED (window))
3090     {
3091       /* "stick" means stick to all desktops _and_ do not scroll with the
3092        * viewport. i.e. glue to the monitor glass in all cases.
3093        */
3094       
3095       XEvent xev;
3096
3097       /* Request stick during viewport scroll */
3098       gdk_wmspec_change_state (TRUE, window,
3099                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
3100                                0);
3101
3102       /* Request desktop 0xFFFFFFFF */
3103       xev.xclient.type = ClientMessage;
3104       xev.xclient.serial = 0;
3105       xev.xclient.send_event = True;
3106       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
3107       xev.xclient.display = gdk_display;
3108       xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_DESKTOP");
3109       xev.xclient.format = 32;
3110
3111       xev.xclient.data.l[0] = 0xFFFFFFFF;
3112       
3113       XSendEvent (gdk_display, _gdk_root_window, False,
3114                   SubstructureRedirectMask | SubstructureNotifyMask,
3115                   &xev);
3116     }
3117   else
3118     {
3119       /* Flip our client side flag, the real work happens on map. */
3120       gdk_synthesize_window_state (window,
3121                                    0,
3122                                    GDK_WINDOW_STATE_STICKY);
3123     }
3124 }
3125
3126 /**
3127  * gdk_window_unstick:
3128  * @window: a toplevel #GdkWindow
3129  *
3130  * Reverse operation for gdk_window_stick(); see gdk_window_stick(),
3131  * and gtk_window_unstick().
3132  * 
3133  **/
3134 void
3135 gdk_window_unstick (GdkWindow *window)
3136 {
3137   g_return_if_fail (GDK_IS_WINDOW (window));
3138
3139   if (GDK_WINDOW_DESTROYED (window))
3140     return;
3141
3142   if (GDK_WINDOW_IS_MAPPED (window))
3143     {
3144       XEvent xev;
3145       Atom type;
3146       gint format;
3147       gulong nitems;
3148       gulong bytes_after;
3149       gulong *current_desktop;
3150       
3151       /* Request unstick from viewport */
3152       gdk_wmspec_change_state (FALSE, window,
3153                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
3154                                0);
3155
3156       /* Get current desktop, then set it; this is a race, but not
3157        * one that matters much in practice.
3158        */
3159       XGetWindowProperty (gdk_display, _gdk_root_window,
3160                           gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP"),
3161                           0, G_MAXLONG,
3162                           False, XA_CARDINAL, &type, &format, &nitems,
3163                           &bytes_after, (guchar **)&current_desktop);
3164
3165       if (type == XA_CARDINAL)
3166         {
3167           xev.xclient.type = ClientMessage;
3168           xev.xclient.serial = 0;
3169           xev.xclient.send_event = True;
3170           xev.xclient.window = GDK_WINDOW_XWINDOW (window);
3171           xev.xclient.display = gdk_display;
3172           xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_DESKTOP");
3173           xev.xclient.format = 32;
3174
3175           xev.xclient.data.l[0] = *current_desktop;
3176       
3177           XSendEvent (gdk_display, _gdk_root_window, False,
3178                       SubstructureRedirectMask | SubstructureNotifyMask,
3179                       &xev);
3180
3181           XFree (current_desktop);
3182         }
3183     }
3184   else
3185     {
3186       /* Flip our client side flag, the real work happens on map. */
3187       gdk_synthesize_window_state (window,
3188                                    GDK_WINDOW_STATE_STICKY,
3189                                    0);
3190
3191     }
3192 }
3193
3194 /**
3195  * gdk_window_maximize:
3196  * @window: a #GdkWindow
3197  *
3198  * Asks the window manager to maximize @window, if the window manager supports
3199  * this operation. Not all window managers support this, and some deliberately
3200  * ignore it or don't have a concept of "maximized"; so you can't rely on the
3201  * maximization actually happening. But it will happen with most standard
3202  * window managers, and GDK makes a best effort to get it to happen.
3203  *
3204  * If the window was already maximized, then this function does nothing.
3205  * 
3206  **/
3207 void
3208 gdk_window_maximize (GdkWindow *window)
3209 {
3210   g_return_if_fail (GDK_IS_WINDOW (window));
3211
3212   if (GDK_WINDOW_DESTROYED (window))
3213     return;
3214
3215   if (GDK_WINDOW_IS_MAPPED (window))
3216     gdk_wmspec_change_state (TRUE, window,
3217                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
3218                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
3219   else
3220     gdk_synthesize_window_state (window,
3221                                  0,
3222                                  GDK_WINDOW_STATE_MAXIMIZED);
3223 }
3224
3225 /**
3226  * gdk_window_unmaximize:
3227  * @window: a #GdkWindow
3228  *
3229  * Asks the window manager to unmaximize @window, if the window manager supports
3230  * this operation. Not all window managers support this, and some deliberately
3231  * ignore it or don't have a concept of "maximized"; so you can't rely on the
3232  * unmaximization actually happening. But it will happen with most standard
3233  * window managers, and GDK makes a best effort to get it to happen.
3234  *
3235  * If the window wasn't maximized, then this function does nothing.
3236  * 
3237  **/
3238 void
3239 gdk_window_unmaximize (GdkWindow *window)
3240 {
3241   g_return_if_fail (GDK_IS_WINDOW (window));
3242
3243   if (GDK_WINDOW_DESTROYED (window))
3244     return;
3245
3246   if (GDK_WINDOW_IS_MAPPED (window))
3247     gdk_wmspec_change_state (FALSE, window,
3248                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
3249                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
3250   else
3251     gdk_synthesize_window_state (window,
3252                                  GDK_WINDOW_STATE_MAXIMIZED,
3253                                  0);
3254 }
3255
3256 /**
3257  * gdk_window_set_group:
3258  * @window: a #GdkWindow
3259  * @leader: group leader window
3260  *
3261  * Sets the group leader window for @window. By default,
3262  * GDK sets the group leader for all toplevel windows
3263  * to a global window implicitly created by GDK. With this function
3264  * you can override this default.
3265  *
3266  * The group leader window allows the window manager to distinguish
3267  * all windows that belong to a single application. It may for example
3268  * allow users to minimize/unminimize all windows belonging to an
3269  * application at once. You should only set a non-default group window
3270  * if your application pretends to be multiple applications.
3271  * The group leader window may not be changed after a window has been
3272  * mapped (with gdk_window_show() for example).
3273  * 
3274  **/
3275 void          
3276 gdk_window_set_group (GdkWindow *window, 
3277                       GdkWindow *leader)
3278 {
3279   XWMHints *wm_hints;
3280   
3281   g_return_if_fail (window != NULL);
3282   g_return_if_fail (GDK_IS_WINDOW (window));
3283   g_return_if_fail (leader != NULL);
3284   g_return_if_fail (GDK_IS_WINDOW (leader));
3285
3286   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
3287     return;
3288   
3289   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
3290                           GDK_WINDOW_XID (window));
3291   if (!wm_hints)
3292     wm_hints = XAllocWMHints ();
3293
3294   wm_hints->flags |= WindowGroupHint;
3295   wm_hints->window_group = GDK_WINDOW_XID (leader);
3296
3297   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
3298                GDK_WINDOW_XID (window), wm_hints);
3299   XFree (wm_hints);
3300 }
3301
3302 static MotifWmHints *
3303 gdk_window_get_mwm_hints (GdkWindow *window)
3304 {
3305   static Atom hints_atom = None;
3306   MotifWmHints *hints;
3307   Atom type;
3308   gint format;
3309   gulong nitems;
3310   gulong bytes_after;
3311   
3312   if (GDK_WINDOW_DESTROYED (window))
3313     return NULL;
3314   
3315   if (!hints_atom)
3316     hints_atom = XInternAtom (GDK_WINDOW_XDISPLAY (window), 
3317                               _XA_MOTIF_WM_HINTS, FALSE);
3318   
3319   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
3320                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3321                       False, AnyPropertyType, &type, &format, &nitems,
3322                       &bytes_after, (guchar **)&hints);
3323
3324   if (type == None)
3325     return NULL;
3326   
3327   return hints;
3328 }
3329
3330 static void
3331 gdk_window_set_mwm_hints (GdkWindow *window,
3332                           MotifWmHints *new_hints)
3333 {
3334   static Atom hints_atom = None;
3335   MotifWmHints *hints;
3336   Atom type;
3337   gint format;
3338   gulong nitems;
3339   gulong bytes_after;
3340   
3341   if (GDK_WINDOW_DESTROYED (window))
3342     return;
3343   
3344   if (!hints_atom)
3345     hints_atom = XInternAtom (GDK_WINDOW_XDISPLAY (window), 
3346                               _XA_MOTIF_WM_HINTS, FALSE);
3347   
3348   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
3349                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3350                       False, AnyPropertyType, &type, &format, &nitems,
3351                       &bytes_after, (guchar **)&hints);
3352   
3353   if (type == None)
3354     hints = new_hints;
3355   else
3356     {
3357       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
3358         {
3359           hints->flags |= MWM_HINTS_FUNCTIONS;
3360           hints->functions = new_hints->functions;
3361         }
3362       if (new_hints->flags & MWM_HINTS_DECORATIONS)
3363         {
3364           hints->flags |= MWM_HINTS_DECORATIONS;
3365           hints->decorations = new_hints->decorations;
3366         }
3367     }
3368   
3369   XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
3370                    hints_atom, hints_atom, 32, PropModeReplace,
3371                    (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
3372   
3373   if (hints != new_hints)
3374     XFree (hints);
3375 }
3376
3377 /**
3378  * gdk_window_set_decorations:
3379  * @window: a #GdkWindow
3380  * @decorations: decoration hint mask
3381  *
3382  * "Decorations" are the features the window manager adds to a toplevel #GdkWindow.
3383  * This function sets the traditional Motif window manager hints that tell the
3384  * window manager which decorations you would like your window to have.
3385  * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
3386  * using the GDK function directly.
3387  *
3388  * The @decorations argument is the logical OR of the fields in
3389  * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
3390  * mask, the other bits indicate which decorations should be turned off.
3391  * If #GDK_DECOR_ALL is not included, then the other bits indicate
3392  * which decorations should be turned on.
3393  *
3394  * Most window managers honor a decorations hint of 0 to disable all decorations,
3395  * but very few honor all possible combinations of bits.
3396  * 
3397  **/
3398 void
3399 gdk_window_set_decorations (GdkWindow      *window,
3400                             GdkWMDecoration decorations)
3401 {
3402   MotifWmHints hints;
3403   
3404   g_return_if_fail (window != NULL);
3405   g_return_if_fail (GDK_IS_WINDOW (window));
3406   
3407   hints.flags = MWM_HINTS_DECORATIONS;
3408   hints.decorations = decorations;
3409   
3410   gdk_window_set_mwm_hints (window, &hints);
3411 }
3412
3413 /**
3414  * gdk_window_get_decorations:
3415  * @window: The #GdkWindow to get the decorations from
3416  * @decorations: The window decorations will be written here
3417  *
3418  * Returns the decorations set on the GdkWindow with #gdk_window_set_decorations
3419  * Returns: TRUE if the window has decorations set, FALSE otherwise.
3420  **/
3421 gboolean
3422 gdk_window_get_decorations(GdkWindow *window,
3423                            GdkWMDecoration *decorations)
3424 {
3425   MotifWmHints *hints;
3426   gboolean result = FALSE;
3427
3428   hints = gdk_window_get_mwm_hints (window);
3429   
3430   if (hints)
3431     {
3432       if (hints->flags & MWM_HINTS_DECORATIONS)
3433         {
3434           *decorations = hints->decorations;
3435           result = TRUE;
3436         }
3437       
3438       XFree (hints);
3439     }
3440
3441   return result;
3442 }
3443
3444 /**
3445  * gdk_window_set_functions:
3446  * @window: a #GdkWindow
3447  * @functions: bitmask of operations to allow on @window
3448  *
3449  * This function isn't really good for much. It sets the traditional
3450  * Motif window manager hint for which operations the window manager
3451  * should allow on a toplevel window. However, few window managers do
3452  * anything reliable or interesting with this hint. Many ignore it
3453  * entirely.
3454  *
3455  * The @functions argument is the logical OR of values from the
3456  * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
3457  * then the other bits indicate which functions to disable; if
3458  * it doesn't include #GDK_FUNC_ALL, it indicates which functions to
3459  * enable.
3460  * 
3461  **/
3462 void
3463 gdk_window_set_functions (GdkWindow    *window,
3464                           GdkWMFunction functions)
3465 {
3466   MotifWmHints hints;
3467   
3468   g_return_if_fail (window != NULL);
3469   g_return_if_fail (GDK_IS_WINDOW (window));
3470   
3471   hints.flags = MWM_HINTS_FUNCTIONS;
3472   hints.functions = functions;
3473   
3474   gdk_window_set_mwm_hints (window, &hints);
3475 }
3476
3477 #ifdef HAVE_SHAPE_EXT
3478
3479 /* 
3480  * propagate the shapes from all child windows of a GDK window to the parent 
3481  * window. Shamelessly ripped from Enlightenment's code
3482  * 
3483  * - Raster
3484  */
3485 struct _gdk_span
3486 {
3487   gint                start;
3488   gint                end;
3489   struct _gdk_span    *next;
3490 };
3491
3492 static void
3493 gdk_add_to_span (struct _gdk_span **s,
3494                  gint               x,
3495                  gint               xx)
3496 {
3497   struct _gdk_span *ptr1, *ptr2, *noo, *ss;
3498   gchar             spanning;
3499   
3500   ptr2 = NULL;
3501   ptr1 = *s;
3502   spanning = 0;
3503   ss = NULL;
3504   /* scan the spans for this line */
3505   while (ptr1)
3506     {
3507       /* -- -> new span */
3508       /* == -> existing span */
3509       /* ## -> spans intersect */
3510       /* if we are in the middle of spanning the span into the line */
3511       if (spanning)
3512         {
3513           /* case: ---- ==== */
3514           if (xx < ptr1->start - 1)
3515             {
3516               /* ends before next span - extend to here */
3517               ss->end = xx;
3518               return;
3519             }
3520           /* case: ----##=== */
3521           else if (xx <= ptr1->end)
3522             {
3523               /* crosses into next span - delete next span and append */
3524               ss->end = ptr1->end;
3525               ss->next = ptr1->next;
3526               g_free (ptr1);
3527               return;
3528             }
3529           /* case: ---###--- */
3530           else
3531             {
3532               /* overlaps next span - delete and keep checking */
3533               ss->next = ptr1->next;
3534               g_free (ptr1);
3535               ptr1 = ss;
3536             }
3537         }
3538       /* otherwise havent started spanning it in yet */
3539       else
3540         {
3541           /* case: ---- ==== */
3542           if (xx < ptr1->start - 1)
3543             {
3544               /* insert span here in list */
3545               noo = g_malloc (sizeof (struct _gdk_span));
3546               
3547               if (noo)
3548                 {
3549                   noo->start = x;
3550                   noo->end = xx;
3551                   noo->next = ptr1;
3552                   if (ptr2)
3553                     ptr2->next = noo;
3554                   else
3555                     *s = noo;
3556                 }
3557               return;
3558             }
3559           /* case: ----##=== */
3560           else if ((x < ptr1->start) && (xx <= ptr1->end))
3561             {
3562               /* expand this span to the left point of the new one */
3563               ptr1->start = x;
3564               return;
3565             }
3566           /* case: ===###=== */
3567           else if ((x >= ptr1->start) && (xx <= ptr1->end))
3568             {
3569               /* throw the span away */
3570               return;
3571             }
3572           /* case: ---###--- */
3573           else if ((x < ptr1->start) && (xx > ptr1->end))
3574             {
3575               ss = ptr1;
3576               spanning = 1;
3577               ptr1->start = x;
3578               ptr1->end = xx;
3579             }
3580           /* case: ===##---- */
3581           else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end))
3582             {
3583               ss = ptr1;
3584               spanning = 1;
3585               ptr1->end = xx;
3586             }
3587           /* case: ==== ---- */
3588           /* case handled by next loop iteration - first case */
3589         }
3590       ptr2 = ptr1;
3591       ptr1 = ptr1->next;
3592     }
3593   /* it started in the middle but spans beyond your current list */
3594   if (spanning)
3595     {
3596       ptr2->end = xx;
3597       return;
3598     }
3599   /* it does not start inside a span or in the middle, so add it to the end */
3600   noo = g_malloc (sizeof (struct _gdk_span));
3601   
3602   if (noo)
3603     {
3604       noo->start = x;
3605       noo->end = xx;
3606       if (ptr2)
3607         {
3608           noo->next = ptr2->next;
3609           ptr2->next = noo;
3610         }
3611       else
3612         {
3613           noo->next = NULL;
3614           *s = noo;
3615         }
3616     }
3617   return;
3618 }
3619
3620 static void
3621 gdk_add_rectangles (Display           *disp,
3622                     Window             win,
3623                     struct _gdk_span **spans,
3624                     gint               basew,
3625                     gint               baseh,
3626                     gint               x,
3627                     gint               y)
3628 {
3629   gint a, k;
3630   gint x1, y1, x2, y2;
3631   gint rn, ord;
3632   XRectangle *rl;
3633   
3634   rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord);
3635   if (rl)
3636     {
3637       /* go through all clip rects in this window's shape */
3638       for (k = 0; k < rn; k++)
3639         {
3640           /* for each clip rect, add it to each line's spans */
3641           x1 = x + rl[k].x;
3642           x2 = x + rl[k].x + (rl[k].width - 1);
3643           y1 = y + rl[k].y;
3644           y2 = y + rl[k].y + (rl[k].height - 1);
3645           if (x1 < 0)
3646             x1 = 0;
3647           if (y1 < 0)
3648             y1 = 0;
3649           if (x2 >= basew)
3650             x2 = basew - 1;
3651           if (y2 >= baseh)
3652             y2 = baseh - 1;
3653           for (a = y1; a <= y2; a++)
3654             {
3655               if ((x2 - x1) >= 0)
3656                 gdk_add_to_span (&spans[a], x1, x2);
3657             }
3658         }
3659       XFree (rl);
3660     }
3661 }
3662
3663 static void
3664 gdk_propagate_shapes (Display *disp,
3665                       Window   win,
3666                       gboolean merge)
3667 {
3668   Window              rt, par, *list = NULL;
3669   gint                i, j, num = 0, num_rects = 0;
3670   gint                x, y, contig;
3671   guint               w, h, d;
3672   gint                baseh, basew;
3673   XRectangle         *rects = NULL;
3674   struct _gdk_span  **spans = NULL, *ptr1, *ptr2, *ptr3;
3675   XWindowAttributes   xatt;
3676   
3677   XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d);
3678   if (h <= 0)
3679     return;
3680   basew = w;
3681   baseh = h;
3682   spans = g_malloc (sizeof (struct _gdk_span *) * h);
3683   
3684   for (i = 0; i < h; i++)
3685     spans[i] = NULL;
3686   XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num);
3687   if (list)
3688     {
3689       /* go through all child windows and create/insert spans */
3690       for (i = 0; i < num; i++)
3691         {
3692           if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped))
3693             if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d))
3694               gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y);
3695         }
3696       if (merge)
3697         gdk_add_rectangles (disp, win, spans, basew, baseh, x, y);
3698       
3699       /* go through the spans list and build a list of rects */
3700       rects = g_malloc (sizeof (XRectangle) * 256);
3701       num_rects = 0;
3702       for (i = 0; i < baseh; i++)
3703         {
3704           ptr1 = spans[i];
3705           /* go through the line for all spans */
3706           while (ptr1)
3707             {
3708               rects[num_rects].x = ptr1->start;
3709               rects[num_rects].y = i;
3710               rects[num_rects].width = ptr1->end - ptr1->start + 1;
3711               rects[num_rects].height = 1;
3712               j = i + 1;
3713               /* if there are more lines */
3714               contig = 1;
3715               /* while contigous rects (same start/end coords) exist */
3716               while ((contig) && (j < baseh))
3717                 {
3718                   /* search next line for spans matching this one */
3719                   contig = 0;
3720                   ptr2 = spans[j];
3721                   ptr3 = NULL;
3722                   while (ptr2)
3723                     {
3724                       /* if we have an exact span match set contig */
3725                       if ((ptr2->start == ptr1->start) &&
3726                           (ptr2->end == ptr1->end))
3727                         {
3728                           contig = 1;
3729                           /* remove the span - not needed */
3730                           if (ptr3)
3731                             {
3732                               ptr3->next = ptr2->next;
3733                               g_free (ptr2);
3734                               ptr2 = NULL;
3735                             }
3736                           else
3737                             {
3738                               spans[j] = ptr2->next;
3739                               g_free (ptr2);
3740                               ptr2 = NULL;
3741                             }
3742                           break;
3743                         }
3744                       /* gone past the span point no point looking */
3745                       else if (ptr2->start < ptr1->start)
3746                         break;
3747                       if (ptr2)
3748                         {
3749                           ptr3 = ptr2;
3750                           ptr2 = ptr2->next;
3751                         }
3752                     }
3753                   /* if a contiguous span was found increase the rect h */
3754                   if (contig)
3755                     {
3756                       rects[num_rects].height++;
3757                       j++;
3758                     }
3759                 }
3760               /* up the rect count */
3761               num_rects++;
3762               /* every 256 new rects increase the rect array */
3763               if ((num_rects % 256) == 0)
3764                 rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256));
3765               ptr1 = ptr1->next;
3766             }
3767         }
3768       /* set the rects as the shape mask */
3769       if (rects)
3770         {
3771           XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects,
3772                                    ShapeSet, YXSorted);
3773           g_free (rects);
3774         }
3775       XFree (list);
3776     }
3777   /* free up all the spans we made */
3778   for (i = 0; i < baseh; i++)
3779     {
3780       ptr1 = spans[i];
3781       while (ptr1)
3782         {
3783           ptr2 = ptr1;
3784           ptr1 = ptr1->next;
3785           g_free (ptr2);
3786         }
3787     }
3788   g_free (spans);
3789 }
3790
3791 #endif /* HAVE_SHAPE_EXT */
3792
3793 /**
3794  * gdk_window_set_child_shapes:
3795  * @window: a #GdkWindow
3796  * 
3797  * Sets the shape mask of @window to the union of shape masks
3798  * for all children of @window, ignoring the shape mask of @window
3799  * itself. Contrast with gdk_window_merge_child_shapes() which includes
3800  * the shape mask of @window in the masks to be merged.
3801  **/
3802 void
3803 gdk_window_set_child_shapes (GdkWindow *window)
3804 {
3805   g_return_if_fail (window != NULL);
3806   g_return_if_fail (GDK_IS_WINDOW (window));
3807   
3808 #ifdef HAVE_SHAPE_EXT
3809   if (!GDK_WINDOW_DESTROYED (window) &&
3810       gdk_window_have_shape_ext ())
3811     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3812                           GDK_WINDOW_XID (window), FALSE);
3813 #endif   
3814 }
3815
3816 /**
3817  * gdk_window_merge_child_shapes:
3818  * @window: a #GdkWindow
3819  * 
3820  * Merges the shape masks for any child windows into the
3821  * shape mask for @window. i.e. the union of all masks
3822  * for @window and its children will become the new mask
3823  * for @window. See gdk_window_shape_combine_mask().
3824  *
3825  * This function is distinct from gdk_window_set_child_shapes()
3826  * because it includes @window's shape mask in the set of shapes to
3827  * be merged.
3828  * 
3829  **/
3830 void
3831 gdk_window_merge_child_shapes (GdkWindow *window)
3832 {
3833   g_return_if_fail (window != NULL);
3834   g_return_if_fail (GDK_IS_WINDOW (window));
3835   
3836 #ifdef HAVE_SHAPE_EXT
3837   if (!GDK_WINDOW_DESTROYED (window) &&
3838       gdk_window_have_shape_ext ())
3839     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3840                           GDK_WINDOW_XID (window), TRUE);
3841 #endif   
3842 }
3843
3844 /* Support for windows that can be guffaw-scrolled
3845  * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
3846  */
3847
3848 static gboolean
3849 gdk_window_gravity_works (void)
3850 {
3851   enum { UNKNOWN, NO, YES };
3852   static gint gravity_works = UNKNOWN;
3853   
3854   if (gravity_works == UNKNOWN)
3855     {
3856       GdkWindowAttr attr;
3857       GdkWindow *parent;
3858       GdkWindow *child;
3859       gint y;
3860       
3861       /* This particular server apparently has a bug so that the test
3862        * works but the actual code crashes it
3863        */
3864       if ((!strcmp (XServerVendor (gdk_display), "Sun Microsystems, Inc.")) &&
3865           (VendorRelease (gdk_display) == 3400))
3866         {
3867           gravity_works = NO;
3868           return FALSE;
3869         }
3870       
3871       attr.window_type = GDK_WINDOW_TEMP;
3872       attr.wclass = GDK_INPUT_OUTPUT;
3873       attr.x = 0;
3874       attr.y = 0;
3875       attr.width = 100;
3876       attr.height = 100;
3877       attr.event_mask = 0;
3878       
3879       parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y);
3880       
3881       attr.window_type = GDK_WINDOW_CHILD;
3882       child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
3883       
3884       gdk_window_set_static_win_gravity (child, TRUE);
3885       
3886       gdk_window_resize (parent, 100, 110);
3887       gdk_window_move (parent, 0, -10);
3888       gdk_window_move_resize (parent, 0, 0, 100, 100);
3889       
3890       gdk_window_resize (parent, 100, 110);
3891       gdk_window_move (parent, 0, -10);
3892       gdk_window_move_resize (parent, 0, 0, 100, 100);
3893       
3894       gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
3895       
3896       gdk_window_destroy (parent);
3897       gdk_window_destroy (child);
3898       
3899       gravity_works = ((y == -20) ? YES : NO);
3900     }
3901   
3902   return (gravity_works == YES);
3903 }
3904
3905 static void
3906 gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
3907 {
3908   XSetWindowAttributes xattributes;
3909   guint xattributes_mask = 0;
3910   
3911   g_return_if_fail (window != NULL);
3912   
3913   xattributes.bit_gravity = StaticGravity;
3914   xattributes_mask |= CWBitGravity;
3915   xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
3916   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3917                            GDK_WINDOW_XID (window),
3918                            CWBitGravity,  &xattributes);
3919 }
3920
3921 static void
3922 gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
3923 {
3924   XSetWindowAttributes xattributes;
3925   
3926   g_return_if_fail (window != NULL);
3927   
3928   xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
3929   
3930   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3931                            GDK_WINDOW_XID (window),
3932                            CWWinGravity,  &xattributes);
3933 }
3934
3935 /**
3936  * gdk_window_set_static_gravities:
3937  * @window: a #GdkWindow
3938  * @use_static: %TRUE to turn on static gravity
3939  *
3940  * Set the bit gravity of the given window to static, and flag it so
3941  * all children get static subwindow gravity. This is used if you are
3942  * implementing scary features that involve deep knowledge of the
3943  * windowing system. Don't worry about it unless you have to.
3944  * 
3945  * Return value: %TRUE if the server supports static gravity
3946  **/
3947 gboolean 
3948 gdk_window_set_static_gravities (GdkWindow *window,
3949                                  gboolean   use_static)
3950 {
3951   GdkWindowObject *private = (GdkWindowObject *)window;
3952   GList *tmp_list;
3953   
3954   g_return_val_if_fail (window != NULL, FALSE);
3955   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
3956
3957   if (!use_static == !private->guffaw_gravity)
3958     return TRUE;
3959   
3960   if (use_static && !gdk_window_gravity_works ())
3961     return FALSE;
3962   
3963   private->guffaw_gravity = use_static;
3964   
3965   if (!GDK_WINDOW_DESTROYED (window))
3966     {
3967       gdk_window_set_static_bit_gravity (window, use_static);
3968       
3969       tmp_list = private->children;
3970       while (tmp_list)
3971         {
3972           gdk_window_set_static_win_gravity (tmp_list->data, use_static);
3973           
3974           tmp_list = tmp_list->next;
3975         }
3976     }
3977   
3978   return TRUE;
3979 }
3980
3981 /* internal function created for and used by gdk_window_xid_at_coords */
3982 Window
3983 gdk_window_xid_at (Window   base,
3984                    gint     bx,
3985                    gint     by,
3986                    gint     x,
3987                    gint     y, 
3988                    GList   *excludes,
3989                    gboolean excl_child)
3990 {
3991   Display *xdisplay;
3992   Window *list = NULL;
3993   Window child = 0, parent_win = 0, root_win = 0;
3994   int i;
3995   unsigned int ww, wh, wb, wd, num;
3996   int wx, wy;
3997   
3998   xdisplay = GDK_DISPLAY ();
3999   if (!XGetGeometry (xdisplay, base, &root_win, &wx, &wy, &ww, &wh, &wb, &wd))
4000     return 0;
4001   wx += bx;
4002   wy += by;
4003   
4004   if (!((x >= wx) &&
4005         (y >= wy) &&
4006         (x < (int) (wx + ww)) &&
4007         (y < (int) (wy + wh))))
4008     return 0;
4009   
4010   if (!XQueryTree (xdisplay, base, &root_win, &parent_win, &list, &num))
4011     return base;
4012   
4013   if (list)
4014     {
4015       for (i = num - 1; ; i--)
4016         {
4017           if ((!excl_child) || (!g_list_find (excludes, (gpointer *) list[i])))
4018             {
4019               if ((child = gdk_window_xid_at (list[i], wx, wy, x, y, excludes, excl_child)) != 0)
4020                 {
4021                   XFree (list);
4022                   return child;
4023                 }
4024             }
4025           if (!i)
4026             break;
4027         }
4028       XFree (list);
4029     }
4030   return base;
4031 }
4032
4033 /* 
4034  * The following fucntion by The Rasterman <raster@redhat.com>
4035  * This function returns the X Window ID in which the x y location is in 
4036  * (x and y being relative to the root window), excluding any windows listed
4037  * in the GList excludes (this is a list of X Window ID's - gpointer being
4038  * the Window ID).
4039  * 
4040  * This is primarily designed for internal gdk use - for DND for example
4041  * when using a shaped icon window as the drag object - you exclude the
4042  * X Window ID of the "icon" (perhaps more if excludes may be needed) and
4043  * You can get back an X Window ID as to what X Window ID is infact under
4044  * those X,Y co-ordinates.
4045  */
4046 Window
4047 gdk_window_xid_at_coords (gint     x,
4048                           gint     y,
4049                           GList   *excludes,
4050                           gboolean excl_child)
4051 {
4052   GdkWindow *window;
4053   Display *xdisplay;
4054   Window *list = NULL;
4055   Window root, child = 0, parent_win = 0, root_win = 0;
4056   unsigned int num;
4057   int i;
4058
4059   window = _gdk_parent_root;
4060   xdisplay = GDK_WINDOW_XDISPLAY (window);
4061   root = GDK_WINDOW_XID (window);
4062   num = g_list_length (excludes);
4063   
4064   gdk_x11_grab_server ();
4065   if (!XQueryTree (xdisplay, root, &root_win, &parent_win, &list, &num))
4066     {
4067       gdk_x11_ungrab_server ();
4068       return root;
4069     }
4070   if (list)
4071     {
4072       i = num - 1;
4073       do
4074         {
4075           XWindowAttributes xwa;
4076           
4077           XGetWindowAttributes (xdisplay, list [i], &xwa);
4078           
4079           if (xwa.map_state != IsViewable)
4080             continue;
4081           
4082           if (excl_child && g_list_find (excludes, (gpointer *) list[i]))
4083             continue;
4084           
4085           if ((child = gdk_window_xid_at (list[i], 0, 0, x, y, excludes, excl_child)) == 0)
4086             continue;
4087           
4088           if (excludes)
4089             {
4090               if (!g_list_find (excludes, (gpointer *) child))
4091                 {
4092                   XFree (list);
4093                   gdk_x11_ungrab_server ();
4094                   return child;
4095                 }
4096             }
4097           else
4098             {
4099               XFree (list);
4100               gdk_x11_ungrab_server ();
4101               return child;
4102             }
4103         } while (--i > 0);
4104       XFree (list);
4105     }
4106   gdk_x11_ungrab_server ();
4107   return root;
4108 }
4109
4110 static void
4111 wmspec_moveresize (GdkWindow *window,
4112                    gint       direction,
4113                    gint       root_x,
4114                    gint       root_y,
4115                    guint32    timestamp)     
4116 {
4117   XEvent xev;
4118
4119   /* Release passive grab */
4120   gdk_pointer_ungrab (timestamp);
4121   
4122   xev.xclient.type = ClientMessage;
4123   xev.xclient.serial = 0;
4124   xev.xclient.send_event = True;
4125   xev.xclient.display = gdk_display;
4126   xev.xclient.window = GDK_WINDOW_XID (window);
4127   xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_MOVERESIZE");
4128   xev.xclient.format = 32;
4129   xev.xclient.data.l[0] = root_x;
4130   xev.xclient.data.l[1] = root_y;
4131   xev.xclient.data.l[2] = direction;
4132   xev.xclient.data.l[3] = 0;
4133   xev.xclient.data.l[4] = 0;
4134   
4135   XSendEvent (gdk_display, _gdk_root_window, False,
4136               SubstructureRedirectMask | SubstructureNotifyMask,
4137               &xev);
4138 }
4139
4140 /* From the WM spec */
4141 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
4142 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
4143 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
4144 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
4145 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
4146 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
4147 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
4148 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
4149 #define _NET_WM_MOVERESIZE_MOVE              8
4150
4151 static void
4152 wmspec_resize_drag (GdkWindow     *window,
4153                     GdkWindowEdge  edge,
4154                     gint           button,
4155                     gint           root_x,
4156                     gint           root_y,
4157                     guint32        timestamp)
4158 {
4159   gint direction;
4160   
4161   /* Let the compiler turn a switch into a table, instead
4162    * of doing the table manually, this way is easier to verify.
4163    */
4164   switch (edge)
4165     {
4166     case GDK_WINDOW_EDGE_NORTH_WEST:
4167       direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
4168       break;
4169
4170     case GDK_WINDOW_EDGE_NORTH:
4171       direction = _NET_WM_MOVERESIZE_SIZE_TOP;
4172       break;
4173
4174     case GDK_WINDOW_EDGE_NORTH_EAST:
4175       direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
4176       break;
4177
4178     case GDK_WINDOW_EDGE_WEST:
4179       direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
4180       break;
4181
4182     case GDK_WINDOW_EDGE_EAST:
4183       direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
4184       break;
4185
4186     case GDK_WINDOW_EDGE_SOUTH_WEST:
4187       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
4188       break;
4189
4190     case GDK_WINDOW_EDGE_SOUTH:
4191       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
4192       break;
4193
4194     case GDK_WINDOW_EDGE_SOUTH_EAST:
4195       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
4196       break;
4197
4198     default:
4199       g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!",
4200                  edge);
4201       return;
4202       break;
4203     }
4204   
4205   wmspec_moveresize (window, direction, root_x, root_y, timestamp);
4206 }
4207
4208 /* This is global for use in gdkevents-x11.c */
4209 GdkWindow *_gdk_moveresize_window;
4210
4211 static GdkWindow *moveresize_emulation_window = NULL;
4212 static gboolean is_resize = FALSE;
4213 static GdkWindowEdge resize_edge;
4214 static gint moveresize_button;
4215 static gint moveresize_x;
4216 static gint moveresize_y;
4217 static gint moveresize_orig_x;
4218 static gint moveresize_orig_y;
4219 static gint moveresize_orig_width;
4220 static gint moveresize_orig_height;
4221 static GdkWindowHints moveresize_geom_mask = 0;
4222 static GdkGeometry moveresize_geometry;
4223 static Time moveresize_process_time;
4224
4225 static XEvent *moveresize_pending_event;
4226
4227 static void
4228 update_pos (gint new_root_x,
4229             gint new_root_y)
4230 {
4231   gint dx, dy;
4232   
4233   dx = new_root_x - moveresize_x;
4234   dy = new_root_y - moveresize_y;
4235
4236   if (is_resize)
4237     {
4238       gint w, h;
4239
4240       w = moveresize_orig_width;
4241       h = moveresize_orig_height;
4242       
4243       switch (resize_edge)
4244         {
4245         case GDK_WINDOW_EDGE_SOUTH_EAST:
4246           w += dx;
4247           h += dy;
4248           break;
4249         }
4250
4251       w = MAX (w, 1);
4252       h = MAX (h, 1);
4253       
4254       if (moveresize_geom_mask)
4255         {
4256           gdk_window_constrain_size (&moveresize_geometry,
4257                                      moveresize_geom_mask,
4258                                      w, h,
4259                                      &w, &h);
4260         }
4261       
4262       gdk_window_resize (_gdk_moveresize_window, w, h);
4263     }
4264   else
4265     {
4266       gint x, y;
4267
4268       x = moveresize_orig_x + dx;
4269       y = moveresize_orig_y + dy;
4270       
4271       gdk_window_move (_gdk_moveresize_window, x, y);
4272     }
4273 }
4274
4275 static void
4276 finish_drag (void)
4277 {
4278   gdk_window_destroy (moveresize_emulation_window);
4279   moveresize_emulation_window = NULL;
4280   _gdk_moveresize_window = NULL;
4281
4282   if (moveresize_pending_event)
4283     {
4284       g_free (moveresize_pending_event);
4285       moveresize_pending_event = NULL;
4286     }
4287 }
4288
4289 static int
4290 lookahead_motion_predicate (Display *display,
4291                             XEvent  *event,
4292                             XPointer arg)
4293 {
4294   gboolean *seen_release = (gboolean *)arg;
4295   
4296   if (*seen_release)
4297     return False;
4298
4299   switch (event->xany.type)
4300     {
4301     case ButtonRelease:
4302       *seen_release = TRUE;
4303       break;
4304     case MotionNotify:
4305       moveresize_process_time = event->xmotion.time;
4306       break;
4307     default:
4308       break;
4309     }
4310
4311   return False;
4312 }
4313
4314 static gboolean
4315 moveresize_lookahead (XEvent *event)
4316 {
4317   XEvent tmp_event;
4318   gboolean seen_release = FALSE;
4319
4320   if (moveresize_process_time)
4321     {
4322       if (event->xmotion.time == moveresize_process_time)
4323         {
4324           moveresize_process_time = 0;
4325           return TRUE;
4326         }
4327       else
4328         return FALSE;
4329     }
4330
4331   XCheckIfEvent (gdk_display, &tmp_event,
4332                  lookahead_motion_predicate, (XPointer)&seen_release);
4333
4334   return moveresize_process_time == 0;
4335 }
4336         
4337 void
4338 _gdk_moveresize_handle_event (XEvent *event)
4339 {
4340   guint button_mask = 0;
4341   GdkWindowObject *window_private = (GdkWindowObject *) _gdk_moveresize_window;
4342   
4343   button_mask = GDK_BUTTON1_MASK << (moveresize_button - 1);
4344   
4345   switch (event->xany.type)
4346     {
4347     case MotionNotify:
4348       if (window_private->resize_count > 0)
4349         {
4350           if (moveresize_pending_event)
4351             *moveresize_pending_event = *event;
4352           else
4353             moveresize_pending_event = g_memdup (event, sizeof (XEvent));
4354
4355           break;
4356         }
4357       if (!moveresize_lookahead (event))
4358         break;
4359       
4360       update_pos (event->xmotion.x_root,
4361                   event->xmotion.y_root);
4362       
4363       /* This should never be triggered in normal cases, but in the
4364        * case where the drag started without an implicit grab being
4365        * in effect, we could miss the release if it occurs before
4366        * we grab the pointer; this ensures that we will never
4367        * get a permanently stuck grab.
4368        */
4369       if ((event->xmotion.state & button_mask) == 0)
4370         finish_drag ();
4371       break;
4372
4373     case ButtonRelease:
4374       update_pos (event->xbutton.x_root,
4375                   event->xbutton.y_root);
4376       
4377       if (event->xbutton.button == moveresize_button)
4378         finish_drag ();
4379       break;
4380     }
4381 }
4382
4383 void
4384 _gdk_moveresize_configure_done (void)
4385 {
4386   XEvent *tmp_event;
4387   
4388   if (moveresize_pending_event)
4389     {
4390       tmp_event = moveresize_pending_event;
4391       moveresize_pending_event = NULL;
4392       _gdk_moveresize_handle_event (tmp_event);
4393       g_free (tmp_event);
4394     }
4395 }
4396
4397 static void
4398 create_moveresize_window (guint32 timestamp)
4399 {
4400   GdkWindowAttr attributes;
4401   gint attributes_mask;
4402   GdkGrabStatus status;
4403
4404   g_assert (moveresize_emulation_window == NULL);
4405   
4406   attributes.x = -100;
4407   attributes.y = -100;
4408   attributes.width = 10;
4409   attributes.height = 10;
4410   attributes.window_type = GDK_WINDOW_TEMP;
4411   attributes.wclass = GDK_INPUT_ONLY;
4412   attributes.override_redirect = TRUE;
4413   attributes.event_mask = 0;
4414
4415   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
4416
4417   moveresize_emulation_window =
4418     gdk_window_new (NULL, &attributes, attributes_mask);
4419
4420   gdk_window_show (moveresize_emulation_window);
4421
4422   status = gdk_pointer_grab (moveresize_emulation_window,
4423                              FALSE,
4424                              GDK_BUTTON_RELEASE_MASK |
4425                              GDK_POINTER_MOTION_MASK,
4426                              NULL,
4427                              NULL,
4428                              timestamp);
4429
4430   if (status != GDK_GRAB_SUCCESS)
4431     {
4432       /* If this fails, some other client has grabbed the window
4433        * already.
4434        */
4435       gdk_window_destroy (moveresize_emulation_window);
4436       moveresize_emulation_window = NULL;
4437     }
4438
4439   moveresize_process_time = 0;
4440 }
4441
4442 static void
4443 emulate_resize_drag (GdkWindow     *window,
4444                      GdkWindowEdge  edge,
4445                      gint           button,
4446                      gint           root_x,
4447                      gint           root_y,
4448                      guint32        timestamp)
4449 {
4450   is_resize = TRUE;
4451   moveresize_button = button;
4452   resize_edge = edge;
4453   moveresize_x = root_x;
4454   moveresize_y = root_y;
4455   _gdk_moveresize_window = GDK_WINDOW (g_object_ref (G_OBJECT (window)));
4456
4457   gdk_window_get_size (window, &moveresize_orig_width, &moveresize_orig_height);
4458   
4459   moveresize_geom_mask = 0;
4460   gdk_window_get_geometry_hints (window,
4461                                  &moveresize_geometry,
4462                                  &moveresize_geom_mask);
4463   
4464   create_moveresize_window (timestamp);
4465 }
4466
4467 static void
4468 emulate_move_drag (GdkWindow     *window,
4469                    gint           button,
4470                    gint           root_x,
4471                    gint           root_y,
4472                    guint32        timestamp)
4473 {
4474   is_resize = FALSE;
4475   moveresize_button = button;
4476   moveresize_x = root_x;
4477   moveresize_y = root_y;
4478   _gdk_moveresize_window = GDK_WINDOW (g_object_ref (G_OBJECT (window)));
4479
4480   gdk_window_get_deskrelative_origin (_gdk_moveresize_window,
4481                                       &moveresize_orig_x,
4482                                       &moveresize_orig_y);
4483   
4484   create_moveresize_window (timestamp);
4485 }
4486
4487 /**
4488  * gdk_window_begin_resize_drag:
4489  * @window: a #GdkWindow
4490  * @edge: the edge or corner from which the drag is started
4491  * @button: the button being used to drag
4492  * @root_x: root window X coordinate of mouse click that began the drag
4493  * @root_y: root window Y coordinate of mouse click that began the drag
4494  * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
4495  *
4496  * Begins a window resize operation (for a toplevel window).
4497  * You might use this function to implement a "window resize grip," for
4498  * example; in fact #GtkStatusbar uses it. The function works best
4499  * with window managers that support the Extended Window Manager Hints spec
4500  * (see http://www.freedesktop.org), but has a fallback implementation
4501  * for other window managers.
4502  * 
4503  **/
4504 void
4505 gdk_window_begin_resize_drag (GdkWindow     *window,
4506                               GdkWindowEdge  edge,
4507                               gint           button,
4508                               gint           root_x,
4509                               gint           root_y,
4510                               guint32        timestamp)
4511 {
4512   g_return_if_fail (GDK_IS_WINDOW (window));
4513   g_return_if_fail (moveresize_emulation_window == NULL);
4514   
4515   if (GDK_WINDOW_DESTROYED (window))
4516     return;
4517
4518   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
4519     wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp);
4520   else
4521     emulate_resize_drag (window, edge, button, root_x, root_y, timestamp);
4522 }
4523
4524 /**
4525  * gdk_window_begin_move_drag:
4526  * @window: a #GdkWindow
4527  * @button: the button being used to drag
4528  * @root_x: root window X coordinate of mouse click that began the drag
4529  * @root_y: root window Y coordinate of mouse click that began the drag
4530  * @timestamp: timestamp of mouse click that began the drag
4531  *
4532  * Begins a window move operation (for a toplevel window).  You might
4533  * use this function to implement a "window move grip," for
4534  * example. The function works best with window managers that support
4535  * the Extended Window Manager Hints spec (see
4536  * http://www.freedesktop.org), but has a fallback implementation for
4537  * other window managers.
4538  * 
4539  **/
4540 void
4541 gdk_window_begin_move_drag (GdkWindow *window,
4542                             gint       button,
4543                             gint       root_x,
4544                             gint       root_y,
4545                             guint32    timestamp)
4546 {
4547   g_return_if_fail (GDK_IS_WINDOW (window));
4548   g_return_if_fail (moveresize_emulation_window == NULL);
4549   
4550   if (GDK_WINDOW_DESTROYED (window))
4551     return;
4552
4553   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
4554     wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE,
4555                        root_x, root_y, timestamp);
4556   else
4557     emulate_move_drag (window, button, root_x, root_y, timestamp);
4558 }