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