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