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