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