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