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