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