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