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