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