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