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