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