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