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