]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkwindow-x11.c
Delete EWMH properties if no private->state flags are set. (#66754)
[~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 (xdisplay,
981                                                         "_NET_WM_STATE_MAXIMIZED_VERT");
982       ++i;
983       atoms[i] = gdk_x11_get_xatom_by_name_for_display (xdisplay,
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 (xdisplay,
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 (xdisplay,
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 (xdisplay,
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 (xdisplay, "_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 (xdisplay, "_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 (xdisplay, "_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 (xdisplay, "_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   if (GDK_WINDOW_DESTROYED (window))
2637     return;
2638   
2639   xparent = GDK_WINDOW_XID (window);
2640   do
2641     {
2642       xwindow = xparent;
2643       if (!XQueryTree (GDK_WINDOW_XDISPLAY (window), xwindow,
2644                        &root, &xparent,
2645                        &children, &nchildren))
2646         return;
2647       
2648       if (children)
2649         XFree (children);
2650     }
2651   while (xparent != root);
2652   
2653   if (xparent == root)
2654     {
2655       unsigned int ww, wh, wb, wd;
2656       int wx, wy;
2657       
2658       if (XGetGeometry (GDK_WINDOW_XDISPLAY (window), xwindow, &root, &wx, &wy, &ww, &wh, &wb, &wd))
2659         {
2660           rect->x = wx;
2661           rect->y = wy;
2662           rect->width = ww;
2663           rect->height = wh;
2664         }
2665     }
2666 }
2667
2668 void
2669 _gdk_windowing_get_pointer (GdkDisplay       *display,
2670                             GdkScreen       **screen,
2671                             gint             *x,
2672                             gint             *y,
2673                             GdkModifierType  *mask)
2674 {
2675   GdkScreen *default_screen;
2676   Window root = None;
2677   Window child;
2678   int rootx, rooty;
2679   int winx;
2680   int winy;
2681   unsigned int xmask;
2682
2683   if (display->closed)
2684     return;
2685
2686   default_screen = gdk_display_get_default_screen (display);
2687   
2688   XQueryPointer (GDK_SCREEN_XDISPLAY (default_screen),
2689                  GDK_SCREEN_XROOTWIN (default_screen),
2690                  &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
2691   
2692   if (root != None)
2693     {
2694       GdkWindow *gdk_root = gdk_window_lookup_for_display (display, root);
2695       *screen = gdk_drawable_get_screen (gdk_root);
2696     }
2697   
2698   *x = rootx;
2699   *y = rooty;
2700   *mask = xmask;
2701 }
2702
2703 GdkWindow*
2704 _gdk_windowing_window_get_pointer (GdkDisplay      *display,
2705                                    GdkWindow       *window,
2706                                    gint            *x,
2707                                    gint            *y,
2708                                    GdkModifierType *mask)
2709 {
2710   GdkWindow *return_val;
2711   Window root;
2712   Window child;
2713   int rootx, rooty;
2714   int winx = 0;
2715   int winy = 0;
2716   unsigned int xmask = 0;
2717   gint xoffset, yoffset;
2718
2719   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
2720   
2721   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2722
2723   return_val = NULL;
2724   if (!GDK_WINDOW_DESTROYED (window) &&
2725       XQueryPointer (GDK_WINDOW_XDISPLAY (window),
2726                      GDK_WINDOW_XID (window),
2727                      &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
2728     {
2729       if (child)
2730         return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child);
2731     }
2732   
2733   *x = winx + xoffset;
2734   *y = winy + yoffset;
2735   *mask = xmask;
2736   
2737   return return_val;
2738 }
2739
2740 GdkWindow*
2741 _gdk_windowing_window_at_pointer (GdkDisplay *display,
2742                                   gint       *win_x,
2743                                   gint       *win_y)
2744 {
2745   GdkWindow *window;
2746   GdkScreen *screen;
2747   Window root;
2748   Window xwindow;
2749   Window child;
2750   Window xwindow_last = 0;
2751   Display *xdisplay;
2752   int rootx = -1, rooty = -1;
2753   int winx, winy;
2754   unsigned int xmask;
2755
2756   screen = gdk_display_get_default_screen (display);
2757   
2758   xwindow = GDK_SCREEN_XROOTWIN (screen);
2759   xdisplay = GDK_SCREEN_XDISPLAY (screen);
2760
2761   /* This function really only works if the mouse pointer is held still
2762    * during its operation. If it moves from one leaf window to another
2763    * than we'll end up with inaccurate values for win_x, win_y
2764    * and the result.
2765    */
2766   XGrabServer (xdisplay);
2767   XQueryPointer (xdisplay, xwindow,
2768                  &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
2769
2770   if (root == xwindow)
2771     xwindow = child;
2772   else
2773     xwindow = root;
2774   
2775   while (xwindow)
2776     {
2777       xwindow_last = xwindow;
2778       XQueryPointer (xdisplay, xwindow,
2779                      &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
2780     }
2781   XUngrabServer (xdisplay);
2782
2783   window = gdk_window_lookup_for_display (GDK_SCREEN_DISPLAY(screen),
2784                                           xwindow_last);
2785   *win_x = window ? winx : -1;
2786   *win_y = window ? winy : -1;
2787
2788   return window;
2789 }
2790
2791 /**
2792  * gdk_window_get_events:
2793  * @window: a #GdkWindow
2794  * 
2795  * Gets the event mask for @window. See gdk_window_set_events().
2796  * 
2797  * Return value: event mask for @window
2798  **/
2799 GdkEventMask  
2800 gdk_window_get_events (GdkWindow *window)
2801 {
2802   XWindowAttributes attrs;
2803   GdkEventMask event_mask;
2804   
2805   g_return_val_if_fail (window != NULL, 0);
2806   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2807
2808   if (GDK_WINDOW_DESTROYED (window))
2809     return 0;
2810   else
2811     {
2812       XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2813                             GDK_WINDOW_XID (window), 
2814                             &attrs);
2815       
2816       event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
2817       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
2818   
2819       return event_mask;
2820     }
2821 }
2822
2823 /**
2824  * gdk_window_set_events:
2825  * @window: a #GdkWindow
2826  * @event_mask: event mask for @window
2827  *
2828  * The event mask for a window determines which events will be reported
2829  * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK
2830  * means the window should report button press events. The event mask
2831  * is the bitwise OR of values from the #GdkEventMask enumeration.
2832  * 
2833  **/
2834 void          
2835 gdk_window_set_events (GdkWindow       *window,
2836                        GdkEventMask     event_mask)
2837 {
2838   long xevent_mask;
2839   int i;
2840   
2841   g_return_if_fail (window != NULL);
2842   g_return_if_fail (GDK_IS_WINDOW (window));
2843   
2844   if (!GDK_WINDOW_DESTROYED (window))
2845     {
2846       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
2847       xevent_mask = StructureNotifyMask | PropertyChangeMask;
2848       for (i = 0; i < _gdk_nenvent_masks; i++)
2849         {
2850           if (event_mask & (1 << (i + 1)))
2851             xevent_mask |= _gdk_event_mask_table[i];
2852         }
2853       
2854       XSelectInput (GDK_WINDOW_XDISPLAY (window),
2855                     GDK_WINDOW_XID (window),
2856                     xevent_mask);
2857     }
2858 }
2859
2860 static void
2861 gdk_window_add_colormap_windows (GdkWindow *window)
2862 {
2863   GdkWindow *toplevel;
2864   Window *old_windows;
2865   Window *new_windows;
2866   int i, count;
2867   
2868   g_return_if_fail (window != NULL);
2869   g_return_if_fail (GDK_IS_WINDOW (window));
2870
2871   if (GDK_WINDOW_DESTROYED (window))
2872     return;
2873   toplevel = gdk_window_get_toplevel (window);
2874   
2875   old_windows = NULL;
2876   if (!XGetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2877                               GDK_WINDOW_XID (toplevel),
2878                               &old_windows, &count))
2879     {
2880       count = 0;
2881     }
2882   
2883   for (i = 0; i < count; i++)
2884     if (old_windows[i] == GDK_WINDOW_XID (window))
2885       {
2886         XFree (old_windows);
2887         return;
2888       }
2889   
2890   new_windows = g_new (Window, count + 1);
2891   
2892   for (i = 0; i < count; i++)
2893     new_windows[i] = old_windows[i];
2894   new_windows[count] = GDK_WINDOW_XID (window);
2895   
2896   XSetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2897                          GDK_WINDOW_XID (toplevel),
2898                          new_windows, count + 1);
2899   
2900   g_free (new_windows);
2901   if (old_windows)
2902     XFree (old_windows);
2903 }
2904
2905 static gboolean
2906 gdk_window_have_shape_ext (GdkDisplay *display)
2907 {
2908   GdkDisplayX11 *display_x11;
2909   
2910   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
2911
2912   display_x11 = GDK_DISPLAY_X11 (display);
2913   
2914   if (display_x11->have_shape == GDK_UNKNOWN)
2915     {
2916       int ignore;
2917       if (XQueryExtension (display_x11->xdisplay, "SHAPE", &ignore, &ignore, &ignore))
2918         display_x11->have_shape = GDK_YES;
2919       else
2920         display_x11->have_shape = GDK_NO;
2921     }
2922   
2923   return (display_x11->have_shape == GDK_YES);
2924 }
2925
2926 #define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.")
2927
2928 /*
2929  * This needs the X11 shape extension.
2930  * If not available, shaped windows will look
2931  * ugly, but programs still work.    Stefan Wille
2932  */
2933 /**
2934  * gdk_window_shape_combine_mask:
2935  * @window: a #GdkWindow
2936  * @mask: shape mask
2937  * @x: X position of shape mask with respect to @window
2938  * @y: Y position of shape mask with respect to @window
2939  *
2940  * Applies a shape mask to @window. Pixels in @window corresponding to
2941  * set bits in the @mask will be visible; pixels in @window
2942  * corresponding to unset bits in the @mask will be transparent. This
2943  * gives a non-rectangular window.
2944  *
2945  * If @mask is %NULL, the shape mask will be unset, and the @x/@y
2946  * parameters are not used.
2947  *
2948  * On the X11 platform, this uses an X server extension which is
2949  * widely available on most common platforms, but not available on
2950  * very old X servers, and occasionally the implementation will be
2951  * buggy. On servers without the shape extension, this function
2952  * will do nothing.
2953  *
2954  * This function works on both toplevel and child windows.
2955  * 
2956  **/
2957 void
2958 gdk_window_shape_combine_mask (GdkWindow *window,
2959                                GdkBitmap *mask,
2960                                gint x, gint y)
2961 {
2962   Pixmap pixmap;
2963   gint xoffset, yoffset;
2964   
2965   g_return_if_fail (window != NULL);
2966   g_return_if_fail (GDK_IS_WINDOW (window));
2967   
2968 #ifdef HAVE_SHAPE_EXT
2969   if (GDK_WINDOW_DESTROYED (window))
2970     return;
2971
2972   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2973
2974   if (xoffset != 0 || yoffset != 0)
2975     {
2976       WARN_SHAPE_TOO_BIG ();
2977       return;
2978     }
2979   
2980   if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
2981     {
2982       if (mask)
2983         {
2984           pixmap = GDK_PIXMAP_XID (mask);
2985         }
2986       else
2987         {
2988           x = 0;
2989           y = 0;
2990           pixmap = None;
2991         }
2992       
2993       XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
2994                          GDK_WINDOW_XID (window),
2995                          ShapeBounding,
2996                          x, y,
2997                          pixmap,
2998                          ShapeSet);
2999     }
3000 #endif /* HAVE_SHAPE_EXT */
3001 }
3002
3003 /**
3004  * gdk_window_shape_combine_region:
3005  * @window: a #GdkWindow
3006  * @shape_region: region of window to be non-transparent
3007  * @offset_x: X position of @shape_region in @window coordinates
3008  * @offset_y: Y position of @shape_region in @window coordinates
3009  *
3010  * Makes pixels in @window outside @shape_region be transparent,
3011  * so that the window may be nonrectangular. See also
3012  * gdk_window_shape_combine_mask() to use a bitmap as the mask.
3013  *
3014  * If @shape_region is %NULL, the shape will be unset, so the whole
3015  * window will be opaque again. @offset_x and @offset_y are ignored
3016  * if @shape_region is %NULL.
3017  * 
3018  * On the X11 platform, this uses an X server extension which is
3019  * widely available on most common platforms, but not available on
3020  * very old X servers, and occasionally the implementation will be
3021  * buggy. On servers without the shape extension, this function
3022  * will do nothing.
3023  *
3024  * This function works on both toplevel and child windows.
3025  * 
3026  **/
3027 void
3028 gdk_window_shape_combine_region (GdkWindow *window,
3029                                  GdkRegion *shape_region,
3030                                  gint       offset_x,
3031                                  gint       offset_y)
3032 {
3033   gint xoffset, yoffset;
3034   
3035   g_return_if_fail (GDK_IS_WINDOW (window));
3036   
3037 #ifdef HAVE_SHAPE_EXT
3038   if (GDK_WINDOW_DESTROYED (window))
3039     return;
3040
3041   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
3042
3043   if (xoffset != 0 || yoffset != 0)
3044     {
3045       WARN_SHAPE_TOO_BIG ();
3046       return;
3047     }
3048   
3049   if (shape_region == NULL)
3050     {
3051       /* Use NULL mask to unset the shape */
3052       gdk_window_shape_combine_mask (window, NULL, 0, 0);
3053       return;
3054     }
3055   
3056   if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
3057     {
3058       gint n_rects = 0;
3059       XRectangle *xrects = NULL;
3060
3061       _gdk_region_get_xrectangles (shape_region,
3062                                    0, 0,
3063                                    &xrects, &n_rects);
3064       
3065       XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
3066                                GDK_WINDOW_XID (window),
3067                                ShapeBounding,
3068                                offset_x, offset_y,
3069                                xrects, n_rects,
3070                                ShapeSet,
3071                                YXBanded);
3072
3073       g_free (xrects);
3074     }
3075 #endif /* HAVE_SHAPE_EXT */
3076 }
3077
3078
3079 /**
3080  * gdk_window_set_override_redirect:
3081  * @window: a toplevel #GdkWindow
3082  * @override_redirect: %TRUE if window should be override redirect
3083  *
3084  * An override redirect window is not under the control of the window manager.
3085  * This means it won't have a titlebar, won't be minimizable, etc. - it will
3086  * be entirely under the control of the application. The window manager
3087  * can't see the override redirect window at all.
3088  *
3089  * Override redirect should only be used for short-lived temporary
3090  * windows, such as popup menus. #GtkMenu uses an override redirect
3091  * window in its implementation, for example.
3092  * 
3093  **/
3094 void
3095 gdk_window_set_override_redirect (GdkWindow *window,
3096                                   gboolean override_redirect)
3097 {
3098   XSetWindowAttributes attr;
3099   
3100   g_return_if_fail (window != NULL);
3101   g_return_if_fail (GDK_IS_WINDOW (window));
3102
3103   if (!GDK_WINDOW_DESTROYED (window))
3104     {
3105       attr.override_redirect = (override_redirect == FALSE)?False:True;
3106       XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3107                                GDK_WINDOW_XID (window),
3108                                CWOverrideRedirect,
3109                                &attr);
3110     }
3111 }
3112
3113
3114 /**
3115  * gdk_window_set_icon_list:
3116  * @window: The #GdkWindow toplevel window to set the icon of.
3117  * @pixbufs: A list of pixbufs, of different sizes.
3118  *
3119  * Sets a list of icons for the window. One of these will be used
3120  * to represent the window when it has been iconified. The icon is
3121  * usually shown in an icon box or some sort of task bar. Which icon
3122  * size is shown depends on the window manager. The window manager
3123  * can scale the icon  but setting several size icons can give better
3124  * image quality since the window manager may only need to scale the
3125  * icon by a small amount or not at all.
3126  *
3127  **/
3128 void
3129 gdk_window_set_icon_list (GdkWindow *window,
3130                           GList     *pixbufs)
3131 {
3132   gulong *data;
3133   guchar *pixels;
3134   gulong *p;
3135   gint size;
3136   GList *l;
3137   GdkPixbuf *pixbuf;
3138   gint width, height, stride;
3139   gint x, y;
3140   gint n_channels;
3141   GdkDisplay *display;
3142   
3143   g_return_if_fail (GDK_IS_WINDOW (window));
3144
3145   if (GDK_WINDOW_DESTROYED (window))
3146     return;
3147
3148   display = gdk_drawable_get_display (window);
3149   
3150   l = pixbufs;
3151   size = 0;
3152   
3153   while (l)
3154     {
3155       pixbuf = l->data;
3156       g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
3157
3158       width = gdk_pixbuf_get_width (pixbuf);
3159       height = gdk_pixbuf_get_height (pixbuf);
3160       
3161       size += 2 + width * height;
3162
3163       l = g_list_next (l);
3164     }
3165
3166   data = g_malloc (size * sizeof (gulong));
3167
3168   l = pixbufs;
3169   p = data;
3170   while (l)
3171     {
3172       pixbuf = l->data;
3173       
3174       width = gdk_pixbuf_get_width (pixbuf);
3175       height = gdk_pixbuf_get_height (pixbuf);
3176       stride = gdk_pixbuf_get_rowstride (pixbuf);
3177       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
3178       
3179       *p++ = width;
3180       *p++ = height;
3181
3182       pixels = gdk_pixbuf_get_pixels (pixbuf);
3183
3184       for (y = 0; y < height; y++)
3185         {
3186           for (x = 0; x < width; x++)
3187             {
3188               guchar r, g, b, a;
3189               
3190               r = pixels[y*stride + x*n_channels + 0];
3191               g = pixels[y*stride + x*n_channels + 1];
3192               b = pixels[y*stride + x*n_channels + 2];
3193               if (n_channels >= 4)
3194                 a = pixels[y*stride + x*n_channels + 3];
3195               else
3196                 a = 255;
3197               
3198               *p++ = a << 24 | r << 16 | g << 8 | b ;
3199             }
3200         }
3201
3202       l = g_list_next (l);
3203     }
3204
3205   if (size > 0)
3206     {
3207       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3208                        GDK_WINDOW_XID (window),
3209                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"),
3210                        XA_CARDINAL, 32,
3211                        PropModeReplace,
3212                        (guchar*) data, size);
3213     }
3214   else
3215     {
3216       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
3217                        GDK_WINDOW_XID (window),
3218                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"));
3219     }
3220   
3221   g_free (data);
3222 }
3223
3224 /**
3225  * gdk_window_set_icon:
3226  * @window: a toplevel #GdkWindow
3227  * @icon_window: a #GdkWindow to use for the icon, or %NULL to unset
3228  * @pixmap: a #GdkPixmap to use as the icon, or %NULL to unset
3229  * @mask: a 1-bit pixmap (#GdkBitmap) to use as mask for @pixmap, or %NULL to have none
3230  *
3231  * Sets the icon of @window as a pixmap or window. If using GTK+, investigate
3232  * gtk_window_set_default_icon_list() first, and then gtk_window_set_icon_list()
3233  * and gtk_window_set_icon(). If those don't meet your needs, look at
3234  * gdk_window_set_icon_list(). Only if all those are too high-level do you
3235  * want to fall back to gdk_window_set_icon().
3236  * 
3237  **/
3238 void          
3239 gdk_window_set_icon (GdkWindow *window, 
3240                      GdkWindow *icon_window,
3241                      GdkPixmap *pixmap,
3242                      GdkBitmap *mask)
3243 {
3244   XWMHints *wm_hints;
3245   
3246   g_return_if_fail (window != NULL);
3247   g_return_if_fail (GDK_IS_WINDOW (window));
3248
3249   if (GDK_WINDOW_DESTROYED (window))
3250     return;
3251
3252   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
3253                           GDK_WINDOW_XID (window));
3254   if (!wm_hints)
3255     wm_hints = XAllocWMHints ();
3256
3257   if (icon_window != NULL)
3258     {
3259       wm_hints->flags |= IconWindowHint;
3260       wm_hints->icon_window = GDK_WINDOW_XID (icon_window);
3261     }
3262   
3263   if (pixmap != NULL)
3264     {
3265       wm_hints->flags |= IconPixmapHint;
3266       wm_hints->icon_pixmap = GDK_PIXMAP_XID (pixmap);
3267     }
3268   
3269   if (mask != NULL)
3270     {
3271       wm_hints->flags |= IconMaskHint;
3272       wm_hints->icon_mask = GDK_PIXMAP_XID (mask);
3273     }
3274
3275   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
3276                GDK_WINDOW_XID (window), wm_hints);
3277   XFree (wm_hints);
3278 }
3279
3280 static gboolean
3281 gdk_window_icon_name_set (GdkWindow *window)
3282 {
3283   return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
3284                                                g_quark_from_static_string ("gdk-icon-name-set")));
3285 }
3286
3287 /**
3288  * gdk_window_set_icon_name:
3289  * @window: a toplevel #GdkWindow
3290  * @name: name of window while iconified (minimized)
3291  *
3292  * Windows may have a name used while minimized, distinct from the
3293  * name they display in their titlebar. Most of the time this is a bad
3294  * idea from a user interface standpoint. But you can set such a name
3295  * with this function, if you like.
3296  *
3297  **/
3298 void          
3299 gdk_window_set_icon_name (GdkWindow   *window, 
3300                           const gchar *name)
3301 {
3302   GdkDisplay *display;
3303   
3304   g_return_if_fail (window != NULL);
3305   g_return_if_fail (GDK_IS_WINDOW (window));
3306
3307   if (GDK_WINDOW_DESTROYED (window))
3308     return;
3309
3310   display = gdk_drawable_get_display (window);
3311
3312   g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
3313                       GUINT_TO_POINTER (TRUE));
3314
3315   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3316                    GDK_WINDOW_XID (window),
3317                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
3318                    gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
3319                    PropModeReplace, name, strlen (name));
3320   
3321   set_text_property (display, GDK_WINDOW_XID (window),
3322                      gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
3323                      name);
3324 }
3325
3326 /**
3327  * gdk_window_iconify:
3328  * @window: a toplevel #GdkWindow
3329  * 
3330  * Asks to iconify (minimize) @window. The window manager may choose
3331  * to ignore the request, but normally will honor it. Using
3332  * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
3333  *
3334  * This function only makes sense when @window is a toplevel window.
3335  *
3336  **/
3337 void
3338 gdk_window_iconify (GdkWindow *window)
3339 {
3340   GdkWindowObject *private;
3341   
3342   g_return_if_fail (window != NULL);
3343   g_return_if_fail (GDK_IS_WINDOW (window));
3344
3345   if (GDK_WINDOW_DESTROYED (window))
3346     return;
3347
3348   private = (GdkWindowObject*) window;
3349
3350   if (GDK_WINDOW_IS_MAPPED (window))
3351     {  
3352       XIconifyWindow (GDK_WINDOW_XDISPLAY (window),
3353                       GDK_WINDOW_XWINDOW (window),
3354                       gdk_screen_get_number (GDK_WINDOW_SCREEN (window)));
3355     }
3356   else
3357     {
3358       /* Flip our client side flag, the real work happens on map. */
3359       gdk_synthesize_window_state (window,
3360                                    0,
3361                                    GDK_WINDOW_STATE_ICONIFIED);
3362     }
3363 }
3364
3365 /**
3366  * gdk_window_deiconify:
3367  * @window: a toplevel #GdkWindow
3368  *
3369  * Attempt to deiconify (unminimize) @window. On X11 the window manager may
3370  * choose to ignore the request to deiconify. When using GTK+,
3371  * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet,
3372  * you probably want to use gtk_window_present(), which raises the window, focuses it,
3373  * unminimizes it, and puts it on the current desktop.
3374  *
3375  **/
3376 void
3377 gdk_window_deiconify (GdkWindow *window)
3378 {
3379   GdkWindowObject *private;
3380   
3381   g_return_if_fail (window != NULL);
3382   g_return_if_fail (GDK_IS_WINDOW (window));
3383
3384   if (GDK_WINDOW_DESTROYED (window))
3385     return;
3386
3387   private = (GdkWindowObject*) window;
3388
3389   if (GDK_WINDOW_IS_MAPPED (window))
3390     {  
3391       gdk_window_show (window);
3392     }
3393   else
3394     {
3395       /* Flip our client side flag, the real work happens on map. */
3396       gdk_synthesize_window_state (window,
3397                                    GDK_WINDOW_STATE_ICONIFIED,
3398                                    0);
3399     }
3400 }
3401
3402 /**
3403  * gdk_window_stick:
3404  * @window: a toplevel #GdkWindow
3405  *
3406  * "Pins" a window such that it's on all workspaces and does not scroll
3407  * with viewports, for window managers that have scrollable viewports.
3408  * (When using #GtkWindow, gtk_window_stick() may be more useful.)
3409  *
3410  * On the X11 platform, this function depends on window manager
3411  * support, so may have no effect with many window managers. However,
3412  * GDK will do the best it can to convince the window manager to stick
3413  * the window. For window managers that don't support this operation,
3414  * there's nothing you can do to force it to happen.
3415  * 
3416  **/
3417 void
3418 gdk_window_stick (GdkWindow *window)
3419 {
3420   g_return_if_fail (GDK_IS_WINDOW (window));
3421
3422   if (GDK_WINDOW_DESTROYED (window))
3423     return;
3424
3425   if (GDK_WINDOW_IS_MAPPED (window))
3426     {
3427       /* "stick" means stick to all desktops _and_ do not scroll with the
3428        * viewport. i.e. glue to the monitor glass in all cases.
3429        */
3430       
3431       XEvent xev;
3432
3433       /* Request stick during viewport scroll */
3434       gdk_wmspec_change_state (TRUE, window,
3435                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
3436                                0);
3437
3438       /* Request desktop 0xFFFFFFFF */
3439       xev.xclient.type = ClientMessage;
3440       xev.xclient.serial = 0;
3441       xev.xclient.send_event = True;
3442       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
3443       xev.xclient.display = GDK_WINDOW_XDISPLAY (window);
3444       xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), 
3445                                                                         "_NET_WM_DESKTOP");
3446       xev.xclient.format = 32;
3447
3448       xev.xclient.data.l[0] = 0xFFFFFFFF;
3449
3450       XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
3451                   SubstructureRedirectMask | SubstructureNotifyMask,
3452                   &xev);
3453     }
3454   else
3455     {
3456       /* Flip our client side flag, the real work happens on map. */
3457       gdk_synthesize_window_state (window,
3458                                    0,
3459                                    GDK_WINDOW_STATE_STICKY);
3460     }
3461 }
3462
3463 /**
3464  * gdk_window_unstick:
3465  * @window: a toplevel #GdkWindow
3466  *
3467  * Reverse operation for gdk_window_stick(); see gdk_window_stick(),
3468  * and gtk_window_unstick().
3469  * 
3470  **/
3471 void
3472 gdk_window_unstick (GdkWindow *window)
3473 {
3474   g_return_if_fail (GDK_IS_WINDOW (window));
3475
3476   if (GDK_WINDOW_DESTROYED (window))
3477     return;
3478
3479   if (GDK_WINDOW_IS_MAPPED (window))
3480     {
3481       XEvent xev;
3482       Atom type;
3483       gint format;
3484       gulong nitems;
3485       gulong bytes_after;
3486       gulong *current_desktop;
3487       GdkDisplay *display = gdk_drawable_get_display (window);
3488       
3489       /* Request unstick from viewport */
3490       gdk_wmspec_change_state (FALSE, window,
3491                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
3492                                0);
3493
3494       /* Get current desktop, then set it; this is a race, but not
3495        * one that matters much in practice.
3496        */
3497       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window),
3498                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"),
3499                           0, G_MAXLONG,
3500                           False, XA_CARDINAL, &type, &format, &nitems,
3501                           &bytes_after, (guchar **)&current_desktop);
3502
3503       if (type == XA_CARDINAL)
3504         {
3505           xev.xclient.type = ClientMessage;
3506           xev.xclient.serial = 0;
3507           xev.xclient.send_event = True;
3508           xev.xclient.window = GDK_WINDOW_XWINDOW (window);
3509           xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
3510           xev.xclient.format = 32;
3511
3512           xev.xclient.data.l[0] = *current_desktop;
3513       
3514           XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
3515                       SubstructureRedirectMask | SubstructureNotifyMask,
3516                       &xev);
3517
3518           XFree (current_desktop);
3519         }
3520     }
3521   else
3522     {
3523       /* Flip our client side flag, the real work happens on map. */
3524       gdk_synthesize_window_state (window,
3525                                    GDK_WINDOW_STATE_STICKY,
3526                                    0);
3527
3528     }
3529 }
3530
3531 /**
3532  * gdk_window_maximize:
3533  * @window: a toplevel #GdkWindow
3534  *
3535  * Maximizes the window. If the window was already maximized, then
3536  * this function does nothing.
3537  * 
3538  * On X11, asks the window manager to maximize @window, if the window
3539  * manager supports this operation. Not all window managers support
3540  * this, and some deliberately ignore it or don't have a concept of
3541  * "maximized"; so you can't rely on the maximization actually
3542  * happening. But it will happen with most standard window managers,
3543  * and GDK makes a best effort to get it to happen.
3544  *
3545  * On Windows, reliably maximizes the window.
3546  * 
3547  **/
3548 void
3549 gdk_window_maximize (GdkWindow *window)
3550 {
3551   g_return_if_fail (GDK_IS_WINDOW (window));
3552
3553   if (GDK_WINDOW_DESTROYED (window))
3554     return;
3555
3556   if (GDK_WINDOW_IS_MAPPED (window))
3557     gdk_wmspec_change_state (TRUE, window,
3558                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
3559                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
3560   else
3561     gdk_synthesize_window_state (window,
3562                                  0,
3563                                  GDK_WINDOW_STATE_MAXIMIZED);
3564 }
3565
3566 /**
3567  * gdk_window_unmaximize:
3568  * @window: a toplevel #GdkWindow
3569  *
3570  * Unmaximizes the window. If the window wasn't maximized, then this
3571  * function does nothing.
3572  * 
3573  * On X11, asks the window manager to unmaximize @window, if the
3574  * window manager supports this operation. Not all window managers
3575  * support this, and some deliberately ignore it or don't have a
3576  * concept of "maximized"; so you can't rely on the unmaximization
3577  * actually happening. But it will happen with most standard window
3578  * managers, and GDK makes a best effort to get it to happen.
3579  *
3580  * On Windows, reliably unmaximizes the window.
3581  * 
3582  **/
3583 void
3584 gdk_window_unmaximize (GdkWindow *window)
3585 {
3586   g_return_if_fail (GDK_IS_WINDOW (window));
3587
3588   if (GDK_WINDOW_DESTROYED (window))
3589     return;
3590
3591   if (GDK_WINDOW_IS_MAPPED (window))
3592     gdk_wmspec_change_state (FALSE, window,
3593                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
3594                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
3595   else
3596     gdk_synthesize_window_state (window,
3597                                  GDK_WINDOW_STATE_MAXIMIZED,
3598                                  0);
3599 }
3600
3601 /**
3602  * gdk_window_fullscreen:
3603  * @window: a toplevel #GdkWindow
3604  *
3605  * Moves the window into fullscreen mode. This means the
3606  * window covers the entire screen and is above any panels
3607  * or task bars.
3608  *
3609  * If the window was already fullscreen, then this function does nothing.
3610  * 
3611  * On X11, asks the window manager to put @window in a fullscreen
3612  * state, if the window manager supports this operation. Not all
3613  * window managers support this, and some deliberately ignore it or
3614  * don't have a concept of "fullscreen"; so you can't rely on the
3615  * fullscreenification actually happening. But it will happen with
3616  * most standard window managers, and GDK makes a best effort to get
3617  * it to happen.
3618  *
3619  * Since: 2.2
3620  **/
3621 void
3622 gdk_window_fullscreen (GdkWindow *window)
3623 {
3624   g_return_if_fail (GDK_IS_WINDOW (window));
3625
3626   if (GDK_WINDOW_DESTROYED (window))
3627     return;
3628
3629   if (GDK_WINDOW_IS_MAPPED (window))
3630     gdk_wmspec_change_state (TRUE, window,
3631                              gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE),
3632                              GDK_NONE);
3633
3634   else
3635     gdk_synthesize_window_state (window,
3636                                  0,
3637                                  GDK_WINDOW_STATE_FULLSCREEN);
3638 }
3639
3640 /**
3641  * gdk_window_unfullscreen:
3642  * @window: a toplevel #GdkWindow
3643  *
3644  * Moves the window out of fullscreen mode. If the window was not
3645  * fullscreen, does nothing.
3646  * 
3647  * On X11, asks the window manager to move @window out of the fullscreen
3648  * state, if the window manager supports this operation. Not all
3649  * window managers support this, and some deliberately ignore it or
3650  * don't have a concept of "fullscreen"; so you can't rely on the
3651  * unfullscreenification actually happening. But it will happen with
3652  * most standard window managers, and GDK makes a best effort to get
3653  * it to happen. 
3654  *
3655  * Since: 2.2
3656  **/
3657 void
3658 gdk_window_unfullscreen (GdkWindow *window)
3659 {
3660   g_return_if_fail (GDK_IS_WINDOW (window));
3661
3662   if (GDK_WINDOW_DESTROYED (window))
3663     return;
3664
3665   if (GDK_WINDOW_IS_MAPPED (window))
3666     gdk_wmspec_change_state (FALSE, window,
3667                              gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE),
3668                              GDK_NONE);
3669
3670   else
3671     gdk_synthesize_window_state (window,
3672                                  GDK_WINDOW_STATE_FULLSCREEN,
3673                                  0);
3674 }
3675
3676
3677 /**
3678  * gdk_window_set_group:
3679  * @window: a toplevel #GdkWindow
3680  * @leader: group leader window
3681  *
3682  * Sets the group leader window for @window. By default,
3683  * GDK sets the group leader for all toplevel windows
3684  * to a global window implicitly created by GDK. With this function
3685  * you can override this default.
3686  *
3687  * The group leader window allows the window manager to distinguish
3688  * all windows that belong to a single application. It may for example
3689  * allow users to minimize/unminimize all windows belonging to an
3690  * application at once. You should only set a non-default group window
3691  * if your application pretends to be multiple applications.
3692  * The group leader window may not be changed after a window has been
3693  * mapped (with gdk_window_show() for example).
3694  * 
3695  **/
3696 void          
3697 gdk_window_set_group (GdkWindow *window, 
3698                       GdkWindow *leader)
3699 {
3700   XWMHints *wm_hints;
3701   
3702   g_return_if_fail (window != NULL);
3703   g_return_if_fail (GDK_IS_WINDOW (window));
3704   g_return_if_fail (leader != NULL);
3705   g_return_if_fail (GDK_IS_WINDOW (leader));
3706
3707   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
3708     return;
3709   
3710   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
3711                           GDK_WINDOW_XID (window));
3712   if (!wm_hints)
3713     wm_hints = XAllocWMHints ();
3714
3715   wm_hints->flags |= WindowGroupHint;
3716   wm_hints->window_group = GDK_WINDOW_XID (leader);
3717
3718   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
3719                GDK_WINDOW_XID (window), wm_hints);
3720   XFree (wm_hints);
3721 }
3722
3723 static MotifWmHints *
3724 gdk_window_get_mwm_hints (GdkWindow *window)
3725 {
3726   GdkDisplay *display;
3727   Atom hints_atom = None;
3728   MotifWmHints *hints;
3729   Atom type;
3730   gint format;
3731   gulong nitems;
3732   gulong bytes_after;
3733   
3734   if (GDK_WINDOW_DESTROYED (window))
3735     return NULL;
3736
3737   display = gdk_drawable_get_display (window);
3738   
3739   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
3740
3741   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
3742                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3743                       False, AnyPropertyType, &type, &format, &nitems,
3744                       &bytes_after, (guchar **)&hints);
3745
3746   if (type == None)
3747     return NULL;
3748   
3749   return hints;
3750 }
3751
3752 static void
3753 gdk_window_set_mwm_hints (GdkWindow *window,
3754                           MotifWmHints *new_hints)
3755 {
3756   GdkDisplay *display;
3757   Atom hints_atom = None;
3758   MotifWmHints *hints;
3759   Atom type;
3760   gint format;
3761   gulong nitems;
3762   gulong bytes_after;
3763   
3764   if (GDK_WINDOW_DESTROYED (window))
3765     return;
3766   
3767   display = gdk_drawable_get_display (window);
3768   
3769   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
3770
3771   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
3772                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3773                       False, AnyPropertyType, &type, &format, &nitems,
3774                       &bytes_after, (guchar **)&hints);
3775   
3776   if (type == None)
3777     hints = new_hints;
3778   else
3779     {
3780       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
3781         {
3782           hints->flags |= MWM_HINTS_FUNCTIONS;
3783           hints->functions = new_hints->functions;
3784         }
3785       if (new_hints->flags & MWM_HINTS_DECORATIONS)
3786         {
3787           hints->flags |= MWM_HINTS_DECORATIONS;
3788           hints->decorations = new_hints->decorations;
3789         }
3790     }
3791   
3792   XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
3793                    hints_atom, hints_atom, 32, PropModeReplace,
3794                    (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
3795   
3796   if (hints != new_hints)
3797     XFree (hints);
3798 }
3799
3800 /**
3801  * gdk_window_set_decorations:
3802  * @window: a toplevel #GdkWindow
3803  * @decorations: decoration hint mask
3804  *
3805  * "Decorations" are the features the window manager adds to a toplevel #GdkWindow.
3806  * This function sets the traditional Motif window manager hints that tell the
3807  * window manager which decorations you would like your window to have.
3808  * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
3809  * using the GDK function directly.
3810  *
3811  * The @decorations argument is the logical OR of the fields in
3812  * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
3813  * mask, the other bits indicate which decorations should be turned off.
3814  * If #GDK_DECOR_ALL is not included, then the other bits indicate
3815  * which decorations should be turned on.
3816  *
3817  * Most window managers honor a decorations hint of 0 to disable all decorations,
3818  * but very few honor all possible combinations of bits.
3819  * 
3820  **/
3821 void
3822 gdk_window_set_decorations (GdkWindow      *window,
3823                             GdkWMDecoration decorations)
3824 {
3825   MotifWmHints hints;
3826   
3827   g_return_if_fail (window != NULL);
3828   g_return_if_fail (GDK_IS_WINDOW (window));
3829   
3830   hints.flags = MWM_HINTS_DECORATIONS;
3831   hints.decorations = decorations;
3832   
3833   gdk_window_set_mwm_hints (window, &hints);
3834 }
3835
3836 /**
3837  * gdk_window_get_decorations:
3838  * @window: The toplevel #GdkWindow to get the decorations from
3839  * @decorations: The window decorations will be written here
3840  *
3841  * Returns the decorations set on the GdkWindow with #gdk_window_set_decorations
3842  * Returns: TRUE if the window has decorations set, FALSE otherwise.
3843  **/
3844 gboolean
3845 gdk_window_get_decorations(GdkWindow       *window,
3846                            GdkWMDecoration *decorations)
3847 {
3848   MotifWmHints *hints;
3849   gboolean result = FALSE;
3850
3851   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
3852
3853   hints = gdk_window_get_mwm_hints (window);
3854   
3855   if (hints)
3856     {
3857       if (hints->flags & MWM_HINTS_DECORATIONS)
3858         {
3859           if (decorations)
3860             *decorations = hints->decorations;
3861           result = TRUE;
3862         }
3863       
3864       XFree (hints);
3865     }
3866
3867   return result;
3868 }
3869
3870 /**
3871  * gdk_window_set_functions:
3872  * @window: a toplevel #GdkWindow
3873  * @functions: bitmask of operations to allow on @window
3874  *
3875  * This function isn't really good for much. It sets the traditional
3876  * Motif window manager hint for which operations the window manager
3877  * should allow on a toplevel window. However, few window managers do
3878  * anything reliable or interesting with this hint. Many ignore it
3879  * entirely.
3880  *
3881  * The @functions argument is the logical OR of values from the
3882  * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
3883  * then the other bits indicate which functions to disable; if
3884  * it doesn't include #GDK_FUNC_ALL, it indicates which functions to
3885  * enable.
3886  * 
3887  **/
3888 void
3889 gdk_window_set_functions (GdkWindow    *window,
3890                           GdkWMFunction functions)
3891 {
3892   MotifWmHints hints;
3893   
3894   g_return_if_fail (window != NULL);
3895   g_return_if_fail (GDK_IS_WINDOW (window));
3896   
3897   hints.flags = MWM_HINTS_FUNCTIONS;
3898   hints.functions = functions;
3899   
3900   gdk_window_set_mwm_hints (window, &hints);
3901 }
3902
3903 #ifdef HAVE_SHAPE_EXT
3904
3905 /* 
3906  * propagate the shapes from all child windows of a GDK window to the parent 
3907  * window. Shamelessly ripped from Enlightenment's code
3908  * 
3909  * - Raster
3910  */
3911 struct _gdk_span
3912 {
3913   gint                start;
3914   gint                end;
3915   struct _gdk_span    *next;
3916 };
3917
3918 static void
3919 gdk_add_to_span (struct _gdk_span **s,
3920                  gint               x,
3921                  gint               xx)
3922 {
3923   struct _gdk_span *ptr1, *ptr2, *noo, *ss;
3924   gchar             spanning;
3925   
3926   ptr2 = NULL;
3927   ptr1 = *s;
3928   spanning = 0;
3929   ss = NULL;
3930   /* scan the spans for this line */
3931   while (ptr1)
3932     {
3933       /* -- -> new span */
3934       /* == -> existing span */
3935       /* ## -> spans intersect */
3936       /* if we are in the middle of spanning the span into the line */
3937       if (spanning)
3938         {
3939           /* case: ---- ==== */
3940           if (xx < ptr1->start - 1)
3941             {
3942               /* ends before next span - extend to here */
3943               ss->end = xx;
3944               return;
3945             }
3946           /* case: ----##=== */
3947           else if (xx <= ptr1->end)
3948             {
3949               /* crosses into next span - delete next span and append */
3950               ss->end = ptr1->end;
3951               ss->next = ptr1->next;
3952               g_free (ptr1);
3953               return;
3954             }
3955           /* case: ---###--- */
3956           else
3957             {
3958               /* overlaps next span - delete and keep checking */
3959               ss->next = ptr1->next;
3960               g_free (ptr1);
3961               ptr1 = ss;
3962             }
3963         }
3964       /* otherwise havent started spanning it in yet */
3965       else
3966         {
3967           /* case: ---- ==== */
3968           if (xx < ptr1->start - 1)
3969             {
3970               /* insert span here in list */
3971               noo = g_malloc (sizeof (struct _gdk_span));
3972               
3973               if (noo)
3974                 {
3975                   noo->start = x;
3976                   noo->end = xx;
3977                   noo->next = ptr1;
3978                   if (ptr2)
3979                     ptr2->next = noo;
3980                   else
3981                     *s = noo;
3982                 }
3983               return;
3984             }
3985           /* case: ----##=== */
3986           else if ((x < ptr1->start) && (xx <= ptr1->end))
3987             {
3988               /* expand this span to the left point of the new one */
3989               ptr1->start = x;
3990               return;
3991             }
3992           /* case: ===###=== */
3993           else if ((x >= ptr1->start) && (xx <= ptr1->end))
3994             {
3995               /* throw the span away */
3996               return;
3997             }
3998           /* case: ---###--- */
3999           else if ((x < ptr1->start) && (xx > ptr1->end))
4000             {
4001               ss = ptr1;
4002               spanning = 1;
4003               ptr1->start = x;
4004               ptr1->end = xx;
4005             }
4006           /* case: ===##---- */
4007           else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end))
4008             {
4009               ss = ptr1;
4010               spanning = 1;
4011               ptr1->end = xx;
4012             }
4013           /* case: ==== ---- */
4014           /* case handled by next loop iteration - first case */
4015         }
4016       ptr2 = ptr1;
4017       ptr1 = ptr1->next;
4018     }
4019   /* it started in the middle but spans beyond your current list */
4020   if (spanning)
4021     {
4022       ptr2->end = xx;
4023       return;
4024     }
4025   /* it does not start inside a span or in the middle, so add it to the end */
4026   noo = g_malloc (sizeof (struct _gdk_span));
4027   
4028   if (noo)
4029     {
4030       noo->start = x;
4031       noo->end = xx;
4032       if (ptr2)
4033         {
4034           noo->next = ptr2->next;
4035           ptr2->next = noo;
4036         }
4037       else
4038         {
4039           noo->next = NULL;
4040           *s = noo;
4041         }
4042     }
4043   return;
4044 }
4045
4046 static void
4047 gdk_add_rectangles (Display           *disp,
4048                     Window             win,
4049                     struct _gdk_span **spans,
4050                     gint               basew,
4051                     gint               baseh,
4052                     gint               x,
4053                     gint               y)
4054 {
4055   gint a, k;
4056   gint x1, y1, x2, y2;
4057   gint rn, ord;
4058   XRectangle *rl;
4059   
4060   rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord);
4061   if (rl)
4062     {
4063       /* go through all clip rects in this window's shape */
4064       for (k = 0; k < rn; k++)
4065         {
4066           /* for each clip rect, add it to each line's spans */
4067           x1 = x + rl[k].x;
4068           x2 = x + rl[k].x + (rl[k].width - 1);
4069           y1 = y + rl[k].y;
4070           y2 = y + rl[k].y + (rl[k].height - 1);
4071           if (x1 < 0)
4072             x1 = 0;
4073           if (y1 < 0)
4074             y1 = 0;
4075           if (x2 >= basew)
4076             x2 = basew - 1;
4077           if (y2 >= baseh)
4078             y2 = baseh - 1;
4079           for (a = y1; a <= y2; a++)
4080             {
4081               if ((x2 - x1) >= 0)
4082                 gdk_add_to_span (&spans[a], x1, x2);
4083             }
4084         }
4085       XFree (rl);
4086     }
4087 }
4088
4089 static void
4090 gdk_propagate_shapes (Display *disp,
4091                       Window   win,
4092                       gboolean merge)
4093 {
4094   Window              rt, par, *list = NULL;
4095   gint                i, j, num = 0, num_rects = 0;
4096   gint                x, y, contig;
4097   guint               w, h, d;
4098   gint                baseh, basew;
4099   XRectangle         *rects = NULL;
4100   struct _gdk_span  **spans = NULL, *ptr1, *ptr2, *ptr3;
4101   XWindowAttributes   xatt;
4102   
4103   XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d);
4104   if (h <= 0)
4105     return;
4106   basew = w;
4107   baseh = h;
4108   spans = g_malloc (sizeof (struct _gdk_span *) * h);
4109   
4110   for (i = 0; i < h; i++)
4111     spans[i] = NULL;
4112   XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num);
4113   if (list)
4114     {
4115       /* go through all child windows and create/insert spans */
4116       for (i = 0; i < num; i++)
4117         {
4118           if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped))
4119             if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d))
4120               gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y);
4121         }
4122       if (merge)
4123         gdk_add_rectangles (disp, win, spans, basew, baseh, x, y);
4124       
4125       /* go through the spans list and build a list of rects */
4126       rects = g_malloc (sizeof (XRectangle) * 256);
4127       num_rects = 0;
4128       for (i = 0; i < baseh; i++)
4129         {
4130           ptr1 = spans[i];
4131           /* go through the line for all spans */
4132           while (ptr1)
4133             {
4134               rects[num_rects].x = ptr1->start;
4135               rects[num_rects].y = i;
4136               rects[num_rects].width = ptr1->end - ptr1->start + 1;
4137               rects[num_rects].height = 1;
4138               j = i + 1;
4139               /* if there are more lines */
4140               contig = 1;
4141               /* while contigous rects (same start/end coords) exist */
4142               while ((contig) && (j < baseh))
4143                 {
4144                   /* search next line for spans matching this one */
4145                   contig = 0;
4146                   ptr2 = spans[j];
4147                   ptr3 = NULL;
4148                   while (ptr2)
4149                     {
4150                       /* if we have an exact span match set contig */
4151                       if ((ptr2->start == ptr1->start) &&
4152                           (ptr2->end == ptr1->end))
4153                         {
4154                           contig = 1;
4155                           /* remove the span - not needed */
4156                           if (ptr3)
4157                             {
4158                               ptr3->next = ptr2->next;
4159                               g_free (ptr2);
4160                               ptr2 = NULL;
4161                             }
4162                           else
4163                             {
4164                               spans[j] = ptr2->next;
4165                               g_free (ptr2);
4166                               ptr2 = NULL;
4167                             }
4168                           break;
4169                         }
4170                       /* gone past the span point no point looking */
4171                       else if (ptr2->start < ptr1->start)
4172                         break;
4173                       if (ptr2)
4174                         {
4175                           ptr3 = ptr2;
4176                           ptr2 = ptr2->next;
4177                         }
4178                     }
4179                   /* if a contiguous span was found increase the rect h */
4180                   if (contig)
4181                     {
4182                       rects[num_rects].height++;
4183                       j++;
4184                     }
4185                 }
4186               /* up the rect count */
4187               num_rects++;
4188               /* every 256 new rects increase the rect array */
4189               if ((num_rects % 256) == 0)
4190                 rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256));
4191               ptr1 = ptr1->next;
4192             }
4193         }
4194       /* set the rects as the shape mask */
4195       if (rects)
4196         {
4197           XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects,
4198                                    ShapeSet, YXSorted);
4199           g_free (rects);
4200         }
4201       XFree (list);
4202     }
4203   /* free up all the spans we made */
4204   for (i = 0; i < baseh; i++)
4205     {
4206       ptr1 = spans[i];
4207       while (ptr1)
4208         {
4209           ptr2 = ptr1;
4210           ptr1 = ptr1->next;
4211           g_free (ptr2);
4212         }
4213     }
4214   g_free (spans);
4215 }
4216
4217 #endif /* HAVE_SHAPE_EXT */
4218
4219 /**
4220  * gdk_window_set_child_shapes:
4221  * @window: a #GdkWindow
4222  * 
4223  * Sets the shape mask of @window to the union of shape masks
4224  * for all children of @window, ignoring the shape mask of @window
4225  * itself. Contrast with gdk_window_merge_child_shapes() which includes
4226  * the shape mask of @window in the masks to be merged.
4227  **/
4228 void
4229 gdk_window_set_child_shapes (GdkWindow *window)
4230 {
4231   g_return_if_fail (window != NULL);
4232   g_return_if_fail (GDK_IS_WINDOW (window));
4233   
4234 #ifdef HAVE_SHAPE_EXT
4235   if (!GDK_WINDOW_DESTROYED (window) &&
4236       gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
4237     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
4238                           GDK_WINDOW_XID (window), FALSE);
4239 #endif   
4240 }
4241
4242 /**
4243  * gdk_window_merge_child_shapes:
4244  * @window: a #GdkWindow
4245  * 
4246  * Merges the shape masks for any child windows into the
4247  * shape mask for @window. i.e. the union of all masks
4248  * for @window and its children will become the new mask
4249  * for @window. See gdk_window_shape_combine_mask().
4250  *
4251  * This function is distinct from gdk_window_set_child_shapes()
4252  * because it includes @window's shape mask in the set of shapes to
4253  * be merged.
4254  * 
4255  **/
4256 void
4257 gdk_window_merge_child_shapes (GdkWindow *window)
4258 {
4259   g_return_if_fail (window != NULL);
4260   g_return_if_fail (GDK_IS_WINDOW (window));
4261   
4262 #ifdef HAVE_SHAPE_EXT
4263   if (!GDK_WINDOW_DESTROYED (window) &&
4264       gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
4265     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
4266                           GDK_WINDOW_XID (window), TRUE);
4267 #endif   
4268 }
4269
4270 /* Support for windows that can be guffaw-scrolled
4271  * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
4272  */
4273
4274 static gboolean
4275 gdk_window_gravity_works (GdkWindow *window)
4276 {
4277   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (window));
4278   
4279   if (display_x11->gravity_works == GDK_UNKNOWN)
4280     {
4281       GdkWindowAttr attr;
4282       GdkWindow *parent;
4283       GdkWindow *child;
4284       gint y;
4285       
4286       /* This particular server apparently has a bug so that the test
4287        * works but the actual code crashes it
4288        */
4289       if ((!strcmp (XServerVendor (display_x11->xdisplay),
4290                     "Sun Microsystems, Inc.")) &&
4291           (VendorRelease (display_x11->xdisplay) == 3400))
4292         {
4293           display_x11->gravity_works = GDK_NO;
4294           return FALSE;
4295         }
4296       
4297       attr.window_type = GDK_WINDOW_TEMP;
4298       attr.wclass = GDK_INPUT_OUTPUT;
4299       attr.x = 0;
4300       attr.y = 0;
4301       attr.width = 100;
4302       attr.height = 100;
4303       attr.event_mask = 0;
4304       
4305       parent = gdk_window_new (gdk_screen_get_root_window (GDK_DRAWABLE_SCREEN (window)),
4306                                &attr, GDK_WA_X | GDK_WA_Y);
4307       
4308       attr.window_type = GDK_WINDOW_CHILD;
4309       child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
4310       
4311       gdk_window_set_static_win_gravity (child, TRUE);
4312       
4313       gdk_window_resize (parent, 100, 110);
4314
4315       gdk_window_move (parent, 0, -10);
4316       gdk_window_move_resize (parent, 0, 0, 100, 100);
4317       
4318       gdk_window_resize (parent, 100, 110);
4319       gdk_window_move (parent, 0, -10);
4320       gdk_window_move_resize (parent, 0, 0, 100, 100);
4321       
4322       gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
4323       
4324       gdk_window_destroy (parent);
4325       gdk_window_destroy (child);
4326       
4327       display_x11->gravity_works = ((y == -20) ? GDK_YES : GDK_NO);
4328     }
4329   
4330   return (display_x11->gravity_works == GDK_YES);
4331 }
4332
4333 static void
4334 gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
4335 {
4336   XSetWindowAttributes xattributes;
4337   GdkWindowObject *private;
4338   guint xattributes_mask = 0;
4339   
4340   g_return_if_fail (window != NULL);
4341
4342   private = GDK_WINDOW_OBJECT (window);
4343   if (private->input_only)
4344     return;
4345   
4346   xattributes.bit_gravity = StaticGravity;
4347   xattributes_mask |= CWBitGravity;
4348   xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
4349   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
4350                            GDK_WINDOW_XID (window),
4351                            CWBitGravity,  &xattributes);
4352 }
4353
4354 static void
4355 gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
4356 {
4357   XSetWindowAttributes xattributes;
4358   
4359   g_return_if_fail (window != NULL);
4360   
4361   xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
4362   
4363   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
4364                            GDK_WINDOW_XID (window),
4365                            CWWinGravity,  &xattributes);
4366 }
4367
4368 /**
4369  * gdk_window_set_static_gravities:
4370  * @window: a #GdkWindow
4371  * @use_static: %TRUE to turn on static gravity
4372  *
4373  * Set the bit gravity of the given window to static, and flag it so
4374  * all children get static subwindow gravity. This is used if you are
4375  * implementing scary features that involve deep knowledge of the
4376  * windowing system. Don't worry about it unless you have to.
4377  * 
4378  * Return value: %TRUE if the server supports static gravity
4379  **/
4380 gboolean 
4381 gdk_window_set_static_gravities (GdkWindow *window,
4382                                  gboolean   use_static)
4383 {
4384   GdkWindowObject *private = (GdkWindowObject *)window;
4385   GList *tmp_list;
4386   
4387   g_return_val_if_fail (window != NULL, FALSE);
4388   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
4389
4390   if (!use_static == !private->guffaw_gravity)
4391     return TRUE;
4392   
4393   if (use_static && !gdk_window_gravity_works (window))
4394     return FALSE;
4395   
4396   private->guffaw_gravity = use_static;
4397   
4398   if (!GDK_WINDOW_DESTROYED (window))
4399     {
4400       gdk_window_set_static_bit_gravity (window, use_static);
4401       
4402       tmp_list = private->children;
4403       while (tmp_list)
4404         {
4405           gdk_window_set_static_win_gravity (tmp_list->data, use_static);
4406           
4407           tmp_list = tmp_list->next;
4408         }
4409     }
4410   
4411   return TRUE;
4412 }
4413
4414 static void
4415 wmspec_moveresize (GdkWindow *window,
4416                    gint       direction,
4417                    gint       root_x,
4418                    gint       root_y,
4419                    guint32    timestamp)     
4420 {
4421   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
4422   
4423   XEvent xev;
4424
4425   /* Release passive grab */
4426   gdk_display_pointer_ungrab (display, timestamp);
4427
4428   xev.xclient.type = ClientMessage;
4429   xev.xclient.serial = 0;
4430   xev.xclient.send_event = True;
4431   xev.xclient.window = GDK_WINDOW_XID (window);
4432   xev.xclient.message_type =
4433     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
4434   xev.xclient.format = 32;
4435   xev.xclient.data.l[0] = root_x;
4436   xev.xclient.data.l[1] = root_y;
4437   xev.xclient.data.l[2] = direction;
4438   xev.xclient.data.l[3] = 0;
4439   xev.xclient.data.l[4] = 0;
4440   
4441   XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
4442               SubstructureRedirectMask | SubstructureNotifyMask,
4443               &xev);
4444 }
4445
4446 typedef struct _MoveResizeData MoveResizeData;
4447
4448 struct _MoveResizeData
4449 {
4450   GdkDisplay *display;
4451   
4452   GdkWindow *moveresize_window;
4453   GdkWindow *moveresize_emulation_window;
4454   gboolean is_resize;
4455   GdkWindowEdge resize_edge;
4456   gint moveresize_button;
4457   gint moveresize_x;
4458   gint moveresize_y;
4459   gint moveresize_orig_x;
4460   gint moveresize_orig_y;
4461   gint moveresize_orig_width;
4462   gint moveresize_orig_height;
4463   GdkWindowHints moveresize_geom_mask;
4464   GdkGeometry moveresize_geometry;
4465   Time moveresize_process_time;
4466   XEvent *moveresize_pending_event;
4467 };
4468
4469 /* From the WM spec */
4470 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
4471 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
4472 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
4473 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
4474 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
4475 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
4476 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
4477 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
4478 #define _NET_WM_MOVERESIZE_MOVE              8
4479
4480 static void
4481 wmspec_resize_drag (GdkWindow     *window,
4482                     GdkWindowEdge  edge,
4483                     gint           button,
4484                     gint           root_x,
4485                     gint           root_y,
4486                     guint32        timestamp)
4487 {
4488   gint direction;
4489   
4490   /* Let the compiler turn a switch into a table, instead
4491    * of doing the table manually, this way is easier to verify.
4492    */
4493   switch (edge)
4494     {
4495     case GDK_WINDOW_EDGE_NORTH_WEST:
4496       direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
4497       break;
4498
4499     case GDK_WINDOW_EDGE_NORTH:
4500       direction = _NET_WM_MOVERESIZE_SIZE_TOP;
4501       break;
4502
4503     case GDK_WINDOW_EDGE_NORTH_EAST:
4504       direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
4505       break;
4506
4507     case GDK_WINDOW_EDGE_WEST:
4508       direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
4509       break;
4510
4511     case GDK_WINDOW_EDGE_EAST:
4512       direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
4513       break;
4514
4515     case GDK_WINDOW_EDGE_SOUTH_WEST:
4516       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
4517       break;
4518
4519     case GDK_WINDOW_EDGE_SOUTH:
4520       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
4521       break;
4522
4523     case GDK_WINDOW_EDGE_SOUTH_EAST:
4524       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
4525       break;
4526
4527     default:
4528       g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!",
4529                  edge);
4530       return;
4531       break;
4532     }
4533   
4534   wmspec_moveresize (window, direction, root_x, root_y, timestamp);
4535 }
4536
4537 static MoveResizeData *
4538 get_move_resize_data (GdkDisplay *display,
4539                       gboolean    create)
4540 {
4541   MoveResizeData *mv_resize;
4542   static GQuark move_resize_quark = 0;
4543
4544   if (!move_resize_quark)
4545     move_resize_quark = g_quark_from_static_string ("gdk-window-moveresize");
4546   
4547   mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark);
4548
4549   if (!mv_resize && create)
4550     {
4551       mv_resize = g_new0 (MoveResizeData, 1);
4552       mv_resize->display = display;
4553       
4554       g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize);
4555     }
4556
4557   return mv_resize;
4558 }
4559
4560 static void
4561 update_pos (MoveResizeData *mv_resize,
4562             gint            new_root_x,
4563             gint            new_root_y)
4564 {
4565   gint dx, dy;
4566
4567   dx = new_root_x - mv_resize->moveresize_x;
4568   dy = new_root_y - mv_resize->moveresize_y;
4569
4570   if (mv_resize->is_resize)
4571     {
4572       gint x, y, w, h;
4573
4574       x = mv_resize->moveresize_orig_x;
4575       y = mv_resize->moveresize_orig_y;
4576
4577       w = mv_resize->moveresize_orig_width;
4578       h = mv_resize->moveresize_orig_height;
4579
4580       switch (mv_resize->resize_edge)
4581         {
4582         case GDK_WINDOW_EDGE_NORTH_WEST:
4583           x += dx;
4584           y += dy;
4585           w -= dx;
4586           h -= dy;
4587           break;
4588         case GDK_WINDOW_EDGE_NORTH:
4589           y += dy;
4590           h -= dy;
4591           break;
4592         case GDK_WINDOW_EDGE_NORTH_EAST:
4593           y += dy;
4594           h -= dy;
4595           w += dx;
4596           break;
4597         case GDK_WINDOW_EDGE_SOUTH_WEST:
4598           h += dy;
4599           x += dx;
4600           w -= dx;
4601           break;
4602         case GDK_WINDOW_EDGE_SOUTH_EAST:
4603           w += dx;
4604           h += dy;
4605           break;
4606         case GDK_WINDOW_EDGE_SOUTH:
4607           h += dy;
4608           break;
4609         case GDK_WINDOW_EDGE_EAST:
4610           w += dx;
4611           break;
4612         case GDK_WINDOW_EDGE_WEST:
4613           x += dx;
4614           w -= dx;
4615           break;
4616         }
4617
4618       x = MAX (x, 0);
4619       y = MAX (y, 0);
4620       w = MAX (w, 1);
4621       h = MAX (h, 1);
4622
4623       if (mv_resize->moveresize_geom_mask)
4624         {
4625           gdk_window_constrain_size (&mv_resize->moveresize_geometry,
4626                                      mv_resize->moveresize_geom_mask,
4627                                      w, h, &w, &h);
4628         }
4629
4630       gdk_window_move_resize (mv_resize->moveresize_window, x, y, w, h);
4631     }
4632   else
4633     {
4634       gint x, y;
4635
4636       x = mv_resize->moveresize_orig_x + dx;
4637       y = mv_resize->moveresize_orig_y + dy;
4638
4639       gdk_window_move (mv_resize->moveresize_window, x, y);
4640     }
4641 }
4642
4643 static void
4644 finish_drag (MoveResizeData *mv_resize)
4645 {
4646   gdk_window_destroy (mv_resize->moveresize_emulation_window);
4647   mv_resize->moveresize_emulation_window = NULL;
4648   mv_resize->moveresize_window = NULL;
4649
4650   if (mv_resize->moveresize_pending_event)
4651     {
4652       g_free (mv_resize->moveresize_pending_event);
4653       mv_resize->moveresize_pending_event = NULL;
4654     }
4655 }
4656
4657 static int
4658 lookahead_motion_predicate (Display *xdisplay,
4659                             XEvent  *event,
4660                             XPointer arg)
4661 {
4662   gboolean *seen_release = (gboolean *)arg;
4663   GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
4664   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4665
4666   if (*seen_release)
4667     return False;
4668
4669   switch (event->xany.type)
4670     {
4671     case ButtonRelease:
4672       *seen_release = TRUE;
4673       break;
4674     case MotionNotify:
4675       mv_resize->moveresize_process_time = event->xmotion.time;
4676       break;
4677     default:
4678       break;
4679     }
4680
4681   return False;
4682 }
4683
4684 static gboolean
4685 moveresize_lookahead (MoveResizeData *mv_resize,
4686                       XEvent         *event)
4687 {
4688   XEvent tmp_event;
4689   gboolean seen_release = FALSE;
4690
4691   if (mv_resize->moveresize_process_time)
4692     {
4693       if (event->xmotion.time == mv_resize->moveresize_process_time)
4694         {
4695           mv_resize->moveresize_process_time = 0;
4696           return TRUE;
4697         }
4698       else
4699         return FALSE;
4700     }
4701
4702   XCheckIfEvent (event->xany.display, &tmp_event,
4703                  lookahead_motion_predicate, (XPointer) & seen_release);
4704
4705   return mv_resize->moveresize_process_time == 0;
4706 }
4707         
4708 gboolean
4709 _gdk_moveresize_handle_event (XEvent *event)
4710 {
4711   guint button_mask = 0;
4712   GdkWindowObject *window_private;
4713   GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
4714   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4715
4716   if (!mv_resize || !mv_resize->moveresize_window)
4717     return FALSE;
4718
4719   window_private = (GdkWindowObject *) mv_resize->moveresize_window;
4720
4721   button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
4722
4723   switch (event->xany.type)
4724     {
4725     case MotionNotify:
4726       if (window_private->resize_count > 0)
4727         {
4728           if (mv_resize->moveresize_pending_event)
4729             *mv_resize->moveresize_pending_event = *event;
4730           else
4731             mv_resize->moveresize_pending_event =
4732               g_memdup (event, sizeof (XEvent));
4733
4734           break;
4735         }
4736       if (!moveresize_lookahead (mv_resize, event))
4737         break;
4738
4739       update_pos (mv_resize,
4740                   event->xmotion.x_root,
4741                   event->xmotion.y_root);
4742
4743       /* This should never be triggered in normal cases, but in the
4744        * case where the drag started without an implicit grab being
4745        * in effect, we could miss the release if it occurs before
4746        * we grab the pointer; this ensures that we will never
4747        * get a permanently stuck grab.
4748        */
4749       if ((event->xmotion.state & button_mask) == 0)
4750         finish_drag (mv_resize);
4751       break;
4752
4753     case ButtonRelease:
4754       update_pos (mv_resize,
4755                   event->xbutton.x_root,
4756                   event->xbutton.y_root);
4757
4758       if (event->xbutton.button == mv_resize->moveresize_button)
4759         finish_drag (mv_resize);
4760       break;
4761     }
4762   return TRUE;
4763 }
4764
4765 gboolean 
4766 _gdk_moveresize_configure_done (GdkDisplay *display,
4767                                 GdkWindow  *window)
4768 {
4769   XEvent *tmp_event;
4770   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4771   
4772   if (!mv_resize || window != mv_resize->moveresize_window)
4773     return FALSE;
4774
4775   if (mv_resize->moveresize_pending_event)
4776     {
4777       tmp_event = mv_resize->moveresize_pending_event;
4778       mv_resize->moveresize_pending_event = NULL;
4779       _gdk_moveresize_handle_event (tmp_event);
4780       g_free (tmp_event);
4781     }
4782   
4783   return TRUE;
4784 }
4785
4786 static void
4787 create_moveresize_window (MoveResizeData *mv_resize,
4788                           guint32         timestamp)
4789 {
4790   GdkWindowAttr attributes;
4791   gint attributes_mask;
4792   GdkGrabStatus status;
4793
4794   g_assert (mv_resize->moveresize_emulation_window == NULL);
4795
4796   attributes.x = -100;
4797   attributes.y = -100;
4798   attributes.width = 10;
4799   attributes.height = 10;
4800   attributes.window_type = GDK_WINDOW_TEMP;
4801   attributes.wclass = GDK_INPUT_ONLY;
4802   attributes.override_redirect = TRUE;
4803   attributes.event_mask = 0;
4804
4805   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
4806
4807   mv_resize->moveresize_emulation_window = 
4808     gdk_window_new (gdk_screen_get_root_window (gdk_display_get_default_screen (mv_resize->display)),
4809                     &attributes,
4810                     attributes_mask);
4811
4812   gdk_window_show (mv_resize->moveresize_emulation_window);
4813
4814   status = gdk_pointer_grab (mv_resize->moveresize_emulation_window,
4815                              FALSE,
4816                              GDK_BUTTON_RELEASE_MASK |
4817                              GDK_POINTER_MOTION_MASK,
4818                              NULL,
4819                              NULL,
4820                              timestamp);
4821
4822   if (status != GDK_GRAB_SUCCESS)
4823     {
4824       /* If this fails, some other client has grabbed the window
4825        * already.
4826        */
4827       gdk_window_destroy (mv_resize->moveresize_emulation_window);
4828       mv_resize->moveresize_emulation_window = NULL;
4829     }
4830
4831   mv_resize->moveresize_process_time = 0;
4832 }
4833
4834 /* 
4835    Calculate mv_resize->moveresize_orig_x and mv_resize->moveresize_orig_y
4836    so that calling XMoveWindow with these coordinates will not move the 
4837    window.
4838    Note that this depends on the WM to implement ICCCM-compliant reference
4839    point handling.
4840 */
4841 static void 
4842 calculate_unmoving_origin (MoveResizeData *mv_resize)
4843 {
4844   GdkRectangle rect;
4845   gint width, height;
4846
4847   if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY &&
4848       mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC)
4849     {
4850       gdk_window_get_origin (mv_resize->moveresize_window,
4851                              &mv_resize->moveresize_orig_x,
4852                              &mv_resize->moveresize_orig_y);
4853     }
4854   else
4855     {
4856       gdk_window_get_frame_extents (mv_resize->moveresize_window, &rect);
4857       gdk_window_get_geometry (mv_resize->moveresize_window, 
4858                                NULL, NULL, &width, &height, NULL);
4859       
4860       switch (mv_resize->moveresize_geometry.win_gravity) 
4861         {
4862         case GDK_GRAVITY_NORTH_WEST:
4863           mv_resize->moveresize_orig_x = rect.x;
4864           mv_resize->moveresize_orig_y = rect.y;
4865           break;
4866         case GDK_GRAVITY_NORTH:
4867           mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
4868           mv_resize->moveresize_orig_y = rect.y;
4869           break;          
4870         case GDK_GRAVITY_NORTH_EAST:
4871           mv_resize->moveresize_orig_x = rect.x + rect.width - width;
4872           mv_resize->moveresize_orig_y = rect.y;
4873           break;
4874         case GDK_GRAVITY_WEST:
4875           mv_resize->moveresize_orig_x = rect.x;
4876           mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
4877           break;
4878         case GDK_GRAVITY_CENTER:
4879           mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
4880           mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
4881           break;
4882         case GDK_GRAVITY_EAST:
4883           mv_resize->moveresize_orig_x = rect.x + rect.width - width;
4884           mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
4885           break;
4886         case GDK_GRAVITY_SOUTH_WEST:
4887           mv_resize->moveresize_orig_x = rect.x;
4888           mv_resize->moveresize_orig_y = rect.y + rect.height - height;
4889           break;
4890         case GDK_GRAVITY_SOUTH:
4891           mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
4892           mv_resize->moveresize_orig_y = rect.y + rect.height - height;
4893           break;
4894         case GDK_GRAVITY_SOUTH_EAST:
4895           mv_resize->moveresize_orig_x = rect.x + rect.width - width;
4896           mv_resize->moveresize_orig_y = rect.y + rect.height - height;
4897           break;
4898         default:
4899           mv_resize->moveresize_orig_x = rect.x;
4900           mv_resize->moveresize_orig_y = rect.y;
4901           break; 
4902         }
4903     }  
4904 }
4905
4906 static void
4907 emulate_resize_drag (GdkWindow     *window,
4908                      GdkWindowEdge  edge,
4909                      gint           button,
4910                      gint           root_x,
4911                      gint           root_y,
4912                      guint32        timestamp)
4913 {
4914   MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE);
4915
4916   mv_resize->is_resize = TRUE;
4917   mv_resize->moveresize_button = button;
4918   mv_resize->resize_edge = edge;
4919   mv_resize->moveresize_x = root_x;
4920   mv_resize->moveresize_y = root_y;
4921   mv_resize->moveresize_window = g_object_ref (window);
4922
4923   gdk_drawable_get_size (window,
4924                          &mv_resize->moveresize_orig_width,
4925                          &mv_resize->moveresize_orig_height);
4926
4927   mv_resize->moveresize_geom_mask = 0;
4928   gdk_window_get_geometry_hints (window,
4929                                  &mv_resize->moveresize_geometry,
4930                                  &mv_resize->moveresize_geom_mask);
4931
4932   calculate_unmoving_origin (mv_resize);
4933
4934   create_moveresize_window (mv_resize, timestamp);
4935 }
4936
4937 static void
4938 emulate_move_drag (GdkWindow     *window,
4939                    gint           button,
4940                    gint           root_x,
4941                    gint           root_y,
4942                    guint32        timestamp)
4943 {
4944   MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE);
4945   
4946   mv_resize->is_resize = FALSE;
4947   mv_resize->moveresize_button = button;
4948   mv_resize->moveresize_x = root_x;
4949   mv_resize->moveresize_y = root_y;
4950
4951   mv_resize->moveresize_window = g_object_ref (window);
4952
4953   calculate_unmoving_origin (mv_resize);
4954
4955   create_moveresize_window (mv_resize, timestamp);
4956 }
4957
4958 /**
4959  * gdk_window_begin_resize_drag:
4960  * @window: a toplevel #GdkWindow
4961  * @edge: the edge or corner from which the drag is started
4962  * @button: the button being used to drag
4963  * @root_x: root window X coordinate of mouse click that began the drag
4964  * @root_y: root window Y coordinate of mouse click that began the drag
4965  * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
4966  *
4967  * Begins a window resize operation (for a toplevel window).
4968  * You might use this function to implement a "window resize grip," for
4969  * example; in fact #GtkStatusbar uses it. The function works best
4970  * with window managers that support the Extended Window Manager Hints spec
4971  * (see http://www.freedesktop.org), but has a fallback implementation
4972  * for other window managers.
4973  * 
4974  **/
4975 void
4976 gdk_window_begin_resize_drag (GdkWindow     *window,
4977                               GdkWindowEdge  edge,
4978                               gint           button,
4979                               gint           root_x,
4980                               gint           root_y,
4981                               guint32        timestamp)
4982 {
4983   g_return_if_fail (GDK_IS_WINDOW (window));
4984
4985   if (GDK_WINDOW_DESTROYED (window))
4986     return;
4987
4988   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
4989                                            gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
4990     wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp);
4991   else
4992     emulate_resize_drag (window, edge, button, root_x, root_y, timestamp);
4993 }
4994
4995 /**
4996  * gdk_window_begin_move_drag:
4997  * @window: a toplevel #GdkWindow
4998  * @button: the button being used to drag
4999  * @root_x: root window X coordinate of mouse click that began the drag
5000  * @root_y: root window Y coordinate of mouse click that began the drag
5001  * @timestamp: timestamp of mouse click that began the drag
5002  *
5003  * Begins a window move operation (for a toplevel window).  You might
5004  * use this function to implement a "window move grip," for
5005  * example. The function works best with window managers that support
5006  * the Extended Window Manager Hints spec (see
5007  * http://www.freedesktop.org), but has a fallback implementation for
5008  * other window managers.
5009  * 
5010  **/
5011 void
5012 gdk_window_begin_move_drag (GdkWindow *window,
5013                             gint       button,
5014                             gint       root_x,
5015                             gint       root_y,
5016                             guint32    timestamp)
5017 {
5018   g_return_if_fail (GDK_IS_WINDOW (window));
5019
5020   if (GDK_WINDOW_DESTROYED (window))
5021     return;
5022
5023   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
5024                                            gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
5025     wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE, root_x, root_y,
5026                        timestamp);
5027   else
5028     emulate_move_drag (window, button, root_x, root_y, timestamp);
5029 }