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