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