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