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