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