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