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