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