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