]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkwindow-x11.c
Set _NET_WM_PID and WM_CLIENT_MACHINE properties on each window, not just
[~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 "gdkprivate-x11.h"
38 #include "gdkregion.h"
39 #include "gdkinternals.h"
40 #include "MwmUtil.h"
41 #include "gdkwindow-x11.h"
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46
47
48 #ifdef HAVE_SHAPE_EXT
49 #include <X11/extensions/shape.h>
50 #endif
51
52 const int _gdk_event_mask_table[21] =
53 {
54   ExposureMask,
55   PointerMotionMask,
56   PointerMotionHintMask,
57   ButtonMotionMask,
58   Button1MotionMask,
59   Button2MotionMask,
60   Button3MotionMask,
61   ButtonPressMask,
62   ButtonReleaseMask,
63   KeyPressMask,
64   KeyReleaseMask,
65   EnterWindowMask,
66   LeaveWindowMask,
67   FocusChangeMask,
68   StructureNotifyMask,
69   PropertyChangeMask,
70   VisibilityChangeMask,
71   0,                            /* PROXIMITY_IN */
72   0,                            /* PROXIMTY_OUT */
73   SubstructureNotifyMask,
74   ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
75 };
76 const int _gdk_nenvent_masks = sizeof (_gdk_event_mask_table) / sizeof (int);
77
78 /* Forward declarations */
79 static gboolean gdk_window_gravity_works          (void);
80 static void     gdk_window_set_static_win_gravity (GdkWindow *window,
81                                                    gboolean   on);
82 static gboolean gdk_window_have_shape_ext         (void);
83 static gboolean gdk_window_icon_name_set          (GdkWindow *window);
84
85 static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable);
86 static void         gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
87                                                       GdkColormap *cmap);
88 static void         gdk_window_impl_x11_get_size    (GdkDrawable *drawable,
89                                                      gint *width,
90                                                      gint *height);
91 static GdkRegion*  gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable);
92 static void gdk_window_impl_x11_init       (GdkWindowImplX11      *window);
93 static void gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass);
94 static void gdk_window_impl_x11_finalize   (GObject            *object);
95
96 static gpointer parent_class = NULL;
97
98 GType
99 gdk_window_impl_x11_get_type (void)
100 {
101   static GType object_type = 0;
102
103   if (!object_type)
104     {
105       static const GTypeInfo object_info =
106       {
107         sizeof (GdkWindowImplX11Class),
108         (GBaseInitFunc) NULL,
109         (GBaseFinalizeFunc) NULL,
110         (GClassInitFunc) gdk_window_impl_x11_class_init,
111         NULL,           /* class_finalize */
112         NULL,           /* class_data */
113         sizeof (GdkWindowImplX11),
114         0,              /* n_preallocs */
115         (GInstanceInitFunc) gdk_window_impl_x11_init,
116       };
117       
118       object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_X11,
119                                             "GdkWindowImplX11",
120                                             &object_info, 0);
121     }
122   
123   return object_type;
124 }
125
126 GType
127 _gdk_window_impl_get_type (void)
128 {
129   return gdk_window_impl_x11_get_type ();
130 }
131
132 static void
133 gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
134 {
135   impl->width = 1;
136   impl->height = 1;
137 }
138
139 static void
140 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
141 {
142   GObjectClass *object_class = G_OBJECT_CLASS (klass);
143   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
144   
145   parent_class = g_type_class_peek_parent (klass);
146
147   object_class->finalize = gdk_window_impl_x11_finalize;
148
149   drawable_class->set_colormap = gdk_window_impl_x11_set_colormap;
150   drawable_class->get_colormap = gdk_window_impl_x11_get_colormap;
151   drawable_class->get_size = gdk_window_impl_x11_get_size;
152
153   /* Visible and clip regions are the same */
154   drawable_class->get_clip_region = gdk_window_impl_x11_get_visible_region;
155   drawable_class->get_visible_region = gdk_window_impl_x11_get_visible_region;
156 }
157
158 static void
159 gdk_window_impl_x11_finalize (GObject *object)
160 {
161   GdkWindowObject *wrapper;
162   GdkDrawableImplX11 *draw_impl;
163   GdkWindowImplX11 *window_impl;
164   
165   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));
166
167   draw_impl = GDK_DRAWABLE_IMPL_X11 (object);
168   window_impl = GDK_WINDOW_IMPL_X11 (object);
169   
170   wrapper = (GdkWindowObject*) draw_impl->wrapper;
171
172   if (!GDK_WINDOW_DESTROYED (wrapper))
173     {
174       gdk_xid_table_remove (draw_impl->xid);
175       if (window_impl->focus_window)
176         gdk_xid_table_remove (window_impl->focus_window);
177     }
178
179   G_OBJECT_CLASS (parent_class)->finalize (object);
180 }
181
182 static GdkColormap*
183 gdk_window_impl_x11_get_colormap (GdkDrawable *drawable)
184 {
185   GdkDrawableImplX11 *drawable_impl;
186   GdkWindowImplX11 *window_impl;
187   
188   g_return_val_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable), NULL);
189
190   drawable_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
191   window_impl = GDK_WINDOW_IMPL_X11 (drawable);
192
193   if (!((GdkWindowObject *) drawable_impl->wrapper)->input_only && 
194       drawable_impl->colormap == NULL)
195     {
196       XWindowAttributes window_attributes;
197
198       XGetWindowAttributes (drawable_impl->xdisplay,
199                             drawable_impl->xid,
200                             &window_attributes);
201       drawable_impl->colormap =
202         gdk_colormap_lookup (window_attributes.colormap);
203     }
204   
205   return drawable_impl->colormap;
206 }
207
208 static void
209 gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
210                                   GdkColormap *cmap)
211 {
212   GdkWindowImplX11 *impl;
213   GdkDrawableImplX11 *draw_impl;
214   
215   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
216
217   impl = GDK_WINDOW_IMPL_X11 (drawable);
218   draw_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
219
220   /* chain up */
221   GDK_DRAWABLE_CLASS (parent_class)->set_colormap (drawable, cmap);
222
223   if (cmap)
224     {
225       XSetWindowColormap (draw_impl->xdisplay,
226                           draw_impl->xid,
227                           GDK_COLORMAP_XCOLORMAP (cmap));
228       
229       if (((GdkWindowObject*)draw_impl->wrapper)->window_type !=
230           GDK_WINDOW_TOPLEVEL)
231         gdk_window_add_colormap_windows (GDK_WINDOW (draw_impl->wrapper));
232     }
233 }
234
235
236 static void
237 gdk_window_impl_x11_get_size (GdkDrawable *drawable,
238                               gint        *width,
239                               gint        *height)
240 {
241   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
242
243   if (width)
244     *width = GDK_WINDOW_IMPL_X11 (drawable)->width;
245   if (height)
246     *height = GDK_WINDOW_IMPL_X11 (drawable)->height;
247 }
248
249 static GdkRegion*
250 gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable)
251 {
252   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (drawable);
253   GdkRectangle result_rect;
254
255   result_rect.x = 0;
256   result_rect.y = 0;
257   result_rect.width = impl->width;
258   result_rect.height = impl->height;
259
260   gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect);
261
262   return gdk_region_rectangle (&result_rect);
263 }
264
265 void
266 _gdk_windowing_window_init (void)
267 {
268   GdkWindowObject *private;
269   GdkWindowImplX11 *impl;
270   GdkDrawableImplX11 *draw_impl;
271   XWindowAttributes xattributes;
272   unsigned int width;
273   unsigned int height;
274   unsigned int border_width;
275   unsigned int depth;
276   int x, y;
277
278   g_assert (_gdk_parent_root == NULL);
279   
280   XGetGeometry (gdk_display, _gdk_root_window, &_gdk_root_window,
281                 &x, &y, &width, &height, &border_width, &depth);
282   XGetWindowAttributes (gdk_display, _gdk_root_window, &xattributes);
283
284   _gdk_parent_root = g_object_new (GDK_TYPE_WINDOW, NULL);
285   private = (GdkWindowObject *)_gdk_parent_root;
286   impl = GDK_WINDOW_IMPL_X11 (private->impl);
287   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
288   
289   draw_impl->xdisplay = gdk_display;
290   draw_impl->xid = _gdk_root_window;
291   draw_impl->wrapper = GDK_DRAWABLE (private);
292   
293   private->window_type = GDK_WINDOW_ROOT;
294   private->depth = depth;
295   impl->width = width;
296   impl->height = height;
297   
298   gdk_xid_table_insert (&_gdk_root_window, _gdk_parent_root);
299 }
300
301 static GdkAtom wm_client_leader_atom = GDK_NONE;
302
303 GdkWindow*
304 gdk_window_new (GdkWindow     *parent,
305                 GdkWindowAttr *attributes,
306                 gint           attributes_mask)
307 {
308   GdkWindow *window;
309   GdkWindowObject *private;
310   GdkWindowObject *parent_private;
311   GdkWindowImplX11 *impl;
312   GdkDrawableImplX11 *draw_impl;
313   
314   GdkVisual *visual;
315   Window xparent;
316   Visual *xvisual;
317   Display *xdisplay;
318   Window xid;
319
320   XSetWindowAttributes xattributes;
321   long xattributes_mask;
322   XSizeHints size_hints;
323   XWMHints wm_hints;
324   XClassHint *class_hint;
325   int x, y, depth;
326   
327   unsigned int class;
328   char *title;
329   int i;
330   int pid;
331   
332   g_return_val_if_fail (attributes != NULL, NULL);
333   
334   if (!parent)
335     parent = _gdk_parent_root;
336
337   g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
338   
339   parent_private = (GdkWindowObject*) parent;
340   if (GDK_WINDOW_DESTROYED (parent))
341     return NULL;
342   
343   xparent = GDK_WINDOW_XID (parent);
344   
345   window = g_object_new (GDK_TYPE_WINDOW, NULL);
346   private = (GdkWindowObject *)window;
347   impl = GDK_WINDOW_IMPL_X11 (private->impl);
348   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
349   draw_impl->wrapper = GDK_DRAWABLE (window);
350   
351   xdisplay = draw_impl->xdisplay = GDK_WINDOW_XDISPLAY (parent); 
352   
353   private->parent = (GdkWindowObject *)parent;
354
355   xattributes_mask = 0;
356   
357   if (attributes_mask & GDK_WA_X)
358     x = attributes->x;
359   else
360     x = 0;
361   
362   if (attributes_mask & GDK_WA_Y)
363     y = attributes->y;
364   else
365     y = 0;
366   
367   private->x = x;
368   private->y = y;
369   impl->width = (attributes->width > 1) ? (attributes->width) : (1);
370   impl->height = (attributes->height > 1) ? (attributes->height) : (1);
371
372   if (attributes->wclass == GDK_INPUT_ONLY)
373     {
374       /* Backwards compatiblity - we've always ignored
375        * attributes->window_type for input-only windows
376        * before
377        */
378       if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT &&
379           GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
380         private->window_type = GDK_WINDOW_TEMP;
381       else
382         private->window_type = GDK_WINDOW_CHILD;
383     }
384   else
385     private->window_type = attributes->window_type;
386
387   _gdk_window_init_position (GDK_WINDOW (private));
388   if (impl->position_info.big)
389     private->guffaw_gravity = TRUE;
390   
391   if (attributes_mask & GDK_WA_VISUAL)
392     visual = attributes->visual;
393   else
394     visual = gdk_visual_get_system ();
395   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
396   
397   xattributes.event_mask = StructureNotifyMask;
398   for (i = 0; i < _gdk_nenvent_masks; i++)
399     {
400       if (attributes->event_mask & (1 << (i + 1)))
401         xattributes.event_mask |= _gdk_event_mask_table[i];
402     }
403   
404   if (xattributes.event_mask)
405     xattributes_mask |= CWEventMask;
406   
407   if (attributes_mask & GDK_WA_NOREDIR)
408     {
409       xattributes.override_redirect =
410         (attributes->override_redirect == FALSE)?False:True;
411       xattributes_mask |= CWOverrideRedirect;
412     } 
413   else
414     xattributes.override_redirect = False;
415
416   if (parent_private && parent_private->guffaw_gravity)
417     {
418       xattributes.win_gravity = StaticGravity;
419       xattributes_mask |= CWWinGravity;
420     }
421   
422   /* Sanity checks */
423   switch (private->window_type)
424     {
425     case GDK_WINDOW_TOPLEVEL:
426     case GDK_WINDOW_DIALOG:
427     case GDK_WINDOW_TEMP:
428       if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT &&
429           GDK_WINDOW_TYPE (parent) != GDK_WINDOW_FOREIGN)
430         {
431           g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
432                      "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
433           xparent = _gdk_root_window;
434         }
435     case GDK_WINDOW_CHILD:
436       break;
437     default:
438       g_warning (G_STRLOC "cannot make windows of type %d", private->window_type);
439       return NULL;
440     }
441           
442   if (attributes->wclass == GDK_INPUT_OUTPUT)
443     {
444       class = InputOutput;
445       depth = visual->depth;
446
447       private->input_only = FALSE;
448       private->depth = depth;
449       
450       if (attributes_mask & GDK_WA_COLORMAP)
451         {
452           draw_impl->colormap = attributes->colormap;
453           gdk_colormap_ref (attributes->colormap);
454         }
455       else
456         {
457           if ((((GdkVisualPrivate*)gdk_visual_get_system ())->xvisual) == xvisual)
458             {
459               draw_impl->colormap =
460                 gdk_colormap_get_system ();
461               gdk_colormap_ref (draw_impl->colormap);
462             }
463           else
464             {
465               draw_impl->colormap =
466                 gdk_colormap_new (visual, FALSE);
467             }
468         }
469       
470       private->bg_color.pixel = BlackPixel (gdk_display, _gdk_screen);
471       xattributes.background_pixel = private->bg_color.pixel;
472
473       private->bg_pixmap = NULL;
474       
475       xattributes.border_pixel = BlackPixel (gdk_display, _gdk_screen);
476       xattributes_mask |= CWBorderPixel | CWBackPixel;
477
478       if (private->guffaw_gravity)
479         xattributes.bit_gravity = StaticGravity;
480       else
481         xattributes.bit_gravity = NorthWestGravity;
482       
483       xattributes_mask |= CWBitGravity;
484
485       xattributes.colormap = GDK_COLORMAP_XCOLORMAP (draw_impl->colormap);
486       xattributes_mask |= CWColormap;
487
488       if (private->window_type == GDK_WINDOW_TEMP)
489         {
490           xattributes.save_under = True;
491           xattributes.override_redirect = True;
492           xattributes.cursor = None;
493           xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
494         }
495     }
496   else
497     {
498       depth = 0;
499       private->depth = 0;
500       class = InputOnly;
501       private->input_only = TRUE;
502       draw_impl->colormap = gdk_colormap_get_system ();
503       gdk_colormap_ref (draw_impl->colormap);
504     }
505
506   xid = draw_impl->xid = XCreateWindow (xdisplay, xparent,
507                                         impl->position_info.x, impl->position_info.y,
508                                         impl->position_info.width, impl->position_info.height,
509                                         0, depth, class, xvisual,
510                                         xattributes_mask, &xattributes);
511
512   gdk_drawable_ref (window);
513   gdk_xid_table_insert (&draw_impl->xid, window);
514   
515   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
516                                   (attributes->cursor) :
517                                   NULL));
518   
519   if (parent_private)
520     parent_private->children = g_list_prepend (parent_private->children, window);
521   
522   switch (GDK_WINDOW_TYPE (private))
523     {
524     case GDK_WINDOW_DIALOG:
525       XSetTransientForHint (xdisplay, xid, xparent);
526     case GDK_WINDOW_TOPLEVEL:
527     case GDK_WINDOW_TEMP:
528       XSetWMProtocols (xdisplay, xid,
529                        _gdk_wm_window_protocols, 3);
530       break;
531     case GDK_WINDOW_CHILD:
532       if ((attributes->wclass == GDK_INPUT_OUTPUT) &&
533           (draw_impl->colormap != gdk_colormap_get_system ()) &&
534           (draw_impl->colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window))))
535         {
536           GDK_NOTE (MISC, g_message ("adding colormap window\n"));
537           gdk_window_add_colormap_windows (window);
538         }
539       
540       return window;
541     default:
542       
543       return window;
544     }
545
546   if (class != InputOnly)
547     {
548       /* The focus window is off the visible area, and serves to receive key
549        * press events so they don't get sent to child windows.
550        */
551       impl->focus_window = XCreateSimpleWindow (xdisplay, xid,
552                                                 -1, -1, 1, 1, 0,
553                                                 xattributes.background_pixel,
554                                                 xattributes.background_pixel);
555       /* FIXME: probably better to actually track the requested event mask for the toplevel
556        */
557       XSelectInput (xdisplay, impl->focus_window,
558                     KeyPressMask | KeyReleaseMask | FocusChangeMask);
559       
560       XMapWindow (xdisplay, impl->focus_window);
561       gdk_xid_table_insert (&impl->focus_window, window);
562     }
563
564   size_hints.flags = PSize;
565   size_hints.width = impl->width;
566   size_hints.height = impl->height;
567   
568   wm_hints.flags = StateHint | WindowGroupHint;
569   wm_hints.window_group = _gdk_leader_window;
570   wm_hints.input = True;
571   wm_hints.initial_state = NormalState;
572   
573   /* FIXME: Is there any point in doing this? Do any WM's pay
574    * attention to PSize, and even if they do, is this the
575    * correct value???
576    */
577   XSetWMNormalHints (xdisplay, xid, &size_hints);
578   
579   XSetWMHints (xdisplay, xid, &wm_hints);
580   
581   if (!wm_client_leader_atom)
582     wm_client_leader_atom = gdk_atom_intern ("WM_CLIENT_LEADER", FALSE);
583
584   /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
585   XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
586
587   pid = getpid ();
588   XChangeProperty (xdisplay, xid,
589                    gdk_atom_intern ("_NET_WM_PID", FALSE),
590                    XA_CARDINAL, 32,
591                    PropModeReplace,
592                    (guchar *)&pid, 1);
593   
594   XChangeProperty (xdisplay, xid,
595                    wm_client_leader_atom,
596                    XA_WINDOW, 32, PropModeReplace,
597                    (guchar*) &_gdk_leader_window, 1);
598   
599   if (attributes_mask & GDK_WA_TITLE)
600     title = attributes->title;
601   else
602     title = g_get_prgname ();
603
604   gdk_window_set_title (window, title);
605   
606   if (attributes_mask & GDK_WA_WMCLASS)
607     {
608       class_hint = XAllocClassHint ();
609       class_hint->res_name = attributes->wmclass_name;
610       class_hint->res_class = attributes->wmclass_class;
611       XSetClassHint (xdisplay, xid, class_hint);
612       XFree (class_hint);
613     }
614   
615   return window;
616 }
617
618 GdkWindow *
619 gdk_window_foreign_new (GdkNativeWindow anid)
620 {
621   GdkWindow *window;
622   GdkWindowObject *private;
623   GdkWindowObject *parent_private;
624   GdkWindowImplX11 *impl;
625   GdkDrawableImplX11 *draw_impl;
626   XWindowAttributes attrs;
627   Window root, parent;
628   Window *children = NULL;
629   guint nchildren;
630   gboolean result;
631
632   gdk_error_trap_push ();
633   result = XGetWindowAttributes (gdk_display, anid, &attrs);
634   if (gdk_error_trap_pop () || !result)
635     return NULL;
636
637   /* FIXME: This is pretty expensive. Maybe the caller should supply
638    *        the parent */
639   gdk_error_trap_push ();
640   result = XQueryTree (gdk_display, anid, &root, &parent, &children, &nchildren);
641   if (gdk_error_trap_pop () || !result)
642     return NULL;
643
644   if (children)
645     XFree (children);
646   
647   window = g_object_new (GDK_TYPE_WINDOW, NULL);
648   private = (GdkWindowObject *)window;
649   impl = GDK_WINDOW_IMPL_X11 (private->impl);
650   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
651   draw_impl->wrapper = GDK_DRAWABLE (window);
652   
653   private->parent = gdk_xid_table_lookup (parent);
654   
655   parent_private = (GdkWindowObject *)private->parent;
656   
657   if (parent_private)
658     parent_private->children = g_list_prepend (parent_private->children, window);
659
660   draw_impl->xid = anid;
661   draw_impl->xdisplay = gdk_display;
662
663   private->x = attrs.x;
664   private->y = attrs.y;
665   impl->width = attrs.width;
666   impl->height = attrs.height;
667   private->window_type = GDK_WINDOW_FOREIGN;
668   private->destroyed = FALSE;
669
670   if (attrs.map_state == IsUnmapped)
671     private->state = GDK_WINDOW_STATE_WITHDRAWN;
672   else
673     private->state = 0;
674
675   private->depth = attrs.depth;
676   
677   _gdk_window_init_position (GDK_WINDOW (private));
678
679   gdk_drawable_ref (window);
680   gdk_xid_table_insert (&GDK_WINDOW_XID (window), window);
681   
682   return window;
683 }
684
685 void
686 _gdk_windowing_window_destroy (GdkWindow *window,
687                                gboolean   recursing,
688                                gboolean   foreign_destroy)
689 {
690   GdkWindowObject *private = (GdkWindowObject *)window;
691
692   g_return_if_fail (GDK_IS_WINDOW (window));
693
694   _gdk_selection_window_destroyed (window);
695   
696   if (private->extension_events != 0)
697     gdk_input_window_destroy (window);
698
699   if (private->window_type == GDK_WINDOW_FOREIGN)
700     {
701       if (!foreign_destroy && (private->parent != NULL))
702         {
703           /* It's somebody else's window, but in our heirarchy,
704            * so reparent it to the root window, and then send
705            * it a delete event, as if we were a WM
706            */
707           XClientMessageEvent xevent;
708           
709           gdk_error_trap_push ();
710           gdk_window_hide (window);
711           gdk_window_reparent (window, NULL, 0, 0);
712           
713           xevent.type = ClientMessage;
714           xevent.window = GDK_WINDOW_XID (window);
715           xevent.message_type = gdk_atom_intern ("WM_PROTOCOLS", FALSE);
716           xevent.format = 32;
717           xevent.data.l[0] = gdk_atom_intern ("WM_DELETE_WINDOW", FALSE);
718           xevent.data.l[1] = CurrentTime;
719           
720           XSendEvent (GDK_WINDOW_XDISPLAY (window),
721                       GDK_WINDOW_XID (window),
722                       False, 0, (XEvent *)&xevent);
723           gdk_flush ();
724           gdk_error_trap_pop ();
725         }
726     }
727   else if (!recursing && !foreign_destroy)
728     XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
729 }
730
731 /* This function is called when the XWindow is really gone.
732  */
733 void
734 gdk_window_destroy_notify (GdkWindow *window)
735 {
736   GdkWindowImplX11 *window_impl;
737
738   g_return_if_fail (window != NULL);
739   
740   window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
741
742   if (!GDK_WINDOW_DESTROYED (window))
743     {
744       if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN)
745         g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_WINDOW_XID (window));
746
747       _gdk_window_destroy (window, TRUE);
748     }
749   
750   gdk_xid_table_remove (GDK_WINDOW_XID (window));
751   if (window_impl->focus_window)
752     gdk_xid_table_remove (window_impl->focus_window);
753   
754   gdk_drawable_unref (window);
755 }
756
757 static void
758 set_initial_hints (GdkWindow *window)
759 {
760   GdkWindowObject *private;
761   GdkAtom atoms[5];
762   gint i;
763   
764   private = (GdkWindowObject*) window;
765
766   if (private->state & GDK_WINDOW_STATE_ICONIFIED)
767     {
768       XWMHints *wm_hints;
769       
770       wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
771                               GDK_WINDOW_XID (window));
772       if (!wm_hints)
773         wm_hints = XAllocWMHints ();
774
775       wm_hints->flags |= StateHint;
776       wm_hints->initial_state = IconicState;
777       
778       XSetWMHints (GDK_WINDOW_XDISPLAY (window),
779                    GDK_WINDOW_XID (window), wm_hints);
780       XFree (wm_hints);
781     }
782
783   /* We set the spec hints regardless of whether the spec is supported,
784    * since it can't hurt and it's kind of expensive to check whether
785    * it's supported.
786    */
787   
788   i = 0;
789
790   if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
791     {
792       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
793       ++i;
794       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);
795       ++i;
796     }
797
798   if (private->state & GDK_WINDOW_STATE_STICKY)
799     {
800       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
801       ++i;
802     }
803
804   if (private->modal_hint)
805     {
806       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MODAL", FALSE);
807       ++i;
808     }
809
810   if (i > 0)
811     {
812       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
813                        GDK_WINDOW_XID (window),
814                        gdk_atom_intern ("_NET_WM_STATE", FALSE),
815                        XA_ATOM, 32, PropModeReplace,
816                        (guchar*) atoms, i);
817     }
818
819   if (private->state & GDK_WINDOW_STATE_STICKY)
820     {
821       atoms[0] = 0xFFFFFFFF;
822       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
823                        GDK_WINDOW_XID (window),
824                        gdk_atom_intern ("_NET_WM_DESKTOP", FALSE),
825                        XA_CARDINAL, 32, PropModeReplace,
826                        (guchar*) atoms, 1);
827     }
828 }
829
830 static void
831 show_window_internal (GdkWindow *window,
832                       gboolean   raise)
833 {
834   GdkWindowObject *private;
835   
836   g_return_if_fail (GDK_IS_WINDOW (window));
837   
838   private = (GdkWindowObject*) window;
839   if (!private->destroyed)
840     {
841       if (raise)
842         XRaiseWindow (GDK_WINDOW_XDISPLAY (window),
843                       GDK_WINDOW_XID (window));
844
845       if (!GDK_WINDOW_IS_MAPPED (window))
846         {
847           set_initial_hints (window);
848           
849           gdk_synthesize_window_state (window,
850                                        GDK_WINDOW_STATE_WITHDRAWN,
851                                        0);
852         }
853       
854       g_assert (GDK_WINDOW_IS_MAPPED (window));
855       
856       if (GDK_WINDOW_IMPL_X11 (private->impl)->position_info.mapped)
857         XMapWindow (GDK_WINDOW_XDISPLAY (window),
858                     GDK_WINDOW_XID (window));
859     }
860 }
861
862 /**
863  * gdk_window_show_unraised:
864  * @window: a #GdkWindow
865  *
866  * Shows a #GdkWindow onscreen, but does not modify its stacking
867  * order. In contrast, gdk_window_show() will raise the window
868  * to the top of the window stack.
869  * 
870  **/
871 void
872 gdk_window_show_unraised (GdkWindow *window)
873 {
874   g_return_if_fail (GDK_IS_WINDOW (window));
875   
876   show_window_internal (window, FALSE);
877 }
878
879 void
880 gdk_window_show (GdkWindow *window)
881 {
882   g_return_if_fail (GDK_IS_WINDOW (window));
883
884   show_window_internal (window, TRUE);
885 }
886
887 void
888 gdk_window_hide (GdkWindow *window)
889 {
890   GdkWindowObject *private;
891   
892   g_return_if_fail (window != NULL);
893
894   private = (GdkWindowObject*) window;
895
896   /* You can't simply unmap toplevel windows. */
897   switch (private->window_type)
898     {
899     case GDK_WINDOW_TOPLEVEL:
900     case GDK_WINDOW_DIALOG:
901     case GDK_WINDOW_TEMP: /* ? */
902       gdk_window_withdraw (window);
903       return;
904       break;
905       
906     case GDK_WINDOW_FOREIGN:
907     case GDK_WINDOW_ROOT:
908     case GDK_WINDOW_CHILD:
909       break;
910     }
911   
912   if (!private->destroyed)
913     {
914       if (GDK_WINDOW_IS_MAPPED (window))
915         gdk_synthesize_window_state (window,
916                                      0,
917                                      GDK_WINDOW_STATE_WITHDRAWN);
918
919       g_assert (!GDK_WINDOW_IS_MAPPED (window));
920       
921       _gdk_window_clear_update_area (window);
922       
923       XUnmapWindow (GDK_WINDOW_XDISPLAY (window),
924                     GDK_WINDOW_XID (window));
925     }
926 }
927
928 void
929 gdk_window_withdraw (GdkWindow *window)
930 {
931   GdkWindowObject *private;
932   
933   g_return_if_fail (window != NULL);
934   
935   private = (GdkWindowObject*) window;
936   if (!private->destroyed)
937     {
938       if (GDK_WINDOW_IS_MAPPED (window))
939         gdk_synthesize_window_state (window,
940                                      0,
941                                      GDK_WINDOW_STATE_WITHDRAWN);
942
943       g_assert (!GDK_WINDOW_IS_MAPPED (window));
944       
945       XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
946                        GDK_WINDOW_XID (window), 0);
947     }
948 }
949
950 void
951 gdk_window_move (GdkWindow *window,
952                  gint       x,
953                  gint       y)
954 {
955   GdkWindowObject *private = (GdkWindowObject *)window;
956   GdkWindowImplX11 *impl;
957
958   g_return_if_fail (window != NULL);
959   g_return_if_fail (GDK_IS_WINDOW (window));
960
961   impl = GDK_WINDOW_IMPL_X11 (private->impl);
962
963   if (!GDK_WINDOW_DESTROYED (window))
964     {
965       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
966         _gdk_window_move_resize_child (window, x, y,
967                                        impl->width, impl->height);
968       else
969         {
970           XMoveWindow (GDK_WINDOW_XDISPLAY (window),
971                        GDK_WINDOW_XID (window),
972                        x, y);
973         }
974     }
975 }
976
977 void
978 gdk_window_resize (GdkWindow *window,
979                    gint       width,
980                    gint       height)
981 {
982   GdkWindowObject *private;
983   
984   g_return_if_fail (window != NULL);
985   g_return_if_fail (GDK_IS_WINDOW (window));
986   
987   if (width < 1)
988     width = 1;
989   if (height < 1)
990     height = 1;
991
992   private = (GdkWindowObject*) window;
993   
994   if (!GDK_WINDOW_DESTROYED (window))
995     {
996       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
997         _gdk_window_move_resize_child (window, private->x, private->y,
998                                        width, height);
999       else
1000         {
1001           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
1002           
1003           if (width != impl->width || height != impl->height)
1004             private->resize_count += 1;
1005
1006           XResizeWindow (GDK_WINDOW_XDISPLAY (window),
1007                          GDK_WINDOW_XID (window),
1008                          width, height);
1009         }
1010     }
1011 }
1012
1013 void
1014 gdk_window_move_resize (GdkWindow *window,
1015                         gint       x,
1016                         gint       y,
1017                         gint       width,
1018                         gint       height)
1019 {
1020   GdkWindowObject *private;
1021   
1022   g_return_if_fail (window != NULL);
1023   g_return_if_fail (GDK_IS_WINDOW (window));
1024
1025   if (width < 1)
1026     width = 1;
1027   if (height < 1)
1028     height = 1;
1029   
1030   private = (GdkWindowObject*) window;
1031
1032   if (!GDK_WINDOW_DESTROYED (window))
1033     {
1034       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1035         _gdk_window_move_resize_child (window, x, y, width, height);
1036       else
1037         {
1038           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
1039           
1040           if (width != impl->width || height != impl->height)
1041             private->resize_count += 1;
1042           
1043           XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
1044                              GDK_WINDOW_XID (window),
1045                              x, y, width, height);
1046         }
1047     }
1048 }
1049
1050 void
1051 gdk_window_reparent (GdkWindow *window,
1052                      GdkWindow *new_parent,
1053                      gint       x,
1054                      gint       y)
1055 {
1056   GdkWindowObject *window_private;
1057   GdkWindowObject *parent_private;
1058   GdkWindowObject *old_parent_private;
1059   
1060   g_return_if_fail (window != NULL);
1061   g_return_if_fail (GDK_IS_WINDOW (window));
1062   g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
1063   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
1064   
1065   if (!new_parent)
1066     new_parent = _gdk_parent_root;
1067   
1068   window_private = (GdkWindowObject*) window;
1069   old_parent_private = (GdkWindowObject*)window_private->parent;
1070   parent_private = (GdkWindowObject*) new_parent;
1071   
1072   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (new_parent))
1073     XReparentWindow (GDK_WINDOW_XDISPLAY (window),
1074                      GDK_WINDOW_XID (window),
1075                      GDK_WINDOW_XID (new_parent),
1076                      x, y);
1077   
1078   window_private->parent = (GdkWindowObject *)new_parent;
1079
1080   /* Switch the window type as appropriate */
1081
1082   switch (GDK_WINDOW_TYPE (new_parent))
1083     {
1084     case GDK_WINDOW_ROOT:
1085     case GDK_WINDOW_FOREIGN:
1086       /* Now a toplevel */
1087       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1088         {
1089           GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
1090           XSetWMProtocols (GDK_WINDOW_XDISPLAY (window),
1091                            GDK_WINDOW_XID (window),
1092                            _gdk_wm_window_protocols, 3);
1093         }
1094     case GDK_WINDOW_TOPLEVEL:
1095     case GDK_WINDOW_CHILD:
1096     case GDK_WINDOW_DIALOG:
1097     case GDK_WINDOW_TEMP:
1098       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
1099           GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
1100         {
1101           /* If we were being sophisticated, we'd save the old window type
1102            * here, and restore it if we were reparented back to the
1103            * toplevel. However, the difference between different types
1104            * of toplevels only really matters on creation anyways.
1105            */
1106           GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
1107         }
1108     }
1109
1110   if (old_parent_private)
1111     old_parent_private->children = g_list_remove (old_parent_private->children, window);
1112   
1113   if ((old_parent_private &&
1114        (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
1115       (!old_parent_private && parent_private->guffaw_gravity))
1116     gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
1117   
1118   parent_private->children = g_list_prepend (parent_private->children, window);
1119   _gdk_window_init_position (GDK_WINDOW (window_private));
1120 }
1121
1122 void
1123 _gdk_windowing_window_clear_area (GdkWindow *window,
1124                                   gint       x,
1125                                   gint       y,
1126                                   gint       width,
1127                                   gint       height)
1128 {
1129   g_return_if_fail (window != NULL);
1130   g_return_if_fail (GDK_IS_WINDOW (window));
1131   
1132   if (!GDK_WINDOW_DESTROYED (window))
1133     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1134                 x, y, width, height, False);
1135 }
1136
1137 void
1138 _gdk_windowing_window_clear_area_e (GdkWindow *window,
1139                                     gint       x,
1140                                     gint       y,
1141                                     gint       width,
1142                                     gint       height)
1143 {
1144   g_return_if_fail (window != NULL);
1145   g_return_if_fail (GDK_IS_WINDOW (window));
1146   
1147   if (!GDK_WINDOW_DESTROYED (window))
1148     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1149                 x, y, width, height, True);
1150 }
1151
1152 void
1153 gdk_window_raise (GdkWindow *window)
1154 {
1155   g_return_if_fail (window != NULL);
1156   g_return_if_fail (GDK_IS_WINDOW (window));
1157   
1158   if (!GDK_WINDOW_DESTROYED (window))
1159     XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1160 }
1161
1162 void
1163 gdk_window_lower (GdkWindow *window)
1164 {
1165   g_return_if_fail (window != NULL);
1166   g_return_if_fail (GDK_IS_WINDOW (window));
1167   
1168   if (!GDK_WINDOW_DESTROYED (window))
1169     XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1170 }
1171
1172 void
1173 gdk_window_focus (GdkWindow *window,
1174                   guint32    timestamp)
1175 {
1176   g_return_if_fail (GDK_IS_WINDOW (window));
1177
1178   if (GDK_WINDOW_DESTROYED (window))
1179     return;
1180   
1181   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE)))
1182     {
1183       XEvent xev;
1184
1185       xev.xclient.type = ClientMessage;
1186       xev.xclient.serial = 0;
1187       xev.xclient.send_event = True;
1188       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
1189       xev.xclient.display = gdk_display;
1190       xev.xclient.message_type = gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE);
1191       xev.xclient.format = 32;
1192       xev.xclient.data.l[0] = 0;
1193       
1194       XSendEvent (gdk_display, _gdk_root_window, False,
1195                   SubstructureRedirectMask | SubstructureNotifyMask,
1196                   &xev);
1197     }
1198   else
1199     {
1200       XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1201
1202       /* There is no way of knowing reliably whether we are viewable so we need
1203        * to trap errors so we don't cause a BadMatch.
1204        */
1205       gdk_error_trap_push ();
1206       XSetInputFocus (GDK_WINDOW_XDISPLAY (window),
1207                       GDK_WINDOW_XWINDOW (window),
1208                       RevertToNone,
1209                       timestamp);
1210       XSync (GDK_WINDOW_XDISPLAY (window), False);
1211       gdk_error_trap_pop ();
1212     }
1213 }
1214
1215 void
1216 gdk_window_set_hints (GdkWindow *window,
1217                       gint       x,
1218                       gint       y,
1219                       gint       min_width,
1220                       gint       min_height,
1221                       gint       max_width,
1222                       gint       max_height,
1223                       gint       flags)
1224 {
1225   XSizeHints size_hints;
1226   
1227   g_return_if_fail (window != NULL);
1228   g_return_if_fail (GDK_IS_WINDOW (window));
1229   
1230   if (GDK_WINDOW_DESTROYED (window))
1231     return;
1232   
1233   size_hints.flags = 0;
1234   
1235   if (flags & GDK_HINT_POS)
1236     {
1237       size_hints.flags |= PPosition;
1238       size_hints.x = x;
1239       size_hints.y = y;
1240     }
1241   
1242   if (flags & GDK_HINT_MIN_SIZE)
1243     {
1244       size_hints.flags |= PMinSize;
1245       size_hints.min_width = min_width;
1246       size_hints.min_height = min_height;
1247     }
1248   
1249   if (flags & GDK_HINT_MAX_SIZE)
1250     {
1251       size_hints.flags |= PMaxSize;
1252       size_hints.max_width = max_width;
1253       size_hints.max_height = max_height;
1254     }
1255   
1256   /* FIXME: Would it be better to delete this property if
1257    *        flags == 0? It would save space on the server
1258    */
1259   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1260                      GDK_WINDOW_XID (window),
1261                      &size_hints);
1262 }
1263
1264 /**
1265  * gdk_window_set_type_hint:
1266  * @window: A #GdkWindow
1267  * @hint: A hint of the function this window will have
1268  *
1269  * The application can use this call to provide a hint to the window
1270  * manager about the functionality of a window. The window manager
1271  * can use this information when determining the decoration and behaviour
1272  * of the window.
1273  *
1274  * The hint must be set before the window is mapped.
1275  **/
1276 void
1277 gdk_window_set_type_hint (GdkWindow        *window,
1278                           GdkWindowTypeHint hint)
1279 {
1280   GdkAtom atom;
1281   
1282   g_return_if_fail (window != NULL);
1283   g_return_if_fail (GDK_IS_WINDOW (window));
1284   
1285   if (GDK_WINDOW_DESTROYED (window))
1286     return;
1287
1288   switch (hint)
1289     {
1290     case GDK_WINDOW_TYPE_HINT_DIALOG:
1291       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DIALOG", FALSE);
1292       break;
1293     case GDK_WINDOW_TYPE_HINT_MENU:
1294       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_MENU", FALSE);
1295       break;
1296     case GDK_WINDOW_TYPE_HINT_TOOLBAR:
1297       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_TOOLBAR", FALSE);
1298       break;
1299     default:
1300       g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint);
1301       /* Fall thru */
1302     case GDK_WINDOW_TYPE_HINT_NORMAL:
1303       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_NORMAL", FALSE);
1304       break;
1305     }
1306
1307   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1308                    GDK_WINDOW_XID (window),
1309                    gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE),
1310                    XA_ATOM, 32, PropModeReplace,
1311                    (guchar *)&atom, 1);
1312 }
1313
1314
1315 static void
1316 gdk_wmspec_change_state (gboolean add,
1317                          GdkWindow *window,
1318                          GdkAtom state1,
1319                          GdkAtom state2)
1320 {
1321   XEvent xev;
1322
1323 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
1324 #define _NET_WM_STATE_ADD           1    /* add/set property */
1325 #define _NET_WM_STATE_TOGGLE        2    /* toggle property  */  
1326   
1327   xev.xclient.type = ClientMessage;
1328   xev.xclient.serial = 0;
1329   xev.xclient.send_event = True;
1330   xev.xclient.display = gdk_display;
1331   xev.xclient.window = GDK_WINDOW_XID (window);
1332   xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
1333   xev.xclient.format = 32;
1334   xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1335   xev.xclient.data.l[1] = state1;
1336   xev.xclient.data.l[2] = state2;
1337   
1338   XSendEvent (gdk_display, _gdk_root_window, False,
1339               SubstructureRedirectMask | SubstructureNotifyMask,
1340               &xev);
1341 }
1342 /**
1343  * gdk_window_set_modal_hint:
1344  * @window: A #GdkWindow
1345  * @modal: TRUE if the window is modal, FALSE otherwise.
1346  *
1347  * The application can use this hint to tell the window manager
1348  * that a certain window has modal behaviour. The window manager
1349  * can use this information to handle modal windows in a special
1350  * way.
1351  *
1352  * You should only use this on windows for which you have
1353  * previously called #gdk_window_set_transient_for()
1354  **/
1355 void
1356 gdk_window_set_modal_hint (GdkWindow *window,
1357                            gboolean   modal)
1358 {
1359   GdkWindowObject *private;
1360
1361   g_return_if_fail (window != NULL);
1362   g_return_if_fail (GDK_IS_WINDOW (window));
1363   
1364   if (GDK_WINDOW_DESTROYED (window))
1365     return;
1366
1367   private = (GdkWindowObject*) window;
1368
1369   private->modal_hint = modal;
1370
1371   if (GDK_WINDOW_IS_MAPPED (window))
1372     gdk_wmspec_change_state (modal, window,
1373                              gdk_atom_intern ("_NET_WM_STATE_MODAL", FALSE),
1374                              0);
1375 }
1376
1377 void 
1378 gdk_window_set_geometry_hints (GdkWindow      *window,
1379                                GdkGeometry    *geometry,
1380                                GdkWindowHints  geom_mask)
1381 {
1382   XSizeHints size_hints;
1383   
1384   g_return_if_fail (window != NULL);
1385   g_return_if_fail (GDK_IS_WINDOW (window));
1386   
1387   if (GDK_WINDOW_DESTROYED (window))
1388     return;
1389   
1390   size_hints.flags = 0;
1391   
1392   if (geom_mask & GDK_HINT_POS)
1393     {
1394       size_hints.flags |= PPosition;
1395       /* We need to initialize the following obsolete fields because KWM 
1396        * apparently uses these fields if they are non-zero.
1397        * #@#!#!$!.
1398        */
1399       size_hints.x = 0;
1400       size_hints.y = 0;
1401     }
1402
1403   if (geom_mask & GDK_HINT_USER_POS)
1404     {
1405       size_hints.flags |= USPosition;
1406     }
1407
1408   if (geom_mask & GDK_HINT_USER_SIZE)
1409     {
1410       size_hints.flags |= USSize;
1411     }
1412   
1413   if (geom_mask & GDK_HINT_MIN_SIZE)
1414     {
1415       size_hints.flags |= PMinSize;
1416       size_hints.min_width = geometry->min_width;
1417       size_hints.min_height = geometry->min_height;
1418     }
1419   
1420   if (geom_mask & GDK_HINT_MAX_SIZE)
1421     {
1422       size_hints.flags |= PMaxSize;
1423       size_hints.max_width = MAX (geometry->max_width, 1);
1424       size_hints.max_height = MAX (geometry->max_height, 1);
1425     }
1426   
1427   if (geom_mask & GDK_HINT_BASE_SIZE)
1428     {
1429       size_hints.flags |= PBaseSize;
1430       size_hints.base_width = geometry->base_width;
1431       size_hints.base_height = geometry->base_height;
1432     }
1433   
1434   if (geom_mask & GDK_HINT_RESIZE_INC)
1435     {
1436       size_hints.flags |= PResizeInc;
1437       size_hints.width_inc = geometry->width_inc;
1438       size_hints.height_inc = geometry->height_inc;
1439     }
1440   
1441   if (geom_mask & GDK_HINT_ASPECT)
1442     {
1443       size_hints.flags |= PAspect;
1444       if (geometry->min_aspect <= 1)
1445         {
1446           size_hints.min_aspect.x = 65536 * geometry->min_aspect;
1447           size_hints.min_aspect.y = 65536;
1448         }
1449       else
1450         {
1451           size_hints.min_aspect.x = 65536;
1452           size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
1453         }
1454       if (geometry->max_aspect <= 1)
1455         {
1456           size_hints.max_aspect.x = 65536 * geometry->max_aspect;
1457           size_hints.max_aspect.y = 65536;
1458         }
1459       else
1460         {
1461           size_hints.max_aspect.x = 65536;
1462           size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
1463         }
1464     }
1465
1466   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1467     {
1468       size_hints.flags |= PWinGravity;
1469       size_hints.win_gravity = geometry->win_gravity;
1470     }
1471   
1472   /* FIXME: Would it be better to delete this property if
1473    *        geom_mask == 0? It would save space on the server
1474    */
1475   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1476                      GDK_WINDOW_XID (window),
1477                      &size_hints);
1478 }
1479
1480 static void
1481 gdk_window_get_geometry_hints (GdkWindow      *window,
1482                                GdkGeometry    *geometry,
1483                                GdkWindowHints *geom_mask)
1484 {
1485   XSizeHints size_hints;  
1486   glong junk_size_mask = 0;
1487
1488   g_return_if_fail (GDK_IS_WINDOW (window));
1489   g_return_if_fail (geometry != NULL);
1490   g_return_if_fail (geom_mask != NULL);
1491
1492   *geom_mask = 0;
1493   
1494   if (GDK_WINDOW_DESTROYED (window))
1495     return;
1496   
1497   if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1498                           GDK_WINDOW_XID (window),
1499                           &size_hints,
1500                           &junk_size_mask))
1501     return;                   
1502
1503   if (size_hints.flags & PMinSize)
1504     {
1505       *geom_mask |= GDK_HINT_MIN_SIZE;
1506       geometry->min_width = size_hints.min_width;
1507       geometry->min_height = size_hints.min_height;
1508     }
1509
1510   if (size_hints.flags & PMaxSize)
1511     {
1512       *geom_mask |= GDK_HINT_MAX_SIZE;
1513       geometry->max_width = MAX (size_hints.max_width, 1);
1514       geometry->max_height = MAX (size_hints.max_height, 1);
1515     }
1516
1517   if (size_hints.flags & PResizeInc)
1518     {
1519       *geom_mask |= GDK_HINT_RESIZE_INC;
1520       geometry->width_inc = size_hints.width_inc;
1521       geometry->height_inc = size_hints.height_inc;
1522     }
1523
1524   if (size_hints.flags & PAspect)
1525     {
1526       *geom_mask |= GDK_HINT_ASPECT;
1527
1528       geometry->min_aspect = (gdouble) size_hints.min_aspect.x / (gdouble) size_hints.min_aspect.y;
1529       geometry->max_aspect = (gdouble) size_hints.max_aspect.x / (gdouble) size_hints.max_aspect.y;
1530     }
1531
1532   if (size_hints.flags & PWinGravity)
1533     {
1534       *geom_mask |= GDK_HINT_WIN_GRAVITY;
1535       geometry->win_gravity = size_hints.win_gravity;
1536     }
1537 }
1538
1539 static gboolean
1540 utf8_is_latin1 (const gchar *str)
1541 {
1542   const char *p = str;
1543
1544   while (*p)
1545     {
1546       gunichar ch = g_utf8_get_char (p);
1547
1548       if (ch > 0xff)
1549         return FALSE;
1550       
1551       p = g_utf8_next_char (p);
1552     }
1553
1554   return TRUE;
1555 }
1556
1557 /* Set the property to @utf8_str as STRING if the @utf8_str is fully
1558  * convertable to STRING, otherwise, set it as compound text
1559  */
1560 static void
1561 set_text_property (GdkWindow   *window,
1562                    GdkAtom      property,
1563                    const gchar *utf8_str)
1564 {
1565   guchar *prop_text = NULL;
1566   GdkAtom prop_type;
1567   gint prop_length;
1568   gint prop_format;
1569   
1570   if (utf8_is_latin1 (utf8_str))
1571     {
1572       prop_type = GDK_TARGET_STRING;
1573       prop_text = gdk_utf8_to_string_target (utf8_str);
1574       prop_length = strlen (prop_text);
1575       prop_format = 8;
1576     }
1577   else
1578     {
1579       gdk_utf8_to_compound_text (utf8_str, &prop_type, &prop_format,
1580                                  &prop_text, &prop_length);
1581     }
1582
1583   if (prop_text)
1584     {
1585       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1586                        GDK_WINDOW_XID (window),
1587                        property,
1588                        prop_type, prop_format,
1589                        PropModeReplace, prop_text,
1590                        prop_length);
1591
1592       g_free (prop_text);
1593     }
1594 }
1595
1596 void
1597 gdk_window_set_title (GdkWindow   *window,
1598                       const gchar *title)
1599 {
1600   g_return_if_fail (window != NULL);
1601   g_return_if_fail (GDK_IS_WINDOW (window));
1602
1603   if (GDK_WINDOW_DESTROYED (window))
1604     return;
1605   
1606   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1607                    GDK_WINDOW_XID (window),
1608                    gdk_atom_intern ("_NET_WM_NAME", FALSE),
1609                    gdk_atom_intern ("UTF8_STRING", FALSE), 8,
1610                    PropModeReplace, title,
1611                    strlen (title));
1612
1613   set_text_property (window, gdk_atom_intern ("WM_NAME", FALSE), title);
1614   if (!gdk_window_icon_name_set (window))
1615     {
1616       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1617                        GDK_WINDOW_XID (window),
1618                        gdk_atom_intern ("_NET_WM_ICON_NAME", FALSE),
1619                        gdk_atom_intern ("UTF8_STRING", FALSE), 8,
1620                        PropModeReplace, title,
1621                        strlen (title));
1622       set_text_property (window, gdk_atom_intern ("WM_ICON_NAME", FALSE), title);
1623     }
1624 }
1625
1626 void          
1627 gdk_window_set_role (GdkWindow   *window,
1628                      const gchar *role)
1629 {
1630   g_return_if_fail (window != NULL);
1631   g_return_if_fail (GDK_IS_WINDOW (window));
1632
1633   if (!GDK_WINDOW_DESTROYED (window))
1634     {
1635       if (role)
1636         XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1637                          gdk_atom_intern ("WM_WINDOW_ROLE", FALSE), XA_STRING,
1638                          8, PropModeReplace, role, strlen (role));
1639       else
1640         XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1641                          gdk_atom_intern ("WM_WINDOW_ROLE", FALSE));
1642     }
1643 }
1644
1645 void          
1646 gdk_window_set_transient_for (GdkWindow *window, 
1647                               GdkWindow *parent)
1648 {
1649   GdkWindowObject *private;
1650   GdkWindowObject *parent_private;
1651   
1652   g_return_if_fail (window != NULL);
1653   g_return_if_fail (GDK_IS_WINDOW (window));
1654   
1655   private = (GdkWindowObject*) window;
1656   parent_private = (GdkWindowObject*) parent;
1657   
1658   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent))
1659     XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
1660                           GDK_WINDOW_XID (window),
1661                           GDK_WINDOW_XID (parent));
1662 }
1663
1664 void
1665 gdk_window_set_background (GdkWindow *window,
1666                            GdkColor  *color)
1667 {
1668   GdkWindowObject *private = (GdkWindowObject *)window;
1669   
1670   g_return_if_fail (window != NULL);
1671   g_return_if_fail (GDK_IS_WINDOW (window));
1672   
1673   if (!GDK_WINDOW_DESTROYED (window))
1674     XSetWindowBackground (GDK_WINDOW_XDISPLAY (window),
1675                           GDK_WINDOW_XID (window), color->pixel);
1676
1677   private->bg_color = *color;
1678
1679   if (private->bg_pixmap &&
1680       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1681       private->bg_pixmap != GDK_NO_BG)
1682     {
1683       gdk_pixmap_unref (private->bg_pixmap);
1684       private->bg_pixmap = NULL;
1685     }
1686 }
1687
1688 void
1689 gdk_window_set_back_pixmap (GdkWindow *window,
1690                             GdkPixmap *pixmap,
1691                             gboolean   parent_relative)
1692 {
1693   GdkWindowObject *private = (GdkWindowObject *)window;
1694   Pixmap xpixmap;
1695   
1696   g_return_if_fail (window != NULL);
1697   g_return_if_fail (GDK_IS_WINDOW (window));
1698   g_return_if_fail (pixmap == NULL || !parent_relative);
1699
1700   if (private->bg_pixmap &&
1701       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1702       private->bg_pixmap != GDK_NO_BG)
1703     gdk_pixmap_unref (private->bg_pixmap);
1704
1705   if (parent_relative)
1706     {
1707       xpixmap = ParentRelative;
1708       private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
1709     }
1710   else
1711     {
1712       if (pixmap)
1713         {
1714           gdk_pixmap_ref (pixmap);
1715           private->bg_pixmap = pixmap;
1716           xpixmap = GDK_PIXMAP_XID (pixmap);
1717         }
1718       else
1719         {
1720           xpixmap = None;
1721           private->bg_pixmap = GDK_NO_BG;
1722         }
1723     }
1724   
1725   if (!GDK_WINDOW_DESTROYED (window))
1726     XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
1727                                 GDK_WINDOW_XID (window), xpixmap);
1728 }
1729
1730 void
1731 gdk_window_set_cursor (GdkWindow *window,
1732                        GdkCursor *cursor)
1733 {
1734   GdkCursorPrivate *cursor_private;
1735   Cursor xcursor;
1736   
1737   g_return_if_fail (window != NULL);
1738   g_return_if_fail (GDK_IS_WINDOW (window));
1739   
1740   cursor_private = (GdkCursorPrivate*) cursor;
1741   
1742   if (!cursor)
1743     xcursor = None;
1744   else
1745     xcursor = cursor_private->xcursor;
1746   
1747   if (!GDK_WINDOW_DESTROYED (window))
1748     XDefineCursor (GDK_WINDOW_XDISPLAY (window),
1749                    GDK_WINDOW_XID (window),
1750                    xcursor);
1751 }
1752
1753 void
1754 gdk_window_get_geometry (GdkWindow *window,
1755                          gint      *x,
1756                          gint      *y,
1757                          gint      *width,
1758                          gint      *height,
1759                          gint      *depth)
1760 {
1761   Window root;
1762   gint tx;
1763   gint ty;
1764   guint twidth;
1765   guint theight;
1766   guint tborder_width;
1767   guint tdepth;
1768   
1769   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
1770   
1771   if (!window)
1772     window = _gdk_parent_root;
1773   
1774   if (!GDK_WINDOW_DESTROYED (window))
1775     {
1776       XGetGeometry (GDK_WINDOW_XDISPLAY (window),
1777                     GDK_WINDOW_XID (window),
1778                     &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
1779       
1780       if (x)
1781         *x = tx;
1782       if (y)
1783         *y = ty;
1784       if (width)
1785         *width = twidth;
1786       if (height)
1787         *height = theight;
1788       if (depth)
1789         *depth = tdepth;
1790     }
1791 }
1792
1793 /**
1794  * gdk_window_get_origin:
1795  * @window: a #GdkWindow
1796  * @x: return location for X coordinate
1797  * @y: return location for Y coordinate
1798  * 
1799  * Obtains the position of a window in root window coordinates.
1800  * (Compare with gdk_window_get_position() and
1801  * gdk_window_get_geometry() which return the position of a window
1802  * relative to its parent window.)
1803  * 
1804  * Return value: not meaningful, ignore
1805  **/
1806 gint
1807 gdk_window_get_origin (GdkWindow *window,
1808                        gint      *x,
1809                        gint      *y)
1810 {
1811   gint return_val;
1812   Window child;
1813   gint tx = 0;
1814   gint ty = 0;
1815   
1816   g_return_val_if_fail (window != NULL, 0);
1817   
1818   if (!GDK_WINDOW_DESTROYED (window))
1819     {
1820       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
1821                                           GDK_WINDOW_XID (window),
1822                                           _gdk_root_window,
1823                                           0, 0, &tx, &ty,
1824                                           &child);
1825       
1826     }
1827   else
1828     return_val = 0;
1829   
1830   if (x)
1831     *x = tx;
1832   if (y)
1833     *y = ty;
1834   
1835   return return_val;
1836 }
1837
1838 /**
1839  * gdk_window_get_deskrelative_origin:
1840  * @window: a #GdkWindow
1841  * @x: return location for X coordinate
1842  * @y: return location for Y coordinate
1843  * 
1844  * This gets the origin of a #GdkWindow relative to
1845  * an Enlightenment-window-manager desktop. As long as you don't
1846  * assume that the user's desktop/workspace covers the entire
1847  * root window (i.e. you don't assume that the desktop begins
1848  * at root window coordinate 0,0) this function is not necessary.
1849  * It's deprecated for that reason.
1850  * 
1851  * Return value: not meaningful
1852  **/
1853 gboolean
1854 gdk_window_get_deskrelative_origin (GdkWindow *window,
1855                                     gint      *x,
1856                                     gint      *y)
1857 {
1858   gboolean return_val = FALSE;
1859   gint num_children, format_return;
1860   Window win, *child, parent, root;
1861   gint tx = 0;
1862   gint ty = 0;
1863   Atom type_return;
1864   static Atom atom = 0;
1865   gulong number_return, bytes_after_return;
1866   guchar *data_return;
1867   
1868   g_return_val_if_fail (window != NULL, 0);
1869   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1870   
1871   if (!GDK_WINDOW_DESTROYED (window))
1872     {
1873       if (!atom)
1874         atom = gdk_atom_intern ("ENLIGHTENMENT_DESKTOP", FALSE);
1875       win = GDK_WINDOW_XID (window);
1876       
1877       while (XQueryTree (GDK_WINDOW_XDISPLAY (window), win, &root, &parent,
1878                          &child, (unsigned int *)&num_children))
1879         {
1880           if ((child) && (num_children > 0))
1881             XFree (child);
1882           
1883           if (!parent)
1884             break;
1885           else
1886             win = parent;
1887           
1888           if (win == root)
1889             break;
1890           
1891           data_return = NULL;
1892           XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), win, atom, 0, 0,
1893                               False, XA_CARDINAL, &type_return, &format_return,
1894                               &number_return, &bytes_after_return, &data_return);
1895           if (type_return == XA_CARDINAL)
1896             {
1897               XFree (data_return);
1898               break;
1899             }
1900         }
1901       
1902       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
1903                                           GDK_WINDOW_XID (window),
1904                                           win,
1905                                           0, 0, &tx, &ty,
1906                                           &root);
1907       if (x)
1908         *x = tx;
1909       if (y)
1910         *y = ty;
1911     }
1912   
1913   
1914   return return_val;
1915 }
1916
1917 /**
1918  * gdk_window_get_root_origin:
1919  * @window: a #GdkWindow
1920  * @x: return location for X position of window frame
1921  * @y: return location for Y position of window frame
1922  *
1923  * Obtains the top-left corner of the window manager frame in root
1924  * window coordinates.
1925  * 
1926  **/
1927 void
1928 gdk_window_get_root_origin (GdkWindow *window,
1929                             gint      *x,
1930                             gint      *y)
1931 {
1932   GdkRectangle rect;
1933
1934   g_return_if_fail (GDK_IS_WINDOW (window));
1935
1936   gdk_window_get_frame_extents (window, &rect);
1937
1938   if (x)
1939     *x = rect.x;
1940
1941   if (y)
1942     *y = rect.y;
1943 }
1944
1945 /**
1946  * gdk_window_get_frame_extents:
1947  * @window: a #GdkWindow
1948  * @rect: rectangle to fill with bounding box of the window frame
1949  *
1950  * Obtains the bounding box of the window, including window manager
1951  * titlebar/borders if any. The frame position is given in root window
1952  * coordinates. To get the position of the window itself (rather than
1953  * the frame) in root window coordinates, use gdk_window_get_origin().
1954  * 
1955  **/
1956 void
1957 gdk_window_get_frame_extents (GdkWindow    *window,
1958                               GdkRectangle *rect)
1959 {
1960   GdkWindowObject *private;
1961   Window xwindow;
1962   Window xparent;
1963   Window root;
1964   Window *children;
1965   unsigned int nchildren;
1966   
1967   g_return_if_fail (GDK_IS_WINDOW (window));
1968   g_return_if_fail (rect != NULL);
1969   
1970   private = (GdkWindowObject*) window;
1971   
1972   rect->x = 0;
1973   rect->y = 0;
1974   rect->width = 1;
1975   rect->height = 1;
1976   
1977   if (GDK_WINDOW_DESTROYED (window))
1978     return;
1979   
1980   while (private->parent && ((GdkWindowObject*) private->parent)->parent)
1981     private = (GdkWindowObject*) private->parent;
1982   if (GDK_WINDOW_DESTROYED (window))
1983     return;
1984   
1985   xparent = GDK_WINDOW_XID (window);
1986   do
1987     {
1988       xwindow = xparent;
1989       if (!XQueryTree (GDK_WINDOW_XDISPLAY (window), xwindow,
1990                        &root, &xparent,
1991                        &children, &nchildren))
1992         return;
1993       
1994       if (children)
1995         XFree (children);
1996     }
1997   while (xparent != root);
1998   
1999   if (xparent == root)
2000     {
2001       unsigned int ww, wh, wb, wd;
2002       int wx, wy;
2003       
2004       if (XGetGeometry (GDK_WINDOW_XDISPLAY (window), xwindow, &root, &wx, &wy, &ww, &wh, &wb, &wd))
2005         {
2006           rect->x = wx;
2007           rect->y = wy;
2008           rect->width = ww;
2009           rect->height = wh;
2010         }
2011     }
2012 }
2013
2014 GdkWindow*
2015 _gdk_windowing_window_get_pointer (GdkWindow       *window,
2016                                    gint            *x,
2017                                    gint            *y,
2018                                    GdkModifierType *mask)
2019 {
2020   GdkWindow *return_val;
2021   Window root;
2022   Window child;
2023   int rootx, rooty;
2024   int winx = 0;
2025   int winy = 0;
2026   unsigned int xmask = 0;
2027   gint xoffset, yoffset;
2028
2029   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
2030   
2031   if (!window)
2032     window = _gdk_parent_root;
2033   
2034   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2035
2036   return_val = NULL;
2037   if (!GDK_WINDOW_DESTROYED (window) &&
2038       XQueryPointer (GDK_WINDOW_XDISPLAY (window),
2039                      GDK_WINDOW_XID (window),
2040                      &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
2041     {
2042       if (child)
2043         return_val = gdk_window_lookup (child);
2044     }
2045   
2046   if (x)
2047     *x = winx + xoffset;
2048   if (y)
2049     *y = winy + yoffset;
2050   if (mask)
2051     *mask = xmask;
2052   
2053   return return_val;
2054 }
2055
2056 GdkWindow*
2057 _gdk_windowing_window_at_pointer (gint *win_x,
2058                                   gint *win_y)
2059 {
2060   GdkWindow *window;
2061   Window root;
2062   Window xwindow;
2063   Window xwindow_last = 0;
2064   Display *xdisplay;
2065   int rootx = -1, rooty = -1;
2066   int winx, winy;
2067   unsigned int xmask;
2068   
2069   xwindow = GDK_ROOT_WINDOW ();
2070   xdisplay = GDK_DISPLAY ();
2071
2072   gdk_x11_grab_server ();
2073   while (xwindow)
2074     {
2075       xwindow_last = xwindow;
2076       XQueryPointer (xdisplay, xwindow,
2077                      &root, &xwindow,
2078                      &rootx, &rooty,
2079                      &winx, &winy,
2080                      &xmask);
2081     }
2082   gdk_x11_ungrab_server ();
2083   
2084   window = gdk_window_lookup (xwindow_last);
2085   
2086   if (win_x)
2087     *win_x = window ? winx : -1;
2088   if (win_y)
2089     *win_y = window ? winy : -1;
2090   
2091   return window;
2092 }
2093
2094 GdkEventMask  
2095 gdk_window_get_events (GdkWindow *window)
2096 {
2097   XWindowAttributes attrs;
2098   GdkEventMask event_mask;
2099   int i;
2100   
2101   g_return_val_if_fail (window != NULL, 0);
2102   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2103
2104   if (GDK_WINDOW_DESTROYED (window))
2105     return 0;
2106   else
2107     {
2108       XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2109                             GDK_WINDOW_XID (window), 
2110                             &attrs);
2111       
2112       event_mask = 0;
2113       for (i = 0; i < _gdk_nenvent_masks; i++)
2114         {
2115           if (attrs.your_event_mask & _gdk_event_mask_table[i])
2116             event_mask |= 1 << (i + 1);
2117         }
2118   
2119       return event_mask;
2120     }
2121 }
2122
2123 void          
2124 gdk_window_set_events (GdkWindow       *window,
2125                        GdkEventMask     event_mask)
2126 {
2127   long xevent_mask;
2128   int i;
2129   
2130   g_return_if_fail (window != NULL);
2131   g_return_if_fail (GDK_IS_WINDOW (window));
2132   
2133   if (!GDK_WINDOW_DESTROYED (window))
2134     {
2135       xevent_mask = StructureNotifyMask;
2136       for (i = 0; i < _gdk_nenvent_masks; i++)
2137         {
2138           if (event_mask & (1 << (i + 1)))
2139             xevent_mask |= _gdk_event_mask_table[i];
2140         }
2141       
2142       XSelectInput (GDK_WINDOW_XDISPLAY (window),
2143                     GDK_WINDOW_XID (window),
2144                     xevent_mask);
2145     }
2146 }
2147
2148 void
2149 gdk_window_add_colormap_windows (GdkWindow *window)
2150 {
2151   GdkWindow *toplevel;
2152   Window *old_windows;
2153   Window *new_windows;
2154   int i, count;
2155   
2156   g_return_if_fail (window != NULL);
2157   g_return_if_fail (GDK_IS_WINDOW (window));
2158   
2159   toplevel = gdk_window_get_toplevel (window);
2160   if (GDK_WINDOW_DESTROYED (toplevel))
2161     return;
2162   
2163   old_windows = NULL;
2164   if (!XGetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2165                               GDK_WINDOW_XID (toplevel),
2166                               &old_windows, &count))
2167     {
2168       count = 0;
2169     }
2170   
2171   for (i = 0; i < count; i++)
2172     if (old_windows[i] == GDK_WINDOW_XID (window))
2173       {
2174         XFree (old_windows);
2175         return;
2176       }
2177   
2178   new_windows = g_new (Window, count + 1);
2179   
2180   for (i = 0; i < count; i++)
2181     new_windows[i] = old_windows[i];
2182   new_windows[count] = GDK_WINDOW_XID (window);
2183   
2184   XSetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2185                          GDK_WINDOW_XID (toplevel),
2186                          new_windows, count + 1);
2187   
2188   g_free (new_windows);
2189   if (old_windows)
2190     XFree (old_windows);
2191 }
2192
2193 static gboolean
2194 gdk_window_have_shape_ext (void)
2195 {
2196   enum { UNKNOWN, NO, YES };
2197   static gint have_shape = UNKNOWN;
2198   
2199   if (have_shape == UNKNOWN)
2200     {
2201       int ignore;
2202       if (XQueryExtension (gdk_display, "SHAPE", &ignore, &ignore, &ignore))
2203         have_shape = YES;
2204       else
2205         have_shape = NO;
2206     }
2207   
2208   return (have_shape == YES);
2209 }
2210
2211 #define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.")
2212
2213 /*
2214  * This needs the X11 shape extension.
2215  * If not available, shaped windows will look
2216  * ugly, but programs still work.    Stefan Wille
2217  */
2218 void
2219 gdk_window_shape_combine_mask (GdkWindow *window,
2220                                GdkBitmap *mask,
2221                                gint x, gint y)
2222 {
2223   Pixmap pixmap;
2224   gint xoffset, yoffset;
2225   
2226   g_return_if_fail (window != NULL);
2227   g_return_if_fail (GDK_IS_WINDOW (window));
2228   
2229 #ifdef HAVE_SHAPE_EXT
2230   if (GDK_WINDOW_DESTROYED (window))
2231     return;
2232
2233   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2234
2235   if (xoffset != 0 || yoffset != 0)
2236     {
2237       WARN_SHAPE_TOO_BIG ();
2238       return;
2239     }
2240   
2241   if (gdk_window_have_shape_ext ())
2242     {
2243       if (mask)
2244         {
2245           pixmap = GDK_PIXMAP_XID (mask);
2246         }
2247       else
2248         {
2249           x = 0;
2250           y = 0;
2251           pixmap = None;
2252         }
2253       
2254       XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
2255                          GDK_WINDOW_XID (window),
2256                          ShapeBounding,
2257                          x, y,
2258                          pixmap,
2259                          ShapeSet);
2260     }
2261 #endif /* HAVE_SHAPE_EXT */
2262 }
2263
2264 void
2265 gdk_window_shape_combine_region (GdkWindow *window,
2266                                  GdkRegion *shape_region,
2267                                  gint       offset_x,
2268                                  gint       offset_y)
2269 {
2270   gint xoffset, yoffset;
2271   
2272   g_return_if_fail (GDK_IS_WINDOW (window));
2273   
2274 #ifdef HAVE_SHAPE_EXT
2275   if (GDK_WINDOW_DESTROYED (window))
2276     return;
2277
2278   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2279
2280   if (xoffset != 0 || yoffset != 0)
2281     {
2282       WARN_SHAPE_TOO_BIG ();
2283       return;
2284     }
2285   
2286   if (shape_region == NULL)
2287     {
2288       /* Use NULL mask to unset the shape */
2289       gdk_window_shape_combine_mask (window, NULL, 0, 0);
2290       return;
2291     }
2292   
2293   if (gdk_window_have_shape_ext ())
2294     {
2295       gint n_rects = 0;
2296       XRectangle *xrects = NULL;
2297
2298       _gdk_region_get_xrectangles (shape_region,
2299                                    0, 0,
2300                                    &xrects, &n_rects);
2301       
2302       XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
2303                                GDK_WINDOW_XID (window),
2304                                ShapeBounding,
2305                                offset_x, offset_y,
2306                                xrects, n_rects,
2307                                ShapeSet,
2308                                YXBanded);
2309
2310       g_free (xrects);
2311     }
2312 #endif /* HAVE_SHAPE_EXT */
2313 }
2314
2315
2316 void
2317 gdk_window_set_override_redirect (GdkWindow *window,
2318                                   gboolean override_redirect)
2319 {
2320   XSetWindowAttributes attr;
2321   
2322   g_return_if_fail (window != NULL);
2323   g_return_if_fail (GDK_IS_WINDOW (window));
2324
2325   if (GDK_WINDOW_DESTROYED (window))
2326     {
2327       attr.override_redirect = (override_redirect == FALSE)?False:True;
2328       XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2329                                GDK_WINDOW_XID (window),
2330                                CWOverrideRedirect,
2331                                &attr);
2332     }
2333 }
2334
2335
2336 /**
2337  * gdk_window_set_icon_list:
2338  * @window: The #GdkWindow toplevel window to set the icon of.
2339  * @pixbufs: A list of pixbufs, of different sizes.
2340  *
2341  * Sets a list of icons for the window. One of these will be used
2342  * to represent the window when it has been iconified. The icon is
2343  * usually shown in an icon box or some sort of task bar. Which icon
2344  * size is shown depends on the window manager. The window manager
2345  * can scale the icon  but setting several size icons can give better
2346  * image quality since the window manager may only need to scale the
2347  * icon by a small amount or not at all.
2348  *
2349  **/
2350 void
2351 gdk_window_set_icon_list (GdkWindow *window,
2352                           GList     *pixbufs)
2353 {
2354   guint *data;
2355   guchar *pixels;
2356   guint *p;
2357   gint size;
2358   GList *l;
2359   GdkPixbuf *pixbuf;
2360   gint width, height, stride;
2361   gint x, y;
2362   gint n_channels;
2363   
2364   g_return_if_fail (GDK_IS_WINDOW (window));
2365
2366   if (GDK_WINDOW_DESTROYED (window))
2367     return;
2368   
2369   l = pixbufs;
2370   size = 0;
2371   
2372   while (l)
2373     {
2374       pixbuf = l->data;
2375       g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
2376
2377       width = gdk_pixbuf_get_width (pixbuf);
2378       height = gdk_pixbuf_get_height (pixbuf);
2379       
2380       size += 2 + width * height;
2381
2382       l = g_list_next (l);
2383     }
2384
2385   data = g_malloc (size*4);
2386
2387   l = pixbufs;
2388   p = data;
2389   while (l)
2390     {
2391       pixbuf = l->data;
2392       
2393       width = gdk_pixbuf_get_width (pixbuf);
2394       height = gdk_pixbuf_get_height (pixbuf);
2395       stride = gdk_pixbuf_get_rowstride (pixbuf);
2396       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
2397       
2398       *p++ = width;
2399       *p++ = height;
2400
2401       pixels = gdk_pixbuf_get_pixels (pixbuf);
2402
2403       for (y = 0; y < height; y++)
2404         {
2405           for (x = 0; x < width; x++)
2406             {
2407               guchar r, g, b, a;
2408               
2409               r = pixels[y*stride + x*n_channels + 0];
2410               g = pixels[y*stride + x*n_channels + 1];
2411               b = pixels[y*stride + x*n_channels + 2];
2412               if (n_channels >= 4)
2413                 a = pixels[y*stride + x*n_channels + 3];
2414               else
2415                 a = 255;
2416               
2417               *p++ = a << 24 | r << 16 | g << 8 | b ;
2418             }
2419         }
2420
2421       l = g_list_next (l);
2422     }
2423
2424   if (size > 0)
2425     {
2426       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
2427                        GDK_WINDOW_XID (window),
2428                        gdk_atom_intern ("_NET_WM_ICON", FALSE),
2429                        XA_CARDINAL, 32,
2430                        PropModeReplace,
2431                        (guchar*) data, size);
2432     }
2433   else
2434     {
2435       XDeleteProperty (GDK_WINDOW_XDISPLAY (window),
2436                        GDK_WINDOW_XID (window),
2437                        gdk_atom_intern ("_NET_WM_ICON", FALSE));
2438     }
2439 }
2440
2441 void          
2442 gdk_window_set_icon (GdkWindow *window, 
2443                      GdkWindow *icon_window,
2444                      GdkPixmap *pixmap,
2445                      GdkBitmap *mask)
2446 {
2447   XWMHints *wm_hints;
2448   
2449   g_return_if_fail (window != NULL);
2450   g_return_if_fail (GDK_IS_WINDOW (window));
2451
2452   if (GDK_WINDOW_DESTROYED (window))
2453     return;
2454
2455   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
2456                           GDK_WINDOW_XID (window));
2457   if (!wm_hints)
2458     wm_hints = XAllocWMHints ();
2459
2460   if (icon_window != NULL)
2461     {
2462       wm_hints->flags |= IconWindowHint;
2463       wm_hints->icon_window = GDK_WINDOW_XID (icon_window);
2464     }
2465   
2466   if (pixmap != NULL)
2467     {
2468       wm_hints->flags |= IconPixmapHint;
2469       wm_hints->icon_pixmap = GDK_PIXMAP_XID (pixmap);
2470     }
2471   
2472   if (mask != NULL)
2473     {
2474       wm_hints->flags |= IconMaskHint;
2475       wm_hints->icon_mask = GDK_PIXMAP_XID (mask);
2476     }
2477
2478   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
2479                GDK_WINDOW_XID (window), wm_hints);
2480   XFree (wm_hints);
2481 }
2482
2483 static gboolean
2484 gdk_window_icon_name_set (GdkWindow *window)
2485 {
2486   return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
2487                                                g_quark_from_static_string ("gdk-icon-name-set")));
2488 }
2489
2490 void          
2491 gdk_window_set_icon_name (GdkWindow   *window, 
2492                           const gchar *name)
2493 {
2494   g_return_if_fail (window != NULL);
2495   g_return_if_fail (GDK_IS_WINDOW (window));
2496
2497   if (GDK_WINDOW_DESTROYED (window))
2498     return;
2499
2500   g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
2501                       GUINT_TO_POINTER (TRUE));
2502
2503   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
2504                    GDK_WINDOW_XID (window),
2505                    gdk_atom_intern ("_NET_WM_ICON_NAME", FALSE),
2506                    gdk_atom_intern ("UTF8_STRING", FALSE), 8,
2507                    PropModeReplace, name,
2508                    strlen (name));
2509   set_text_property (window, gdk_atom_intern ("WM_ICON_NAME", FALSE), name);
2510 }
2511
2512 void
2513 gdk_window_iconify (GdkWindow *window)
2514 {
2515   Display *display;
2516   GdkWindowObject *private;
2517   
2518   g_return_if_fail (window != NULL);
2519   g_return_if_fail (GDK_IS_WINDOW (window));
2520
2521   if (GDK_WINDOW_DESTROYED (window))
2522     return;
2523
2524   display = GDK_WINDOW_XDISPLAY (window);
2525
2526   private = (GdkWindowObject*) window;
2527
2528   if (GDK_WINDOW_IS_MAPPED (window))
2529     {  
2530       XIconifyWindow (display, GDK_WINDOW_XWINDOW (window), DefaultScreen (display));
2531
2532     }
2533   else
2534     {
2535       /* Flip our client side flag, the real work happens on map. */
2536       gdk_synthesize_window_state (window,
2537                                    0,
2538                                    GDK_WINDOW_STATE_ICONIFIED);
2539     }
2540 }
2541
2542 void
2543 gdk_window_deiconify (GdkWindow *window)
2544 {
2545   Display *display;
2546   GdkWindowObject *private;
2547   
2548   g_return_if_fail (window != NULL);
2549   g_return_if_fail (GDK_IS_WINDOW (window));
2550
2551   if (GDK_WINDOW_DESTROYED (window))
2552     return;
2553
2554   display = GDK_WINDOW_XDISPLAY (window);
2555
2556   private = (GdkWindowObject*) window;
2557
2558   if (GDK_WINDOW_IS_MAPPED (window))
2559     {  
2560       gdk_window_show (window);
2561     }
2562   else
2563     {
2564       /* Flip our client side flag, the real work happens on map. */
2565       gdk_synthesize_window_state (window,
2566                                    GDK_WINDOW_STATE_ICONIFIED,
2567                                    0);
2568     }
2569 }
2570
2571 void
2572 gdk_window_stick (GdkWindow *window)
2573 {
2574   g_return_if_fail (GDK_IS_WINDOW (window));
2575
2576   if (GDK_WINDOW_DESTROYED (window))
2577     return;
2578
2579   if (GDK_WINDOW_IS_MAPPED (window))
2580     {
2581       /* "stick" means stick to all desktops _and_ do not scroll with the
2582        * viewport. i.e. glue to the monitor glass in all cases.
2583        */
2584       
2585       XEvent xev;
2586
2587       /* Request stick during viewport scroll */
2588       gdk_wmspec_change_state (TRUE, window,
2589                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
2590                                0);
2591
2592       /* Request desktop 0xFFFFFFFF */
2593       xev.xclient.type = ClientMessage;
2594       xev.xclient.serial = 0;
2595       xev.xclient.send_event = True;
2596       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
2597       xev.xclient.display = gdk_display;
2598       xev.xclient.message_type = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
2599       xev.xclient.format = 32;
2600
2601       xev.xclient.data.l[0] = 0xFFFFFFFF;
2602       
2603       XSendEvent (gdk_display, _gdk_root_window, False,
2604                   SubstructureRedirectMask | SubstructureNotifyMask,
2605                   &xev);
2606     }
2607   else
2608     {
2609       /* Flip our client side flag, the real work happens on map. */
2610       gdk_synthesize_window_state (window,
2611                                    0,
2612                                    GDK_WINDOW_STATE_STICKY);
2613     }
2614 }
2615
2616 void
2617 gdk_window_unstick (GdkWindow *window)
2618 {
2619   g_return_if_fail (GDK_IS_WINDOW (window));
2620
2621   if (GDK_WINDOW_DESTROYED (window))
2622     return;
2623
2624   if (GDK_WINDOW_IS_MAPPED (window))
2625     {
2626       XEvent xev;
2627       Atom type;
2628       gint format;
2629       gulong nitems;
2630       gulong bytes_after;
2631       gulong *current_desktop;
2632       
2633       /* Request unstick from viewport */
2634       gdk_wmspec_change_state (FALSE, window,
2635                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
2636                                0);
2637
2638       /* Get current desktop, then set it; this is a race, but not
2639        * one that matters much in practice.
2640        */
2641       XGetWindowProperty (gdk_display, _gdk_root_window,
2642                           gdk_atom_intern ("_NET_CURRENT_DESKTOP", FALSE),
2643                           0, G_MAXLONG,
2644                           False, XA_CARDINAL, &type, &format, &nitems,
2645                           &bytes_after, (guchar **)&current_desktop);
2646
2647       if (type == XA_CARDINAL)
2648         {
2649           xev.xclient.type = ClientMessage;
2650           xev.xclient.serial = 0;
2651           xev.xclient.send_event = True;
2652           xev.xclient.window = GDK_WINDOW_XWINDOW (window);
2653           xev.xclient.display = gdk_display;
2654           xev.xclient.message_type = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
2655           xev.xclient.format = 32;
2656
2657           xev.xclient.data.l[0] = *current_desktop;
2658       
2659           XSendEvent (gdk_display, _gdk_root_window, False,
2660                       SubstructureRedirectMask | SubstructureNotifyMask,
2661                       &xev);
2662
2663           XFree (current_desktop);
2664         }
2665     }
2666   else
2667     {
2668       /* Flip our client side flag, the real work happens on map. */
2669       gdk_synthesize_window_state (window,
2670                                    GDK_WINDOW_STATE_STICKY,
2671                                    0);
2672
2673     }
2674 }
2675
2676 void
2677 gdk_window_maximize (GdkWindow *window)
2678 {
2679   g_return_if_fail (GDK_IS_WINDOW (window));
2680
2681   if (GDK_WINDOW_DESTROYED (window))
2682     return;
2683
2684   if (GDK_WINDOW_IS_MAPPED (window))
2685     gdk_wmspec_change_state (TRUE, window,
2686                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
2687                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
2688   else
2689     gdk_synthesize_window_state (window,
2690                                  0,
2691                                  GDK_WINDOW_STATE_MAXIMIZED);
2692 }
2693
2694 void
2695 gdk_window_unmaximize (GdkWindow *window)
2696 {
2697   g_return_if_fail (GDK_IS_WINDOW (window));
2698
2699   if (GDK_WINDOW_DESTROYED (window))
2700     return;
2701
2702   if (GDK_WINDOW_IS_MAPPED (window))
2703     gdk_wmspec_change_state (FALSE, window,
2704                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
2705                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
2706   else
2707     gdk_synthesize_window_state (window,
2708                                  GDK_WINDOW_STATE_MAXIMIZED,
2709                                  0);
2710 }
2711
2712 void          
2713 gdk_window_set_group (GdkWindow *window, 
2714                       GdkWindow *leader)
2715 {
2716   XWMHints *wm_hints;
2717   
2718   g_return_if_fail (window != NULL);
2719   g_return_if_fail (GDK_IS_WINDOW (window));
2720   g_return_if_fail (leader != NULL);
2721   g_return_if_fail (GDK_IS_WINDOW (leader));
2722
2723   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
2724     return;
2725   
2726   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
2727                           GDK_WINDOW_XID (window));
2728   if (!wm_hints)
2729     wm_hints = XAllocWMHints ();
2730
2731   wm_hints->flags |= WindowGroupHint;
2732   wm_hints->window_group = GDK_WINDOW_XID (leader);
2733
2734   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
2735                GDK_WINDOW_XID (window), wm_hints);
2736   XFree (wm_hints);
2737 }
2738
2739 static MotifWmHints *
2740 gdk_window_get_mwm_hints (GdkWindow *window)
2741 {
2742   static Atom hints_atom = None;
2743   MotifWmHints *hints;
2744   Atom type;
2745   gint format;
2746   gulong nitems;
2747   gulong bytes_after;
2748   
2749   if (GDK_WINDOW_DESTROYED (window))
2750     return NULL;
2751   
2752   if (!hints_atom)
2753     hints_atom = XInternAtom (GDK_WINDOW_XDISPLAY (window), 
2754                               _XA_MOTIF_WM_HINTS, FALSE);
2755   
2756   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
2757                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
2758                       False, AnyPropertyType, &type, &format, &nitems,
2759                       &bytes_after, (guchar **)&hints);
2760
2761   if (type == None)
2762     return NULL;
2763   
2764   return hints;
2765 }
2766
2767 static void
2768 gdk_window_set_mwm_hints (GdkWindow *window,
2769                           MotifWmHints *new_hints)
2770 {
2771   static Atom hints_atom = None;
2772   MotifWmHints *hints;
2773   Atom type;
2774   gint format;
2775   gulong nitems;
2776   gulong bytes_after;
2777   
2778   if (GDK_WINDOW_DESTROYED (window))
2779     return;
2780   
2781   if (!hints_atom)
2782     hints_atom = XInternAtom (GDK_WINDOW_XDISPLAY (window), 
2783                               _XA_MOTIF_WM_HINTS, FALSE);
2784   
2785   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
2786                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
2787                       False, AnyPropertyType, &type, &format, &nitems,
2788                       &bytes_after, (guchar **)&hints);
2789   
2790   if (type == None)
2791     hints = new_hints;
2792   else
2793     {
2794       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
2795         {
2796           hints->flags |= MWM_HINTS_FUNCTIONS;
2797           hints->functions = new_hints->functions;
2798         }
2799       if (new_hints->flags & MWM_HINTS_DECORATIONS)
2800         {
2801           hints->flags |= MWM_HINTS_DECORATIONS;
2802           hints->decorations = new_hints->decorations;
2803         }
2804     }
2805   
2806   XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
2807                    hints_atom, hints_atom, 32, PropModeReplace,
2808                    (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
2809   
2810   if (hints != new_hints)
2811     XFree (hints);
2812 }
2813
2814 void
2815 gdk_window_set_decorations (GdkWindow      *window,
2816                             GdkWMDecoration decorations)
2817 {
2818   MotifWmHints hints;
2819   
2820   g_return_if_fail (window != NULL);
2821   g_return_if_fail (GDK_IS_WINDOW (window));
2822   
2823   hints.flags = MWM_HINTS_DECORATIONS;
2824   hints.decorations = decorations;
2825   
2826   gdk_window_set_mwm_hints (window, &hints);
2827 }
2828
2829 /**
2830  * gdk_window_get_decorations:
2831  * @window: The #GdkWindow to get the decorations from
2832  * @decorations: The window decorations will be written here
2833  *
2834  * Returns the decorations set on the GdkWindow with #gdk_window_set_decorations
2835  * Returns: TRUE if the window has decorations set, FALSE otherwise.
2836  **/
2837 gboolean
2838 gdk_window_get_decorations(GdkWindow *window,
2839                            GdkWMDecoration *decorations)
2840 {
2841   MotifWmHints *hints;
2842   gboolean result = FALSE;
2843
2844   hints = gdk_window_get_mwm_hints (window);
2845   
2846   if (hints)
2847     {
2848       if (hints->flags & MWM_HINTS_DECORATIONS)
2849         {
2850           *decorations = hints->decorations;
2851           result = TRUE;
2852         }
2853       
2854       XFree (hints);
2855     }
2856
2857   return result;
2858 }
2859
2860 void
2861 gdk_window_set_functions (GdkWindow    *window,
2862                           GdkWMFunction functions)
2863 {
2864   MotifWmHints hints;
2865   
2866   g_return_if_fail (window != NULL);
2867   g_return_if_fail (GDK_IS_WINDOW (window));
2868   
2869   hints.flags = MWM_HINTS_FUNCTIONS;
2870   hints.functions = functions;
2871   
2872   gdk_window_set_mwm_hints (window, &hints);
2873 }
2874
2875 #ifdef HAVE_SHAPE_EXT
2876
2877 /* 
2878  * propagate the shapes from all child windows of a GDK window to the parent 
2879  * window. Shamelessly ripped from Enlightenment's code
2880  * 
2881  * - Raster
2882  */
2883 struct _gdk_span
2884 {
2885   gint                start;
2886   gint                end;
2887   struct _gdk_span    *next;
2888 };
2889
2890 static void
2891 gdk_add_to_span (struct _gdk_span **s,
2892                  gint               x,
2893                  gint               xx)
2894 {
2895   struct _gdk_span *ptr1, *ptr2, *noo, *ss;
2896   gchar             spanning;
2897   
2898   ptr2 = NULL;
2899   ptr1 = *s;
2900   spanning = 0;
2901   ss = NULL;
2902   /* scan the spans for this line */
2903   while (ptr1)
2904     {
2905       /* -- -> new span */
2906       /* == -> existing span */
2907       /* ## -> spans intersect */
2908       /* if we are in the middle of spanning the span into the line */
2909       if (spanning)
2910         {
2911           /* case: ---- ==== */
2912           if (xx < ptr1->start - 1)
2913             {
2914               /* ends before next span - extend to here */
2915               ss->end = xx;
2916               return;
2917             }
2918           /* case: ----##=== */
2919           else if (xx <= ptr1->end)
2920             {
2921               /* crosses into next span - delete next span and append */
2922               ss->end = ptr1->end;
2923               ss->next = ptr1->next;
2924               g_free (ptr1);
2925               return;
2926             }
2927           /* case: ---###--- */
2928           else
2929             {
2930               /* overlaps next span - delete and keep checking */
2931               ss->next = ptr1->next;
2932               g_free (ptr1);
2933               ptr1 = ss;
2934             }
2935         }
2936       /* otherwise havent started spanning it in yet */
2937       else
2938         {
2939           /* case: ---- ==== */
2940           if (xx < ptr1->start - 1)
2941             {
2942               /* insert span here in list */
2943               noo = g_malloc (sizeof (struct _gdk_span));
2944               
2945               if (noo)
2946                 {
2947                   noo->start = x;
2948                   noo->end = xx;
2949                   noo->next = ptr1;
2950                   if (ptr2)
2951                     ptr2->next = noo;
2952                   else
2953                     *s = noo;
2954                 }
2955               return;
2956             }
2957           /* case: ----##=== */
2958           else if ((x < ptr1->start) && (xx <= ptr1->end))
2959             {
2960               /* expand this span to the left point of the new one */
2961               ptr1->start = x;
2962               return;
2963             }
2964           /* case: ===###=== */
2965           else if ((x >= ptr1->start) && (xx <= ptr1->end))
2966             {
2967               /* throw the span away */
2968               return;
2969             }
2970           /* case: ---###--- */
2971           else if ((x < ptr1->start) && (xx > ptr1->end))
2972             {
2973               ss = ptr1;
2974               spanning = 1;
2975               ptr1->start = x;
2976               ptr1->end = xx;
2977             }
2978           /* case: ===##---- */
2979           else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end))
2980             {
2981               ss = ptr1;
2982               spanning = 1;
2983               ptr1->end = xx;
2984             }
2985           /* case: ==== ---- */
2986           /* case handled by next loop iteration - first case */
2987         }
2988       ptr2 = ptr1;
2989       ptr1 = ptr1->next;
2990     }
2991   /* it started in the middle but spans beyond your current list */
2992   if (spanning)
2993     {
2994       ptr2->end = xx;
2995       return;
2996     }
2997   /* it does not start inside a span or in the middle, so add it to the end */
2998   noo = g_malloc (sizeof (struct _gdk_span));
2999   
3000   if (noo)
3001     {
3002       noo->start = x;
3003       noo->end = xx;
3004       if (ptr2)
3005         {
3006           noo->next = ptr2->next;
3007           ptr2->next = noo;
3008         }
3009       else
3010         {
3011           noo->next = NULL;
3012           *s = noo;
3013         }
3014     }
3015   return;
3016 }
3017
3018 static void
3019 gdk_add_rectangles (Display           *disp,
3020                     Window             win,
3021                     struct _gdk_span **spans,
3022                     gint               basew,
3023                     gint               baseh,
3024                     gint               x,
3025                     gint               y)
3026 {
3027   gint a, k;
3028   gint x1, y1, x2, y2;
3029   gint rn, ord;
3030   XRectangle *rl;
3031   
3032   rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord);
3033   if (rl)
3034     {
3035       /* go through all clip rects in this window's shape */
3036       for (k = 0; k < rn; k++)
3037         {
3038           /* for each clip rect, add it to each line's spans */
3039           x1 = x + rl[k].x;
3040           x2 = x + rl[k].x + (rl[k].width - 1);
3041           y1 = y + rl[k].y;
3042           y2 = y + rl[k].y + (rl[k].height - 1);
3043           if (x1 < 0)
3044             x1 = 0;
3045           if (y1 < 0)
3046             y1 = 0;
3047           if (x2 >= basew)
3048             x2 = basew - 1;
3049           if (y2 >= baseh)
3050             y2 = baseh - 1;
3051           for (a = y1; a <= y2; a++)
3052             {
3053               if ((x2 - x1) >= 0)
3054                 gdk_add_to_span (&spans[a], x1, x2);
3055             }
3056         }
3057       XFree (rl);
3058     }
3059 }
3060
3061 static void
3062 gdk_propagate_shapes (Display *disp,
3063                       Window   win,
3064                       gboolean merge)
3065 {
3066   Window              rt, par, *list = NULL;
3067   gint                i, j, num = 0, num_rects = 0;
3068   gint                x, y, contig;
3069   guint               w, h, d;
3070   gint                baseh, basew;
3071   XRectangle         *rects = NULL;
3072   struct _gdk_span  **spans = NULL, *ptr1, *ptr2, *ptr3;
3073   XWindowAttributes   xatt;
3074   
3075   XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d);
3076   if (h <= 0)
3077     return;
3078   basew = w;
3079   baseh = h;
3080   spans = g_malloc (sizeof (struct _gdk_span *) * h);
3081   
3082   for (i = 0; i < h; i++)
3083     spans[i] = NULL;
3084   XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num);
3085   if (list)
3086     {
3087       /* go through all child windows and create/insert spans */
3088       for (i = 0; i < num; i++)
3089         {
3090           if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped))
3091             if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d))
3092               gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y);
3093         }
3094       if (merge)
3095         gdk_add_rectangles (disp, win, spans, basew, baseh, x, y);
3096       
3097       /* go through the spans list and build a list of rects */
3098       rects = g_malloc (sizeof (XRectangle) * 256);
3099       num_rects = 0;
3100       for (i = 0; i < baseh; i++)
3101         {
3102           ptr1 = spans[i];
3103           /* go through the line for all spans */
3104           while (ptr1)
3105             {
3106               rects[num_rects].x = ptr1->start;
3107               rects[num_rects].y = i;
3108               rects[num_rects].width = ptr1->end - ptr1->start + 1;
3109               rects[num_rects].height = 1;
3110               j = i + 1;
3111               /* if there are more lines */
3112               contig = 1;
3113               /* while contigous rects (same start/end coords) exist */
3114               while ((contig) && (j < baseh))
3115                 {
3116                   /* search next line for spans matching this one */
3117                   contig = 0;
3118                   ptr2 = spans[j];
3119                   ptr3 = NULL;
3120                   while (ptr2)
3121                     {
3122                       /* if we have an exact span match set contig */
3123                       if ((ptr2->start == ptr1->start) &&
3124                           (ptr2->end == ptr1->end))
3125                         {
3126                           contig = 1;
3127                           /* remove the span - not needed */
3128                           if (ptr3)
3129                             {
3130                               ptr3->next = ptr2->next;
3131                               g_free (ptr2);
3132                               ptr2 = NULL;
3133                             }
3134                           else
3135                             {
3136                               spans[j] = ptr2->next;
3137                               g_free (ptr2);
3138                               ptr2 = NULL;
3139                             }
3140                           break;
3141                         }
3142                       /* gone past the span point no point looking */
3143                       else if (ptr2->start < ptr1->start)
3144                         break;
3145                       if (ptr2)
3146                         {
3147                           ptr3 = ptr2;
3148                           ptr2 = ptr2->next;
3149                         }
3150                     }
3151                   /* if a contiguous span was found increase the rect h */
3152                   if (contig)
3153                     {
3154                       rects[num_rects].height++;
3155                       j++;
3156                     }
3157                 }
3158               /* up the rect count */
3159               num_rects++;
3160               /* every 256 new rects increase the rect array */
3161               if ((num_rects % 256) == 0)
3162                 rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256));
3163               ptr1 = ptr1->next;
3164             }
3165         }
3166       /* set the rects as the shape mask */
3167       if (rects)
3168         {
3169           XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects,
3170                                    ShapeSet, YXSorted);
3171           g_free (rects);
3172         }
3173       XFree (list);
3174     }
3175   /* free up all the spans we made */
3176   for (i = 0; i < baseh; i++)
3177     {
3178       ptr1 = spans[i];
3179       while (ptr1)
3180         {
3181           ptr2 = ptr1;
3182           ptr1 = ptr1->next;
3183           g_free (ptr2);
3184         }
3185     }
3186   g_free (spans);
3187 }
3188
3189 #endif /* HAVE_SHAPE_EXT */
3190
3191 void
3192 gdk_window_set_child_shapes (GdkWindow *window)
3193 {
3194   g_return_if_fail (window != NULL);
3195   g_return_if_fail (GDK_IS_WINDOW (window));
3196   
3197 #ifdef HAVE_SHAPE_EXT
3198   if (!GDK_WINDOW_DESTROYED (window) &&
3199       gdk_window_have_shape_ext ())
3200     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3201                           GDK_WINDOW_XID (window), FALSE);
3202 #endif   
3203 }
3204
3205 void
3206 gdk_window_merge_child_shapes (GdkWindow *window)
3207 {
3208   g_return_if_fail (window != NULL);
3209   g_return_if_fail (GDK_IS_WINDOW (window));
3210   
3211 #ifdef HAVE_SHAPE_EXT
3212   if (!GDK_WINDOW_DESTROYED (window) &&
3213       gdk_window_have_shape_ext ())
3214     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3215                           GDK_WINDOW_XID (window), TRUE);
3216 #endif   
3217 }
3218
3219 /* Support for windows that can be guffaw-scrolled
3220  * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
3221  */
3222
3223 static gboolean
3224 gdk_window_gravity_works (void)
3225 {
3226   enum { UNKNOWN, NO, YES };
3227   static gint gravity_works = UNKNOWN;
3228   
3229   if (gravity_works == UNKNOWN)
3230     {
3231       GdkWindowAttr attr;
3232       GdkWindow *parent;
3233       GdkWindow *child;
3234       gint y;
3235       
3236       /* This particular server apparently has a bug so that the test
3237        * works but the actual code crashes it
3238        */
3239       if ((!strcmp (XServerVendor (gdk_display), "Sun Microsystems, Inc.")) &&
3240           (VendorRelease (gdk_display) == 3400))
3241         {
3242           gravity_works = NO;
3243           return FALSE;
3244         }
3245       
3246       attr.window_type = GDK_WINDOW_TEMP;
3247       attr.wclass = GDK_INPUT_OUTPUT;
3248       attr.x = 0;
3249       attr.y = 0;
3250       attr.width = 100;
3251       attr.height = 100;
3252       attr.event_mask = 0;
3253       
3254       parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y);
3255       
3256       attr.window_type = GDK_WINDOW_CHILD;
3257       child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
3258       
3259       gdk_window_set_static_win_gravity (child, TRUE);
3260       
3261       gdk_window_resize (parent, 100, 110);
3262       gdk_window_move (parent, 0, -10);
3263       gdk_window_move_resize (parent, 0, 0, 100, 100);
3264       
3265       gdk_window_resize (parent, 100, 110);
3266       gdk_window_move (parent, 0, -10);
3267       gdk_window_move_resize (parent, 0, 0, 100, 100);
3268       
3269       gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
3270       
3271       gdk_window_destroy (parent);
3272       gdk_window_destroy (child);
3273       
3274       gravity_works = ((y == -20) ? YES : NO);
3275     }
3276   
3277   return (gravity_works == YES);
3278 }
3279
3280 static void
3281 gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
3282 {
3283   XSetWindowAttributes xattributes;
3284   guint xattributes_mask = 0;
3285   
3286   g_return_if_fail (window != NULL);
3287   
3288   xattributes.bit_gravity = StaticGravity;
3289   xattributes_mask |= CWBitGravity;
3290   xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
3291   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3292                            GDK_WINDOW_XID (window),
3293                            CWBitGravity,  &xattributes);
3294 }
3295
3296 static void
3297 gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
3298 {
3299   XSetWindowAttributes xattributes;
3300   
3301   g_return_if_fail (window != NULL);
3302   
3303   xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
3304   
3305   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3306                            GDK_WINDOW_XID (window),
3307                            CWWinGravity,  &xattributes);
3308 }
3309
3310 /*************************************************************
3311  * gdk_window_set_static_gravities:
3312  *     Set the bit gravity of the given window to static,
3313  *     and flag it so all children get static subwindow
3314  *     gravity.
3315  *   arguments:
3316  *     window: window for which to set static gravity
3317  *     use_static: Whether to turn static gravity on or off.
3318  *   results:
3319  *     Does the XServer support static gravity?
3320  *************************************************************/
3321
3322 gboolean 
3323 gdk_window_set_static_gravities (GdkWindow *window,
3324                                  gboolean   use_static)
3325 {
3326   GdkWindowObject *private = (GdkWindowObject *)window;
3327   GList *tmp_list;
3328   
3329   g_return_val_if_fail (window != NULL, FALSE);
3330   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
3331
3332   if (!use_static == !private->guffaw_gravity)
3333     return TRUE;
3334   
3335   if (use_static && !gdk_window_gravity_works ())
3336     return FALSE;
3337   
3338   private->guffaw_gravity = use_static;
3339   
3340   if (!GDK_WINDOW_DESTROYED (window))
3341     {
3342       gdk_window_set_static_bit_gravity (window, use_static);
3343       
3344       tmp_list = private->children;
3345       while (tmp_list)
3346         {
3347           gdk_window_set_static_win_gravity (window, use_static);
3348           
3349           tmp_list = tmp_list->next;
3350         }
3351     }
3352   
3353   return TRUE;
3354 }
3355
3356 /* internal function created for and used by gdk_window_xid_at_coords */
3357 Window
3358 gdk_window_xid_at (Window   base,
3359                    gint     bx,
3360                    gint     by,
3361                    gint     x,
3362                    gint     y, 
3363                    GList   *excludes,
3364                    gboolean excl_child)
3365 {
3366   Display *xdisplay;
3367   Window *list = NULL;
3368   Window child = 0, parent_win = 0, root_win = 0;
3369   int i;
3370   unsigned int ww, wh, wb, wd, num;
3371   int wx, wy;
3372   
3373   xdisplay = GDK_DISPLAY ();
3374   if (!XGetGeometry (xdisplay, base, &root_win, &wx, &wy, &ww, &wh, &wb, &wd))
3375     return 0;
3376   wx += bx;
3377   wy += by;
3378   
3379   if (!((x >= wx) &&
3380         (y >= wy) &&
3381         (x < (int) (wx + ww)) &&
3382         (y < (int) (wy + wh))))
3383     return 0;
3384   
3385   if (!XQueryTree (xdisplay, base, &root_win, &parent_win, &list, &num))
3386     return base;
3387   
3388   if (list)
3389     {
3390       for (i = num - 1; ; i--)
3391         {
3392           if ((!excl_child) || (!g_list_find (excludes, (gpointer *) list[i])))
3393             {
3394               if ((child = gdk_window_xid_at (list[i], wx, wy, x, y, excludes, excl_child)) != 0)
3395                 {
3396                   XFree (list);
3397                   return child;
3398                 }
3399             }
3400           if (!i)
3401             break;
3402         }
3403       XFree (list);
3404     }
3405   return base;
3406 }
3407
3408 /* 
3409  * The following fucntion by The Rasterman <raster@redhat.com>
3410  * This function returns the X Window ID in which the x y location is in 
3411  * (x and y being relative to the root window), excluding any windows listed
3412  * in the GList excludes (this is a list of X Window ID's - gpointer being
3413  * the Window ID).
3414  * 
3415  * This is primarily designed for internal gdk use - for DND for example
3416  * when using a shaped icon window as the drag object - you exclude the
3417  * X Window ID of the "icon" (perhaps more if excludes may be needed) and
3418  * You can get back an X Window ID as to what X Window ID is infact under
3419  * those X,Y co-ordinates.
3420  */
3421 Window
3422 gdk_window_xid_at_coords (gint     x,
3423                           gint     y,
3424                           GList   *excludes,
3425                           gboolean excl_child)
3426 {
3427   GdkWindow *window;
3428   Display *xdisplay;
3429   Window *list = NULL;
3430   Window root, child = 0, parent_win = 0, root_win = 0;
3431   unsigned int num;
3432   int i;
3433
3434   window = _gdk_parent_root;
3435   xdisplay = GDK_WINDOW_XDISPLAY (window);
3436   root = GDK_WINDOW_XID (window);
3437   num = g_list_length (excludes);
3438   
3439   gdk_x11_grab_server ();
3440   if (!XQueryTree (xdisplay, root, &root_win, &parent_win, &list, &num))
3441     {
3442       gdk_x11_ungrab_server ();
3443       return root;
3444     }
3445   if (list)
3446     {
3447       i = num - 1;
3448       do
3449         {
3450           XWindowAttributes xwa;
3451           
3452           XGetWindowAttributes (xdisplay, list [i], &xwa);
3453           
3454           if (xwa.map_state != IsViewable)
3455             continue;
3456           
3457           if (excl_child && g_list_find (excludes, (gpointer *) list[i]))
3458             continue;
3459           
3460           if ((child = gdk_window_xid_at (list[i], 0, 0, x, y, excludes, excl_child)) == 0)
3461             continue;
3462           
3463           if (excludes)
3464             {
3465               if (!g_list_find (excludes, (gpointer *) child))
3466                 {
3467                   XFree (list);
3468                   gdk_x11_ungrab_server ();
3469                   return child;
3470                 }
3471             }
3472           else
3473             {
3474               XFree (list);
3475               gdk_x11_ungrab_server ();
3476               return child;
3477             }
3478         } while (--i > 0);
3479       XFree (list);
3480     }
3481   gdk_x11_ungrab_server ();
3482   return root;
3483 }
3484
3485 static void
3486 wmspec_moveresize (GdkWindow *window,
3487                    gint       direction,
3488                    gint       root_x,
3489                    gint       root_y,
3490                    guint32    timestamp)     
3491 {
3492   XEvent xev;
3493
3494   /* Release passive grab */
3495   gdk_pointer_ungrab (timestamp);
3496   
3497   xev.xclient.type = ClientMessage;
3498   xev.xclient.serial = 0;
3499   xev.xclient.send_event = True;
3500   xev.xclient.display = gdk_display;
3501   xev.xclient.window = GDK_WINDOW_XID (window);
3502   xev.xclient.message_type = gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE);
3503   xev.xclient.format = 32;
3504   xev.xclient.data.l[0] = root_x;
3505   xev.xclient.data.l[1] = root_y;
3506   xev.xclient.data.l[2] = direction;
3507   xev.xclient.data.l[3] = 0;
3508   xev.xclient.data.l[4] = 0;
3509   
3510   XSendEvent (gdk_display, _gdk_root_window, False,
3511               SubstructureRedirectMask | SubstructureNotifyMask,
3512               &xev);
3513 }
3514
3515 /* From the WM spec */
3516 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
3517 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
3518 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
3519 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
3520 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
3521 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
3522 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
3523 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
3524 #define _NET_WM_MOVERESIZE_MOVE              8
3525
3526 static void
3527 wmspec_resize_drag (GdkWindow     *window,
3528                     GdkWindowEdge  edge,
3529                     gint           button,
3530                     gint           root_x,
3531                     gint           root_y,
3532                     guint32        timestamp)
3533 {
3534   gint direction;
3535   
3536   /* Let the compiler turn a switch into a table, instead
3537    * of doing the table manually, this way is easier to verify.
3538    */
3539   switch (edge)
3540     {
3541     case GDK_WINDOW_EDGE_NORTH_WEST:
3542       direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
3543       break;
3544
3545     case GDK_WINDOW_EDGE_NORTH:
3546       direction = _NET_WM_MOVERESIZE_SIZE_TOP;
3547       break;
3548
3549     case GDK_WINDOW_EDGE_NORTH_EAST:
3550       direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
3551       break;
3552
3553     case GDK_WINDOW_EDGE_WEST:
3554       direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
3555       break;
3556
3557     case GDK_WINDOW_EDGE_EAST:
3558       direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
3559       break;
3560
3561     case GDK_WINDOW_EDGE_SOUTH_WEST:
3562       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
3563       break;
3564
3565     case GDK_WINDOW_EDGE_SOUTH:
3566       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
3567       break;
3568
3569     case GDK_WINDOW_EDGE_SOUTH_EAST:
3570       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
3571       break;
3572
3573     default:
3574       g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!",
3575                  edge);
3576       return;
3577       break;
3578     }
3579   
3580   wmspec_moveresize (window, direction, root_x, root_y, timestamp);
3581 }
3582
3583 /* This is global for use in gdkevents-x11.c */
3584 GdkWindow *_gdk_moveresize_window;
3585
3586 static GdkWindow *moveresize_emulation_window = NULL;
3587 static gboolean is_resize = FALSE;
3588 static GdkWindowEdge resize_edge;
3589 static gint moveresize_button;
3590 static gint moveresize_x;
3591 static gint moveresize_y;
3592 static gint moveresize_orig_x;
3593 static gint moveresize_orig_y;
3594 static gint moveresize_orig_width;
3595 static gint moveresize_orig_height;
3596 static GdkWindowHints moveresize_geom_mask = 0;
3597 static GdkGeometry moveresize_geometry;
3598 static Time moveresize_process_time;
3599
3600 static XEvent *moveresize_pending_event;
3601
3602 static void
3603 update_pos (gint new_root_x,
3604             gint new_root_y)
3605 {
3606   gint dx, dy;
3607   
3608   dx = new_root_x - moveresize_x;
3609   dy = new_root_y - moveresize_y;
3610
3611   if (is_resize)
3612     {
3613       gint w, h;
3614
3615       w = moveresize_orig_width;
3616       h = moveresize_orig_height;
3617       
3618       switch (resize_edge)
3619         {
3620         case GDK_WINDOW_EDGE_SOUTH_EAST:
3621           w += dx;
3622           h += dy;
3623           break;
3624         }
3625
3626       w = MAX (w, 1);
3627       h = MAX (h, 1);
3628       
3629       if (moveresize_geom_mask)
3630         {
3631           gdk_window_constrain_size (&moveresize_geometry,
3632                                      moveresize_geom_mask,
3633                                      w, h,
3634                                      &w, &h);
3635         }
3636       
3637       gdk_window_resize (_gdk_moveresize_window, w, h);
3638     }
3639   else
3640     {
3641       gint x, y;
3642
3643       x = moveresize_orig_x + dx;
3644       y = moveresize_orig_y + dy;
3645       
3646       gdk_window_move (_gdk_moveresize_window, x, y);
3647     }
3648 }
3649
3650 static void
3651 finish_drag (void)
3652 {
3653   gdk_window_destroy (moveresize_emulation_window);
3654   moveresize_emulation_window = NULL;
3655   _gdk_moveresize_window = NULL;
3656
3657   if (moveresize_pending_event)
3658     {
3659       g_free (moveresize_pending_event);
3660       moveresize_pending_event = NULL;
3661     }
3662 }
3663
3664 static int
3665 lookahead_motion_predicate (Display *display,
3666                             XEvent  *event,
3667                             XPointer arg)
3668 {
3669   gboolean *seen_release = (gboolean *)arg;
3670   
3671   if (*seen_release)
3672     return False;
3673
3674   switch (event->xany.type)
3675     {
3676     case ButtonRelease:
3677       *seen_release = TRUE;
3678       break;
3679     case MotionNotify:
3680       moveresize_process_time = event->xmotion.time;
3681       break;
3682     default:
3683       break;
3684     }
3685
3686   return False;
3687 }
3688
3689 static gboolean
3690 moveresize_lookahead (XEvent *event)
3691 {
3692   XEvent tmp_event;
3693   gboolean seen_release = FALSE;
3694
3695   if (moveresize_process_time)
3696     {
3697       if (event->xmotion.time == moveresize_process_time)
3698         {
3699           moveresize_process_time = 0;
3700           return TRUE;
3701         }
3702       else
3703         return FALSE;
3704     }
3705
3706   XCheckIfEvent (gdk_display, &tmp_event,
3707                  lookahead_motion_predicate, (XPointer)&seen_release);
3708
3709   return moveresize_process_time == 0;
3710 }
3711         
3712 void
3713 _gdk_moveresize_handle_event (XEvent *event)
3714 {
3715   guint button_mask = 0;
3716   GdkWindowObject *window_private = (GdkWindowObject *) _gdk_moveresize_window;
3717   
3718   button_mask = GDK_BUTTON1_MASK << (moveresize_button - 1);
3719   
3720   switch (event->xany.type)
3721     {
3722     case MotionNotify:
3723       if (window_private->resize_count > 0)
3724         {
3725           if (moveresize_pending_event)
3726             *moveresize_pending_event = *event;
3727           else
3728             moveresize_pending_event = g_memdup (event, sizeof (XEvent));
3729
3730           break;
3731         }
3732       if (!moveresize_lookahead (event))
3733         break;
3734       
3735       update_pos (event->xmotion.x_root,
3736                   event->xmotion.y_root);
3737       
3738       /* This should never be triggered in normal cases, but in the
3739        * case where the drag started without an implicit grab being
3740        * in effect, we could miss the release if it occurs before
3741        * we grab the pointer; this ensures that we will never
3742        * get a permanently stuck grab.
3743        */
3744       if ((event->xmotion.state & button_mask) == 0)
3745         finish_drag ();
3746       break;
3747
3748     case ButtonRelease:
3749       update_pos (event->xbutton.x_root,
3750                   event->xbutton.y_root);
3751       
3752       if (event->xbutton.button == moveresize_button)
3753         finish_drag ();
3754       break;
3755     }
3756 }
3757
3758 void
3759 _gdk_moveresize_configure_done (void)
3760 {
3761   XEvent *tmp_event;
3762   
3763   if (moveresize_pending_event)
3764     {
3765       tmp_event = moveresize_pending_event;
3766       moveresize_pending_event = NULL;
3767       _gdk_moveresize_handle_event (tmp_event);
3768       g_free (tmp_event);
3769     }
3770 }
3771
3772 static void
3773 create_moveresize_window (guint32 timestamp)
3774 {
3775   GdkWindowAttr attributes;
3776   gint attributes_mask;
3777   GdkGrabStatus status;
3778
3779   g_assert (moveresize_emulation_window == NULL);
3780   
3781   attributes.x = -100;
3782   attributes.y = -100;
3783   attributes.width = 10;
3784   attributes.height = 10;
3785   attributes.window_type = GDK_WINDOW_TEMP;
3786   attributes.wclass = GDK_INPUT_ONLY;
3787   attributes.override_redirect = TRUE;
3788   attributes.event_mask = 0;
3789
3790   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
3791
3792   moveresize_emulation_window =
3793     gdk_window_new (NULL, &attributes, attributes_mask);
3794
3795   gdk_window_show (moveresize_emulation_window);
3796
3797   status = gdk_pointer_grab (moveresize_emulation_window,
3798                              FALSE,
3799                              GDK_BUTTON_RELEASE_MASK |
3800                              GDK_POINTER_MOTION_MASK,
3801                              FALSE,
3802                              NULL,
3803                              timestamp);
3804
3805   if (status != GDK_GRAB_SUCCESS)
3806     {
3807       /* If this fails, some other client has grabbed the window
3808        * already.
3809        */
3810       gdk_window_destroy (moveresize_emulation_window);
3811       moveresize_emulation_window = NULL;
3812     }
3813
3814   moveresize_process_time = 0;
3815 }
3816
3817 static void
3818 emulate_resize_drag (GdkWindow     *window,
3819                      GdkWindowEdge  edge,
3820                      gint           button,
3821                      gint           root_x,
3822                      gint           root_y,
3823                      guint32        timestamp)
3824 {
3825   is_resize = TRUE;
3826   moveresize_button = button;
3827   resize_edge = edge;
3828   moveresize_x = root_x;
3829   moveresize_y = root_y;
3830   _gdk_moveresize_window = GDK_WINDOW (g_object_ref (G_OBJECT (window)));
3831
3832   gdk_window_get_size (window, &moveresize_orig_width, &moveresize_orig_height);
3833   
3834   moveresize_geom_mask = 0;
3835   gdk_window_get_geometry_hints (window,
3836                                  &moveresize_geometry,
3837                                  &moveresize_geom_mask);
3838   
3839   create_moveresize_window (timestamp);
3840 }
3841
3842 static void
3843 emulate_move_drag (GdkWindow     *window,
3844                    gint           button,
3845                    gint           root_x,
3846                    gint           root_y,
3847                    guint32        timestamp)
3848 {
3849   is_resize = FALSE;
3850   moveresize_button = button;
3851   moveresize_x = root_x;
3852   moveresize_y = root_y;
3853   _gdk_moveresize_window = GDK_WINDOW (g_object_ref (G_OBJECT (window)));
3854
3855   gdk_window_get_deskrelative_origin (_gdk_moveresize_window,
3856                                       &moveresize_orig_x,
3857                                       &moveresize_orig_y);
3858   
3859   create_moveresize_window (timestamp);
3860 }
3861
3862 void
3863 gdk_window_begin_resize_drag (GdkWindow     *window,
3864                               GdkWindowEdge  edge,
3865                               gint           button,
3866                               gint           root_x,
3867                               gint           root_y,
3868                               guint32        timestamp)
3869 {
3870   g_return_if_fail (GDK_IS_WINDOW (window));
3871   g_return_if_fail (moveresize_emulation_window == NULL);
3872   
3873   if (GDK_WINDOW_DESTROYED (window))
3874     return;
3875
3876   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
3877     wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp);
3878   else
3879     emulate_resize_drag (window, edge, button, root_x, root_y, timestamp);
3880 }
3881
3882 void
3883 gdk_window_begin_move_drag (GdkWindow *window,
3884                             gint       button,
3885                             gint       root_x,
3886                             gint       root_y,
3887                             guint32    timestamp)
3888 {
3889   g_return_if_fail (GDK_IS_WINDOW (window));
3890   g_return_if_fail (moveresize_emulation_window == NULL);
3891   
3892   if (GDK_WINDOW_DESTROYED (window))
3893     return;
3894
3895   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
3896     wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE,
3897                        root_x, root_y, timestamp);
3898   else
3899     emulate_move_drag (window, button, root_x, root_y, timestamp);
3900 }