]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkwindow-x11.c
Merge branch 'master' into broadway
[~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 /**
973  * gdk_window_lookup:
974  * @anid: a native window handle.
975  *
976  * Looks up the #GdkWindow that wraps the given native window handle. 
977  *
978  * For example in the X backend, a native window handle is an Xlib
979  * <type>XID</type>.
980  *
981  * Return value: (transfer none): the #GdkWindow wrapper for the native
982  *    window, or %NULL if there is none.
983  **/
984 GdkWindow *
985 gdk_window_lookup (GdkNativeWindow anid)
986 {
987   return (GdkWindow*) gdk_xid_table_lookup (anid);
988 }
989
990 static void
991 gdk_toplevel_x11_free_contents (GdkDisplay *display,
992                                 GdkToplevelX11 *toplevel)
993 {
994   if (toplevel->icon_pixmap)
995     {
996       cairo_surface_destroy (toplevel->icon_pixmap);
997       toplevel->icon_pixmap = NULL;
998     }
999   if (toplevel->icon_mask)
1000     {
1001       cairo_surface_destroy (toplevel->icon_mask);
1002       toplevel->icon_mask = NULL;
1003     }
1004   if (toplevel->group_leader)
1005     {
1006       g_object_unref (toplevel->group_leader);
1007       toplevel->group_leader = NULL;
1008     }
1009 #ifdef HAVE_XSYNC
1010   if (toplevel->update_counter != None)
1011     {
1012       XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display), 
1013                            toplevel->update_counter);
1014       toplevel->update_counter = None;
1015
1016       XSyncIntToValue (&toplevel->current_counter_value, 0);
1017     }
1018 #endif
1019 }
1020
1021 static void
1022 _gdk_x11_window_destroy (GdkWindow *window,
1023                          gboolean   recursing,
1024                          gboolean   foreign_destroy)
1025 {
1026   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
1027   GdkToplevelX11 *toplevel;
1028   
1029   g_return_if_fail (GDK_IS_WINDOW (window));
1030
1031   _gdk_selection_window_destroyed (window);
1032   
1033   toplevel = _gdk_x11_window_get_toplevel (window);
1034   if (toplevel)
1035     gdk_toplevel_x11_free_contents (GDK_WINDOW_DISPLAY (window), toplevel);
1036
1037   if (impl->cairo_surface)
1038     {
1039       cairo_surface_finish (impl->cairo_surface);
1040       cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key,
1041                                    NULL, NULL);
1042     }
1043
1044   if (!recursing && !foreign_destroy)
1045     {
1046       XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1047     }
1048 }
1049
1050 static cairo_surface_t *
1051 gdk_window_x11_resize_cairo_surface (GdkWindow       *window,
1052                                      cairo_surface_t *surface,
1053                                      gint             width,
1054                                      gint             height)
1055 {
1056   cairo_xlib_surface_set_size (surface, width, height);
1057
1058   return surface;
1059 }
1060
1061 void
1062 _gdk_windowing_window_destroy_foreign (GdkWindow *window)
1063 {
1064   /* It's somebody else's window, but in our hierarchy,
1065    * so reparent it to the root window, and then send
1066    * it a delete event, as if we were a WM
1067    */
1068   XClientMessageEvent xclient;
1069   
1070   gdk_error_trap_push ();
1071   gdk_window_hide (window);
1072   gdk_window_reparent (window, NULL, 0, 0);
1073   
1074   memset (&xclient, 0, sizeof (xclient));
1075   xclient.type = ClientMessage;
1076   xclient.window = GDK_WINDOW_XID (window);
1077   xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
1078                                                                "WM_PROTOCOLS");
1079   xclient.format = 32;
1080   xclient.data.l[0] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
1081                                                             "WM_DELETE_WINDOW");
1082   xclient.data.l[1] = CurrentTime;
1083   xclient.data.l[2] = 0;
1084   xclient.data.l[3] = 0;
1085   xclient.data.l[4] = 0;
1086   
1087   XSendEvent (GDK_WINDOW_XDISPLAY (window),
1088               GDK_WINDOW_XID (window),
1089               False, 0, (XEvent *)&xclient);
1090   gdk_error_trap_pop_ignored ();
1091 }
1092
1093 static GdkWindow *
1094 get_root (GdkWindow *window)
1095 {
1096   GdkScreen *screen = gdk_window_get_screen (window);
1097
1098   return gdk_screen_get_root_window (screen);
1099 }
1100
1101 /* This function is called when the XWindow is really gone.
1102  */
1103 void
1104 gdk_window_destroy_notify (GdkWindow *window)
1105 {
1106   GdkWindowImplX11 *window_impl;
1107
1108   window_impl = GDK_WINDOW_IMPL_X11 ((window)->impl);
1109
1110   if (!GDK_WINDOW_DESTROYED (window))
1111     {
1112       if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN)
1113         g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_WINDOW_XID (window));
1114
1115       _gdk_window_destroy (window, TRUE);
1116     }
1117   
1118   _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), GDK_WINDOW_XID (window));
1119   if (window_impl->toplevel && window_impl->toplevel->focus_window)
1120     _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), window_impl->toplevel->focus_window);
1121
1122   _gdk_xgrab_check_destroy (window);
1123   
1124   g_object_unref (window);
1125 }
1126
1127 static void
1128 update_wm_hints (GdkWindow *window,
1129                  gboolean   force)
1130 {
1131   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
1132   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
1133   XWMHints wm_hints;
1134
1135   if (!force &&
1136       !toplevel->is_leader &&
1137       window->state & GDK_WINDOW_STATE_WITHDRAWN)
1138     return;
1139
1140   wm_hints.flags = StateHint | InputHint;
1141   wm_hints.input = window->accept_focus ? True : False;
1142   wm_hints.initial_state = NormalState;
1143   
1144   if (window->state & GDK_WINDOW_STATE_ICONIFIED)
1145     {
1146       wm_hints.flags |= StateHint;
1147       wm_hints.initial_state = IconicState;
1148     }
1149
1150   if (toplevel->icon_pixmap)
1151     {
1152       wm_hints.flags |= IconPixmapHint;
1153       wm_hints.icon_pixmap = cairo_xlib_surface_get_drawable (toplevel->icon_pixmap);
1154     }
1155
1156   if (toplevel->icon_mask)
1157     {
1158       wm_hints.flags |= IconMaskHint;
1159       wm_hints.icon_mask = cairo_xlib_surface_get_drawable (toplevel->icon_mask);
1160     }
1161   
1162   wm_hints.flags |= WindowGroupHint;
1163   if (toplevel->group_leader && !GDK_WINDOW_DESTROYED (toplevel->group_leader))
1164     {
1165       wm_hints.flags |= WindowGroupHint;
1166       wm_hints.window_group = GDK_WINDOW_XID (toplevel->group_leader);
1167     }
1168   else
1169     wm_hints.window_group = GDK_DISPLAY_X11 (display)->leader_window;
1170
1171   if (toplevel->urgency_hint)
1172     wm_hints.flags |= XUrgencyHint;
1173   
1174   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
1175                GDK_WINDOW_XID (window),
1176                &wm_hints);
1177 }
1178
1179 static void
1180 set_initial_hints (GdkWindow *window)
1181 {
1182   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
1183   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
1184   Window xwindow = GDK_WINDOW_XID (window);  
1185   GdkToplevelX11 *toplevel;
1186   Atom atoms[9];
1187   gint i;
1188
1189   toplevel = _gdk_x11_window_get_toplevel (window);
1190
1191   if (!toplevel)
1192     return;
1193
1194   update_wm_hints (window, TRUE);
1195   
1196   /* We set the spec hints regardless of whether the spec is supported,
1197    * since it can't hurt and it's kind of expensive to check whether
1198    * it's supported.
1199    */
1200   
1201   i = 0;
1202
1203   if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
1204     {
1205       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1206                                                         "_NET_WM_STATE_MAXIMIZED_VERT");
1207       ++i;
1208       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1209                                                         "_NET_WM_STATE_MAXIMIZED_HORZ");
1210       ++i;
1211       toplevel->have_maxhorz = toplevel->have_maxvert = TRUE;
1212     }
1213
1214   if (window->state & GDK_WINDOW_STATE_ABOVE)
1215     {
1216       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1217                                                         "_NET_WM_STATE_ABOVE");
1218       ++i;
1219     }
1220   
1221   if (window->state & GDK_WINDOW_STATE_BELOW)
1222     {
1223       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1224                                                         "_NET_WM_STATE_BELOW");
1225       ++i;
1226     }
1227   
1228   if (window->state & GDK_WINDOW_STATE_STICKY)
1229     {
1230       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1231                                                         "_NET_WM_STATE_STICKY");
1232       ++i;
1233       toplevel->have_sticky = TRUE;
1234     }
1235
1236   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1237     {
1238       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1239                                                         "_NET_WM_STATE_FULLSCREEN");
1240       ++i;
1241       toplevel->have_fullscreen = TRUE;
1242     }
1243
1244   if (window->modal_hint)
1245     {
1246       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1247                                                         "_NET_WM_STATE_MODAL");
1248       ++i;
1249     }
1250
1251   if (toplevel->skip_taskbar_hint)
1252     {
1253       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1254                                                         "_NET_WM_STATE_SKIP_TASKBAR");
1255       ++i;
1256     }
1257
1258   if (toplevel->skip_pager_hint)
1259     {
1260       atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
1261                                                         "_NET_WM_STATE_SKIP_PAGER");
1262       ++i;
1263     }
1264
1265   if (i > 0)
1266     {
1267       XChangeProperty (xdisplay,
1268                        xwindow,
1269                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
1270                        XA_ATOM, 32, PropModeReplace,
1271                        (guchar*) atoms, i);
1272     }
1273   else 
1274     {
1275       XDeleteProperty (xdisplay,
1276                        xwindow,
1277                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"));
1278     }
1279
1280   if (window->state & GDK_WINDOW_STATE_STICKY)
1281     {
1282       atoms[0] = 0xFFFFFFFF;
1283       XChangeProperty (xdisplay,
1284                        xwindow,
1285                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
1286                        XA_CARDINAL, 32, PropModeReplace,
1287                        (guchar*) atoms, 1);
1288       toplevel->on_all_desktops = TRUE;
1289     }
1290   else
1291     {
1292       XDeleteProperty (xdisplay,
1293                        xwindow,
1294                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"));
1295     }
1296
1297   toplevel->map_serial = NextRequest (xdisplay);
1298 }
1299
1300 static void
1301 gdk_window_x11_show (GdkWindow *window, gboolean already_mapped)
1302 {
1303   GdkDisplay *display;
1304   GdkDisplayX11 *display_x11;
1305   GdkToplevelX11 *toplevel;
1306   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
1307   Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
1308   Window xwindow = GDK_WINDOW_XID (window);
1309   gboolean unset_bg;
1310
1311   if (!already_mapped)
1312     set_initial_hints (window);
1313       
1314   if (WINDOW_IS_TOPLEVEL (window))
1315     {
1316       display = gdk_window_get_display (window);
1317       display_x11 = GDK_DISPLAY_X11 (display);
1318       toplevel = _gdk_x11_window_get_toplevel (window);
1319       
1320       if (toplevel->user_time != 0 &&
1321               display_x11->user_time != 0 &&
1322           XSERVER_TIME_IS_LATER (display_x11->user_time, toplevel->user_time))
1323         gdk_x11_window_set_user_time (window, display_x11->user_time);
1324     }
1325   
1326   unset_bg = !window->input_only &&
1327     (window->window_type == GDK_WINDOW_CHILD ||
1328      impl->override_redirect) &&
1329     gdk_window_is_viewable (window);
1330   
1331   if (unset_bg)
1332     _gdk_x11_window_tmp_unset_bg (window, TRUE);
1333   
1334   XMapWindow (xdisplay, xwindow);
1335   
1336   if (unset_bg)
1337     _gdk_x11_window_tmp_reset_bg (window, TRUE);
1338 }
1339
1340 static void
1341 pre_unmap (GdkWindow *window)
1342 {
1343   GdkWindow *start_window = NULL;
1344
1345   if (window->input_only)
1346     return;
1347
1348   if (window->window_type == GDK_WINDOW_CHILD)
1349     start_window = _gdk_window_get_impl_window ((GdkWindow *)window->parent);
1350   else if (window->window_type == GDK_WINDOW_TEMP)
1351     start_window = get_root (window);
1352
1353   if (start_window)
1354     _gdk_x11_window_tmp_unset_bg (start_window, TRUE);
1355 }
1356
1357 static void
1358 post_unmap (GdkWindow *window)
1359 {
1360   GdkWindow *start_window = NULL;
1361   
1362   if (window->input_only)
1363     return;
1364
1365   if (window->window_type == GDK_WINDOW_CHILD)
1366     start_window = _gdk_window_get_impl_window ((GdkWindow *)window->parent);
1367   else if (window->window_type == GDK_WINDOW_TEMP)
1368     start_window = get_root (window);
1369
1370   if (start_window)
1371     {
1372       _gdk_x11_window_tmp_reset_bg (start_window, TRUE);
1373
1374       if (window->window_type == GDK_WINDOW_CHILD && window->parent)
1375         {
1376           GdkRectangle invalid_rect;
1377       
1378           gdk_window_get_position (window, &invalid_rect.x, &invalid_rect.y);
1379           invalid_rect.width = gdk_window_get_width (window);
1380           invalid_rect.height = gdk_window_get_height (window);
1381           gdk_window_invalidate_rect ((GdkWindow *)window->parent,
1382                                       &invalid_rect, TRUE);
1383         }
1384     }
1385 }
1386
1387 static void
1388 gdk_window_x11_hide (GdkWindow *window)
1389 {
1390   /* We'll get the unmap notify eventually, and handle it then,
1391    * but checking here makes things more consistent if we are
1392    * just doing stuff ourself.
1393    */
1394   _gdk_xgrab_check_unmap (window,
1395                           NextRequest (GDK_WINDOW_XDISPLAY (window)));
1396
1397   /* You can't simply unmap toplevel windows. */
1398   switch (window->window_type)
1399     {
1400     case GDK_WINDOW_TOPLEVEL:
1401     case GDK_WINDOW_TEMP: /* ? */
1402       gdk_window_withdraw (window);
1403       return;
1404       
1405     case GDK_WINDOW_FOREIGN:
1406     case GDK_WINDOW_ROOT:
1407     case GDK_WINDOW_CHILD:
1408       break;
1409     }
1410   
1411   _gdk_window_clear_update_area (window);
1412   
1413   pre_unmap (window);
1414   XUnmapWindow (GDK_WINDOW_XDISPLAY (window),
1415                 GDK_WINDOW_XID (window));
1416   post_unmap (window);
1417 }
1418
1419 static void
1420 gdk_window_x11_withdraw (GdkWindow *window)
1421 {
1422   if (!window->destroyed)
1423     {
1424       if (GDK_WINDOW_IS_MAPPED (window))
1425         gdk_synthesize_window_state (window,
1426                                      0,
1427                                      GDK_WINDOW_STATE_WITHDRAWN);
1428
1429       g_assert (!GDK_WINDOW_IS_MAPPED (window));
1430
1431       pre_unmap (window);
1432       
1433       XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
1434                        GDK_WINDOW_XID (window), 0);
1435
1436       post_unmap (window);
1437     }
1438 }
1439
1440 static inline void
1441 window_x11_move (GdkWindow *window,
1442                  gint       x,
1443                  gint       y)
1444 {
1445   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
1446
1447   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1448     {
1449       _gdk_window_move_resize_child (window,
1450                                      x, y,
1451                                      window->width, window->height);
1452     }
1453   else
1454     {
1455       XMoveWindow (GDK_WINDOW_XDISPLAY (window),
1456                    GDK_WINDOW_XID (window),
1457                    x, y);
1458
1459       if (impl->override_redirect)
1460         {
1461           window->x = x;
1462           window->y = y;
1463         }
1464     }
1465 }
1466
1467 static inline void
1468 window_x11_resize (GdkWindow *window,
1469                    gint       width,
1470                    gint       height)
1471 {
1472   if (width < 1)
1473     width = 1;
1474
1475   if (height < 1)
1476     height = 1;
1477
1478   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1479     {
1480       _gdk_window_move_resize_child (window,
1481                                      window->x, window->y,
1482                                      width, height);
1483     }
1484   else
1485     {
1486       GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
1487
1488       XResizeWindow (GDK_WINDOW_XDISPLAY (window),
1489                      GDK_WINDOW_XID (window),
1490                      width, height);
1491
1492       if (impl->override_redirect)
1493         {
1494           window->width = width;
1495           window->height = height;
1496           _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
1497         }
1498       else
1499         {
1500           if (width != window->width || height != window->height)
1501             window->resize_count += 1;
1502         }
1503     }
1504
1505   _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
1506 }
1507
1508 static inline void
1509 window_x11_move_resize (GdkWindow *window,
1510                         gint       x,
1511                         gint       y,
1512                         gint       width,
1513                         gint       height)
1514 {
1515   if (width < 1)
1516     width = 1;
1517
1518   if (height < 1)
1519     height = 1;
1520
1521   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1522     {
1523       _gdk_window_move_resize_child (window, x, y, width, height);
1524       _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
1525     }
1526   else
1527     {
1528       GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
1529
1530       XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
1531                          GDK_WINDOW_XID (window),
1532                          x, y, width, height);
1533
1534       if (impl->override_redirect)
1535         {
1536           window->x = x;
1537           window->y = y;
1538
1539           window->width = width;
1540           window->height = height;
1541
1542           _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
1543         }
1544       else
1545         {
1546           if (width != window->width || height != window->height)
1547             window->resize_count += 1;
1548         }
1549     }
1550 }
1551
1552 static void
1553 gdk_window_x11_move_resize (GdkWindow *window,
1554                             gboolean   with_move,
1555                             gint       x,
1556                             gint       y,
1557                             gint       width,
1558                             gint       height)
1559 {
1560   if (with_move && (width < 0 && height < 0))
1561     window_x11_move (window, x, y);
1562   else
1563     {
1564       if (with_move)
1565         window_x11_move_resize (window, x, y, width, height);
1566       else
1567         window_x11_resize (window, width, height);
1568     }
1569 }
1570
1571 static gboolean
1572 gdk_window_x11_reparent (GdkWindow *window,
1573                          GdkWindow *new_parent,
1574                          gint       x,
1575                          gint       y)
1576 {
1577   GdkWindowImplX11 *impl;
1578
1579   impl = GDK_WINDOW_IMPL_X11 (window->impl);
1580
1581   _gdk_x11_window_tmp_unset_bg (window, TRUE);
1582   _gdk_x11_window_tmp_unset_parent_bg (window);
1583   XReparentWindow (GDK_WINDOW_XDISPLAY (window),
1584                    GDK_WINDOW_XID (window),
1585                    GDK_WINDOW_XID (new_parent),
1586                    new_parent->abs_x + x, new_parent->abs_y + y);
1587   _gdk_x11_window_tmp_reset_parent_bg (window);
1588   _gdk_x11_window_tmp_reset_bg (window, TRUE);
1589
1590   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
1591     new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
1592
1593   window->parent = new_parent;
1594
1595   /* Switch the window type as appropriate */
1596
1597   switch (GDK_WINDOW_TYPE (new_parent))
1598     {
1599     case GDK_WINDOW_ROOT:
1600     case GDK_WINDOW_FOREIGN:
1601       /* Reparenting to toplevel */
1602       
1603       if (!WINDOW_IS_TOPLEVEL (window) &&
1604           GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
1605         {
1606           /* This is also done in common code at a later stage, but we
1607              need it in setup_toplevel, so do it here too */
1608           if (window->toplevel_window_type != -1)
1609             GDK_WINDOW_TYPE (window) = window->toplevel_window_type;
1610           else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1611             GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
1612           
1613           /* Wasn't a toplevel, set up */
1614           setup_toplevel_window (window, new_parent);
1615         }
1616
1617       break;
1618       
1619     case GDK_WINDOW_TOPLEVEL:
1620     case GDK_WINDOW_CHILD:
1621     case GDK_WINDOW_TEMP:
1622       if (WINDOW_IS_TOPLEVEL (window) &&
1623           impl->toplevel)
1624         {
1625           if (impl->toplevel->focus_window)
1626             {
1627               XDestroyWindow (GDK_WINDOW_XDISPLAY (window), impl->toplevel->focus_window);
1628               _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), impl->toplevel->focus_window);
1629             }
1630           
1631           gdk_toplevel_x11_free_contents (GDK_WINDOW_DISPLAY (window), 
1632                                           impl->toplevel);
1633           g_free (impl->toplevel);
1634           impl->toplevel = NULL;
1635         }
1636     }
1637
1638   return FALSE;
1639 }
1640
1641 static void
1642 gdk_window_x11_raise (GdkWindow *window)
1643 {
1644   XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1645 }
1646
1647 static void
1648 gdk_window_x11_restack_under (GdkWindow *window,
1649                               GList *native_siblings /* in requested order, first is bottom-most */)
1650 {
1651   Window *windows;
1652   int n_windows, i;
1653   GList *l;
1654
1655   n_windows = g_list_length (native_siblings) + 1;
1656   windows = g_new (Window, n_windows);
1657
1658   windows[0] = GDK_WINDOW_XID (window);
1659   /* Reverse order, as input order is bottom-most first */
1660   i = n_windows - 1;
1661   for (l = native_siblings; l != NULL; l = l->next)
1662     windows[i--] = GDK_WINDOW_XID (l->data);
1663  
1664   XRestackWindows (GDK_WINDOW_XDISPLAY (window), windows, n_windows);
1665   
1666   g_free (windows);
1667 }
1668
1669 static void
1670 gdk_window_x11_restack_toplevel (GdkWindow *window,
1671                                  GdkWindow *sibling,
1672                                  gboolean   above)
1673 {
1674   XWindowChanges changes;
1675
1676   changes.sibling = GDK_WINDOW_XID (sibling);
1677   changes.stack_mode = above ? Above : Below;
1678   XReconfigureWMWindow (GDK_WINDOW_XDISPLAY (window),
1679                         GDK_WINDOW_XID (window),
1680                         gdk_screen_get_number (GDK_WINDOW_SCREEN (window)),
1681                         CWStackMode | CWSibling, &changes);
1682 }
1683
1684 static void
1685 gdk_window_x11_lower (GdkWindow *window)
1686 {
1687   XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1688 }
1689
1690 /**
1691  * gdk_x11_window_move_to_current_desktop:
1692  * @window: a #GdkWindow
1693  * 
1694  * Moves the window to the correct workspace when running under a 
1695  * window manager that supports multiple workspaces, as described
1696  * in the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended 
1697  * Window Manager Hints</ulink>.  Will not do anything if the
1698  * window is already on all workspaces.
1699  * 
1700  * Since: 2.8
1701  */
1702 void
1703 gdk_x11_window_move_to_current_desktop (GdkWindow *window)
1704 {
1705   GdkToplevelX11 *toplevel;
1706
1707   g_return_if_fail (GDK_IS_WINDOW (window));
1708   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
1709
1710   toplevel = _gdk_x11_window_get_toplevel (window);
1711
1712   if (toplevel->on_all_desktops)
1713     return;
1714   
1715   move_to_current_desktop (window);
1716 }
1717
1718 static void
1719 move_to_current_desktop (GdkWindow *window)
1720 {
1721   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
1722                                            gdk_atom_intern_static_string ("_NET_WM_DESKTOP")))
1723     {
1724       Atom type;
1725       gint format;
1726       gulong nitems;
1727       gulong bytes_after;
1728       guchar *data;
1729       gulong *current_desktop;
1730       GdkDisplay *display;
1731       
1732       display = gdk_window_get_display (window);
1733
1734       /* Get current desktop, then set it; this is a race, but not
1735        * one that matters much in practice.
1736        */
1737       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), 
1738                           GDK_WINDOW_XROOTWIN (window),
1739                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"),
1740                           0, G_MAXLONG,
1741                           False, XA_CARDINAL, &type, &format, &nitems,
1742                           &bytes_after, &data);
1743
1744       if (type == XA_CARDINAL)
1745         {
1746           XClientMessageEvent xclient;
1747           current_desktop = (gulong *)data;
1748           
1749           memset (&xclient, 0, sizeof (xclient));
1750           xclient.type = ClientMessage;
1751           xclient.serial = 0;
1752           xclient.send_event = True;
1753           xclient.window = GDK_WINDOW_XID (window);
1754           xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
1755           xclient.format = 32;
1756
1757           xclient.data.l[0] = *current_desktop;
1758           xclient.data.l[1] = 0;
1759           xclient.data.l[2] = 0;
1760           xclient.data.l[3] = 0;
1761           xclient.data.l[4] = 0;
1762       
1763           XSendEvent (GDK_DISPLAY_XDISPLAY (display), 
1764                       GDK_WINDOW_XROOTWIN (window), 
1765                       False,
1766                       SubstructureRedirectMask | SubstructureNotifyMask,
1767                       (XEvent *)&xclient);
1768
1769           XFree (current_desktop);
1770         }
1771     }
1772 }
1773
1774 /**
1775  * gdk_window_focus:
1776  * @window: a #GdkWindow
1777  * @timestamp: timestamp of the event triggering the window focus
1778  *
1779  * Sets keyboard focus to @window. In most cases, gtk_window_present() 
1780  * should be used on a #GtkWindow, rather than calling this function.
1781  * 
1782  **/
1783 void
1784 gdk_window_focus (GdkWindow *window,
1785                   guint32    timestamp)
1786 {
1787   GdkDisplay *display;
1788
1789   g_return_if_fail (GDK_IS_WINDOW (window));
1790
1791   if (GDK_WINDOW_DESTROYED (window) ||
1792       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
1793     return;
1794
1795   display = GDK_WINDOW_DISPLAY (window);
1796
1797   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
1798                                            gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
1799     {
1800       XClientMessageEvent xclient;
1801
1802       memset (&xclient, 0, sizeof (xclient));
1803       xclient.type = ClientMessage;
1804       xclient.window = GDK_WINDOW_XID (window);
1805       xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
1806                                                                         "_NET_ACTIVE_WINDOW");
1807       xclient.format = 32;
1808       xclient.data.l[0] = 1; /* requestor type; we're an app */
1809       xclient.data.l[1] = timestamp;
1810       xclient.data.l[2] = None; /* currently active window */
1811       xclient.data.l[3] = 0;
1812       xclient.data.l[4] = 0;
1813       
1814       XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
1815                   SubstructureRedirectMask | SubstructureNotifyMask,
1816                   (XEvent *)&xclient);
1817     }
1818   else
1819     {
1820       XRaiseWindow (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window));
1821
1822       /* There is no way of knowing reliably whether we are viewable;
1823        * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
1824        */
1825       _gdk_x11_set_input_focus_safe (display, GDK_WINDOW_XID (window),
1826                                      RevertToParent,
1827                                      timestamp);
1828     }
1829 }
1830
1831 /**
1832  * gdk_window_set_type_hint:
1833  * @window: A toplevel #GdkWindow
1834  * @hint: A hint of the function this window will have
1835  *
1836  * The application can use this call to provide a hint to the window
1837  * manager about the functionality of a window. The window manager
1838  * can use this information when determining the decoration and behaviour
1839  * of the window.
1840  *
1841  * The hint must be set before the window is mapped.
1842  **/
1843 void
1844 gdk_window_set_type_hint (GdkWindow        *window,
1845                           GdkWindowTypeHint hint)
1846 {
1847   GdkDisplay *display;
1848   Atom atom;
1849   
1850   if (GDK_WINDOW_DESTROYED (window) ||
1851       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
1852     return;
1853
1854   display = gdk_window_get_display (window);
1855
1856   switch (hint)
1857     {
1858     case GDK_WINDOW_TYPE_HINT_DIALOG:
1859       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG");
1860       break;
1861     case GDK_WINDOW_TYPE_HINT_MENU:
1862       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU");
1863       break;
1864     case GDK_WINDOW_TYPE_HINT_TOOLBAR:
1865       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR");
1866       break;
1867     case GDK_WINDOW_TYPE_HINT_UTILITY:
1868       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY");
1869       break;
1870     case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
1871       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH");
1872       break;
1873     case GDK_WINDOW_TYPE_HINT_DOCK:
1874       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK");
1875       break;
1876     case GDK_WINDOW_TYPE_HINT_DESKTOP:
1877       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP");
1878       break;
1879     case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
1880       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
1881       break;
1882     case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
1883       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU");
1884       break;
1885     case GDK_WINDOW_TYPE_HINT_TOOLTIP:
1886       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP");
1887       break;
1888     case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
1889       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION");
1890       break;
1891     case GDK_WINDOW_TYPE_HINT_COMBO:
1892       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO");
1893       break;
1894     case GDK_WINDOW_TYPE_HINT_DND:
1895       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND");
1896       break;
1897     default:
1898       g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint);
1899       /* Fall thru */
1900     case GDK_WINDOW_TYPE_HINT_NORMAL:
1901       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NORMAL");
1902       break;
1903     }
1904
1905   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
1906                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
1907                    XA_ATOM, 32, PropModeReplace,
1908                    (guchar *)&atom, 1);
1909 }
1910
1911 /**
1912  * gdk_window_get_type_hint:
1913  * @window: A toplevel #GdkWindow
1914  *
1915  * This function returns the type hint set for a window.
1916  *
1917  * Return value: The type hint set for @window
1918  *
1919  * Since: 2.10
1920  **/
1921 GdkWindowTypeHint
1922 gdk_window_get_type_hint (GdkWindow *window)
1923 {
1924   GdkDisplay *display;
1925   GdkWindowTypeHint type;
1926   Atom type_return;
1927   gint format_return;
1928   gulong nitems_return;
1929   gulong bytes_after_return;
1930   guchar *data = NULL;
1931
1932   g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
1933
1934   if (GDK_WINDOW_DESTROYED (window) ||
1935       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
1936     return GDK_WINDOW_TYPE_HINT_NORMAL;
1937
1938   type = GDK_WINDOW_TYPE_HINT_NORMAL;
1939
1940   display = gdk_window_get_display (window);
1941
1942   if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
1943                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
1944                           0, G_MAXLONG, False, XA_ATOM, &type_return,
1945                           &format_return, &nitems_return, &bytes_after_return,
1946                           &data) == Success)
1947     {
1948       if ((type_return == XA_ATOM) && (format_return == 32) &&
1949           (data) && (nitems_return == 1))
1950         {
1951           Atom atom = *(Atom*)data;
1952
1953           if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG"))
1954             type = GDK_WINDOW_TYPE_HINT_DIALOG;
1955           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU"))
1956             type = GDK_WINDOW_TYPE_HINT_MENU;
1957           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR"))
1958             type = GDK_WINDOW_TYPE_HINT_TOOLBAR;
1959           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY"))
1960             type = GDK_WINDOW_TYPE_HINT_UTILITY;
1961           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH"))
1962             type = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
1963           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK"))
1964             type = GDK_WINDOW_TYPE_HINT_DOCK;
1965           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP"))
1966             type = GDK_WINDOW_TYPE_HINT_DESKTOP;
1967           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"))
1968             type = GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU;
1969           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU"))
1970             type = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
1971           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP"))
1972             type = GDK_WINDOW_TYPE_HINT_TOOLTIP;
1973           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION"))
1974             type = GDK_WINDOW_TYPE_HINT_NOTIFICATION;
1975           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO"))
1976             type = GDK_WINDOW_TYPE_HINT_COMBO;
1977           else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND"))
1978             type = GDK_WINDOW_TYPE_HINT_DND;
1979         }
1980
1981       if (type_return != None && data != NULL)
1982         XFree (data);
1983     }
1984
1985   return type;
1986 }
1987
1988 static void
1989 gdk_wmspec_change_state (gboolean   add,
1990                          GdkWindow *window,
1991                          GdkAtom    state1,
1992                          GdkAtom    state2)
1993 {
1994   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
1995   XClientMessageEvent xclient;
1996   
1997 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
1998 #define _NET_WM_STATE_ADD           1    /* add/set property */
1999 #define _NET_WM_STATE_TOGGLE        2    /* toggle property  */  
2000   
2001   memset (&xclient, 0, sizeof (xclient));
2002   xclient.type = ClientMessage;
2003   xclient.window = GDK_WINDOW_XID (window);
2004   xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
2005   xclient.format = 32;
2006   xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
2007   xclient.data.l[1] = gdk_x11_atom_to_xatom_for_display (display, state1);
2008   xclient.data.l[2] = gdk_x11_atom_to_xatom_for_display (display, state2);
2009   xclient.data.l[3] = 0;
2010   xclient.data.l[4] = 0;
2011   
2012   XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
2013               SubstructureRedirectMask | SubstructureNotifyMask,
2014               (XEvent *)&xclient);
2015 }
2016
2017 /**
2018  * gdk_window_set_modal_hint:
2019  * @window: A toplevel #GdkWindow
2020  * @modal: %TRUE if the window is modal, %FALSE otherwise.
2021  *
2022  * The application can use this hint to tell the window manager
2023  * that a certain window has modal behaviour. The window manager
2024  * can use this information to handle modal windows in a special
2025  * way.
2026  *
2027  * You should only use this on windows for which you have
2028  * previously called gdk_window_set_transient_for()
2029  **/
2030 void
2031 gdk_window_set_modal_hint (GdkWindow *window,
2032                            gboolean   modal)
2033 {
2034   if (GDK_WINDOW_DESTROYED (window) ||
2035       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2036     return;
2037
2038   window->modal_hint = modal;
2039
2040   if (GDK_WINDOW_IS_MAPPED (window))
2041     gdk_wmspec_change_state (modal, window,
2042                              gdk_atom_intern_static_string ("_NET_WM_STATE_MODAL"), 
2043                              GDK_NONE);
2044 }
2045
2046 /**
2047  * gdk_window_set_skip_taskbar_hint:
2048  * @window: a toplevel #GdkWindow
2049  * @skips_taskbar: %TRUE to skip the taskbar
2050  * 
2051  * Toggles whether a window should appear in a task list or window
2052  * list. If a window's semantic type as specified with
2053  * gdk_window_set_type_hint() already fully describes the window, this
2054  * function should <emphasis>not</emphasis> be called in addition, 
2055  * instead you should allow the window to be treated according to 
2056  * standard policy for its semantic type.
2057  *
2058  * Since: 2.2
2059  **/
2060 void
2061 gdk_window_set_skip_taskbar_hint (GdkWindow *window,
2062                                   gboolean   skips_taskbar)
2063 {
2064   GdkToplevelX11 *toplevel;
2065   
2066   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
2067   
2068   if (GDK_WINDOW_DESTROYED (window) ||
2069       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2070     return;
2071
2072   toplevel = _gdk_x11_window_get_toplevel (window);
2073   toplevel->skip_taskbar_hint = skips_taskbar;
2074
2075   if (GDK_WINDOW_IS_MAPPED (window))
2076     gdk_wmspec_change_state (skips_taskbar, window,
2077                              gdk_atom_intern_static_string ("_NET_WM_STATE_SKIP_TASKBAR"),
2078                              GDK_NONE);
2079 }
2080
2081 /**
2082  * gdk_window_set_skip_pager_hint:
2083  * @window: a toplevel #GdkWindow
2084  * @skips_pager: %TRUE to skip the pager
2085  * 
2086  * Toggles whether a window should appear in a pager (workspace
2087  * switcher, or other desktop utility program that displays a small
2088  * thumbnail representation of the windows on the desktop). If a
2089  * window's semantic type as specified with gdk_window_set_type_hint()
2090  * already fully describes the window, this function should 
2091  * <emphasis>not</emphasis> be called in addition, instead you should 
2092  * allow the window to be treated according to standard policy for 
2093  * its semantic type.
2094  *
2095  * Since: 2.2
2096  **/
2097 void
2098 gdk_window_set_skip_pager_hint (GdkWindow *window,
2099                                 gboolean   skips_pager)
2100 {
2101   GdkToplevelX11 *toplevel;
2102     
2103   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
2104   
2105   if (GDK_WINDOW_DESTROYED (window) ||
2106       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2107     return;
2108
2109   toplevel = _gdk_x11_window_get_toplevel (window);
2110   toplevel->skip_pager_hint = skips_pager;
2111   
2112   if (GDK_WINDOW_IS_MAPPED (window))
2113     gdk_wmspec_change_state (skips_pager, window,
2114                              gdk_atom_intern_static_string ("_NET_WM_STATE_SKIP_PAGER"), 
2115                              GDK_NONE);
2116 }
2117
2118 /**
2119  * gdk_window_set_urgency_hint:
2120  * @window: a toplevel #GdkWindow
2121  * @urgent: %TRUE if the window is urgent
2122  * 
2123  * Toggles whether a window needs the user's
2124  * urgent attention.
2125  *
2126  * Since: 2.8
2127  **/
2128 void
2129 gdk_window_set_urgency_hint (GdkWindow *window,
2130                              gboolean   urgent)
2131 {
2132   GdkToplevelX11 *toplevel;
2133     
2134   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
2135   
2136   if (GDK_WINDOW_DESTROYED (window) ||
2137       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2138     return;
2139
2140   toplevel = _gdk_x11_window_get_toplevel (window);
2141   toplevel->urgency_hint = urgent;
2142   
2143   update_wm_hints (window, FALSE);
2144 }
2145
2146 /**
2147  * gdk_window_set_geometry_hints:
2148  * @window: a toplevel #GdkWindow
2149  * @geometry: geometry hints
2150  * @geom_mask: bitmask indicating fields of @geometry to pay attention to
2151  *
2152  * Sets the geometry hints for @window. Hints flagged in @geom_mask
2153  * are set, hints not flagged in @geom_mask are unset.
2154  * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
2155  *
2156  * This function provides hints to the windowing system about
2157  * acceptable sizes for a toplevel window. The purpose of 
2158  * this is to constrain user resizing, but the windowing system
2159  * will typically  (but is not required to) also constrain the
2160  * current size of the window to the provided values and
2161  * constrain programatic resizing via gdk_window_resize() or
2162  * gdk_window_move_resize().
2163  * 
2164  * Note that on X11, this effect has no effect on windows
2165  * of type %GDK_WINDOW_TEMP or windows where override redirect
2166  * has been turned on via gdk_window_set_override_redirect()
2167  * since these windows are not resizable by the user.
2168  * 
2169  * Since you can't count on the windowing system doing the
2170  * constraints for programmatic resizes, you should generally
2171  * call gdk_window_constrain_size() yourself to determine
2172  * appropriate sizes.
2173  *
2174  **/
2175 void 
2176 gdk_window_set_geometry_hints (GdkWindow         *window,
2177                                const GdkGeometry *geometry,
2178                                GdkWindowHints     geom_mask)
2179 {
2180   XSizeHints size_hints;
2181   
2182   if (GDK_WINDOW_DESTROYED (window) ||
2183       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2184     return;
2185   
2186   size_hints.flags = 0;
2187   
2188   if (geom_mask & GDK_HINT_POS)
2189     {
2190       size_hints.flags |= PPosition;
2191       /* We need to initialize the following obsolete fields because KWM 
2192        * apparently uses these fields if they are non-zero.
2193        * #@#!#!$!.
2194        */
2195       size_hints.x = 0;
2196       size_hints.y = 0;
2197     }
2198
2199   if (geom_mask & GDK_HINT_USER_POS)
2200     {
2201       size_hints.flags |= USPosition;
2202     }
2203
2204   if (geom_mask & GDK_HINT_USER_SIZE)
2205     {
2206       size_hints.flags |= USSize;
2207     }
2208   
2209   if (geom_mask & GDK_HINT_MIN_SIZE)
2210     {
2211       size_hints.flags |= PMinSize;
2212       size_hints.min_width = geometry->min_width;
2213       size_hints.min_height = geometry->min_height;
2214     }
2215   
2216   if (geom_mask & GDK_HINT_MAX_SIZE)
2217     {
2218       size_hints.flags |= PMaxSize;
2219       size_hints.max_width = MAX (geometry->max_width, 1);
2220       size_hints.max_height = MAX (geometry->max_height, 1);
2221     }
2222   
2223   if (geom_mask & GDK_HINT_BASE_SIZE)
2224     {
2225       size_hints.flags |= PBaseSize;
2226       size_hints.base_width = geometry->base_width;
2227       size_hints.base_height = geometry->base_height;
2228     }
2229   
2230   if (geom_mask & GDK_HINT_RESIZE_INC)
2231     {
2232       size_hints.flags |= PResizeInc;
2233       size_hints.width_inc = geometry->width_inc;
2234       size_hints.height_inc = geometry->height_inc;
2235     }
2236   
2237   if (geom_mask & GDK_HINT_ASPECT)
2238     {
2239       size_hints.flags |= PAspect;
2240       if (geometry->min_aspect <= 1)
2241         {
2242           size_hints.min_aspect.x = 65536 * geometry->min_aspect;
2243           size_hints.min_aspect.y = 65536;
2244         }
2245       else
2246         {
2247           size_hints.min_aspect.x = 65536;
2248           size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
2249         }
2250       if (geometry->max_aspect <= 1)
2251         {
2252           size_hints.max_aspect.x = 65536 * geometry->max_aspect;
2253           size_hints.max_aspect.y = 65536;
2254         }
2255       else
2256         {
2257           size_hints.max_aspect.x = 65536;
2258           size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
2259         }
2260     }
2261
2262   if (geom_mask & GDK_HINT_WIN_GRAVITY)
2263     {
2264       size_hints.flags |= PWinGravity;
2265       size_hints.win_gravity = geometry->win_gravity;
2266     }
2267   
2268   /* FIXME: Would it be better to delete this property if
2269    *        geom_mask == 0? It would save space on the server
2270    */
2271   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
2272                      GDK_WINDOW_XID (window),
2273                      &size_hints);
2274 }
2275
2276 static void
2277 gdk_window_get_geometry_hints (GdkWindow      *window,
2278                                GdkGeometry    *geometry,
2279                                GdkWindowHints *geom_mask)
2280 {
2281   XSizeHints *size_hints;  
2282   glong junk_supplied_mask = 0;
2283
2284   g_return_if_fail (GDK_IS_WINDOW (window));
2285   g_return_if_fail (geometry != NULL);
2286   g_return_if_fail (geom_mask != NULL);
2287
2288   *geom_mask = 0;
2289   
2290   if (GDK_WINDOW_DESTROYED (window) ||
2291       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2292     return;
2293
2294   size_hints = XAllocSizeHints ();
2295   if (!size_hints)
2296     return;
2297   
2298   if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
2299                           GDK_WINDOW_XID (window),
2300                           size_hints,
2301                           &junk_supplied_mask))
2302     size_hints->flags = 0;
2303
2304   if (size_hints->flags & PMinSize)
2305     {
2306       *geom_mask |= GDK_HINT_MIN_SIZE;
2307       geometry->min_width = size_hints->min_width;
2308       geometry->min_height = size_hints->min_height;
2309     }
2310
2311   if (size_hints->flags & PMaxSize)
2312     {
2313       *geom_mask |= GDK_HINT_MAX_SIZE;
2314       geometry->max_width = MAX (size_hints->max_width, 1);
2315       geometry->max_height = MAX (size_hints->max_height, 1);
2316     }
2317
2318   if (size_hints->flags & PResizeInc)
2319     {
2320       *geom_mask |= GDK_HINT_RESIZE_INC;
2321       geometry->width_inc = size_hints->width_inc;
2322       geometry->height_inc = size_hints->height_inc;
2323     }
2324
2325   if (size_hints->flags & PAspect)
2326     {
2327       *geom_mask |= GDK_HINT_ASPECT;
2328
2329       geometry->min_aspect = (gdouble) size_hints->min_aspect.x / (gdouble) size_hints->min_aspect.y;
2330       geometry->max_aspect = (gdouble) size_hints->max_aspect.x / (gdouble) size_hints->max_aspect.y;
2331     }
2332
2333   if (size_hints->flags & PWinGravity)
2334     {
2335       *geom_mask |= GDK_HINT_WIN_GRAVITY;
2336       geometry->win_gravity = size_hints->win_gravity;
2337     }
2338
2339   XFree (size_hints);
2340 }
2341
2342 static gboolean
2343 utf8_is_latin1 (const gchar *str)
2344 {
2345   const char *p = str;
2346
2347   while (*p)
2348     {
2349       gunichar ch = g_utf8_get_char (p);
2350
2351       if (ch > 0xff)
2352         return FALSE;
2353       
2354       p = g_utf8_next_char (p);
2355     }
2356
2357   return TRUE;
2358 }
2359
2360 /* Set the property to @utf8_str as STRING if the @utf8_str is fully
2361  * convertable to STRING, otherwise, set it as compound text
2362  */
2363 static void
2364 set_text_property (GdkDisplay  *display,
2365                    Window       xwindow,
2366                    Atom         property,
2367                    const gchar *utf8_str)
2368 {
2369   gchar *prop_text = NULL;
2370   Atom prop_type;
2371   gint prop_length;
2372   gint prop_format;
2373   gboolean is_compound_text;
2374   
2375   if (utf8_is_latin1 (utf8_str))
2376     {
2377       prop_type = XA_STRING;
2378       prop_text = gdk_utf8_to_string_target (utf8_str);
2379       prop_length = prop_text ? strlen (prop_text) : 0;
2380       prop_format = 8;
2381       is_compound_text = FALSE;
2382     }
2383   else
2384     {
2385       GdkAtom gdk_type;
2386       
2387       gdk_utf8_to_compound_text_for_display (display,
2388                                              utf8_str, &gdk_type, &prop_format,
2389                                              (guchar **)&prop_text, &prop_length);
2390       prop_type = gdk_x11_atom_to_xatom_for_display (display, gdk_type);
2391       is_compound_text = TRUE;
2392     }
2393
2394   if (prop_text)
2395     {
2396       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
2397                        xwindow,
2398                        property,
2399                        prop_type, prop_format,
2400                        PropModeReplace, (guchar *)prop_text,
2401                        prop_length);
2402
2403       if (is_compound_text)
2404         gdk_free_compound_text ((guchar *)prop_text);
2405       else
2406         g_free (prop_text);
2407     }
2408 }
2409
2410 /* Set WM_NAME and _NET_WM_NAME
2411  */
2412 static void
2413 set_wm_name (GdkDisplay  *display,
2414              Window       xwindow,
2415              const gchar *name)
2416 {
2417   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
2418                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"),
2419                    gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2420                    PropModeReplace, (guchar *)name, strlen (name));
2421   
2422   set_text_property (display, xwindow,
2423                      gdk_x11_get_xatom_by_name_for_display (display, "WM_NAME"),
2424                      name);
2425 }
2426
2427 /**
2428  * gdk_window_set_title:
2429  * @window: a toplevel #GdkWindow
2430  * @title: title of @window
2431  *
2432  * Sets the title of a toplevel window, to be displayed in the titlebar.
2433  * If you haven't explicitly set the icon name for the window
2434  * (using gdk_window_set_icon_name()), the icon name will be set to
2435  * @title as well. @title must be in UTF-8 encoding (as with all
2436  * user-readable strings in GDK/GTK+). @title may not be %NULL.
2437  **/
2438 void
2439 gdk_window_set_title (GdkWindow   *window,
2440                       const gchar *title)
2441 {
2442   GdkDisplay *display;
2443   Display *xdisplay;
2444   Window xwindow;
2445   
2446   g_return_if_fail (title != NULL);
2447
2448   if (GDK_WINDOW_DESTROYED (window) ||
2449       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2450     return;
2451   
2452   display = gdk_window_get_display (window);
2453   xdisplay = GDK_DISPLAY_XDISPLAY (display);
2454   xwindow = GDK_WINDOW_XID (window);
2455
2456   set_wm_name (display, xwindow, title);
2457   
2458   if (!gdk_window_icon_name_set (window))
2459     {
2460       XChangeProperty (xdisplay, xwindow,
2461                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
2462                        gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2463                        PropModeReplace, (guchar *)title, strlen (title));
2464       
2465       set_text_property (display, xwindow,
2466                          gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
2467                          title);
2468     }
2469 }
2470
2471 /**
2472  * gdk_window_set_role:
2473  * @window: a toplevel #GdkWindow
2474  * @role: a string indicating its role
2475  *
2476  * When using GTK+, typically you should use gtk_window_set_role() instead
2477  * of this low-level function.
2478  * 
2479  * The window manager and session manager use a window's role to
2480  * distinguish it from other kinds of window in the same application.
2481  * When an application is restarted after being saved in a previous
2482  * session, all windows with the same title and role are treated as
2483  * interchangeable.  So if you have two windows with the same title
2484  * that should be distinguished for session management purposes, you
2485  * should set the role on those windows. It doesn't matter what string
2486  * you use for the role, as long as you have a different role for each
2487  * non-interchangeable kind of window.
2488  * 
2489  **/
2490 void          
2491 gdk_window_set_role (GdkWindow   *window,
2492                      const gchar *role)
2493 {
2494   GdkDisplay *display;
2495
2496   display = gdk_window_get_display (window);
2497
2498   if (GDK_WINDOW_DESTROYED (window) ||
2499       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2500     return;
2501
2502   if (role)
2503     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
2504                      gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"),
2505                      XA_STRING, 8, PropModeReplace, (guchar *)role, strlen (role));
2506   else
2507     XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
2508                      gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"));
2509 }
2510
2511 /**
2512  * gdk_window_set_startup_id:
2513  * @window: a toplevel #GdkWindow
2514  * @startup_id: a string with startup-notification identifier
2515  *
2516  * When using GTK+, typically you should use gtk_window_set_startup_id()
2517  * instead of this low-level function.
2518  *
2519  * Since: 2.12
2520  *
2521  **/
2522 void
2523 gdk_window_set_startup_id (GdkWindow   *window,
2524                            const gchar *startup_id)
2525 {
2526   GdkDisplay *display;
2527
2528   g_return_if_fail (GDK_IS_WINDOW (window));
2529
2530   display = gdk_window_get_display (window);
2531
2532   if (GDK_WINDOW_DESTROYED (window) ||
2533       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2534     return;
2535
2536   if (startup_id)
2537     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
2538                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"), 
2539                      gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2540                      PropModeReplace, (unsigned char *)startup_id, strlen (startup_id));
2541   else
2542     XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
2543                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
2544 }
2545
2546 /**
2547  * gdk_window_set_transient_for:
2548  * @window: a toplevel #GdkWindow
2549  * @parent: another toplevel #GdkWindow
2550  *
2551  * Indicates to the window manager that @window is a transient dialog
2552  * associated with the application window @parent. This allows the
2553  * window manager to do things like center @window on @parent and
2554  * keep @window above @parent.
2555  *
2556  * See gtk_window_set_transient_for() if you're using #GtkWindow or
2557  * #GtkDialog.
2558  **/
2559 void
2560 gdk_window_set_transient_for (GdkWindow *window,
2561                               GdkWindow *parent)
2562 {
2563   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent) &&
2564       WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
2565     XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
2566                           GDK_WINDOW_XID (window),
2567                           GDK_WINDOW_XID (parent));
2568 }
2569
2570 static gboolean
2571 gdk_window_x11_set_back_color (GdkWindow *window,
2572                                double     red,
2573                                double     green,
2574                                double     blue,
2575                                double     alpha)
2576 {
2577   GdkVisual *visual = gdk_window_get_visual (window);
2578
2579   /* I suppose we could handle these, but that'd require fiddling with 
2580    * xrender formats... */
2581   if (alpha != 1.0)
2582     return FALSE;
2583
2584   switch (visual->type)
2585     {
2586     case GDK_VISUAL_DIRECT_COLOR:
2587     case GDK_VISUAL_TRUE_COLOR:
2588         {
2589           /* If bits not used for color are used for something other than padding,
2590            * it's likely alpha, so we set them to 1s.
2591            */
2592           guint padding, pixel;
2593
2594           /* Shifting by >= width-of-type isn't defined in C */
2595           if (visual->depth >= 32)
2596             padding = 0;
2597           else
2598             padding = ((~(guint32)0)) << visual->depth;
2599           
2600           pixel = ~ (visual->red_mask | visual->green_mask | visual->blue_mask | padding);
2601           
2602           pixel += (((int) (red   * ((1 << visual->red_prec  ) - 1))) << visual->red_shift  ) +
2603                    (((int) (green * ((1 << visual->green_prec) - 1))) << visual->green_shift) +
2604                    (((int) (blue  * ((1 << visual->blue_prec ) - 1))) << visual->blue_shift );
2605
2606           XSetWindowBackground (GDK_WINDOW_XDISPLAY (window),
2607                                 GDK_WINDOW_XID (window), pixel);
2608         }
2609       return TRUE;
2610
2611     /* These require fiddling with the colormap, and as they're essentially unused
2612      * we're just gonna skip them for now.
2613      */
2614     case GDK_VISUAL_PSEUDO_COLOR:
2615     case GDK_VISUAL_GRAYSCALE:
2616     case GDK_VISUAL_STATIC_GRAY:
2617     case GDK_VISUAL_STATIC_COLOR:
2618     default:
2619       break;
2620     }
2621
2622   return FALSE;
2623 }
2624
2625 static gboolean
2626 matrix_is_identity (cairo_matrix_t *matrix)
2627 {
2628   return matrix->xx == 1.0 && matrix->yy == 1.0 &&
2629     matrix->yx == 0.0 && matrix->xy == 0.0 &&
2630     matrix->x0 == 0.0 && matrix->y0 == 0.0;
2631 }
2632
2633 static void
2634 gdk_window_x11_set_background (GdkWindow      *window,
2635                                cairo_pattern_t *pattern)
2636 {
2637   double r, g, b, a;
2638   cairo_surface_t *surface;
2639   cairo_matrix_t matrix;
2640
2641   if (GDK_WINDOW_DESTROYED (window))
2642     return;
2643
2644   if (pattern == NULL)
2645     {
2646       GdkWindow *parent;
2647
2648       /* X throws BadMatch if the parent has a different visual when
2649        * using ParentRelative */
2650       parent = gdk_window_get_parent (window);
2651       if (parent && gdk_window_get_visual (parent) == gdk_window_get_visual (window))
2652         XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
2653                                     GDK_WINDOW_XID (window), ParentRelative);
2654       else
2655         XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
2656                                     GDK_WINDOW_XID (window), None);
2657       return;
2658     }
2659
2660   switch (cairo_pattern_get_type (pattern))
2661     {
2662     case CAIRO_PATTERN_TYPE_SOLID:
2663       cairo_pattern_get_rgba (pattern, &r, &g, &b, &a);
2664       if (gdk_window_x11_set_back_color (window, r, g, b, a))
2665         return;
2666       break;
2667     case CAIRO_PATTERN_TYPE_SURFACE:
2668       cairo_pattern_get_matrix (pattern, &matrix);
2669       if (cairo_pattern_get_surface (pattern, &surface) == CAIRO_STATUS_SUCCESS &&
2670           matrix_is_identity (&matrix) &&
2671           cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB &&
2672           cairo_xlib_surface_get_visual (surface) == GDK_VISUAL_XVISUAL (gdk_window_get_visual ((window))) &&
2673           cairo_xlib_surface_get_display (surface) == GDK_WINDOW_XDISPLAY (window))
2674         {
2675           double x, y;
2676
2677           cairo_surface_get_device_offset (surface, &x, &y);
2678           /* XXX: This still bombs for non-pixmaps, but there's no way to
2679            * detect we're not a pixmap in Cairo... */
2680           if (x == 0.0 && y == 0.0)
2681             {
2682               XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
2683                                           GDK_WINDOW_XID (window),
2684                                           cairo_xlib_surface_get_drawable (surface));
2685               return;
2686             }
2687         }
2688       /* fall through */
2689     case CAIRO_PATTERN_TYPE_LINEAR:
2690     case CAIRO_PATTERN_TYPE_RADIAL:
2691     default:
2692       /* fallback: just use black */
2693       break;
2694     }
2695
2696   XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
2697                               GDK_WINDOW_XID (window), None);
2698 }
2699
2700 static void
2701 gdk_window_x11_set_device_cursor (GdkWindow *window,
2702                                   GdkDevice *device,
2703                                   GdkCursor *cursor)
2704 {
2705   GdkWindowImplX11 *impl;
2706
2707   g_return_if_fail (GDK_IS_WINDOW (window));
2708   g_return_if_fail (GDK_IS_DEVICE (device));
2709
2710   impl = GDK_WINDOW_IMPL_X11 (window->impl);
2711
2712   if (!cursor)
2713     g_hash_table_remove (impl->device_cursor, device);
2714   else
2715     {
2716       _gdk_x11_cursor_update_theme (cursor);
2717       g_hash_table_replace (impl->device_cursor,
2718                             device, gdk_cursor_ref (cursor));
2719     }
2720
2721   if (!GDK_WINDOW_DESTROYED (window))
2722     GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
2723 }
2724
2725 GdkCursor *
2726 _gdk_x11_window_get_cursor (GdkWindow *window)
2727 {
2728   GdkWindowImplX11 *impl;
2729   
2730   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2731     
2732   impl = GDK_WINDOW_IMPL_X11 (window->impl);
2733
2734   return impl->cursor;
2735 }
2736
2737 static void
2738 gdk_window_x11_get_geometry (GdkWindow *window,
2739                              gint      *x,
2740                              gint      *y,
2741                              gint      *width,
2742                              gint      *height,
2743                              gint      *depth)
2744 {
2745   Window root;
2746   gint tx;
2747   gint ty;
2748   guint twidth;
2749   guint theight;
2750   guint tborder_width;
2751   guint tdepth;
2752   
2753   if (!GDK_WINDOW_DESTROYED (window))
2754     {
2755       XGetGeometry (GDK_WINDOW_XDISPLAY (window),
2756                     GDK_WINDOW_XID (window),
2757                     &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
2758       
2759       if (x)
2760         *x = tx;
2761       if (y)
2762         *y = ty;
2763       if (width)
2764         *width = twidth;
2765       if (height)
2766         *height = theight;
2767       if (depth)
2768         *depth = tdepth;
2769     }
2770 }
2771
2772 static gint
2773 gdk_window_x11_get_root_coords (GdkWindow *window,
2774                                 gint       x,
2775                                 gint       y,
2776                                 gint      *root_x,
2777                                 gint      *root_y)
2778 {
2779   gint return_val;
2780   Window child;
2781   gint tx;
2782   gint ty;
2783   
2784   return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
2785                                       GDK_WINDOW_XID (window),
2786                                       GDK_WINDOW_XROOTWIN (window),
2787                                       x, y, &tx, &ty,
2788                                       &child);
2789   
2790   if (root_x)
2791     *root_x = tx;
2792   if (root_y)
2793     *root_y = ty;
2794   
2795   return return_val;
2796 }
2797
2798 /**
2799  * gdk_window_get_root_origin:
2800  * @window: a toplevel #GdkWindow
2801  * @x: return location for X position of window frame
2802  * @y: return location for Y position of window frame
2803  *
2804  * Obtains the top-left corner of the window manager frame in root
2805  * window coordinates.
2806  * 
2807  **/
2808 void
2809 gdk_window_get_root_origin (GdkWindow *window,
2810                             gint      *x,
2811                             gint      *y)
2812 {
2813   GdkRectangle rect;
2814
2815   gdk_window_get_frame_extents (window, &rect);
2816
2817   if (x)
2818     *x = rect.x;
2819
2820   if (y)
2821     *y = rect.y;
2822 }
2823
2824 /**
2825  * gdk_window_get_frame_extents:
2826  * @window: a toplevel #GdkWindow
2827  * @rect: rectangle to fill with bounding box of the window frame
2828  *
2829  * Obtains the bounding box of the window, including window manager
2830  * titlebar/borders if any. The frame position is given in root window
2831  * coordinates. To get the position of the window itself (rather than
2832  * the frame) in root window coordinates, use gdk_window_get_origin().
2833  * 
2834  **/
2835 void
2836 gdk_window_get_frame_extents (GdkWindow    *window,
2837                               GdkRectangle *rect)
2838 {
2839   GdkDisplay *display;
2840   GdkWindowImplX11 *impl;
2841   Window xwindow;
2842   Window xparent;
2843   Window root;
2844   Window child;
2845   Window *children;
2846   guchar *data;
2847   Window *vroots;
2848   Atom type_return;
2849   guint nchildren;
2850   guint nvroots;
2851   gulong nitems_return;
2852   gulong bytes_after_return;
2853   gint format_return;
2854   gint i;
2855   guint ww, wh, wb, wd;
2856   gint wx, wy;
2857   gboolean got_frame_extents = FALSE;
2858   
2859   g_return_if_fail (rect != NULL);
2860   
2861   rect->x = 0;
2862   rect->y = 0;
2863   rect->width = 1;
2864   rect->height = 1;
2865   
2866   while (window->parent && (window->parent)->parent)
2867     window = window->parent;
2868
2869   /* Refine our fallback answer a bit using local information */
2870   rect->x = window->x;
2871   rect->y = window->y;
2872   rect->width = window->width;
2873   rect->height = window->height;
2874
2875   impl = GDK_WINDOW_IMPL_X11 (window->impl);
2876   if (GDK_WINDOW_DESTROYED (window) || impl->override_redirect)
2877     return;
2878
2879   nvroots = 0;
2880   vroots = NULL;
2881
2882   gdk_error_trap_push();
2883   
2884   display = gdk_window_get_display (window);
2885   xwindow = GDK_WINDOW_XID (window);
2886
2887   /* first try: use _NET_FRAME_EXTENTS */
2888   if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
2889                           gdk_x11_get_xatom_by_name_for_display (display,
2890                                                                  "_NET_FRAME_EXTENTS"),
2891                           0, G_MAXLONG, False, XA_CARDINAL, &type_return,
2892                           &format_return, &nitems_return, &bytes_after_return,
2893                           &data)
2894       == Success)
2895     {
2896       if ((type_return == XA_CARDINAL) && (format_return == 32) &&
2897           (nitems_return == 4) && (data))
2898         {
2899           gulong *ldata = (gulong *) data;
2900           got_frame_extents = TRUE;
2901
2902           /* try to get the real client window geometry */
2903           if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
2904                             &root, &wx, &wy, &ww, &wh, &wb, &wd) &&
2905               XTranslateCoordinates (GDK_DISPLAY_XDISPLAY (display),
2906                                      xwindow, root, 0, 0, &wx, &wy, &child))
2907             {
2908               rect->x = wx;
2909               rect->y = wy;
2910               rect->width = ww;
2911               rect->height = wh;
2912             }
2913
2914           /* _NET_FRAME_EXTENTS format is left, right, top, bottom */
2915           rect->x -= ldata[0];
2916           rect->y -= ldata[2];
2917           rect->width += ldata[0] + ldata[1];
2918           rect->height += ldata[2] + ldata[3];
2919         }
2920
2921       if (data)
2922         XFree (data);
2923     }
2924
2925   if (got_frame_extents)
2926     goto out;
2927
2928   /* no frame extents property available, which means we either have a WM that
2929      is not EWMH compliant or is broken - try fallback and walk up the window
2930      tree to get our window's parent which hopefully is the window frame */
2931
2932   /* use NETWM_VIRTUAL_ROOTS if available */
2933   root = GDK_WINDOW_XROOTWIN (window);
2934
2935   if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), root,
2936                           gdk_x11_get_xatom_by_name_for_display (display, 
2937                                                                  "_NET_VIRTUAL_ROOTS"),
2938                           0, G_MAXLONG, False, XA_WINDOW, &type_return,
2939                           &format_return, &nitems_return, &bytes_after_return,
2940                           &data)
2941       == Success)
2942     {
2943       if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
2944         {
2945           nvroots = nitems_return;
2946           vroots = (Window *)data;
2947         }
2948     }
2949
2950   xparent = GDK_WINDOW_XID (window);
2951
2952   do
2953     {
2954       xwindow = xparent;
2955
2956       if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xwindow,
2957                        &root, &xparent,
2958                        &children, &nchildren))
2959         goto out;
2960       
2961       if (children)
2962         XFree (children);
2963
2964       /* check virtual roots */
2965       for (i = 0; i < nvroots; i++)
2966         {
2967           if (xparent == vroots[i])
2968             {
2969               root = xparent;
2970               break;
2971            }
2972         }
2973     }
2974   while (xparent != root);
2975   
2976   if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow, 
2977                     &root, &wx, &wy, &ww, &wh, &wb, &wd))
2978     {
2979       rect->x = wx;
2980       rect->y = wy;
2981       rect->width = ww;
2982       rect->height = wh;
2983     }
2984
2985  out:
2986   if (vroots)
2987     XFree (vroots);
2988
2989   gdk_error_trap_pop_ignored ();
2990 }
2991
2992 void
2993 _gdk_windowing_get_device_state (GdkDisplay       *display,
2994                                  GdkDevice        *device,
2995                                  GdkScreen       **screen,
2996                                  gint             *x,
2997                                  gint             *y,
2998                                  GdkModifierType  *mask)
2999 {
3000   GdkScreen *default_screen;
3001
3002   if (display->closed)
3003     return;
3004
3005   default_screen = gdk_display_get_default_screen (display);
3006
3007
3008   if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
3009     {
3010       GdkWindow *root;
3011
3012       GDK_DEVICE_GET_CLASS (device)->query_state (device,
3013                                                   gdk_screen_get_root_window (default_screen),
3014                                                   &root, NULL,
3015                                                   x, y,
3016                                                   NULL, NULL,
3017                                                   mask);
3018       *screen = gdk_window_get_screen (root);
3019     }
3020   else
3021     {
3022       XSetWindowAttributes attributes;
3023       Display *xdisplay;
3024       Window xwindow, w, root, child;
3025       int rootx, rooty, winx, winy;
3026       unsigned int xmask;
3027
3028       /* FIXME: untrusted clients not multidevice-safe */
3029
3030       xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
3031       xwindow = GDK_SCREEN_XROOTWIN (default_screen);
3032
3033       w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
3034                          CopyFromParent, InputOnly, CopyFromParent,
3035                          0, &attributes);
3036       XQueryPointer (xdisplay, w,
3037                      &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
3038       XDestroyWindow (xdisplay, w);
3039
3040       if (root != None)
3041         {
3042           GdkWindow *gdk_root = gdk_window_lookup_for_display (display, root);
3043           *screen = gdk_window_get_screen (gdk_root);
3044         }
3045
3046       *x = rootx;
3047       *y = rooty;
3048       *mask = xmask;
3049     }
3050 }
3051
3052 static gboolean
3053 gdk_window_x11_get_device_state (GdkWindow       *window,
3054                                  GdkDevice       *device,
3055                                  gint            *x,
3056                                  gint            *y,
3057                                  GdkModifierType *mask)
3058 {
3059   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
3060   gboolean return_val;
3061
3062   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
3063
3064   return_val = TRUE;
3065
3066   if (!GDK_WINDOW_DESTROYED (window))
3067     {
3068       if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
3069         {
3070           GdkWindow *child;
3071
3072           GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
3073                                                       NULL, &child,
3074                                                       NULL, NULL,
3075                                                       x, y, mask);
3076           return_val = (child != NULL);
3077         }
3078       else
3079         {
3080           GdkScreen *screen;
3081           int originx, originy;
3082           int rootx, rooty;
3083           int winx = 0;
3084           int winy = 0;
3085           unsigned int xmask = 0;
3086
3087           _gdk_windowing_get_device_state (gdk_window_get_display (window), device,
3088                                            &screen, &rootx, &rooty, &xmask);
3089           gdk_window_get_origin (window, &originx, &originy);
3090           winx = rootx - originx;
3091           winy = rooty - originy;
3092
3093           *x = winx;
3094           *y = winy;
3095           *mask = xmask;
3096         }
3097     }
3098
3099   return return_val;
3100 }
3101
3102 /**
3103  * gdk_display_warp_pointer:
3104  * @display: a #GdkDisplay
3105  * @screen: the screen of @display to warp the pointer to
3106  * @x: the x coordinate of the destination
3107  * @y: the y coordinate of the destination
3108  * 
3109  * Warps the pointer of @display to the point @x,@y on 
3110  * the screen @screen, unless the pointer is confined
3111  * to a window by a grab, in which case it will be moved
3112  * as far as allowed by the grab. Warping the pointer 
3113  * creates events as if the user had moved the mouse 
3114  * instantaneously to the destination.
3115  * 
3116  * Note that the pointer should normally be under the
3117  * control of the user. This function was added to cover
3118  * some rare use cases like keyboard navigation support
3119  * for the color picker in the #GtkColorSelectionDialog.
3120  *
3121  * Since: 2.8
3122  *
3123  * Deprecated: 3.0: Use gdk_display_warp_device() instead.
3124  */ 
3125 void
3126 gdk_display_warp_pointer (GdkDisplay *display,
3127                           GdkScreen  *screen,
3128                           gint        x,
3129                           gint        y)
3130 {
3131   GdkDevice *device;
3132
3133   g_return_if_fail (GDK_IS_DISPLAY (display));
3134   g_return_if_fail (GDK_IS_SCREEN (screen));
3135
3136   device = display->core_pointer;
3137   GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
3138 }
3139
3140 /**
3141  * gdk_display_warp_device:
3142  * @display: a #GdkDisplay.
3143  * @device: a #GdkDevice.
3144  * @screen: the screen of @display to warp @device to.
3145  * @x: the X coordinate of the destination.
3146  * @y: the Y coordinate of the destination.
3147  *
3148  * Warps @device in @display to the point @x,@y on
3149  * the screen @screen, unless the device is confined
3150  * to a window by a grab, in which case it will be moved
3151  * as far as allowed by the grab. Warping the pointer
3152  * creates events as if the user had moved the mouse
3153  * instantaneously to the destination.
3154  *
3155  * Note that the pointer should normally be under the
3156  * control of the user. This function was added to cover
3157  * some rare use cases like keyboard navigation support
3158  * for the color picker in the #GtkColorSelectionDialog.
3159  *
3160  * Since: 3.0
3161  **/
3162 void
3163 gdk_display_warp_device (GdkDisplay *display,
3164                          GdkDevice  *device,
3165                          GdkScreen  *screen,
3166                          gint        x,
3167                          gint        y)
3168 {
3169   g_return_if_fail (GDK_IS_DISPLAY (display));
3170   g_return_if_fail (GDK_IS_DEVICE (device));
3171   g_return_if_fail (GDK_IS_SCREEN (screen));
3172   g_return_if_fail (display == gdk_device_get_display (device));
3173
3174   GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
3175 }
3176
3177 GdkWindow*
3178 _gdk_windowing_window_at_device_position (GdkDisplay      *display,
3179                                           GdkDevice       *device,
3180                                           gint            *win_x,
3181                                           gint            *win_y,
3182                                           GdkModifierType *mask,
3183                                           gboolean         get_toplevel)
3184 {
3185   GdkWindow *window;
3186   GdkScreen *screen;
3187
3188   screen = gdk_display_get_default_screen (display);
3189
3190   /* This function really only works if the mouse pointer is held still
3191    * during its operation. If it moves from one leaf window to another
3192    * than we'll end up with inaccurate values for win_x, win_y
3193    * and the result.
3194    */
3195   gdk_x11_display_grab (display);
3196   if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
3197     window = GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask, get_toplevel);
3198   else
3199     {
3200       gint i, screens, width, height;
3201       GList *toplevels, *list;
3202       Window pointer_window, root, xwindow, child;
3203       Window xwindow_last = 0;
3204       Display *xdisplay;
3205       int rootx = -1, rooty = -1;
3206       int winx, winy;
3207       unsigned int xmask;
3208
3209       /* FIXME: untrusted clients case not multidevice-safe */
3210
3211       xwindow = GDK_SCREEN_XROOTWIN (screen);
3212       xdisplay = GDK_SCREEN_XDISPLAY (screen);
3213
3214       pointer_window = None;
3215       screens = gdk_display_get_n_screens (display);
3216       for (i = 0; i < screens; ++i) {
3217         screen = gdk_display_get_screen (display, i);
3218         toplevels = gdk_screen_get_toplevel_windows (screen);
3219         for (list = toplevels; list != NULL; list = g_list_next (list)) {
3220           window = GDK_WINDOW (list->data);
3221           xwindow = GDK_WINDOW_XID (window);
3222           gdk_error_trap_push ();
3223           XQueryPointer (xdisplay, xwindow,
3224                          &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
3225           if (gdk_error_trap_pop ())
3226             continue;
3227           if (child != None) 
3228             {
3229               pointer_window = child;
3230               break;
3231             }
3232           gdk_window_get_geometry (window, NULL, NULL, &width, &height, NULL);
3233           if (winx >= 0 && winy >= 0 && winx < width && winy < height) 
3234             {
3235               /* A childless toplevel, or below another window? */
3236               XSetWindowAttributes attributes;
3237               Window w;
3238               
3239               w = XCreateWindow (xdisplay, xwindow, winx, winy, 1, 1, 0, 
3240                                  CopyFromParent, InputOnly, CopyFromParent, 
3241                                  0, &attributes);
3242               XMapWindow (xdisplay, w);
3243               XQueryPointer (xdisplay, xwindow, 
3244                              &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
3245               XDestroyWindow (xdisplay, w);
3246               if (child == w) 
3247                 {
3248                   pointer_window = xwindow;
3249                   break;
3250                 }
3251             }
3252         }
3253         g_list_free (toplevels);
3254         if (pointer_window != None)
3255           break;
3256       }
3257       xwindow = pointer_window;
3258
3259       while (xwindow)
3260         {
3261           xwindow_last = xwindow;
3262           gdk_error_trap_push ();
3263           XQueryPointer (xdisplay, xwindow,
3264                          &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
3265           if (gdk_error_trap_pop ())
3266             break;
3267           if (get_toplevel && xwindow_last != root &&
3268               (window = gdk_window_lookup_for_display (display, xwindow_last)) != NULL &&
3269               GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
3270             break;
3271         }
3272
3273       window = gdk_window_lookup_for_display (display, xwindow_last);
3274
3275       *win_x = window ? winx : -1;
3276       *win_y = window ? winy : -1;
3277       if (mask)
3278         *mask = xmask;
3279     }
3280
3281   gdk_x11_display_ungrab (display);
3282
3283   return window;
3284 }
3285
3286 static GdkEventMask
3287 gdk_window_x11_get_events (GdkWindow *window)
3288 {
3289   XWindowAttributes attrs;
3290   GdkEventMask event_mask;
3291   GdkEventMask filtered;
3292
3293   if (GDK_WINDOW_DESTROYED (window))
3294     return 0;
3295   else
3296     {
3297       XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3298                             GDK_WINDOW_XID (window),
3299                             &attrs);
3300       event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
3301       /* if property change was filtered out before, keep it filtered out */
3302       filtered = GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK;
3303       window->event_mask = event_mask & ((window->event_mask & filtered) | ~filtered);
3304
3305       return event_mask;
3306     }
3307 }
3308 static void
3309 gdk_window_x11_set_events (GdkWindow    *window,
3310                            GdkEventMask  event_mask)
3311 {
3312   long xevent_mask = 0;
3313   
3314   if (!GDK_WINDOW_DESTROYED (window))
3315     {
3316       GdkDisplayX11 *display_x11;
3317
3318       if (GDK_WINDOW_XID (window) != GDK_WINDOW_XROOTWIN (window))
3319         xevent_mask = StructureNotifyMask | PropertyChangeMask;
3320
3321       display_x11 = GDK_DISPLAY_X11 (gdk_window_get_display (window));
3322       gdk_event_source_select_events ((GdkEventSource *) display_x11->event_source,
3323                                       GDK_WINDOW_XID (window), event_mask,
3324                                       xevent_mask);
3325     }
3326 }
3327
3328 static inline void
3329 do_shape_combine_region (GdkWindow       *window,
3330                          const cairo_region_t *shape_region,
3331                          gint             offset_x,
3332                          gint             offset_y,
3333                          gint             shape)
3334 {
3335   if (GDK_WINDOW_DESTROYED (window))
3336     return;
3337
3338   if (shape_region == NULL)
3339     {
3340       /* Use NULL mask to unset the shape */
3341       if (shape == ShapeBounding
3342           ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))
3343           : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
3344         {
3345           if (shape == ShapeBounding)
3346             {
3347               _gdk_x11_window_tmp_unset_parent_bg (window);
3348               _gdk_x11_window_tmp_unset_bg (window, TRUE);
3349             }
3350           XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
3351                              GDK_WINDOW_XID (window),
3352                              shape,
3353                              0, 0,
3354                              None,
3355                              ShapeSet);
3356           if (shape == ShapeBounding)
3357             {
3358               _gdk_x11_window_tmp_reset_parent_bg (window);
3359               _gdk_x11_window_tmp_reset_bg (window, TRUE);
3360             }
3361         }
3362       return;
3363     }
3364   
3365   if (shape == ShapeBounding
3366       ? gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window))
3367       : gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
3368     {
3369       gint n_rects = 0;
3370       XRectangle *xrects = NULL;
3371
3372       _gdk_region_get_xrectangles (shape_region,
3373                                    0, 0,
3374                                    &xrects, &n_rects);
3375       
3376       if (shape == ShapeBounding)
3377         {
3378           _gdk_x11_window_tmp_unset_parent_bg (window);
3379           _gdk_x11_window_tmp_unset_bg (window, TRUE);
3380         }
3381       XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
3382                                GDK_WINDOW_XID (window),
3383                                shape,
3384                                offset_x, offset_y,
3385                                xrects, n_rects,
3386                                ShapeSet,
3387                                YXBanded);
3388
3389       if (shape == ShapeBounding)
3390         {
3391           _gdk_x11_window_tmp_reset_parent_bg (window);
3392           _gdk_x11_window_tmp_reset_bg (window, TRUE);
3393         }
3394       
3395       g_free (xrects);
3396     }
3397 }
3398
3399 static void
3400 gdk_window_x11_shape_combine_region (GdkWindow       *window,
3401                                      const cairo_region_t *shape_region,
3402                                      gint             offset_x,
3403                                      gint             offset_y)
3404 {
3405   do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding);
3406 }
3407
3408 static void 
3409 gdk_window_x11_input_shape_combine_region (GdkWindow       *window,
3410                                            const cairo_region_t *shape_region,
3411                                            gint             offset_x,
3412                                            gint             offset_y)
3413 {
3414 #ifdef ShapeInput
3415   do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeInput);
3416 #endif
3417 }
3418
3419
3420 /**
3421  * gdk_window_set_override_redirect:
3422  * @window: a toplevel #GdkWindow
3423  * @override_redirect: %TRUE if window should be override redirect
3424  *
3425  * An override redirect window is not under the control of the window manager.
3426  * This means it won't have a titlebar, won't be minimizable, etc. - it will
3427  * be entirely under the control of the application. The window manager
3428  * can't see the override redirect window at all.
3429  *
3430  * Override redirect should only be used for short-lived temporary
3431  * windows, such as popup menus. #GtkMenu uses an override redirect
3432  * window in its implementation, for example.
3433  * 
3434  **/
3435 void
3436 gdk_window_set_override_redirect (GdkWindow *window,
3437                                   gboolean override_redirect)
3438 {
3439   XSetWindowAttributes attr;
3440   
3441   if (!GDK_WINDOW_DESTROYED (window) &&
3442       WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3443     {
3444       GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
3445
3446       attr.override_redirect = (override_redirect? True : False);
3447       XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3448                                GDK_WINDOW_XID (window),
3449                                CWOverrideRedirect,
3450                                &attr);
3451
3452       impl->override_redirect = attr.override_redirect;
3453     }
3454 }
3455
3456 /**
3457  * gdk_window_set_accept_focus:
3458  * @window: a toplevel #GdkWindow
3459  * @accept_focus: %TRUE if the window should receive input focus
3460  *
3461  * Setting @accept_focus to %FALSE hints the desktop environment that the
3462  * window doesn't want to receive input focus. 
3463  *
3464  * On X, it is the responsibility of the window manager to interpret this 
3465  * hint. ICCCM-compliant window manager usually respect it.
3466  *
3467  * Since: 2.4 
3468  **/
3469 void
3470 gdk_window_set_accept_focus (GdkWindow *window,
3471                              gboolean accept_focus)
3472 {
3473   accept_focus = accept_focus != FALSE;
3474
3475   if (window->accept_focus != accept_focus)
3476     {
3477       window->accept_focus = accept_focus;
3478
3479       if (!GDK_WINDOW_DESTROYED (window) &&
3480           WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3481         update_wm_hints (window, FALSE);
3482     }
3483 }
3484
3485 /**
3486  * gdk_window_set_focus_on_map:
3487  * @window: a toplevel #GdkWindow
3488  * @focus_on_map: %TRUE if the window should receive input focus when mapped
3489  *
3490  * Setting @focus_on_map to %FALSE hints the desktop environment that the
3491  * window doesn't want to receive input focus when it is mapped.  
3492  * focus_on_map should be turned off for windows that aren't triggered
3493  * interactively (such as popups from network activity).
3494  *
3495  * On X, it is the responsibility of the window manager to interpret
3496  * this hint. Window managers following the freedesktop.org window
3497  * manager extension specification should respect it.
3498  *
3499  * Since: 2.6 
3500  **/
3501 void
3502 gdk_window_set_focus_on_map (GdkWindow *window,
3503                              gboolean focus_on_map)
3504 {
3505   focus_on_map = focus_on_map != FALSE;
3506
3507   if (window->focus_on_map != focus_on_map)
3508     {
3509       window->focus_on_map = focus_on_map;
3510       
3511       if ((!GDK_WINDOW_DESTROYED (window)) &&
3512           (!window->focus_on_map) &&
3513           WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3514         gdk_x11_window_set_user_time (window, 0);
3515     }
3516 }
3517
3518 /**
3519  * gdk_x11_window_set_user_time:
3520  * @window: A toplevel #GdkWindow
3521  * @timestamp: An XServer timestamp to which the property should be set
3522  *
3523  * The application can use this call to update the _NET_WM_USER_TIME
3524  * property on a toplevel window.  This property stores an Xserver
3525  * time which represents the time of the last user input event
3526  * received for this window.  This property may be used by the window
3527  * manager to alter the focus, stacking, and/or placement behavior of
3528  * windows when they are mapped depending on whether the new window
3529  * was created by a user action or is a "pop-up" window activated by a
3530  * timer or some other event.
3531  *
3532  * Note that this property is automatically updated by GDK, so this
3533  * function should only be used by applications which handle input
3534  * events bypassing GDK.
3535  *
3536  * Since: 2.6
3537  **/
3538 void
3539 gdk_x11_window_set_user_time (GdkWindow *window,
3540                               guint32    timestamp)
3541 {
3542   GdkDisplay *display;
3543   GdkDisplayX11 *display_x11;
3544   GdkToplevelX11 *toplevel;
3545   glong timestamp_long = (glong)timestamp;
3546   Window xid;
3547
3548   if (GDK_WINDOW_DESTROYED (window) ||
3549       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3550     return;
3551
3552   display = gdk_window_get_display (window);
3553   display_x11 = GDK_DISPLAY_X11 (display);
3554   toplevel = _gdk_x11_window_get_toplevel (window);
3555
3556   if (!toplevel)
3557     {
3558       g_warning ("gdk_window_set_user_time called on non-toplevel\n");
3559       return;
3560     }
3561
3562   if (toplevel->focus_window != None &&
3563       gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
3564                                            gdk_atom_intern_static_string ("_NET_WM_USER_TIME_WINDOW")))
3565     xid = toplevel->focus_window;
3566   else
3567     xid = GDK_WINDOW_XID (window);
3568
3569   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xid,
3570                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_USER_TIME"),
3571                    XA_CARDINAL, 32, PropModeReplace,
3572                    (guchar *)&timestamp_long, 1);
3573
3574   if (timestamp_long != GDK_CURRENT_TIME &&
3575       (display_x11->user_time == GDK_CURRENT_TIME ||
3576        XSERVER_TIME_IS_LATER (timestamp_long, display_x11->user_time)))
3577     display_x11->user_time = timestamp_long;
3578
3579   if (toplevel)
3580     toplevel->user_time = timestamp_long;
3581 }
3582
3583 #define GDK_SELECTION_MAX_SIZE(display)                                 \
3584   MIN(262144,                                                           \
3585       XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0     \
3586        ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100         \
3587        : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
3588
3589 static void
3590 gdk_window_update_icon (GdkWindow *window,
3591                         GList     *icon_list)
3592 {
3593   GdkToplevelX11 *toplevel;
3594   GdkPixbuf *best_icon;
3595   GList *tmp_list;
3596   int best_size;
3597   
3598   toplevel = _gdk_x11_window_get_toplevel (window);
3599
3600   if (toplevel->icon_pixmap != NULL)
3601     {
3602       cairo_surface_destroy (toplevel->icon_pixmap);
3603       toplevel->icon_pixmap = NULL;
3604     }
3605   
3606   if (toplevel->icon_mask != NULL)
3607     {
3608       cairo_surface_destroy (toplevel->icon_mask);
3609       toplevel->icon_mask = NULL;
3610     }
3611   
3612 #define IDEAL_SIZE 48
3613   
3614   best_size = G_MAXINT;
3615   best_icon = NULL;
3616   for (tmp_list = icon_list; tmp_list; tmp_list = tmp_list->next)
3617     {
3618       GdkPixbuf *pixbuf = tmp_list->data;
3619       int this;
3620   
3621       /* average width and height - if someone passes in a rectangular
3622        * icon they deserve what they get.
3623        */
3624       this = gdk_pixbuf_get_width (pixbuf) + gdk_pixbuf_get_height (pixbuf);
3625       this /= 2;
3626   
3627       if (best_icon == NULL)
3628         {
3629           best_icon = pixbuf;
3630           best_size = this;
3631         }
3632       else
3633         {
3634           /* icon is better if it's 32 pixels or larger, and closer to
3635            * the ideal size than the current best.
3636            */
3637           if (this >= 32 &&
3638               (ABS (best_size - IDEAL_SIZE) <
3639                ABS (this - IDEAL_SIZE)))
3640             {
3641               best_icon = pixbuf;
3642               best_size = this;
3643             }
3644         }
3645     }
3646
3647   if (best_icon)
3648     {
3649       int width = gdk_pixbuf_get_width (best_icon);
3650       int height = gdk_pixbuf_get_height (best_icon);
3651       cairo_t *cr;
3652
3653       toplevel->icon_pixmap = gdk_x11_window_create_pixmap_surface (window,
3654                                                                     width,
3655                                                                     height);
3656
3657       cr = cairo_create (toplevel->icon_pixmap);
3658       cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3659       gdk_cairo_set_source_pixbuf (cr, best_icon, 0, 0);
3660       if (gdk_pixbuf_get_has_alpha (best_icon))
3661         {
3662           /* Saturate the image, so it has bilevel alpha */
3663           cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
3664           cairo_paint (cr);
3665           cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
3666           cairo_paint (cr);
3667           cairo_pop_group_to_source (cr);
3668         }
3669       cairo_paint (cr);
3670       cairo_destroy (cr);
3671
3672       if (gdk_pixbuf_get_has_alpha (best_icon))
3673         {
3674           toplevel->icon_mask = _gdk_x11_window_create_bitmap_surface (window,
3675                                                                        width,
3676                                                                        height);
3677
3678           cr = cairo_create (toplevel->icon_mask);
3679           gdk_cairo_set_source_pixbuf (cr, best_icon, 0, 0);
3680           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3681           cairo_paint (cr);
3682           cairo_destroy (cr);
3683         }
3684     }
3685
3686   update_wm_hints (window, FALSE);
3687 }
3688
3689 /**
3690  * gdk_window_set_icon_list:
3691  * @window: The #GdkWindow toplevel window to set the icon of.
3692  * @pixbufs: (transfer none) (element-type GdkPixbuf):
3693  *     A list of pixbufs, of different sizes.
3694  *
3695  * Sets a list of icons for the window. One of these will be used
3696  * to represent the window when it has been iconified. The icon is
3697  * usually shown in an icon box or some sort of task bar. Which icon
3698  * size is shown depends on the window manager. The window manager
3699  * can scale the icon  but setting several size icons can give better
3700  * image quality since the window manager may only need to scale the
3701  * icon by a small amount or not at all.
3702  *
3703  **/
3704 void
3705 gdk_window_set_icon_list (GdkWindow *window,
3706                           GList     *pixbufs)
3707 {
3708   gulong *data;
3709   guchar *pixels;
3710   gulong *p;
3711   gint size;
3712   GList *l;
3713   GdkPixbuf *pixbuf;
3714   gint width, height, stride;
3715   gint x, y;
3716   gint n_channels;
3717   GdkDisplay *display;
3718   gint n;
3719   
3720   if (GDK_WINDOW_DESTROYED (window) ||
3721       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3722     return;
3723
3724   display = gdk_window_get_display (window);
3725   
3726   l = pixbufs;
3727   size = 0;
3728   n = 0;
3729   while (l)
3730     {
3731       pixbuf = l->data;
3732       g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
3733
3734       width = gdk_pixbuf_get_width (pixbuf);
3735       height = gdk_pixbuf_get_height (pixbuf);
3736       
3737       /* silently ignore overlarge icons */
3738       if (size + 2 + width * height > GDK_SELECTION_MAX_SIZE(display))
3739         {
3740           g_warning ("gdk_window_set_icon_list: icons too large");
3741           break;
3742         }
3743      
3744       n++;
3745       size += 2 + width * height;
3746       
3747       l = g_list_next (l);
3748     }
3749
3750   data = g_malloc (size * sizeof (gulong));
3751
3752   l = pixbufs;
3753   p = data;
3754   while (l && n > 0)
3755     {
3756       pixbuf = l->data;
3757       
3758       width = gdk_pixbuf_get_width (pixbuf);
3759       height = gdk_pixbuf_get_height (pixbuf);
3760       stride = gdk_pixbuf_get_rowstride (pixbuf);
3761       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
3762       
3763       *p++ = width;
3764       *p++ = height;
3765
3766       pixels = gdk_pixbuf_get_pixels (pixbuf);
3767
3768       for (y = 0; y < height; y++)
3769         {
3770           for (x = 0; x < width; x++)
3771             {
3772               guchar r, g, b, a;
3773               
3774               r = pixels[y*stride + x*n_channels + 0];
3775               g = pixels[y*stride + x*n_channels + 1];
3776               b = pixels[y*stride + x*n_channels + 2];
3777               if (n_channels >= 4)
3778                 a = pixels[y*stride + x*n_channels + 3];
3779               else
3780                 a = 255;
3781               
3782               *p++ = a << 24 | r << 16 | g << 8 | b ;
3783             }
3784         }
3785
3786       l = g_list_next (l);
3787       n--;
3788     }
3789
3790   if (size > 0)
3791     {
3792       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3793                        GDK_WINDOW_XID (window),
3794                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"),
3795                        XA_CARDINAL, 32,
3796                        PropModeReplace,
3797                        (guchar*) data, size);
3798     }
3799   else
3800     {
3801       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
3802                        GDK_WINDOW_XID (window),
3803                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"));
3804     }
3805   
3806   g_free (data);
3807
3808   gdk_window_update_icon (window, pixbufs);
3809 }
3810
3811 static gboolean
3812 gdk_window_icon_name_set (GdkWindow *window)
3813 {
3814   return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
3815                                                g_quark_from_static_string ("gdk-icon-name-set")));
3816 }
3817
3818 /**
3819  * gdk_window_set_icon_name:
3820  * @window: a toplevel #GdkWindow
3821  * @name: name of window while iconified (minimized)
3822  *
3823  * Windows may have a name used while minimized, distinct from the
3824  * name they display in their titlebar. Most of the time this is a bad
3825  * idea from a user interface standpoint. But you can set such a name
3826  * with this function, if you like.
3827  *
3828  * After calling this with a non-%NULL @name, calls to gdk_window_set_title()
3829  * will not update the icon title.
3830  *
3831  * Using %NULL for @name unsets the icon title; further calls to
3832  * gdk_window_set_title() will again update the icon title as well.
3833  **/
3834 void
3835 gdk_window_set_icon_name (GdkWindow   *window, 
3836                           const gchar *name)
3837 {
3838   GdkDisplay *display;
3839
3840   if (GDK_WINDOW_DESTROYED (window) ||
3841       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3842     return;
3843
3844   display = gdk_window_get_display (window);
3845
3846   g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
3847                       GUINT_TO_POINTER (name != NULL));
3848
3849   if (name != NULL)
3850     {
3851       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3852                        GDK_WINDOW_XID (window),
3853                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
3854                        gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
3855                        PropModeReplace, (guchar *)name, strlen (name));
3856
3857       set_text_property (display, GDK_WINDOW_XID (window),
3858                          gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
3859                          name);
3860     }
3861   else
3862     {
3863       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
3864                        GDK_WINDOW_XID (window),
3865                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"));
3866       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
3867                        GDK_WINDOW_XID (window),
3868                        gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"));
3869     }
3870 }
3871
3872 /**
3873  * gdk_window_iconify:
3874  * @window: a toplevel #GdkWindow
3875  * 
3876  * Asks to iconify (minimize) @window. The window manager may choose
3877  * to ignore the request, but normally will honor it. Using
3878  * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
3879  *
3880  * This function only makes sense when @window is a toplevel window.
3881  *
3882  **/
3883 void
3884 gdk_window_iconify (GdkWindow *window)
3885 {
3886   if (GDK_WINDOW_DESTROYED (window) ||
3887       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3888     return;
3889
3890   if (GDK_WINDOW_IS_MAPPED (window))
3891     {  
3892       XIconifyWindow (GDK_WINDOW_XDISPLAY (window),
3893                       GDK_WINDOW_XID (window),
3894                       gdk_screen_get_number (GDK_WINDOW_SCREEN (window)));
3895     }
3896   else
3897     {
3898       /* Flip our client side flag, the real work happens on map. */
3899       gdk_synthesize_window_state (window,
3900                                    0,
3901                                    GDK_WINDOW_STATE_ICONIFIED);
3902     }
3903 }
3904
3905 /**
3906  * gdk_window_deiconify:
3907  * @window: a toplevel #GdkWindow
3908  *
3909  * Attempt to deiconify (unminimize) @window. On X11 the window manager may
3910  * choose to ignore the request to deiconify. When using GTK+,
3911  * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet,
3912  * you probably want to use gtk_window_present(), which raises the window, focuses it,
3913  * unminimizes it, and puts it on the current desktop.
3914  *
3915  **/
3916 void
3917 gdk_window_deiconify (GdkWindow *window)
3918 {
3919   if (GDK_WINDOW_DESTROYED (window) ||
3920       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3921     return;
3922
3923   if (GDK_WINDOW_IS_MAPPED (window))
3924     {  
3925       gdk_window_show (window);
3926     }
3927   else
3928     {
3929       /* Flip our client side flag, the real work happens on map. */
3930       gdk_synthesize_window_state (window,
3931                                    GDK_WINDOW_STATE_ICONIFIED,
3932                                    0);
3933     }
3934 }
3935
3936 /**
3937  * gdk_window_stick:
3938  * @window: a toplevel #GdkWindow
3939  *
3940  * "Pins" a window such that it's on all workspaces and does not scroll
3941  * with viewports, for window managers that have scrollable viewports.
3942  * (When using #GtkWindow, gtk_window_stick() may be more useful.)
3943  *
3944  * On the X11 platform, this function depends on window manager
3945  * support, so may have no effect with many window managers. However,
3946  * GDK will do the best it can to convince the window manager to stick
3947  * the window. For window managers that don't support this operation,
3948  * there's nothing you can do to force it to happen.
3949  * 
3950  **/
3951 void
3952 gdk_window_stick (GdkWindow *window)
3953 {
3954   if (GDK_WINDOW_DESTROYED (window) ||
3955       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
3956     return;
3957
3958   if (GDK_WINDOW_IS_MAPPED (window))
3959     {
3960       /* "stick" means stick to all desktops _and_ do not scroll with the
3961        * viewport. i.e. glue to the monitor glass in all cases.
3962        */
3963       
3964       XClientMessageEvent xclient;
3965
3966       /* Request stick during viewport scroll */
3967       gdk_wmspec_change_state (TRUE, window,
3968                                gdk_atom_intern_static_string ("_NET_WM_STATE_STICKY"),
3969                                GDK_NONE);
3970
3971       /* Request desktop 0xFFFFFFFF */
3972       memset (&xclient, 0, sizeof (xclient));
3973       xclient.type = ClientMessage;
3974       xclient.window = GDK_WINDOW_XID (window);
3975       xclient.display = GDK_WINDOW_XDISPLAY (window);
3976       xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), 
3977                                                                         "_NET_WM_DESKTOP");
3978       xclient.format = 32;
3979
3980       xclient.data.l[0] = 0xFFFFFFFF;
3981       xclient.data.l[1] = 0;
3982       xclient.data.l[2] = 0;
3983       xclient.data.l[3] = 0;
3984       xclient.data.l[4] = 0;
3985
3986       XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
3987                   SubstructureRedirectMask | SubstructureNotifyMask,
3988                   (XEvent *)&xclient);
3989     }
3990   else
3991     {
3992       /* Flip our client side flag, the real work happens on map. */
3993       gdk_synthesize_window_state (window,
3994                                    0,
3995                                    GDK_WINDOW_STATE_STICKY);
3996     }
3997 }
3998
3999 /**
4000  * gdk_window_unstick:
4001  * @window: a toplevel #GdkWindow
4002  *
4003  * Reverse operation for gdk_window_stick(); see gdk_window_stick(),
4004  * and gtk_window_unstick().
4005  * 
4006  **/
4007 void
4008 gdk_window_unstick (GdkWindow *window)
4009 {
4010   if (GDK_WINDOW_DESTROYED (window) ||
4011       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4012     return;
4013
4014   if (GDK_WINDOW_IS_MAPPED (window))
4015     {
4016       /* Request unstick from viewport */
4017       gdk_wmspec_change_state (FALSE, window,
4018                                gdk_atom_intern_static_string ("_NET_WM_STATE_STICKY"),
4019                                GDK_NONE);
4020
4021       move_to_current_desktop (window);
4022     }
4023   else
4024     {
4025       /* Flip our client side flag, the real work happens on map. */
4026       gdk_synthesize_window_state (window,
4027                                    GDK_WINDOW_STATE_STICKY,
4028                                    0);
4029
4030     }
4031 }
4032
4033 /**
4034  * gdk_window_maximize:
4035  * @window: a toplevel #GdkWindow
4036  *
4037  * Maximizes the window. If the window was already maximized, then
4038  * this function does nothing.
4039  * 
4040  * On X11, asks the window manager to maximize @window, if the window
4041  * manager supports this operation. Not all window managers support
4042  * this, and some deliberately ignore it or don't have a concept of
4043  * "maximized"; so you can't rely on the maximization actually
4044  * happening. But it will happen with most standard window managers,
4045  * and GDK makes a best effort to get it to happen.
4046  *
4047  * On Windows, reliably maximizes the window.
4048  * 
4049  **/
4050 void
4051 gdk_window_maximize (GdkWindow *window)
4052 {
4053   if (GDK_WINDOW_DESTROYED (window) ||
4054       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4055     return;
4056
4057   if (GDK_WINDOW_IS_MAPPED (window))
4058     gdk_wmspec_change_state (TRUE, window,
4059                              gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
4060                              gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
4061   else
4062     gdk_synthesize_window_state (window,
4063                                  0,
4064                                  GDK_WINDOW_STATE_MAXIMIZED);
4065 }
4066
4067 /**
4068  * gdk_window_unmaximize:
4069  * @window: a toplevel #GdkWindow
4070  *
4071  * Unmaximizes the window. If the window wasn't maximized, then this
4072  * function does nothing.
4073  * 
4074  * On X11, asks the window manager to unmaximize @window, if the
4075  * window manager supports this operation. Not all window managers
4076  * support this, and some deliberately ignore it or don't have a
4077  * concept of "maximized"; so you can't rely on the unmaximization
4078  * actually happening. But it will happen with most standard window
4079  * managers, and GDK makes a best effort to get it to happen.
4080  *
4081  * On Windows, reliably unmaximizes the window.
4082  * 
4083  **/
4084 void
4085 gdk_window_unmaximize (GdkWindow *window)
4086 {
4087   if (GDK_WINDOW_DESTROYED (window) ||
4088       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4089     return;
4090
4091   if (GDK_WINDOW_IS_MAPPED (window))
4092     gdk_wmspec_change_state (FALSE, window,
4093                              gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
4094                              gdk_atom_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
4095   else
4096     gdk_synthesize_window_state (window,
4097                                  GDK_WINDOW_STATE_MAXIMIZED,
4098                                  0);
4099 }
4100
4101 /**
4102  * gdk_window_fullscreen:
4103  * @window: a toplevel #GdkWindow
4104  *
4105  * Moves the window into fullscreen mode. This means the
4106  * window covers the entire screen and is above any panels
4107  * or task bars.
4108  *
4109  * If the window was already fullscreen, then this function does nothing.
4110  * 
4111  * On X11, asks the window manager to put @window in a fullscreen
4112  * state, if the window manager supports this operation. Not all
4113  * window managers support this, and some deliberately ignore it or
4114  * don't have a concept of "fullscreen"; so you can't rely on the
4115  * fullscreenification actually happening. But it will happen with
4116  * most standard window managers, and GDK makes a best effort to get
4117  * it to happen.
4118  *
4119  * Since: 2.2
4120  **/
4121 void
4122 gdk_window_fullscreen (GdkWindow *window)
4123 {
4124   if (GDK_WINDOW_DESTROYED (window) ||
4125       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4126     return;
4127
4128   if (GDK_WINDOW_IS_MAPPED (window))
4129     gdk_wmspec_change_state (TRUE, window,
4130                              gdk_atom_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
4131                              GDK_NONE);
4132
4133   else
4134     gdk_synthesize_window_state (window,
4135                                  0,
4136                                  GDK_WINDOW_STATE_FULLSCREEN);
4137 }
4138
4139 /**
4140  * gdk_window_unfullscreen:
4141  * @window: a toplevel #GdkWindow
4142  *
4143  * Moves the window out of fullscreen mode. If the window was not
4144  * fullscreen, does nothing.
4145  * 
4146  * On X11, asks the window manager to move @window out of the fullscreen
4147  * state, if the window manager supports this operation. Not all
4148  * window managers support this, and some deliberately ignore it or
4149  * don't have a concept of "fullscreen"; so you can't rely on the
4150  * unfullscreenification actually happening. But it will happen with
4151  * most standard window managers, and GDK makes a best effort to get
4152  * it to happen. 
4153  *
4154  * Since: 2.2
4155  **/
4156 void
4157 gdk_window_unfullscreen (GdkWindow *window)
4158 {
4159   if (GDK_WINDOW_DESTROYED (window) ||
4160       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4161     return;
4162
4163   if (GDK_WINDOW_IS_MAPPED (window))
4164     gdk_wmspec_change_state (FALSE, window,
4165                              gdk_atom_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
4166                              GDK_NONE);
4167
4168   else
4169     gdk_synthesize_window_state (window,
4170                                  GDK_WINDOW_STATE_FULLSCREEN,
4171                                  0);
4172 }
4173
4174 /**
4175  * gdk_window_set_keep_above:
4176  * @window: a toplevel #GdkWindow
4177  * @setting: whether to keep @window above other windows
4178  *
4179  * Set if @window must be kept above other windows. If the
4180  * window was already above, then this function does nothing.
4181  * 
4182  * On X11, asks the window manager to keep @window above, if the window
4183  * manager supports this operation. Not all window managers support
4184  * this, and some deliberately ignore it or don't have a concept of
4185  * "keep above"; so you can't rely on the window being kept above.
4186  * But it will happen with most standard window managers,
4187  * and GDK makes a best effort to get it to happen.
4188  *
4189  * Since: 2.4
4190  **/
4191 void
4192 gdk_window_set_keep_above (GdkWindow *window,
4193                            gboolean   setting)
4194 {
4195   g_return_if_fail (GDK_IS_WINDOW (window));
4196
4197   if (GDK_WINDOW_DESTROYED (window) ||
4198       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4199     return;
4200
4201   if (GDK_WINDOW_IS_MAPPED (window))
4202     {
4203       if (setting)
4204         gdk_wmspec_change_state (FALSE, window,
4205                                  gdk_atom_intern_static_string ("_NET_WM_STATE_BELOW"),
4206                                  GDK_NONE);
4207       gdk_wmspec_change_state (setting, window,
4208                                gdk_atom_intern_static_string ("_NET_WM_STATE_ABOVE"),
4209                                GDK_NONE);
4210     }
4211   else
4212     gdk_synthesize_window_state (window,
4213                                  setting ? GDK_WINDOW_STATE_BELOW : GDK_WINDOW_STATE_ABOVE,
4214                                  setting ? GDK_WINDOW_STATE_ABOVE : 0);
4215 }
4216
4217 /**
4218  * gdk_window_set_keep_below:
4219  * @window: a toplevel #GdkWindow
4220  * @setting: whether to keep @window below other windows
4221  *
4222  * Set if @window must be kept below other windows. If the
4223  * window was already below, then this function does nothing.
4224  * 
4225  * On X11, asks the window manager to keep @window below, if the window
4226  * manager supports this operation. Not all window managers support
4227  * this, and some deliberately ignore it or don't have a concept of
4228  * "keep below"; so you can't rely on the window being kept below.
4229  * But it will happen with most standard window managers,
4230  * and GDK makes a best effort to get it to happen.
4231  *
4232  * Since: 2.4
4233  **/
4234 void
4235 gdk_window_set_keep_below (GdkWindow *window, gboolean setting)
4236 {
4237   g_return_if_fail (GDK_IS_WINDOW (window));
4238
4239   if (GDK_WINDOW_DESTROYED (window) ||
4240       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4241     return;
4242
4243   if (GDK_WINDOW_IS_MAPPED (window))
4244     {
4245       if (setting)
4246         gdk_wmspec_change_state (FALSE, window,
4247                                  gdk_atom_intern_static_string ("_NET_WM_STATE_ABOVE"),
4248                                  GDK_NONE);
4249       gdk_wmspec_change_state (setting, window,
4250                                gdk_atom_intern_static_string ("_NET_WM_STATE_BELOW"),
4251                                GDK_NONE);
4252     }
4253   else
4254     gdk_synthesize_window_state (window,
4255                                  setting ? GDK_WINDOW_STATE_ABOVE : GDK_WINDOW_STATE_BELOW,
4256                                  setting ? GDK_WINDOW_STATE_BELOW : 0);
4257 }
4258
4259 /**
4260  * gdk_window_get_group:
4261  * @window: a toplevel #GdkWindow
4262  * 
4263  * Returns the group leader window for @window. See gdk_window_set_group().
4264  * 
4265  * Return value: (transfer none): the group leader window for @window
4266  *
4267  * Since: 2.4
4268  **/
4269 GdkWindow *
4270 gdk_window_get_group (GdkWindow *window)
4271 {
4272   GdkToplevelX11 *toplevel;
4273   
4274   if (GDK_WINDOW_DESTROYED (window) ||
4275       !WINDOW_IS_TOPLEVEL (window))
4276     return NULL;
4277   
4278   toplevel = _gdk_x11_window_get_toplevel (window);
4279
4280   return toplevel->group_leader;
4281 }
4282
4283 /**
4284  * gdk_window_set_group:
4285  * @window: a toplevel #GdkWindow
4286  * @leader: group leader window, or %NULL to restore the default group leader window
4287  *
4288  * Sets the group leader window for @window. By default,
4289  * GDK sets the group leader for all toplevel windows
4290  * to a global window implicitly created by GDK. With this function
4291  * you can override this default.
4292  *
4293  * The group leader window allows the window manager to distinguish
4294  * all windows that belong to a single application. It may for example
4295  * allow users to minimize/unminimize all windows belonging to an
4296  * application at once. You should only set a non-default group window
4297  * if your application pretends to be multiple applications.
4298  **/
4299 void          
4300 gdk_window_set_group (GdkWindow *window,
4301                       GdkWindow *leader)
4302 {
4303   GdkToplevelX11 *toplevel;
4304   
4305   g_return_if_fail (GDK_IS_WINDOW (window));
4306   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
4307   g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader));
4308
4309   if (GDK_WINDOW_DESTROYED (window) ||
4310       (leader != NULL && GDK_WINDOW_DESTROYED (leader)) ||
4311       !WINDOW_IS_TOPLEVEL (window))
4312     return;
4313
4314   toplevel = _gdk_x11_window_get_toplevel (window);
4315
4316   if (leader == NULL)
4317     leader = gdk_display_get_default_group (gdk_window_get_display (window));
4318   
4319   if (toplevel->group_leader != leader)
4320     {
4321       if (toplevel->group_leader)
4322         g_object_unref (toplevel->group_leader);
4323       toplevel->group_leader = g_object_ref (leader);
4324       (_gdk_x11_window_get_toplevel (leader))->is_leader = TRUE;      
4325     }
4326
4327   update_wm_hints (window, FALSE);
4328 }
4329
4330 static MotifWmHints *
4331 gdk_window_get_mwm_hints (GdkWindow *window)
4332 {
4333   GdkDisplay *display;
4334   Atom hints_atom = None;
4335   guchar *data;
4336   Atom type;
4337   gint format;
4338   gulong nitems;
4339   gulong bytes_after;
4340   
4341   if (GDK_WINDOW_DESTROYED (window))
4342     return NULL;
4343
4344   display = gdk_window_get_display (window);
4345   
4346   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
4347
4348   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
4349                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
4350                       False, AnyPropertyType, &type, &format, &nitems,
4351                       &bytes_after, &data);
4352
4353   if (type == None)
4354     return NULL;
4355   
4356   return (MotifWmHints *)data;
4357 }
4358
4359 static void
4360 gdk_window_set_mwm_hints (GdkWindow *window,
4361                           MotifWmHints *new_hints)
4362 {
4363   GdkDisplay *display;
4364   Atom hints_atom = None;
4365   guchar *data;
4366   MotifWmHints *hints;
4367   Atom type;
4368   gint format;
4369   gulong nitems;
4370   gulong bytes_after;
4371   
4372   if (GDK_WINDOW_DESTROYED (window))
4373     return;
4374   
4375   display = gdk_window_get_display (window);
4376   
4377   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
4378
4379   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
4380                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
4381                       False, AnyPropertyType, &type, &format, &nitems,
4382                       &bytes_after, &data);
4383   
4384   if (type == None)
4385     hints = new_hints;
4386   else
4387     {
4388       hints = (MotifWmHints *)data;
4389         
4390       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
4391         {
4392           hints->flags |= MWM_HINTS_FUNCTIONS;
4393           hints->functions = new_hints->functions;
4394         }
4395       if (new_hints->flags & MWM_HINTS_DECORATIONS)
4396         {
4397           hints->flags |= MWM_HINTS_DECORATIONS;
4398           hints->decorations = new_hints->decorations;
4399         }
4400     }
4401   
4402   XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
4403                    hints_atom, hints_atom, 32, PropModeReplace,
4404                    (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
4405   
4406   if (hints != new_hints)
4407     XFree (hints);
4408 }
4409
4410 /**
4411  * gdk_window_set_decorations:
4412  * @window: a toplevel #GdkWindow
4413  * @decorations: decoration hint mask
4414  *
4415  * "Decorations" are the features the window manager adds to a toplevel #GdkWindow.
4416  * This function sets the traditional Motif window manager hints that tell the
4417  * window manager which decorations you would like your window to have.
4418  * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
4419  * using the GDK function directly.
4420  *
4421  * The @decorations argument is the logical OR of the fields in
4422  * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
4423  * mask, the other bits indicate which decorations should be turned off.
4424  * If #GDK_DECOR_ALL is not included, then the other bits indicate
4425  * which decorations should be turned on.
4426  *
4427  * Most window managers honor a decorations hint of 0 to disable all decorations,
4428  * but very few honor all possible combinations of bits.
4429  * 
4430  **/
4431 void
4432 gdk_window_set_decorations (GdkWindow      *window,
4433                             GdkWMDecoration decorations)
4434 {
4435   MotifWmHints hints;
4436
4437   if (GDK_WINDOW_DESTROYED (window) ||
4438       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4439     return;
4440   
4441   /* initialize to zero to avoid writing uninitialized data to socket */
4442   memset(&hints, 0, sizeof(hints));
4443   hints.flags = MWM_HINTS_DECORATIONS;
4444   hints.decorations = decorations;
4445   
4446   gdk_window_set_mwm_hints (window, &hints);
4447 }
4448
4449 /**
4450  * gdk_window_get_decorations:
4451  * @window: The toplevel #GdkWindow to get the decorations from
4452  * @decorations: The window decorations will be written here
4453  *
4454  * Returns the decorations set on the GdkWindow with
4455  * gdk_window_set_decorations().
4456  *
4457  * Returns: %TRUE if the window has decorations set, %FALSE otherwise.
4458  **/
4459 gboolean
4460 gdk_window_get_decorations(GdkWindow       *window,
4461                            GdkWMDecoration *decorations)
4462 {
4463   MotifWmHints *hints;
4464   gboolean result = FALSE;
4465
4466   if (GDK_WINDOW_DESTROYED (window) ||
4467       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4468     return FALSE;
4469   
4470   hints = gdk_window_get_mwm_hints (window);
4471   
4472   if (hints)
4473     {
4474       if (hints->flags & MWM_HINTS_DECORATIONS)
4475         {
4476           if (decorations)
4477             *decorations = hints->decorations;
4478           result = TRUE;
4479         }
4480       
4481       XFree (hints);
4482     }
4483
4484   return result;
4485 }
4486
4487 /**
4488  * gdk_window_set_functions:
4489  * @window: a toplevel #GdkWindow
4490  * @functions: bitmask of operations to allow on @window
4491  *
4492  * Sets hints about the window management functions to make available
4493  * via buttons on the window frame.
4494  * 
4495  * On the X backend, this function sets the traditional Motif window 
4496  * manager hint for this purpose. However, few window managers do
4497  * anything reliable or interesting with this hint. Many ignore it
4498  * entirely.
4499  *
4500  * The @functions argument is the logical OR of values from the
4501  * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
4502  * then the other bits indicate which functions to disable; if
4503  * it doesn't include #GDK_FUNC_ALL, it indicates which functions to
4504  * enable.
4505  * 
4506  **/
4507 void
4508 gdk_window_set_functions (GdkWindow    *window,
4509                           GdkWMFunction functions)
4510 {
4511   MotifWmHints hints;
4512   
4513   g_return_if_fail (GDK_IS_WINDOW (window));
4514
4515   if (GDK_WINDOW_DESTROYED (window) ||
4516       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
4517     return;
4518   
4519   /* initialize to zero to avoid writing uninitialized data to socket */
4520   memset(&hints, 0, sizeof(hints));
4521   hints.flags = MWM_HINTS_FUNCTIONS;
4522   hints.functions = functions;
4523   
4524   gdk_window_set_mwm_hints (window, &hints);
4525 }
4526
4527 cairo_region_t *
4528 _xwindow_get_shape (Display *xdisplay,
4529                     Window window,
4530                     gint shape_type)
4531 {
4532   cairo_region_t *shape;
4533   GdkRectangle *rl;
4534   XRectangle *xrl;
4535   gint rn, ord, i;
4536
4537   shape = NULL;
4538   rn = 0;
4539
4540   xrl = XShapeGetRectangles (xdisplay,
4541                              window,
4542                              shape_type, &rn, &ord);
4543
4544   if (xrl == NULL || rn == 0)
4545     return cairo_region_create (); /* Empty */
4546
4547   if (ord != YXBanded)
4548     {
4549       /* This really shouldn't happen with any xserver, as they
4550          generally convert regions to YXBanded internally */
4551       g_warning ("non YXBanded shape masks not supported");
4552       XFree (xrl);
4553       return NULL;
4554     }
4555
4556   rl = g_new (GdkRectangle, rn);
4557   for (i = 0; i < rn; i++)
4558     {
4559       rl[i].x = xrl[i].x;
4560       rl[i].y = xrl[i].y;
4561       rl[i].width = xrl[i].width;
4562       rl[i].height = xrl[i].height;
4563     }
4564   XFree (xrl);
4565   
4566   shape = cairo_region_create_rectangles (rl, rn);
4567   g_free (rl);
4568   
4569   return shape;
4570 }
4571
4572
4573 static cairo_region_t *
4574 gdk_x11_window_get_shape (GdkWindow *window)
4575 {
4576   if (!GDK_WINDOW_DESTROYED (window) &&
4577       gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
4578     return _xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
4579                               GDK_WINDOW_XID (window), ShapeBounding);
4580
4581   return NULL;
4582 }
4583
4584 static cairo_region_t *
4585 gdk_x11_window_get_input_shape (GdkWindow *window)
4586 {
4587 #if defined(ShapeInput)
4588   if (!GDK_WINDOW_DESTROYED (window) &&
4589       gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
4590     return _xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
4591                               GDK_WINDOW_XID (window),
4592                               ShapeInput);
4593 #endif
4594
4595   return NULL;
4596 }
4597
4598 static void
4599 gdk_window_set_static_bit_gravity (GdkWindow *window,
4600                                    gboolean   on)
4601 {
4602   XSetWindowAttributes xattributes;
4603   guint xattributes_mask = 0;
4604   
4605   g_return_if_fail (GDK_IS_WINDOW (window));
4606
4607   if (window->input_only)
4608     return;
4609   
4610   xattributes.bit_gravity = StaticGravity;
4611   xattributes_mask |= CWBitGravity;
4612   xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
4613   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
4614                            GDK_WINDOW_XID (window),
4615                            CWBitGravity,  &xattributes);
4616 }
4617
4618 static void
4619 gdk_window_set_static_win_gravity (GdkWindow *window,
4620                                    gboolean   on)
4621 {
4622   XSetWindowAttributes xattributes;
4623   
4624   g_return_if_fail (GDK_IS_WINDOW (window));
4625   
4626   xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
4627   
4628   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
4629                            GDK_WINDOW_XID (window),
4630                            CWWinGravity,  &xattributes);
4631 }
4632
4633 static gboolean
4634 gdk_window_x11_set_static_gravities (GdkWindow *window,
4635                                      gboolean   use_static)
4636 {
4637   GList *tmp_list;
4638   
4639   if (!use_static == !window->guffaw_gravity)
4640     return TRUE;
4641
4642   window->guffaw_gravity = use_static;
4643   
4644   if (!GDK_WINDOW_DESTROYED (window))
4645     {
4646       gdk_window_set_static_bit_gravity (window, use_static);
4647       
4648       tmp_list = window->children;
4649       while (tmp_list)
4650         {
4651           gdk_window_set_static_win_gravity (tmp_list->data, use_static);
4652           
4653           tmp_list = tmp_list->next;
4654         }
4655     }
4656   
4657   return TRUE;
4658 }
4659
4660 static void
4661 wmspec_moveresize (GdkWindow *window,
4662                    gint       direction,
4663                    gint       root_x,
4664                    gint       root_y,
4665                    guint32    timestamp)     
4666 {
4667   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
4668   
4669   XClientMessageEvent xclient;
4670
4671   /* Release passive grab */
4672   gdk_display_pointer_ungrab (display, timestamp);
4673
4674   memset (&xclient, 0, sizeof (xclient));
4675   xclient.type = ClientMessage;
4676   xclient.window = GDK_WINDOW_XID (window);
4677   xclient.message_type =
4678     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
4679   xclient.format = 32;
4680   xclient.data.l[0] = root_x;
4681   xclient.data.l[1] = root_y;
4682   xclient.data.l[2] = direction;
4683   xclient.data.l[3] = 0;
4684   xclient.data.l[4] = 0;
4685   
4686   XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
4687               SubstructureRedirectMask | SubstructureNotifyMask,
4688               (XEvent *)&xclient);
4689 }
4690
4691 typedef struct _MoveResizeData MoveResizeData;
4692
4693 struct _MoveResizeData
4694 {
4695   GdkDisplay *display;
4696   
4697   GdkWindow *moveresize_window;
4698   GdkWindow *moveresize_emulation_window;
4699   gboolean is_resize;
4700   GdkWindowEdge resize_edge;
4701   gint moveresize_button;
4702   gint moveresize_x;
4703   gint moveresize_y;
4704   gint moveresize_orig_x;
4705   gint moveresize_orig_y;
4706   gint moveresize_orig_width;
4707   gint moveresize_orig_height;
4708   GdkWindowHints moveresize_geom_mask;
4709   GdkGeometry moveresize_geometry;
4710   Time moveresize_process_time;
4711   XEvent *moveresize_pending_event;
4712 };
4713
4714 /* From the WM spec */
4715 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
4716 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
4717 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
4718 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
4719 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
4720 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
4721 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
4722 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
4723 #define _NET_WM_MOVERESIZE_MOVE              8
4724
4725 static void
4726 wmspec_resize_drag (GdkWindow     *window,
4727                     GdkWindowEdge  edge,
4728                     gint           button,
4729                     gint           root_x,
4730                     gint           root_y,
4731                     guint32        timestamp)
4732 {
4733   gint direction;
4734   
4735   /* Let the compiler turn a switch into a table, instead
4736    * of doing the table manually, this way is easier to verify.
4737    */
4738   switch (edge)
4739     {
4740     case GDK_WINDOW_EDGE_NORTH_WEST:
4741       direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
4742       break;
4743
4744     case GDK_WINDOW_EDGE_NORTH:
4745       direction = _NET_WM_MOVERESIZE_SIZE_TOP;
4746       break;
4747
4748     case GDK_WINDOW_EDGE_NORTH_EAST:
4749       direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
4750       break;
4751
4752     case GDK_WINDOW_EDGE_WEST:
4753       direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
4754       break;
4755
4756     case GDK_WINDOW_EDGE_EAST:
4757       direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
4758       break;
4759
4760     case GDK_WINDOW_EDGE_SOUTH_WEST:
4761       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
4762       break;
4763
4764     case GDK_WINDOW_EDGE_SOUTH:
4765       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
4766       break;
4767
4768     case GDK_WINDOW_EDGE_SOUTH_EAST:
4769       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
4770       break;
4771
4772     default:
4773       g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!",
4774                  edge);
4775       return;
4776     }
4777   
4778   wmspec_moveresize (window, direction, root_x, root_y, timestamp);
4779 }
4780
4781 static MoveResizeData *
4782 get_move_resize_data (GdkDisplay *display,
4783                       gboolean    create)
4784 {
4785   MoveResizeData *mv_resize;
4786   static GQuark move_resize_quark = 0;
4787
4788   if (!move_resize_quark)
4789     move_resize_quark = g_quark_from_static_string ("gdk-window-moveresize");
4790   
4791   mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark);
4792
4793   if (!mv_resize && create)
4794     {
4795       mv_resize = g_new0 (MoveResizeData, 1);
4796       mv_resize->display = display;
4797       
4798       g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize);
4799     }
4800
4801   return mv_resize;
4802 }
4803
4804 static void
4805 update_pos (MoveResizeData *mv_resize,
4806             gint            new_root_x,
4807             gint            new_root_y)
4808 {
4809   gint dx, dy;
4810
4811   dx = new_root_x - mv_resize->moveresize_x;
4812   dy = new_root_y - mv_resize->moveresize_y;
4813
4814   if (mv_resize->is_resize)
4815     {
4816       gint x, y, w, h;
4817
4818       x = mv_resize->moveresize_orig_x;
4819       y = mv_resize->moveresize_orig_y;
4820
4821       w = mv_resize->moveresize_orig_width;
4822       h = mv_resize->moveresize_orig_height;
4823
4824       switch (mv_resize->resize_edge)
4825         {
4826         case GDK_WINDOW_EDGE_NORTH_WEST:
4827           x += dx;
4828           y += dy;
4829           w -= dx;
4830           h -= dy;
4831           break;
4832         case GDK_WINDOW_EDGE_NORTH:
4833           y += dy;
4834           h -= dy;
4835           break;
4836         case GDK_WINDOW_EDGE_NORTH_EAST:
4837           y += dy;
4838           h -= dy;
4839           w += dx;
4840           break;
4841         case GDK_WINDOW_EDGE_SOUTH_WEST:
4842           h += dy;
4843           x += dx;
4844           w -= dx;
4845           break;
4846         case GDK_WINDOW_EDGE_SOUTH_EAST:
4847           w += dx;
4848           h += dy;
4849           break;
4850         case GDK_WINDOW_EDGE_SOUTH:
4851           h += dy;
4852           break;
4853         case GDK_WINDOW_EDGE_EAST:
4854           w += dx;
4855           break;
4856         case GDK_WINDOW_EDGE_WEST:
4857           x += dx;
4858           w -= dx;
4859           break;
4860         }
4861
4862       x = MAX (x, 0);
4863       y = MAX (y, 0);
4864       w = MAX (w, 1);
4865       h = MAX (h, 1);
4866
4867       if (mv_resize->moveresize_geom_mask)
4868         {
4869           gdk_window_constrain_size (&mv_resize->moveresize_geometry,
4870                                      mv_resize->moveresize_geom_mask,
4871                                      w, h, &w, &h);
4872         }
4873
4874       gdk_window_move_resize (mv_resize->moveresize_window, x, y, w, h);
4875     }
4876   else
4877     {
4878       gint x, y;
4879
4880       x = mv_resize->moveresize_orig_x + dx;
4881       y = mv_resize->moveresize_orig_y + dy;
4882
4883       gdk_window_move (mv_resize->moveresize_window, x, y);
4884     }
4885 }
4886
4887 static void
4888 finish_drag (MoveResizeData *mv_resize)
4889 {
4890   gdk_window_destroy (mv_resize->moveresize_emulation_window);
4891   mv_resize->moveresize_emulation_window = NULL;
4892   g_object_unref (mv_resize->moveresize_window);
4893   mv_resize->moveresize_window = NULL;
4894
4895   if (mv_resize->moveresize_pending_event)
4896     {
4897       g_free (mv_resize->moveresize_pending_event);
4898       mv_resize->moveresize_pending_event = NULL;
4899     }
4900 }
4901
4902 static int
4903 lookahead_motion_predicate (Display *xdisplay,
4904                             XEvent  *event,
4905                             XPointer arg)
4906 {
4907   gboolean *seen_release = (gboolean *)arg;
4908   GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
4909   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4910
4911   if (*seen_release)
4912     return False;
4913
4914   switch (event->xany.type)
4915     {
4916     case ButtonRelease:
4917       *seen_release = TRUE;
4918       break;
4919     case MotionNotify:
4920       mv_resize->moveresize_process_time = event->xmotion.time;
4921       break;
4922     default:
4923       break;
4924     }
4925
4926   return False;
4927 }
4928
4929 static gboolean
4930 moveresize_lookahead (MoveResizeData *mv_resize,
4931                       XEvent         *event)
4932 {
4933   XEvent tmp_event;
4934   gboolean seen_release = FALSE;
4935
4936   if (mv_resize->moveresize_process_time)
4937     {
4938       if (event->xmotion.time == mv_resize->moveresize_process_time)
4939         {
4940           mv_resize->moveresize_process_time = 0;
4941           return TRUE;
4942         }
4943       else
4944         return FALSE;
4945     }
4946
4947   XCheckIfEvent (event->xany.display, &tmp_event,
4948                  lookahead_motion_predicate, (XPointer) & seen_release);
4949
4950   return mv_resize->moveresize_process_time == 0;
4951 }
4952         
4953 gboolean
4954 _gdk_moveresize_handle_event (XEvent *event)
4955 {
4956   guint button_mask = 0;
4957   GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
4958   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
4959
4960   if (!mv_resize || !mv_resize->moveresize_window)
4961     return FALSE;
4962
4963   button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
4964
4965   switch (event->xany.type)
4966     {
4967     case MotionNotify:
4968       if (mv_resize->moveresize_window->resize_count > 0)
4969         {
4970           if (mv_resize->moveresize_pending_event)
4971             *mv_resize->moveresize_pending_event = *event;
4972           else
4973             mv_resize->moveresize_pending_event =
4974               g_memdup (event, sizeof (XEvent));
4975
4976           break;
4977         }
4978       if (!moveresize_lookahead (mv_resize, event))
4979         break;
4980
4981       update_pos (mv_resize,
4982                   event->xmotion.x_root,
4983                   event->xmotion.y_root);
4984
4985       /* This should never be triggered in normal cases, but in the
4986        * case where the drag started without an implicit grab being
4987        * in effect, we could miss the release if it occurs before
4988        * we grab the pointer; this ensures that we will never
4989        * get a permanently stuck grab.
4990        */
4991       if ((event->xmotion.state & button_mask) == 0)
4992         finish_drag (mv_resize);
4993       break;
4994
4995     case ButtonRelease:
4996       update_pos (mv_resize,
4997                   event->xbutton.x_root,
4998                   event->xbutton.y_root);
4999
5000       if (event->xbutton.button == mv_resize->moveresize_button)
5001         finish_drag (mv_resize);
5002       break;
5003     }
5004   return TRUE;
5005 }
5006
5007 gboolean 
5008 _gdk_moveresize_configure_done (GdkDisplay *display,
5009                                 GdkWindow  *window)
5010 {
5011   XEvent *tmp_event;
5012   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
5013   
5014   if (!mv_resize || window != mv_resize->moveresize_window)
5015     return FALSE;
5016
5017   if (mv_resize->moveresize_pending_event)
5018     {
5019       tmp_event = mv_resize->moveresize_pending_event;
5020       mv_resize->moveresize_pending_event = NULL;
5021       _gdk_moveresize_handle_event (tmp_event);
5022       g_free (tmp_event);
5023     }
5024   
5025   return TRUE;
5026 }
5027
5028 static void
5029 create_moveresize_window (MoveResizeData *mv_resize,
5030                           guint32         timestamp)
5031 {
5032   GdkWindowAttr attributes;
5033   gint attributes_mask;
5034   GdkGrabStatus status;
5035
5036   g_assert (mv_resize->moveresize_emulation_window == NULL);
5037
5038   attributes.x = -100;
5039   attributes.y = -100;
5040   attributes.width = 10;
5041   attributes.height = 10;
5042   attributes.window_type = GDK_WINDOW_TEMP;
5043   attributes.wclass = GDK_INPUT_ONLY;
5044   attributes.override_redirect = TRUE;
5045   attributes.event_mask = 0;
5046
5047   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
5048
5049   mv_resize->moveresize_emulation_window = 
5050     gdk_window_new (gdk_screen_get_root_window (gdk_display_get_default_screen (mv_resize->display)),
5051                     &attributes,
5052                     attributes_mask);
5053
5054   gdk_window_show (mv_resize->moveresize_emulation_window);
5055
5056   status = gdk_pointer_grab (mv_resize->moveresize_emulation_window,
5057                              FALSE,
5058                              GDK_BUTTON_RELEASE_MASK |
5059                              GDK_POINTER_MOTION_MASK,
5060                              NULL,
5061                              NULL,
5062                              timestamp);
5063
5064   if (status != GDK_GRAB_SUCCESS)
5065     {
5066       /* If this fails, some other client has grabbed the window
5067        * already.
5068        */
5069       finish_drag (mv_resize);
5070     }
5071
5072   mv_resize->moveresize_process_time = 0;
5073 }
5074
5075 /* 
5076    Calculate mv_resize->moveresize_orig_x and mv_resize->moveresize_orig_y
5077    so that calling XMoveWindow with these coordinates will not move the 
5078    window.
5079    Note that this depends on the WM to implement ICCCM-compliant reference
5080    point handling.
5081 */
5082 static void 
5083 calculate_unmoving_origin (MoveResizeData *mv_resize)
5084 {
5085   GdkRectangle rect;
5086   gint width, height;
5087
5088   if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY &&
5089       mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC)
5090     {
5091       gdk_window_get_origin (mv_resize->moveresize_window,
5092                              &mv_resize->moveresize_orig_x,
5093                              &mv_resize->moveresize_orig_y);
5094     }
5095   else
5096     {
5097       gdk_window_get_frame_extents (mv_resize->moveresize_window, &rect);
5098       gdk_window_get_geometry (mv_resize->moveresize_window, 
5099                                NULL, NULL, &width, &height, NULL);
5100       
5101       switch (mv_resize->moveresize_geometry.win_gravity) 
5102         {
5103         case GDK_GRAVITY_NORTH_WEST:
5104           mv_resize->moveresize_orig_x = rect.x;
5105           mv_resize->moveresize_orig_y = rect.y;
5106           break;
5107         case GDK_GRAVITY_NORTH:
5108           mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
5109           mv_resize->moveresize_orig_y = rect.y;
5110           break;          
5111         case GDK_GRAVITY_NORTH_EAST:
5112           mv_resize->moveresize_orig_x = rect.x + rect.width - width;
5113           mv_resize->moveresize_orig_y = rect.y;
5114           break;
5115         case GDK_GRAVITY_WEST:
5116           mv_resize->moveresize_orig_x = rect.x;
5117           mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
5118           break;
5119         case GDK_GRAVITY_CENTER:
5120           mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
5121           mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
5122           break;
5123         case GDK_GRAVITY_EAST:
5124           mv_resize->moveresize_orig_x = rect.x + rect.width - width;
5125           mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
5126           break;
5127         case GDK_GRAVITY_SOUTH_WEST:
5128           mv_resize->moveresize_orig_x = rect.x;
5129           mv_resize->moveresize_orig_y = rect.y + rect.height - height;
5130           break;
5131         case GDK_GRAVITY_SOUTH:
5132           mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
5133           mv_resize->moveresize_orig_y = rect.y + rect.height - height;
5134           break;
5135         case GDK_GRAVITY_SOUTH_EAST:
5136           mv_resize->moveresize_orig_x = rect.x + rect.width - width;
5137           mv_resize->moveresize_orig_y = rect.y + rect.height - height;
5138           break;
5139         default:
5140           mv_resize->moveresize_orig_x = rect.x;
5141           mv_resize->moveresize_orig_y = rect.y;
5142           break; 
5143         }
5144     }  
5145 }
5146
5147 static void
5148 emulate_resize_drag (GdkWindow     *window,
5149                      GdkWindowEdge  edge,
5150                      gint           button,
5151                      gint           root_x,
5152                      gint           root_y,
5153                      guint32        timestamp)
5154 {
5155   MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE);
5156
5157   mv_resize->is_resize = TRUE;
5158   mv_resize->moveresize_button = button;
5159   mv_resize->resize_edge = edge;
5160   mv_resize->moveresize_x = root_x;
5161   mv_resize->moveresize_y = root_y;
5162   mv_resize->moveresize_window = g_object_ref (window);
5163
5164   mv_resize->moveresize_orig_width = gdk_window_get_width (window);
5165   mv_resize->moveresize_orig_height = gdk_window_get_height (window);
5166
5167   mv_resize->moveresize_geom_mask = 0;
5168   gdk_window_get_geometry_hints (window,
5169                                  &mv_resize->moveresize_geometry,
5170                                  &mv_resize->moveresize_geom_mask);
5171
5172   calculate_unmoving_origin (mv_resize);
5173
5174   create_moveresize_window (mv_resize, timestamp);
5175 }
5176
5177 static void
5178 emulate_move_drag (GdkWindow     *window,
5179                    gint           button,
5180                    gint           root_x,
5181                    gint           root_y,
5182                    guint32        timestamp)
5183 {
5184   MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE);
5185   
5186   mv_resize->is_resize = FALSE;
5187   mv_resize->moveresize_button = button;
5188   mv_resize->moveresize_x = root_x;
5189   mv_resize->moveresize_y = root_y;
5190
5191   mv_resize->moveresize_window = g_object_ref (window);
5192
5193   calculate_unmoving_origin (mv_resize);
5194
5195   create_moveresize_window (mv_resize, timestamp);
5196 }
5197
5198 /**
5199  * gdk_window_begin_resize_drag:
5200  * @window: a toplevel #GdkWindow
5201  * @edge: the edge or corner from which the drag is started
5202  * @button: the button being used to drag
5203  * @root_x: root window X coordinate of mouse click that began the drag
5204  * @root_y: root window Y coordinate of mouse click that began the drag
5205  * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
5206  *
5207  * Begins a window resize operation (for a toplevel window).
5208  * You might use this function to implement a "window resize grip," for
5209  * example; in fact #GtkStatusbar uses it. The function works best
5210  * with window managers that support the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended Window Manager Hints</ulink>, but has a 
5211  * fallback implementation for other window managers.
5212  * 
5213  **/
5214 void
5215 gdk_window_begin_resize_drag (GdkWindow     *window,
5216                               GdkWindowEdge  edge,
5217                               gint           button,
5218                               gint           root_x,
5219                               gint           root_y,
5220                               guint32        timestamp)
5221 {
5222   if (GDK_WINDOW_DESTROYED (window) ||
5223       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
5224     return;
5225
5226   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
5227                                            gdk_atom_intern_static_string ("_NET_WM_MOVERESIZE")))
5228     wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp);
5229   else
5230     emulate_resize_drag (window, edge, button, root_x, root_y, timestamp);
5231 }
5232
5233 /**
5234  * gdk_window_begin_move_drag:
5235  * @window: a toplevel #GdkWindow
5236  * @button: the button being used to drag
5237  * @root_x: root window X coordinate of mouse click that began the drag
5238  * @root_y: root window Y coordinate of mouse click that began the drag
5239  * @timestamp: timestamp of mouse click that began the drag
5240  *
5241  * Begins a window move operation (for a toplevel window).  You might
5242  * use this function to implement a "window move grip," for
5243  * example. The function works best with window managers that support
5244  * the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended 
5245  * Window Manager Hints</ulink>, but has a fallback implementation for
5246  * other window managers.
5247  * 
5248  **/
5249 void
5250 gdk_window_begin_move_drag (GdkWindow *window,
5251                             gint       button,
5252                             gint       root_x,
5253                             gint       root_y,
5254                             guint32    timestamp)
5255 {
5256   if (GDK_WINDOW_DESTROYED (window) ||
5257       !WINDOW_IS_TOPLEVEL (window))
5258     return;
5259
5260   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
5261                                            gdk_atom_intern_static_string ("_NET_WM_MOVERESIZE")))
5262     wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE, root_x, root_y,
5263                        timestamp);
5264   else
5265     emulate_move_drag (window, button, root_x, root_y, timestamp);
5266 }
5267
5268 /**
5269  * gdk_window_enable_synchronized_configure:
5270  * @window: a toplevel #GdkWindow
5271  * 
5272  * Indicates that the application will cooperate with the window
5273  * system in synchronizing the window repaint with the window
5274  * manager during resizing operations. After an application calls
5275  * this function, it must call gdk_window_configure_finished() every
5276  * time it has finished all processing associated with a set of
5277  * Configure events. Toplevel GTK+ windows automatically use this
5278  * protocol.
5279  * 
5280  * On X, calling this function makes @window participate in the
5281  * _NET_WM_SYNC_REQUEST window manager protocol.
5282  * 
5283  * Since: 2.6
5284  **/
5285 void
5286 gdk_window_enable_synchronized_configure (GdkWindow *window)
5287 {
5288   GdkWindowImplX11 *impl;
5289
5290   if (!GDK_IS_WINDOW_IMPL_X11 (window->impl))
5291     return;
5292   
5293   impl = GDK_WINDOW_IMPL_X11 (window->impl);
5294           
5295   if (!impl->use_synchronized_configure)
5296     {
5297       /* This basically means you want to do fancy X specific stuff, so
5298          ensure we have a native window */
5299       gdk_window_ensure_native (window);
5300
5301       impl->use_synchronized_configure = TRUE;
5302       ensure_sync_counter (window);
5303     }
5304 }
5305
5306 /**
5307  * gdk_window_configure_finished:
5308  * @window: a toplevel #GdkWindow
5309  * 
5310  * Signal to the window system that the application has finished
5311  * handling Configure events it has received. Window Managers can
5312  * use this to better synchronize the frame repaint with the
5313  * application. GTK+ applications will automatically call this
5314  * function when appropriate.
5315  *
5316  * This function can only be called if gdk_window_enable_synchronized_configure()
5317  * was called previously.
5318  *
5319  * Since: 2.6
5320  **/
5321 void
5322 gdk_window_configure_finished (GdkWindow *window)
5323 {
5324   GdkWindowImplX11 *impl;
5325
5326   if (!WINDOW_IS_TOPLEVEL (window))
5327     return;
5328   
5329   impl = GDK_WINDOW_IMPL_X11 (window->impl);
5330   if (!impl->use_synchronized_configure)
5331     return;
5332   
5333 #ifdef HAVE_XSYNC
5334   if (!GDK_WINDOW_DESTROYED (window))
5335     {
5336       GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
5337       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
5338
5339       if (toplevel && toplevel->update_counter != None &&
5340           GDK_DISPLAY_X11 (display)->use_sync &&
5341           !XSyncValueIsZero (toplevel->current_counter_value))
5342         {
5343           XSyncSetCounter (GDK_WINDOW_XDISPLAY (window), 
5344                            toplevel->update_counter,
5345                            toplevel->current_counter_value);
5346           
5347           XSyncIntToValue (&toplevel->current_counter_value, 0);
5348         }
5349     }
5350 #endif
5351 }
5352
5353 static gboolean
5354 gdk_x11_window_beep (GdkWindow *window)
5355 {
5356   GdkDisplay *display;
5357
5358   display = GDK_WINDOW_DISPLAY (window);
5359
5360 #ifdef HAVE_XKB
5361   if (GDK_DISPLAY_X11 (display)->use_xkb)
5362     {
5363       XkbBell (GDK_DISPLAY_XDISPLAY (display),
5364                GDK_WINDOW_XID (window),
5365                0,
5366                None);
5367       return TRUE;
5368     }
5369 #endif
5370
5371   return FALSE;
5372 }
5373
5374 /**
5375  * gdk_window_set_opacity:
5376  * @window: a top-level #GdkWindow
5377  * @opacity: opacity
5378  *
5379  * Request the windowing system to make @window partially transparent,
5380  * with opacity 0 being fully transparent and 1 fully opaque. (Values
5381  * of the opacity parameter are clamped to the [0,1] range.) 
5382  *
5383  * On X11, this works only on X screens with a compositing manager 
5384  * running.
5385  *
5386  * For setting up per-pixel alpha, see gdk_screen_get_rgba_visual().
5387  * For making non-toplevel windows translucent, see 
5388  * gdk_window_set_composited().
5389  *
5390  * Since: 2.12
5391  */
5392 void
5393 gdk_window_set_opacity (GdkWindow *window,
5394                         gdouble    opacity)
5395 {
5396   GdkDisplay *display;
5397   guint32 cardinal;
5398   
5399   g_return_if_fail (GDK_IS_WINDOW (window));
5400
5401   if (GDK_WINDOW_DESTROYED (window) ||
5402       !WINDOW_IS_TOPLEVEL (window))
5403     return;
5404
5405   display = gdk_window_get_display (window);
5406
5407   if (opacity < 0)
5408     opacity = 0;
5409   else if (opacity > 1)
5410     opacity = 1;
5411
5412   cardinal = opacity * 0xffffffff;
5413
5414   if (cardinal == 0xffffffff)
5415     XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
5416                      GDK_WINDOW_XID (window),
5417                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"));
5418   else
5419     XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
5420                      GDK_WINDOW_XID (window),
5421                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"),
5422                      XA_CARDINAL, 32,
5423                      PropModeReplace,
5424                      (guchar *) &cardinal, 1);
5425 }
5426
5427 void
5428 _gdk_windowing_window_set_composited (GdkWindow *window,
5429                                       gboolean   composited)
5430 {
5431 #if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
5432   GdkWindowImplX11 *impl;
5433   GdkDisplay *display;
5434   Display *dpy;
5435   Window xid;
5436
5437   impl = GDK_WINDOW_IMPL_X11 (window->impl);
5438
5439   display = gdk_window_get_display (window);
5440   dpy = GDK_DISPLAY_XDISPLAY (display);
5441   xid = GDK_WINDOW_XID (window);
5442
5443   if (composited)
5444     {
5445       XCompositeRedirectWindow (dpy, xid, CompositeRedirectManual);
5446       impl->damage = XDamageCreate (dpy, xid, XDamageReportBoundingBox);
5447     }
5448   else
5449     {
5450       XCompositeUnredirectWindow (dpy, xid, CompositeRedirectManual);
5451       XDamageDestroy (dpy, impl->damage);
5452       impl->damage = None;
5453     }
5454 #endif
5455 }
5456
5457 void
5458 _gdk_windowing_window_process_updates_recurse (GdkWindow *window,
5459                                                cairo_region_t *region)
5460 {
5461   _gdk_window_process_updates_recurse (window, region);
5462 }
5463
5464 void
5465 _gdk_windowing_before_process_all_updates (void)
5466 {
5467 }
5468
5469 void
5470 _gdk_windowing_after_process_all_updates (void)
5471 {
5472 }
5473
5474 static Bool
5475 timestamp_predicate (Display *display,
5476                      XEvent  *xevent,
5477                      XPointer arg)
5478 {
5479   Window xwindow = GPOINTER_TO_UINT (arg);
5480   GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
5481
5482   if (xevent->type == PropertyNotify &&
5483       xevent->xproperty.window == xwindow &&
5484       xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
5485                                                                        "GDK_TIMESTAMP_PROP"))
5486     return True;
5487
5488   return False;
5489 }
5490
5491 /**
5492  * gdk_x11_get_server_time:
5493  * @window: a #GdkWindow, used for communication with the server.
5494  *          The window must have GDK_PROPERTY_CHANGE_MASK in its
5495  *          events mask or a hang will result.
5496  *
5497  * Routine to get the current X server time stamp.
5498  *
5499  * Return value: the time stamp.
5500  **/
5501 guint32
5502 gdk_x11_get_server_time (GdkWindow *window)
5503 {
5504   Display *xdisplay;
5505   Window   xwindow;
5506   guchar c = 'a';
5507   XEvent xevent;
5508   Atom timestamp_prop_atom;
5509
5510   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
5511   g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
5512
5513   xdisplay = GDK_WINDOW_XDISPLAY (window);
5514   xwindow = GDK_WINDOW_XID (window);
5515   timestamp_prop_atom =
5516     gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
5517                                            "GDK_TIMESTAMP_PROP");
5518
5519   XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
5520                    timestamp_prop_atom,
5521                    8, PropModeReplace, &c, 1);
5522
5523   XIfEvent (xdisplay, &xevent,
5524             timestamp_predicate, GUINT_TO_POINTER(xwindow));
5525
5526   return xevent.xproperty.time;
5527 }
5528
5529 /**
5530  * gdk_x11_window_get_xid:
5531  * @window: a native #GdkWindow.
5532  * 
5533  * Returns the X resource (window) belonging to a #GdkWindow.
5534  * 
5535  * Return value: the ID of @drawable's X resource.
5536  **/
5537 XID
5538 gdk_x11_window_get_xid (GdkWindow *window)
5539 {
5540   /* Try to ensure the window has a native window */
5541   if (!_gdk_window_has_impl (window))
5542     {
5543       gdk_window_ensure_native (window);
5544
5545       /* We sync here to ensure the window is created in the Xserver when
5546        * this function returns. This is required because the returned XID
5547        * for this window must be valid immediately, even with another
5548        * connection to the Xserver */
5549       gdk_display_sync (gdk_window_get_display (window));
5550     }
5551   
5552   if (!GDK_WINDOW_IS_X11 (window))
5553     {
5554       g_warning (G_STRLOC " drawable is not a native X11 window");
5555       return None;
5556     }
5557   
5558   return GDK_WINDOW_IMPL_X11 (window->impl)->xid;
5559 }
5560
5561 static void
5562 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
5563 {
5564   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5565   GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
5566   
5567   object_class->finalize = gdk_window_impl_x11_finalize;
5568   
5569   impl_class->ref_cairo_surface = gdk_x11_ref_cairo_surface;
5570   impl_class->show = gdk_window_x11_show;
5571   impl_class->hide = gdk_window_x11_hide;
5572   impl_class->withdraw = gdk_window_x11_withdraw;
5573   impl_class->set_events = gdk_window_x11_set_events;
5574   impl_class->get_events = gdk_window_x11_get_events;
5575   impl_class->raise = gdk_window_x11_raise;
5576   impl_class->lower = gdk_window_x11_lower;
5577   impl_class->restack_under = gdk_window_x11_restack_under;
5578   impl_class->restack_toplevel = gdk_window_x11_restack_toplevel;
5579   impl_class->move_resize = gdk_window_x11_move_resize;
5580   impl_class->set_background = gdk_window_x11_set_background;
5581   impl_class->reparent = gdk_window_x11_reparent;
5582   impl_class->set_device_cursor = gdk_window_x11_set_device_cursor;
5583   impl_class->get_geometry = gdk_window_x11_get_geometry;
5584   impl_class->get_root_coords = gdk_window_x11_get_root_coords;
5585   impl_class->get_device_state = gdk_window_x11_get_device_state;
5586   impl_class->shape_combine_region = gdk_window_x11_shape_combine_region;
5587   impl_class->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
5588   impl_class->set_static_gravities = gdk_window_x11_set_static_gravities;
5589   impl_class->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
5590   impl_class->translate = _gdk_x11_window_translate;
5591   impl_class->destroy = _gdk_x11_window_destroy;
5592   impl_class->resize_cairo_surface = gdk_window_x11_resize_cairo_surface;
5593   impl_class->get_shape = gdk_x11_window_get_shape;
5594   impl_class->get_input_shape = gdk_x11_window_get_input_shape;
5595   impl_class->beep = gdk_x11_window_beep;
5596 }
5597