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