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