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