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