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