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