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