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