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