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