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