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