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