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