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