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