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