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