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