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