]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkwindow-x11.c
Start of integration of Erwann Chenede's multihead work from the
[~andy/gtk] / gdk / x11 / gdkwindow-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <netinet/in.h>
31 #include <unistd.h>
32 #include "gdk.h"
33 #include "config.h"
34
35 #include "gdkwindow.h"
36 #include "gdkinputprivate.h"
37 #include "gdkdisplay-x11.h"
38 #include "gdkprivate-x11.h"
39 #include "gdkregion.h"
40 #include "gdkinternals.h"
41 #include "MwmUtil.h"
42 #include "gdkwindow-x11.h"
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47
48
49 #ifdef HAVE_SHAPE_EXT
50 #include <X11/extensions/shape.h>
51 #endif
52
53 const int _gdk_event_mask_table[21] =
54 {
55   ExposureMask,
56   PointerMotionMask,
57   PointerMotionHintMask,
58   ButtonMotionMask,
59   Button1MotionMask,
60   Button2MotionMask,
61   Button3MotionMask,
62   ButtonPressMask,
63   ButtonReleaseMask,
64   KeyPressMask,
65   KeyReleaseMask,
66   EnterWindowMask,
67   LeaveWindowMask,
68   FocusChangeMask,
69   StructureNotifyMask,
70   PropertyChangeMask,
71   VisibilityChangeMask,
72   0,                            /* PROXIMITY_IN */
73   0,                            /* PROXIMTY_OUT */
74   SubstructureNotifyMask,
75   ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
76 };
77 const int _gdk_nenvent_masks = sizeof (_gdk_event_mask_table) / sizeof (int);
78
79 /* Forward declarations */
80 static gboolean gdk_window_gravity_works          (GdkWindow  *window);
81 static void     gdk_window_set_static_win_gravity (GdkWindow  *window,
82                                                    gboolean    on);
83 static gboolean gdk_window_have_shape_ext         (GdkDisplay *display);
84 static gboolean gdk_window_icon_name_set          (GdkWindow  *window);
85
86 static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable);
87 static void         gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
88                                                       GdkColormap *cmap);
89 static void         gdk_window_impl_x11_get_size    (GdkDrawable *drawable,
90                                                      gint *width,
91                                                      gint *height);
92 static GdkRegion*  gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable);
93 static void gdk_window_impl_x11_init       (GdkWindowImplX11      *window);
94 static void gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass);
95 static void gdk_window_impl_x11_finalize   (GObject            *object);
96
97 static gpointer parent_class = NULL;
98
99 GType
100 gdk_window_impl_x11_get_type (void)
101 {
102   static GType object_type = 0;
103
104   if (!object_type)
105     {
106       static const GTypeInfo object_info =
107       {
108         sizeof (GdkWindowImplX11Class),
109         (GBaseInitFunc) NULL,
110         (GBaseFinalizeFunc) NULL,
111         (GClassInitFunc) gdk_window_impl_x11_class_init,
112         NULL,           /* class_finalize */
113         NULL,           /* class_data */
114         sizeof (GdkWindowImplX11),
115         0,              /* n_preallocs */
116         (GInstanceInitFunc) gdk_window_impl_x11_init,
117       };
118       
119       object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_X11,
120                                             "GdkWindowImplX11",
121                                             &object_info, 0);
122     }
123   
124   return object_type;
125 }
126
127 GType
128 _gdk_window_impl_get_type (void)
129 {
130   return gdk_window_impl_x11_get_type ();
131 }
132
133 static void
134 gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
135 {
136   impl->width = 1;
137   impl->height = 1;
138 }
139
140 static void
141 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
142 {
143   GObjectClass *object_class = G_OBJECT_CLASS (klass);
144   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
145   
146   parent_class = g_type_class_peek_parent (klass);
147
148   object_class->finalize = gdk_window_impl_x11_finalize;
149
150   drawable_class->set_colormap = gdk_window_impl_x11_set_colormap;
151   drawable_class->get_colormap = gdk_window_impl_x11_get_colormap;
152   drawable_class->get_size = gdk_window_impl_x11_get_size;
153
154   /* Visible and clip regions are the same */
155   drawable_class->get_clip_region = gdk_window_impl_x11_get_visible_region;
156   drawable_class->get_visible_region = gdk_window_impl_x11_get_visible_region;
157 }
158
159 static void
160 gdk_window_impl_x11_finalize (GObject *object)
161 {
162   GdkWindowObject *wrapper;
163   GdkDrawableImplX11 *draw_impl;
164   GdkWindowImplX11 *window_impl;
165   
166   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));
167
168   draw_impl = GDK_DRAWABLE_IMPL_X11 (object);
169   window_impl = GDK_WINDOW_IMPL_X11 (object);
170   
171   wrapper = (GdkWindowObject*) draw_impl->wrapper;
172
173   _gdk_xgrab_check_destroy (GDK_WINDOW (wrapper));
174
175   if (!GDK_WINDOW_DESTROYED (wrapper))
176     {
177       _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (object), draw_impl->xid);
178       if (window_impl->focus_window)
179         _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (object), window_impl->focus_window);
180     }
181
182   G_OBJECT_CLASS (parent_class)->finalize (object);
183 }
184
185 static GdkColormap*
186 gdk_window_impl_x11_get_colormap (GdkDrawable *drawable)
187 {
188   GdkDrawableImplX11 *drawable_impl;
189   GdkWindowImplX11 *window_impl;
190   
191   g_return_val_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable), NULL);
192
193   drawable_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
194   window_impl = GDK_WINDOW_IMPL_X11 (drawable);
195
196   if (!((GdkWindowObject *) drawable_impl->wrapper)->input_only && 
197       drawable_impl->colormap == NULL)
198     {
199       XWindowAttributes window_attributes;
200
201       XGetWindowAttributes (GDK_SCREEN_XDISPLAY (drawable_impl->screen),
202                             drawable_impl->xid,
203                             &window_attributes);
204       drawable_impl->colormap =
205         gdk_colormap_lookup (window_attributes.colormap);
206     }
207   
208   return drawable_impl->colormap;
209 }
210
211 static void
212 gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
213                                   GdkColormap *cmap)
214 {
215   GdkWindowImplX11 *impl;
216   GdkDrawableImplX11 *draw_impl;
217   
218   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
219
220   impl = GDK_WINDOW_IMPL_X11 (drawable);
221   draw_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
222
223   /* chain up */
224   GDK_DRAWABLE_CLASS (parent_class)->set_colormap (drawable, cmap);
225
226   if (cmap)
227     {
228       XSetWindowColormap (GDK_SCREEN_XDISPLAY (draw_impl->screen),
229                           draw_impl->xid,
230                           GDK_COLORMAP_XCOLORMAP (cmap));
231
232       if (((GdkWindowObject*)draw_impl->wrapper)->window_type !=
233           GDK_WINDOW_TOPLEVEL)
234         gdk_window_add_colormap_windows (GDK_WINDOW (draw_impl->wrapper));
235     }
236 }
237
238
239 static void
240 gdk_window_impl_x11_get_size (GdkDrawable *drawable,
241                               gint        *width,
242                               gint        *height)
243 {
244   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
245
246   if (width)
247     *width = GDK_WINDOW_IMPL_X11 (drawable)->width;
248   if (height)
249     *height = GDK_WINDOW_IMPL_X11 (drawable)->height;
250 }
251
252 static GdkRegion*
253 gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable)
254 {
255   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (drawable);
256   GdkRectangle result_rect;
257
258   result_rect.x = 0;
259   result_rect.y = 0;
260   result_rect.width = impl->width;
261   result_rect.height = impl->height;
262
263   gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect);
264
265   return gdk_region_rectangle (&result_rect);
266 }
267
268 void
269 _gdk_windowing_window_init (GdkScreen * screen)
270 {
271   GdkWindowObject *private;
272   GdkWindowImplX11 *impl;
273   GdkDrawableImplX11 *draw_impl;
274   GdkScreenX11 *screen_x11;
275   XWindowAttributes xattributes;
276   unsigned int width;
277   unsigned int height;
278   unsigned int border_width;
279   unsigned int depth;
280   int x, y;
281
282   screen_x11 = GDK_SCREEN_X11 (screen);
283
284   g_assert (screen_x11->root_window == NULL);
285
286   screen_x11->default_colormap = gdk_screen_get_system_colormap (screen);
287
288   XGetGeometry (screen_x11->xdisplay, screen_x11->xroot_window,
289                 &screen_x11->xroot_window, &x, &y, &width, &height, &border_width, &depth);
290   XGetWindowAttributes (screen_x11->xdisplay, screen_x11->xroot_window, &xattributes);
291
292   screen_x11->root_window = g_object_new (GDK_TYPE_WINDOW, NULL);
293   private = (GdkWindowObject *)screen_x11->root_window;
294   impl = GDK_WINDOW_IMPL_X11 (private->impl);
295   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
296   
297   draw_impl->screen = screen;
298   draw_impl->xid = screen_x11->xroot_window;
299   draw_impl->wrapper = GDK_DRAWABLE (private);
300   
301   private->window_type = GDK_WINDOW_ROOT;
302   private->depth = depth;
303   impl->width = width;
304   impl->height = height;
305   screen_x11->colormap_initialised = TRUE;
306   
307   _gdk_xid_table_insert (screen_x11->display,
308                          &screen_x11->xroot_window,
309                          screen_x11->root_window);
310 }
311
312 static void
313 set_wm_protocols (GdkWindow *window)
314 {
315   GdkDisplay *display = gdk_drawable_get_display (window);
316   Atom protocols[3];
317   
318   protocols[0] = gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW");
319   protocols[1] = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
320   protocols[2] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING");
321
322   XSetWMProtocols (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), protocols, 3);
323 }
324
325 /**
326  * gdk_window_new:
327  * @parent: a #GdkWindow, or %NULL to create the window as a child of
328  *   the default root window for the default display.
329  * @attributes: attributes of the new window
330  * @attributes_mask: mask indicating which fields in @attributes are valid
331  * 
332  * Creates a new #GdkWindow using the attributes from
333  * @attributes. Seep #GdkWindowAttr and #GdkWindowAttributesType for
334  * more details.  Note: to use this on displays other than the default
335  * display, @parent must be specified.
336  * 
337  * Return value: the new #GdkWindow
338  **/
339 GdkWindow*
340 gdk_window_new (GdkWindow     *parent,
341                 GdkWindowAttr *attributes,
342                 gint           attributes_mask)
343 {
344   GdkWindow *window;
345   GdkWindowObject *private;
346   GdkWindowImplX11 *impl;
347   GdkDrawableImplX11 *draw_impl;
348   GdkScreenX11 *screen_x11;
349   GdkScreen *screen;
350   
351   GdkVisual *visual;
352   Window xparent;
353   Visual *xvisual;
354   Display *xdisplay;
355   Window xid;
356
357   XSetWindowAttributes xattributes;
358   long xattributes_mask;
359   XSizeHints size_hints;
360   XWMHints wm_hints;
361   XClassHint *class_hint;
362   int x, y, depth;
363   
364   unsigned int class;
365   char *title;
366   int i;
367   long pid;
368   
369   g_return_val_if_fail (attributes != NULL, NULL);
370   
371   if (!parent)
372     {
373       GDK_NOTE (MULTIHEAD,
374                 g_warning ("gdk_window_new(): no parent specified reverting to parent = default root window"));
375       
376       screen = gdk_get_default_screen ();
377       parent = gdk_screen_get_root_window (screen);
378     }
379   else
380     screen = gdk_drawable_get_screen (parent);
381
382   screen_x11 = GDK_SCREEN_X11 (screen);
383
384   g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
385   
386   if (GDK_WINDOW_DESTROYED (parent))
387     return NULL;
388   
389   xparent = GDK_WINDOW_XID (parent);
390   
391   window = g_object_new (GDK_TYPE_WINDOW, NULL);
392   private = (GdkWindowObject *)window;
393   impl = GDK_WINDOW_IMPL_X11 (private->impl);
394   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
395   draw_impl->wrapper = GDK_DRAWABLE (window);
396   
397   draw_impl->screen = screen;
398   xdisplay = screen_x11->xdisplay;
399
400   /* Windows with a foreign parent are treated as if they are children
401    * of the root window, except for actual creation.
402    */
403   if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
404     parent = gdk_screen_get_root_window (screen);
405   
406   private->parent = (GdkWindowObject *)parent;
407
408   xattributes_mask = 0;
409   
410   if (attributes_mask & GDK_WA_X)
411     x = attributes->x;
412   else
413     x = 0;
414   
415   if (attributes_mask & GDK_WA_Y)
416     y = attributes->y;
417   else
418     y = 0;
419   
420   private->x = x;
421   private->y = y;
422   impl->width = (attributes->width > 1) ? (attributes->width) : (1);
423   impl->height = (attributes->height > 1) ? (attributes->height) : (1);
424
425   if (attributes->wclass == GDK_INPUT_ONLY)
426     {
427       /* Backwards compatiblity - we've always ignored
428        * attributes->window_type for input-only windows
429        * before
430        */
431       if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT)
432         private->window_type = GDK_WINDOW_TEMP;
433       else
434         private->window_type = GDK_WINDOW_CHILD;
435     }
436   else
437     private->window_type = attributes->window_type;
438
439   _gdk_window_init_position (GDK_WINDOW (private));
440   if (impl->position_info.big)
441     private->guffaw_gravity = TRUE;
442   
443   if (attributes_mask & GDK_WA_VISUAL)
444     visual = attributes->visual;
445   else
446     visual = gdk_screen_get_system_visual (screen);
447   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
448   
449   xattributes.event_mask = StructureNotifyMask;
450   for (i = 0; i < _gdk_nenvent_masks; i++)
451     {
452       if (attributes->event_mask & (1 << (i + 1)))
453         xattributes.event_mask |= _gdk_event_mask_table[i];
454     }
455   private->event_mask = attributes->event_mask;
456   
457   if (xattributes.event_mask)
458     xattributes_mask |= CWEventMask;
459   
460   if (attributes_mask & GDK_WA_NOREDIR)
461     {
462       xattributes.override_redirect =
463         (attributes->override_redirect == FALSE)?False:True;
464       xattributes_mask |= CWOverrideRedirect;
465     } 
466   else
467     xattributes.override_redirect = False;
468
469   if (private->parent && private->parent->guffaw_gravity)
470     {
471       xattributes.win_gravity = StaticGravity;
472       xattributes_mask |= CWWinGravity;
473     }
474   
475   /* Sanity checks */
476   switch (private->window_type)
477     {
478     case GDK_WINDOW_TOPLEVEL:
479     case GDK_WINDOW_DIALOG:
480     case GDK_WINDOW_TEMP:
481       if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT)
482         {
483           g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
484                      "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
485           xparent = GDK_SCREEN_XROOTWIN (screen);
486         }
487     case GDK_WINDOW_CHILD:
488       break;
489     default:
490       g_warning (G_STRLOC "cannot make windows of type %d", private->window_type);
491       return NULL;
492     }
493           
494   if (attributes->wclass == GDK_INPUT_OUTPUT)
495     {
496       class = InputOutput;
497       depth = visual->depth;
498
499       private->input_only = FALSE;
500       private->depth = depth;
501       
502       if (attributes_mask & GDK_WA_COLORMAP)
503         {
504           draw_impl->colormap = attributes->colormap;
505           gdk_colormap_ref (attributes->colormap);
506         }
507       else
508         {
509           if ((((GdkVisualPrivate *)gdk_screen_get_system_visual (screen))->xvisual) ==  xvisual)
510             {
511               draw_impl->colormap = gdk_screen_get_system_colormap (screen);
512               gdk_colormap_ref (draw_impl->colormap);
513             }
514           else
515             {
516               draw_impl->colormap = gdk_colormap_new (visual, FALSE);
517             }
518         }
519       
520       private->bg_color.pixel = BlackPixel (xdisplay, screen_x11->screen_num);
521       xattributes.background_pixel = private->bg_color.pixel;
522
523       private->bg_pixmap = NULL;
524       
525       xattributes.border_pixel = BlackPixel (xdisplay, screen_x11->screen_num);
526       xattributes_mask |= CWBorderPixel | CWBackPixel;
527
528       if (private->guffaw_gravity)
529         xattributes.bit_gravity = StaticGravity;
530       else
531         xattributes.bit_gravity = NorthWestGravity;
532       
533       xattributes_mask |= CWBitGravity;
534
535       xattributes.colormap = GDK_COLORMAP_XCOLORMAP (draw_impl->colormap);
536       xattributes_mask |= CWColormap;
537
538       if (private->window_type == GDK_WINDOW_TEMP)
539         {
540           xattributes.save_under = True;
541           xattributes.override_redirect = True;
542           xattributes.cursor = None;
543           xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
544         }
545     }
546   else
547     {
548       depth = 0;
549       private->depth = 0;
550       class = InputOnly;
551       private->input_only = TRUE;
552       draw_impl->colormap = gdk_screen_get_system_colormap (screen);
553       gdk_colormap_ref (draw_impl->colormap);
554     }
555
556   xid = draw_impl->xid = XCreateWindow (xdisplay, xparent,
557                                         impl->position_info.x, impl->position_info.y,
558                                         impl->position_info.width, impl->position_info.height,
559                                         0, depth, class, xvisual,
560                                         xattributes_mask, &xattributes);
561
562   gdk_drawable_ref (window);
563   _gdk_xid_table_insert (screen_x11->display, &draw_impl->xid, window);
564   
565   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
566                                   (attributes->cursor) :
567                                   NULL));
568   
569   if (private->parent)
570     private->parent->children = g_list_prepend (private->parent->children, window);
571   
572   switch (GDK_WINDOW_TYPE (private))
573     {
574     case GDK_WINDOW_DIALOG:
575       XSetTransientForHint (xdisplay, xid, xparent);
576     case GDK_WINDOW_TOPLEVEL:
577     case GDK_WINDOW_TEMP:
578       set_wm_protocols (window);
579       break;
580     case GDK_WINDOW_CHILD:
581       if ((attributes->wclass == GDK_INPUT_OUTPUT) &&
582           (draw_impl->colormap != gdk_screen_get_system_colormap (screen)) &&
583           (draw_impl->colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window))))
584         {
585           GDK_NOTE (MISC, g_message ("adding colormap window\n"));
586           gdk_window_add_colormap_windows (window);
587         }
588       
589       return window;
590     default:
591       
592       return window;
593     }
594
595   if (class != InputOnly)
596     {
597       /* The focus window is off the visible area, and serves to receive key
598        * press events so they don't get sent to child windows.
599        */
600       impl->focus_window = XCreateSimpleWindow (xdisplay, xid,
601                                                 -1, -1, 1, 1, 0,
602                                                 xattributes.background_pixel,
603                                                 xattributes.background_pixel);
604       /* FIXME: probably better to actually track the requested event mask for the toplevel
605        */
606       XSelectInput (xdisplay, impl->focus_window,
607                     KeyPressMask | KeyReleaseMask | FocusChangeMask);
608       
609       XMapWindow (xdisplay, impl->focus_window);
610       _gdk_xid_table_insert (screen_x11->display, &impl->focus_window, window);
611     }
612
613   size_hints.flags = PSize;
614   size_hints.width = impl->width;
615   size_hints.height = impl->height;
616   
617   wm_hints.flags = StateHint | WindowGroupHint;
618   wm_hints.window_group = GDK_DISPLAY_X11 (screen_x11->display)->leader_window;
619   wm_hints.input = True;
620   wm_hints.initial_state = NormalState;
621   
622   /* FIXME: Is there any point in doing this? Do any WM's pay
623    * attention to PSize, and even if they do, is this the
624    * correct value???
625    */
626   XSetWMNormalHints (xdisplay, xid, &size_hints);
627   
628   XSetWMHints (xdisplay, xid, &wm_hints);
629   
630   /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
631   XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
632
633   pid = getpid ();
634   XChangeProperty (xdisplay, xid,
635                    gdk_x11_get_xatom_by_name_for_display (screen_x11->display, "_NET_WM_PID"),
636                    XA_CARDINAL, 32,
637                    PropModeReplace,
638                    (guchar *)&pid, 1);
639   
640   XChangeProperty (xdisplay, xid, 
641                    gdk_x11_get_xatom_by_name_for_display (screen_x11->display, "WM_CLIENT_LEADER"),
642                    XA_WINDOW, 32, PropModeReplace,
643                    (guchar *) &GDK_DISPLAY_X11 (screen_x11->display)->leader_window, 1);
644   
645   if (attributes_mask & GDK_WA_TITLE)
646     title = attributes->title;
647   else
648     title = g_get_prgname ();
649
650   gdk_window_set_title (window, title);
651   
652   if (attributes_mask & GDK_WA_WMCLASS)
653     {
654       class_hint = XAllocClassHint ();
655       class_hint->res_name = attributes->wmclass_name;
656       class_hint->res_class = attributes->wmclass_class;
657       XSetClassHint (xdisplay, xid, class_hint);
658       XFree (class_hint);
659     }
660   
661   return window;
662 }
663
664 static GdkEventMask
665 x_event_mask_to_gdk_event_mask (long mask)
666 {
667   GdkEventMask event_mask = 0;
668   int i;
669
670   for (i = 0; i < _gdk_nenvent_masks; i++)
671     {
672       if (mask & _gdk_event_mask_table[i])
673         event_mask |= 1 << (i + 1);
674     }
675
676   return event_mask;
677 }
678
679 /**
680  * gdk_window_foreign_new_for_display:
681  * @display: the #GdkDisplay where the window handle comes from.
682  * @anid: a native window handle.
683  * 
684  * Wraps a native window in a #GdkWindow.
685  * This may fail if the window has been destroyed.
686  *
687  * For example in the X backend, a native window handle is an Xlib
688  * <type>XID</type>.
689  * 
690  * Return value: the newly-created #GdkWindow wrapper for the 
691  *    native window or %NULL if the window has been destroyed.
692  **/
693 GdkWindow *
694 gdk_window_foreign_new_for_display (GdkDisplay     *display,
695                                     GdkNativeWindow anid)
696 {
697   GdkWindow *window;
698   GdkWindowObject *private;
699   GdkWindowImplX11 *impl;
700   GdkDrawableImplX11 *draw_impl;
701   GdkDisplayX11 *display_x11;
702   XWindowAttributes attrs;
703   Window root, parent;
704   Window *children = NULL;
705   guint nchildren;
706   gboolean result;
707
708   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
709
710   display_x11 = GDK_DISPLAY_X11 (display);
711   
712   gdk_error_trap_push ();
713   result = XGetWindowAttributes (display_x11->xdisplay, anid, &attrs);
714   if (gdk_error_trap_pop () || !result)
715     return NULL;
716
717   /* FIXME: This is pretty expensive. Maybe the caller should supply
718    *        the parent */
719   gdk_error_trap_push ();
720   result = XQueryTree (display_x11->xdisplay, anid, &root, &parent, &children, &nchildren);
721   if (gdk_error_trap_pop () || !result)
722     return NULL;
723
724   if (children)
725     XFree (children);
726   
727   window = g_object_new (GDK_TYPE_WINDOW, NULL);
728   private = (GdkWindowObject *)window;
729   impl = GDK_WINDOW_IMPL_X11 (private->impl);
730   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
731   draw_impl->wrapper = GDK_DRAWABLE (window);
732   draw_impl->screen = _gdk_x11_display_screen_for_xrootwin (display, root);
733   
734   private->parent = gdk_xid_table_lookup_for_display (display, parent);
735   
736   if (!private->parent || GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_FOREIGN)
737     private->parent = (GdkWindowObject *) gdk_screen_get_root_window (draw_impl->screen);
738   
739   private->parent->children = g_list_prepend (private->parent->children, window);
740
741   draw_impl->xid = anid;
742
743   private->x = attrs.x;
744   private->y = attrs.y;
745   impl->width = attrs.width;
746   impl->height = attrs.height;
747   private->window_type = GDK_WINDOW_FOREIGN;
748   private->destroyed = FALSE;
749
750   private->event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
751
752   if (attrs.map_state == IsUnmapped)
753     private->state = GDK_WINDOW_STATE_WITHDRAWN;
754   else
755     private->state = 0;
756
757   private->depth = attrs.depth;
758   
759   _gdk_window_init_position (GDK_WINDOW (private));
760
761   gdk_drawable_ref (window);
762   _gdk_xid_table_insert (display, &GDK_WINDOW_XID (window), window);
763   return window;
764 }
765
766 /**
767  * gdk_window_foreign_new:
768  * @anid: a native window handle.
769  * 
770  * Wraps a native window for the default display in a #GdkWindow.
771  * This may fail if the window has been destroyed.
772  *
773  * For example in the X backend, a native window handle is an Xlib
774  * <type>XID</type>.
775  * 
776  * Return value: the newly-created #GdkWindow wrapper for the 
777  *    native window or %NULL if the window has been destroyed.
778  **/
779 GdkWindow *
780 gdk_window_foreign_new (GdkNativeWindow anid)
781 {
782   return gdk_window_foreign_new_for_display (gdk_get_default_display (), anid);
783 }
784
785 /**
786  * gdk_window_lookup_for_display:
787  * @display: the #GdkDisplay corresponding to the window handle
788  * @anid: a native window handle.
789  *
790  * Looks up the #GdkWindow that wraps the given native window handle.
791  *
792  * For example in the X backend, a native window handle is an Xlib
793  * <type>XID</type>.
794  *
795  * Return value: the #GdkWindow wrapper for the native window, 
796  *    or %NULL if there is none.
797  **/
798 GdkWindow *
799 gdk_window_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid)
800 {
801   return (GdkWindow*) gdk_xid_table_lookup_for_display (display, anid);
802 }
803
804 /**
805  * gdk_window_lookup:
806  * @anid: a native window handle.
807  *
808  * Looks up the #GdkWindow that wraps the given native window handle. 
809  *
810  * For example in the X backend, a native window handle is an Xlib
811  * <type>XID</type>.
812  *
813  * Return value: the #GdkWindow wrapper for the native window, 
814  *    or %NULL if there is none.
815  **/
816 GdkWindow *
817 gdk_window_lookup (GdkNativeWindow anid)
818 {
819   return (GdkWindow*) gdk_xid_table_lookup (anid);
820 }
821
822 void
823 _gdk_windowing_window_destroy (GdkWindow *window,
824                                gboolean   recursing,
825                                gboolean   foreign_destroy)
826 {
827   GdkWindowObject *private = (GdkWindowObject *)window;
828
829   g_return_if_fail (GDK_IS_WINDOW (window));
830
831   _gdk_selection_window_destroyed (window);
832   
833   if (private->extension_events != 0)
834     gdk_input_window_destroy (window);
835
836 #ifdef HAVE_XFT  
837   {
838     GdkDrawableImplX11 *draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
839
840     if (draw_impl->picture)
841       XRenderFreePicture (GDK_WINDOW_XDISPLAY (window), draw_impl->picture);
842   }
843 #endif /* HAVE_XFT */  
844
845   if (private->window_type == GDK_WINDOW_FOREIGN)
846     {
847       if (!foreign_destroy && (private->parent != NULL))
848         {
849           /* It's somebody else's window, but in our heirarchy,
850            * so reparent it to the root window, and then send
851            * it a delete event, as if we were a WM
852            */
853           XClientMessageEvent xevent;
854           
855           gdk_error_trap_push ();
856           gdk_window_hide (window);
857           gdk_window_reparent (window, NULL, 0, 0);
858           
859           xevent.type = ClientMessage;
860           xevent.window = GDK_WINDOW_XID (window);
861           xevent.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
862                                                                        "WM_PROTOCOLS");
863           xevent.format = 32;
864           xevent.data.l[0] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
865                                                                     "WM_DELETE_WINDOW");
866           xevent.data.l[1] = CurrentTime;
867           
868           XSendEvent (GDK_WINDOW_XDISPLAY (window),
869                       GDK_WINDOW_XID (window),
870                       False, 0, (XEvent *)&xevent);
871           gdk_display_sync (GDK_WINDOW_DISPLAY (window));
872           gdk_error_trap_pop ();
873         }
874     }
875   else if (!recursing && !foreign_destroy)
876     {
877       XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
878     }
879 }
880
881 /* This function is called when the XWindow is really gone.
882  */
883 void
884 gdk_window_destroy_notify (GdkWindow *window)
885 {
886   GdkWindowImplX11 *window_impl;
887
888   g_return_if_fail (window != NULL);
889   
890   window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
891
892   if (!GDK_WINDOW_DESTROYED (window))
893     {
894       if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN)
895         g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_WINDOW_XID (window));
896
897       _gdk_window_destroy (window, TRUE);
898     }
899   
900   _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), GDK_WINDOW_XID (window));
901   if (window_impl->focus_window)
902     _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), window_impl->focus_window);
903
904   _gdk_xgrab_check_destroy (window);
905   
906   gdk_drawable_unref (window);
907 }
908
909 static void
910 set_initial_hints (GdkWindow *window)
911 {
912   GdkWindowObject *private;
913   Atom atoms[5];
914   gint i;
915   
916   private = (GdkWindowObject*) window;
917
918   if (private->state & GDK_WINDOW_STATE_ICONIFIED)
919     {
920       XWMHints *wm_hints;
921       
922       wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
923                               GDK_WINDOW_XID (window));
924       if (!wm_hints)
925         wm_hints = XAllocWMHints ();
926
927       wm_hints->flags |= StateHint;
928       wm_hints->initial_state = IconicState;
929       
930       XSetWMHints (GDK_WINDOW_XDISPLAY (window),
931                    GDK_WINDOW_XID (window), wm_hints);
932       XFree (wm_hints);
933     }
934
935   /* We set the spec hints regardless of whether the spec is supported,
936    * since it can't hurt and it's kind of expensive to check whether
937    * it's supported.
938    */
939   
940   i = 0;
941
942   if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
943     {
944       atoms[i] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
945                                                         "_NET_WM_STATE_MAXIMIZED_VERT");
946       ++i;
947       atoms[i] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
948                                                         "_NET_WM_STATE_MAXIMIZED_HORZ");
949       ++i;
950     }
951
952   if (private->state & GDK_WINDOW_STATE_STICKY)
953     {
954       atoms[i] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
955                                                         "_NET_WM_STATE_STICKY");
956       ++i;
957     }
958
959   if (private->modal_hint)
960     {
961       atoms[i] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
962                                                         "_NET_WM_STATE_MODAL");
963       ++i;
964     }
965
966   if (i > 0)
967     {
968       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
969                        GDK_WINDOW_XID (window),
970                        gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), "_NET_WM_STATE"),
971                        XA_ATOM, 32, PropModeReplace,
972                        (guchar*) atoms, i);
973     }
974
975   if (private->state & GDK_WINDOW_STATE_STICKY)
976     {
977       atoms[0] = 0xFFFFFFFF;
978       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
979                        GDK_WINDOW_XID (window),
980                        gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), "_NET_WM_DESKTOP"),
981                        XA_CARDINAL, 32, PropModeReplace,
982                        (guchar*) atoms, 1);
983     }
984 }
985
986 static void
987 show_window_internal (GdkWindow *window,
988                       gboolean   raise)
989 {
990   GdkWindowObject *private;
991   
992   g_return_if_fail (GDK_IS_WINDOW (window));
993   
994   private = (GdkWindowObject*) window;
995   if (!private->destroyed)
996     {
997       if (raise)
998         XRaiseWindow (GDK_WINDOW_XDISPLAY (window),
999                       GDK_WINDOW_XID (window));
1000
1001       if (!GDK_WINDOW_IS_MAPPED (window))
1002         {
1003           set_initial_hints (window);
1004           
1005           gdk_synthesize_window_state (window,
1006                                        GDK_WINDOW_STATE_WITHDRAWN,
1007                                        0);
1008         }
1009       
1010       g_assert (GDK_WINDOW_IS_MAPPED (window));
1011       
1012       if (GDK_WINDOW_IMPL_X11 (private->impl)->position_info.mapped)
1013         XMapWindow (GDK_WINDOW_XDISPLAY (window),
1014                     GDK_WINDOW_XID (window));
1015     }
1016 }
1017
1018 /**
1019  * gdk_window_show_unraised:
1020  * @window: a #GdkWindow
1021  *
1022  * Shows a #GdkWindow onscreen, but does not modify its stacking
1023  * order. In contrast, gdk_window_show() will raise the window
1024  * to the top of the window stack.
1025  *
1026  * On the X11 platform, in Xlib terms, this function calls
1027  * XMapWindow() (it also updates some internal GDK state, which means
1028  * that you can't really use XMapWindow() directly on a GDK window).
1029  * 
1030  **/
1031 void
1032 gdk_window_show_unraised (GdkWindow *window)
1033 {
1034   g_return_if_fail (GDK_IS_WINDOW (window));
1035   
1036   show_window_internal (window, FALSE);
1037 }
1038
1039 /**
1040  * gdk_window_show:
1041  * @window: a #GdkWindow
1042  *
1043  * Like gdk_window_show_unraised(), but also raises the window to the
1044  * top of the window stack (moves the window to the front of the
1045  * Z-order).
1046  *
1047  * This function maps a window so it's visible onscreen. Its opposite
1048  * is gdk_window_hide().
1049  *
1050  * When implementing a #GtkWidget, you should call this function on the widget's
1051  * #GdkWindow as part of the "map" method.
1052  * 
1053  **/
1054 void
1055 gdk_window_show (GdkWindow *window)
1056 {
1057   g_return_if_fail (GDK_IS_WINDOW (window));
1058
1059   show_window_internal (window, TRUE);
1060 }
1061
1062 /**
1063  * gdk_window_hide:
1064  * @window: a #GdkWindow
1065  *
1066  * For toplevel windows, withdraws them, so they will no longer be
1067  * known to the window manager; for all windows, unmaps them, so
1068  * they won't be displayed. Normally done automatically as
1069  * part of gtk_widget_hide().
1070  * 
1071  **/
1072 void
1073 gdk_window_hide (GdkWindow *window)
1074 {
1075   GdkWindowObject *private;
1076   
1077   g_return_if_fail (window != NULL);
1078
1079   private = (GdkWindowObject*) window;
1080
1081   /* We'll get the unmap notify eventually, and handle it then,
1082    * but checking here makes things more consistent if we are
1083    * just doing stuff ourself.
1084    */
1085   _gdk_xgrab_check_unmap (window,
1086                           NextRequest (GDK_WINDOW_XDISPLAY (window)));
1087
1088   /* You can't simply unmap toplevel windows. */
1089   switch (private->window_type)
1090     {
1091     case GDK_WINDOW_TOPLEVEL:
1092     case GDK_WINDOW_DIALOG:
1093     case GDK_WINDOW_TEMP: /* ? */
1094       gdk_window_withdraw (window);
1095       return;
1096       break;
1097       
1098     case GDK_WINDOW_FOREIGN:
1099     case GDK_WINDOW_ROOT:
1100     case GDK_WINDOW_CHILD:
1101       break;
1102     }
1103   
1104   if (!private->destroyed)
1105     {
1106       if (GDK_WINDOW_IS_MAPPED (window))
1107         gdk_synthesize_window_state (window,
1108                                      0,
1109                                      GDK_WINDOW_STATE_WITHDRAWN);
1110
1111       g_assert (!GDK_WINDOW_IS_MAPPED (window));
1112       
1113       _gdk_window_clear_update_area (window);
1114       
1115       XUnmapWindow (GDK_WINDOW_XDISPLAY (window),
1116                     GDK_WINDOW_XID (window));
1117     }
1118 }
1119
1120 /**
1121  * gdk_window_withdraw:
1122  * @window: a toplevel #GdkWindow
1123  * 
1124  * Withdraws a window (unmaps it and asks the window manager to forget about it).
1125  * Normally done automatically by gtk_widget_hide() called on a #GtkWindow.
1126  * 
1127  **/
1128 void
1129 gdk_window_withdraw (GdkWindow *window)
1130 {
1131   GdkWindowObject *private;
1132   
1133   g_return_if_fail (window != NULL);
1134   
1135   private = (GdkWindowObject*) window;
1136   if (!private->destroyed)
1137     {
1138       if (GDK_WINDOW_IS_MAPPED (window))
1139         gdk_synthesize_window_state (window,
1140                                      0,
1141                                      GDK_WINDOW_STATE_WITHDRAWN);
1142
1143       g_assert (!GDK_WINDOW_IS_MAPPED (window));
1144       
1145       XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
1146                        GDK_WINDOW_XID (window), 0);
1147     }
1148 }
1149
1150 /**
1151  * gdk_window_move:
1152  * @window: a #GdkWindow
1153  * @x: X coordinate relative to window's parent
1154  * @y: Y coordinate relative to window's parent
1155  *
1156  * Repositions a window relative to its parent window.
1157  * For toplevel windows, window managers may ignore or modify the move;
1158  * you should probably use gtk_window_move() on a #GtkWindow widget
1159  * anyway, instead of using GDK functions. For child windows,
1160  * the move will reliably succeed.
1161  *
1162  * If you're also planning to resize the window, use gdk_window_move_resize()
1163  * to both move and resize simultaneously, for a nicer visual effect.
1164  * 
1165  **/
1166 void
1167 gdk_window_move (GdkWindow *window,
1168                  gint       x,
1169                  gint       y)
1170 {
1171   GdkWindowObject *private = (GdkWindowObject *)window;
1172   GdkWindowImplX11 *impl;
1173
1174   g_return_if_fail (window != NULL);
1175   g_return_if_fail (GDK_IS_WINDOW (window));
1176
1177   impl = GDK_WINDOW_IMPL_X11 (private->impl);
1178
1179   if (!GDK_WINDOW_DESTROYED (window))
1180     {
1181       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1182         _gdk_window_move_resize_child (window, x, y,
1183                                        impl->width, impl->height);
1184       else
1185         {
1186           XMoveWindow (GDK_WINDOW_XDISPLAY (window),
1187                        GDK_WINDOW_XID (window),
1188                        x, y);
1189         }
1190     }
1191 }
1192
1193 /**
1194  * gdk_window_resize:
1195  * @window: a #GdkWindow
1196  * @width: new width of the window
1197  * @height: new height of the window
1198  *
1199  * Resizes @window; for toplevel windows, asks the window manager to resize
1200  * the window. The window manager may not allow the resize. When using GTK+,
1201  * use gtk_window_resize() instead of this low-level GDK function.
1202  *
1203  * Windows may not be resized below 1x1.
1204  * 
1205  * If you're also planning to move the window, use gdk_window_move_resize()
1206  * to both move and resize simultaneously, for a nicer visual effect.
1207  * 
1208  **/
1209 void
1210 gdk_window_resize (GdkWindow *window,
1211                    gint       width,
1212                    gint       height)
1213 {
1214   GdkWindowObject *private;
1215   
1216   g_return_if_fail (window != NULL);
1217   g_return_if_fail (GDK_IS_WINDOW (window));
1218   
1219   if (width < 1)
1220     width = 1;
1221   if (height < 1)
1222     height = 1;
1223
1224   private = (GdkWindowObject*) window;
1225   
1226   if (!GDK_WINDOW_DESTROYED (window))
1227     {
1228       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1229         _gdk_window_move_resize_child (window, private->x, private->y,
1230                                        width, height);
1231       else
1232         {
1233           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
1234           
1235           if (width != impl->width || height != impl->height)
1236             private->resize_count += 1;
1237
1238           XResizeWindow (GDK_WINDOW_XDISPLAY (window),
1239                          GDK_WINDOW_XID (window),
1240                          width, height);
1241         }
1242     }
1243 }
1244
1245 /**
1246  * gdk_window_move_resize:
1247  * @window: a #GdkWindow
1248  * @x: new X position relative to window's parent
1249  * @y: new Y position relative to window's parent
1250  * @width: new width
1251  * @height: new height
1252  *
1253  * Equivalent to calling gdk_window_move() and gdk_window_resize(),
1254  * except that both operations are performed at once, avoiding strange
1255  * visual effects. (i.e. the user may be able to see the window first
1256  * move, then resize, if you don't use gdk_window_move_resize().)
1257  * 
1258  **/
1259 void
1260 gdk_window_move_resize (GdkWindow *window,
1261                         gint       x,
1262                         gint       y,
1263                         gint       width,
1264                         gint       height)
1265 {
1266   GdkWindowObject *private;
1267   
1268   g_return_if_fail (window != NULL);
1269   g_return_if_fail (GDK_IS_WINDOW (window));
1270
1271   if (width < 1)
1272     width = 1;
1273   if (height < 1)
1274     height = 1;
1275   
1276   private = (GdkWindowObject*) window;
1277
1278   if (!GDK_WINDOW_DESTROYED (window))
1279     {
1280       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1281         _gdk_window_move_resize_child (window, x, y, width, height);
1282       else
1283         {
1284           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
1285           
1286           if (width != impl->width || height != impl->height)
1287             private->resize_count += 1;
1288           
1289           XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
1290                              GDK_WINDOW_XID (window),
1291                              x, y, width, height);
1292         }
1293     }
1294 }
1295
1296 /**
1297  * gdk_window_reparent:
1298  * @window: a #GdkWindow
1299  * @new_parent: new parent to move @window into
1300  * @x: X location inside the new parent
1301  * @y: Y location inside the new parent
1302  *
1303  * Reparents @window into the given @new_parent. The window being
1304  * reparented will be unmapped as a side effect.
1305  * 
1306  **/
1307 void
1308 gdk_window_reparent (GdkWindow *window,
1309                      GdkWindow *new_parent,
1310                      gint       x,
1311                      gint       y)
1312 {
1313   GdkDisplay *display;
1314   GdkWindowObject *window_private;
1315   GdkWindowObject *parent_private;
1316   GdkWindowObject *old_parent_private;
1317   
1318   g_return_if_fail (window != NULL);
1319   g_return_if_fail (GDK_IS_WINDOW (window));
1320   g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
1321   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
1322   
1323   if (!new_parent)
1324     new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
1325
1326   display = GDK_WINDOW_DISPLAY (window);
1327   
1328   window_private = (GdkWindowObject*) window;
1329   old_parent_private = (GdkWindowObject*)window_private->parent;
1330   parent_private = (GdkWindowObject*) new_parent;
1331   
1332   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (new_parent))
1333     XReparentWindow (GDK_WINDOW_XDISPLAY (window),
1334                      GDK_WINDOW_XID (window),
1335                      GDK_WINDOW_XID (new_parent),
1336                      x, y);
1337
1338   window_private->x = x;
1339   window_private->y = y;
1340   
1341   /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
1342    * the root window
1343    */
1344   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
1345     new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
1346   
1347   window_private->parent = (GdkWindowObject *)new_parent;
1348
1349   /* Switch the window type as appropriate */
1350
1351   switch (GDK_WINDOW_TYPE (new_parent))
1352     {
1353     case GDK_WINDOW_ROOT:
1354     case GDK_WINDOW_FOREIGN:
1355       /* Now a toplevel */
1356       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1357         set_wm_protocols (window);
1358       break;
1359     case GDK_WINDOW_TOPLEVEL:
1360     case GDK_WINDOW_CHILD:
1361     case GDK_WINDOW_DIALOG:
1362     case GDK_WINDOW_TEMP:
1363       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
1364           GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
1365         {
1366           /* If we were being sophisticated, we'd save the old window type
1367            * here, and restore it if we were reparented back to the
1368            * toplevel. However, the difference between different types
1369            * of toplevels only really matters on creation anyways.
1370            */
1371           GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
1372         }
1373     }
1374
1375   if (old_parent_private)
1376     old_parent_private->children = g_list_remove (old_parent_private->children, window);
1377   
1378   if ((old_parent_private &&
1379        (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
1380       (!old_parent_private && parent_private->guffaw_gravity))
1381     gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
1382   
1383   parent_private->children = g_list_prepend (parent_private->children, window);
1384   _gdk_window_init_position (GDK_WINDOW (window_private));
1385 }
1386
1387 void
1388 _gdk_windowing_window_clear_area (GdkWindow *window,
1389                                   gint       x,
1390                                   gint       y,
1391                                   gint       width,
1392                                   gint       height)
1393 {
1394   g_return_if_fail (window != NULL);
1395   g_return_if_fail (GDK_IS_WINDOW (window));
1396   
1397   if (!GDK_WINDOW_DESTROYED (window))
1398     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1399                 x, y, width, height, False);
1400 }
1401
1402 void
1403 _gdk_windowing_window_clear_area_e (GdkWindow *window,
1404                                     gint       x,
1405                                     gint       y,
1406                                     gint       width,
1407                                     gint       height)
1408 {
1409   g_return_if_fail (window != NULL);
1410   g_return_if_fail (GDK_IS_WINDOW (window));
1411   
1412   if (!GDK_WINDOW_DESTROYED (window))
1413     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1414                 x, y, width, height, True);
1415 }
1416
1417
1418 /**
1419  * gdk_window_raise:
1420  * @window: a #GdkWindow
1421  * 
1422  * Raises @window to the top of the Z-order (stacking order), so that
1423  * other windows with the same parent window appear below @window.
1424  * If @window is a toplevel, the window manager may choose to deny the
1425  * request to move the window in the Z-order, gdk_window_raise() only
1426  * requests the restack, does not guarantee it.
1427  * 
1428  **/
1429 void
1430 gdk_window_raise (GdkWindow *window)
1431 {
1432   g_return_if_fail (window != NULL);
1433   g_return_if_fail (GDK_IS_WINDOW (window));
1434   
1435   if (!GDK_WINDOW_DESTROYED (window))
1436     XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1437 }
1438
1439 /**
1440  * gdk_window_lower:
1441  * @window: a #GdkWindow
1442  * 
1443  * Lowers @window to the bottom of the Z-order (stacking order), so that
1444  * other windows with the same parent window appear above @window.
1445  * If @window is a toplevel, the window manager may choose to deny the
1446  * request to move the window in the Z-order, gdk_window_lower() only
1447  * requests the restack, does not guarantee it.
1448  *
1449  * Note that gdk_window_show() raises the window again, so don't call this
1450  * function before gdk_window_show(). (Try gdk_window_show_unraised().)
1451  * 
1452  **/
1453 void
1454 gdk_window_lower (GdkWindow *window)
1455 {
1456   g_return_if_fail (window != NULL);
1457   g_return_if_fail (GDK_IS_WINDOW (window));
1458   
1459   if (!GDK_WINDOW_DESTROYED (window))
1460     XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1461 }
1462
1463 /**
1464  * gdk_window_focus:
1465  * @window: a #GdkWindow
1466  * @timestamp: timestamp of the event triggering the window focus
1467  *
1468  * Sets keyboard focus to @window. If @window is not onscreen this
1469  * will not work. In most cases, gtk_window_present() should be used on
1470  * a #GtkWindow, rather than calling this function.
1471  * 
1472  **/
1473 void
1474 gdk_window_focus (GdkWindow *window,
1475                   guint32    timestamp)
1476 {
1477   g_return_if_fail (GDK_IS_WINDOW (window));
1478
1479   if (GDK_WINDOW_DESTROYED (window))
1480     return;
1481
1482   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
1483                                            gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE)))
1484     {
1485       XEvent xev;
1486
1487       xev.xclient.type = ClientMessage;
1488       xev.xclient.serial = 0;
1489       xev.xclient.send_event = True;
1490       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
1491       xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
1492                                                                         "_NET_ACTIVE_WINDOW");
1493       xev.xclient.format = 32;
1494       xev.xclient.data.l[0] = 0;
1495       
1496       XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
1497                   SubstructureRedirectMask | SubstructureNotifyMask,
1498                   &xev);
1499     }
1500   else
1501     {
1502       XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1503
1504       /* There is no way of knowing reliably whether we are viewable so we need
1505        * to trap errors so we don't cause a BadMatch.
1506        */
1507       gdk_error_trap_push ();
1508       XSetInputFocus (GDK_WINDOW_XDISPLAY (window),
1509                       GDK_WINDOW_XWINDOW (window),
1510                       RevertToParent,
1511                       timestamp);
1512       XSync (GDK_WINDOW_XDISPLAY (window), False);
1513       gdk_error_trap_pop ();
1514     }
1515 }
1516
1517 /**
1518  * gdk_window_set_hints:
1519  * @window: a #GdkWindow
1520  * @x: ignored field, does not matter
1521  * @y: ignored field, does not matter
1522  * @min_width: minimum width hint
1523  * @min_height: minimum height hint
1524  * @max_width: max width hint
1525  * @max_height: max height hint
1526  * @flags: logical OR of GDK_HINT_POS, GDK_HINT_MIN_SIZE, and/or GDK_HINT_MAX_SIZE
1527  *
1528  * This function is broken and useless and you should ignore it.
1529  * If using GTK+, use functions such as gtk_window_resize(), gtk_window_set_size_request(),
1530  * gtk_window_move(), gtk_window_parse_geometry(), and gtk_window_set_geometry_hints(),
1531  * depending on what you're trying to do.
1532  *
1533  * If using GDK directly, use gdk_window_set_geometry_hints().
1534  * 
1535  **/
1536 void
1537 gdk_window_set_hints (GdkWindow *window,
1538                       gint       x,
1539                       gint       y,
1540                       gint       min_width,
1541                       gint       min_height,
1542                       gint       max_width,
1543                       gint       max_height,
1544                       gint       flags)
1545 {
1546   XSizeHints size_hints;
1547   
1548   g_return_if_fail (window != NULL);
1549   g_return_if_fail (GDK_IS_WINDOW (window));
1550   
1551   if (GDK_WINDOW_DESTROYED (window))
1552     return;
1553   
1554   size_hints.flags = 0;
1555   
1556   if (flags & GDK_HINT_POS)
1557     {
1558       size_hints.flags |= PPosition;
1559       size_hints.x = x;
1560       size_hints.y = y;
1561     }
1562   
1563   if (flags & GDK_HINT_MIN_SIZE)
1564     {
1565       size_hints.flags |= PMinSize;
1566       size_hints.min_width = min_width;
1567       size_hints.min_height = min_height;
1568     }
1569   
1570   if (flags & GDK_HINT_MAX_SIZE)
1571     {
1572       size_hints.flags |= PMaxSize;
1573       size_hints.max_width = max_width;
1574       size_hints.max_height = max_height;
1575     }
1576   
1577   /* FIXME: Would it be better to delete this property if
1578    *        flags == 0? It would save space on the server
1579    */
1580   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1581                      GDK_WINDOW_XID (window),
1582                      &size_hints);
1583 }
1584
1585 /**
1586  * gdk_window_set_type_hint:
1587  * @window: A #GdkWindow
1588  * @hint: A hint of the function this window will have
1589  *
1590  * The application can use this call to provide a hint to the window
1591  * manager about the functionality of a window. The window manager
1592  * can use this information when determining the decoration and behaviour
1593  * of the window.
1594  *
1595  * The hint must be set before the window is mapped.
1596  **/
1597 void
1598 gdk_window_set_type_hint (GdkWindow        *window,
1599                           GdkWindowTypeHint hint)
1600 {
1601   GdkDisplay *display;
1602   Atom atom;
1603   
1604   g_return_if_fail (window != NULL);
1605   g_return_if_fail (GDK_IS_WINDOW (window));
1606   
1607   if (GDK_WINDOW_DESTROYED (window))
1608     return;
1609
1610   display = gdk_drawable_get_display (window);
1611
1612   switch (hint)
1613     {
1614     case GDK_WINDOW_TYPE_HINT_DIALOG:
1615       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG");
1616       break;
1617     case GDK_WINDOW_TYPE_HINT_MENU:
1618       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU");
1619       break;
1620     case GDK_WINDOW_TYPE_HINT_TOOLBAR:
1621       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR");
1622       break;
1623     default:
1624       g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint);
1625       /* Fall thru */
1626     case GDK_WINDOW_TYPE_HINT_NORMAL:
1627       atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NORMAL");
1628       break;
1629     }
1630
1631   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
1632                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
1633                    XA_ATOM, 32, PropModeReplace,
1634                    (guchar *)&atom, 1);
1635 }
1636
1637
1638 static void
1639 gdk_wmspec_change_state (gboolean   add,
1640                          GdkWindow *window,
1641                          GdkAtom    state1,
1642                          GdkAtom    state2)
1643 {
1644   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
1645   XEvent xev;
1646   
1647 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
1648 #define _NET_WM_STATE_ADD           1    /* add/set property */
1649 #define _NET_WM_STATE_TOGGLE        2    /* toggle property  */  
1650   
1651   xev.xclient.type = ClientMessage;
1652   xev.xclient.serial = 0;
1653   xev.xclient.send_event = True;
1654   xev.xclient.window = GDK_WINDOW_XID (window);
1655   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
1656   xev.xclient.format = 32;
1657   xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1658   xev.xclient.data.l[1] = gdk_x11_atom_to_xatom_for_display (display, state1);
1659   xev.xclient.data.l[2] = gdk_x11_atom_to_xatom_for_display (display, state2);
1660   
1661   XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
1662               SubstructureRedirectMask | SubstructureNotifyMask,
1663               &xev);
1664 }
1665
1666 /**
1667  * gdk_window_set_modal_hint:
1668  * @window: A #GdkWindow
1669  * @modal: TRUE if the window is modal, FALSE otherwise.
1670  *
1671  * The application can use this hint to tell the window manager
1672  * that a certain window has modal behaviour. The window manager
1673  * can use this information to handle modal windows in a special
1674  * way.
1675  *
1676  * You should only use this on windows for which you have
1677  * previously called #gdk_window_set_transient_for()
1678  **/
1679 void
1680 gdk_window_set_modal_hint (GdkWindow *window,
1681                            gboolean   modal)
1682 {
1683   GdkWindowObject *private;
1684
1685   g_return_if_fail (window != NULL);
1686   g_return_if_fail (GDK_IS_WINDOW (window));
1687   
1688   if (GDK_WINDOW_DESTROYED (window))
1689     return;
1690
1691   private = (GdkWindowObject*) window;
1692
1693   private->modal_hint = modal;
1694
1695   if (GDK_WINDOW_IS_MAPPED (window))
1696     gdk_wmspec_change_state (modal, window,
1697                              gdk_atom_intern ("_NET_WM_STATE_MODAL", FALSE), 
1698                              0);
1699 }
1700
1701 /**
1702  * gdk_window_set_geometry_hints:
1703  * @window: a #GdkWindow
1704  * @geometry: geometry hints
1705  * @geom_mask: bitmask indicating fields of @geometry to pay attention to
1706  *
1707  * Sets the geometry hints for @window. Hints flagged in @geom_mask
1708  * are set, hints not flagged in @geom_mask are unset.
1709  * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
1710  * 
1711  **/
1712 void 
1713 gdk_window_set_geometry_hints (GdkWindow      *window,
1714                                GdkGeometry    *geometry,
1715                                GdkWindowHints  geom_mask)
1716 {
1717   XSizeHints size_hints;
1718   
1719   g_return_if_fail (window != NULL);
1720   g_return_if_fail (GDK_IS_WINDOW (window));
1721   
1722   if (GDK_WINDOW_DESTROYED (window))
1723     return;
1724   
1725   size_hints.flags = 0;
1726   
1727   if (geom_mask & GDK_HINT_POS)
1728     {
1729       size_hints.flags |= PPosition;
1730       /* We need to initialize the following obsolete fields because KWM 
1731        * apparently uses these fields if they are non-zero.
1732        * #@#!#!$!.
1733        */
1734       size_hints.x = 0;
1735       size_hints.y = 0;
1736     }
1737
1738   if (geom_mask & GDK_HINT_USER_POS)
1739     {
1740       size_hints.flags |= USPosition;
1741     }
1742
1743   if (geom_mask & GDK_HINT_USER_SIZE)
1744     {
1745       size_hints.flags |= USSize;
1746     }
1747   
1748   if (geom_mask & GDK_HINT_MIN_SIZE)
1749     {
1750       size_hints.flags |= PMinSize;
1751       size_hints.min_width = geometry->min_width;
1752       size_hints.min_height = geometry->min_height;
1753     }
1754   
1755   if (geom_mask & GDK_HINT_MAX_SIZE)
1756     {
1757       size_hints.flags |= PMaxSize;
1758       size_hints.max_width = MAX (geometry->max_width, 1);
1759       size_hints.max_height = MAX (geometry->max_height, 1);
1760     }
1761   
1762   if (geom_mask & GDK_HINT_BASE_SIZE)
1763     {
1764       size_hints.flags |= PBaseSize;
1765       size_hints.base_width = geometry->base_width;
1766       size_hints.base_height = geometry->base_height;
1767     }
1768   
1769   if (geom_mask & GDK_HINT_RESIZE_INC)
1770     {
1771       size_hints.flags |= PResizeInc;
1772       size_hints.width_inc = geometry->width_inc;
1773       size_hints.height_inc = geometry->height_inc;
1774     }
1775   
1776   if (geom_mask & GDK_HINT_ASPECT)
1777     {
1778       size_hints.flags |= PAspect;
1779       if (geometry->min_aspect <= 1)
1780         {
1781           size_hints.min_aspect.x = 65536 * geometry->min_aspect;
1782           size_hints.min_aspect.y = 65536;
1783         }
1784       else
1785         {
1786           size_hints.min_aspect.x = 65536;
1787           size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
1788         }
1789       if (geometry->max_aspect <= 1)
1790         {
1791           size_hints.max_aspect.x = 65536 * geometry->max_aspect;
1792           size_hints.max_aspect.y = 65536;
1793         }
1794       else
1795         {
1796           size_hints.max_aspect.x = 65536;
1797           size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
1798         }
1799     }
1800
1801   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1802     {
1803       size_hints.flags |= PWinGravity;
1804       size_hints.win_gravity = geometry->win_gravity;
1805     }
1806   
1807   /* FIXME: Would it be better to delete this property if
1808    *        geom_mask == 0? It would save space on the server
1809    */
1810   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1811                      GDK_WINDOW_XID (window),
1812                      &size_hints);
1813 }
1814
1815 static void
1816 gdk_window_get_geometry_hints (GdkWindow      *window,
1817                                GdkGeometry    *geometry,
1818                                GdkWindowHints *geom_mask)
1819 {
1820   XSizeHints size_hints;  
1821   glong junk_size_mask = 0;
1822
1823   g_return_if_fail (GDK_IS_WINDOW (window));
1824   g_return_if_fail (geometry != NULL);
1825   g_return_if_fail (geom_mask != NULL);
1826
1827   *geom_mask = 0;
1828   
1829   if (GDK_WINDOW_DESTROYED (window))
1830     return;
1831   
1832   if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1833                           GDK_WINDOW_XID (window),
1834                           &size_hints,
1835                           &junk_size_mask))
1836     return;                   
1837
1838   if (size_hints.flags & PMinSize)
1839     {
1840       *geom_mask |= GDK_HINT_MIN_SIZE;
1841       geometry->min_width = size_hints.min_width;
1842       geometry->min_height = size_hints.min_height;
1843     }
1844
1845   if (size_hints.flags & PMaxSize)
1846     {
1847       *geom_mask |= GDK_HINT_MAX_SIZE;
1848       geometry->max_width = MAX (size_hints.max_width, 1);
1849       geometry->max_height = MAX (size_hints.max_height, 1);
1850     }
1851
1852   if (size_hints.flags & PResizeInc)
1853     {
1854       *geom_mask |= GDK_HINT_RESIZE_INC;
1855       geometry->width_inc = size_hints.width_inc;
1856       geometry->height_inc = size_hints.height_inc;
1857     }
1858
1859   if (size_hints.flags & PAspect)
1860     {
1861       *geom_mask |= GDK_HINT_ASPECT;
1862
1863       geometry->min_aspect = (gdouble) size_hints.min_aspect.x / (gdouble) size_hints.min_aspect.y;
1864       geometry->max_aspect = (gdouble) size_hints.max_aspect.x / (gdouble) size_hints.max_aspect.y;
1865     }
1866
1867   if (size_hints.flags & PWinGravity)
1868     {
1869       *geom_mask |= GDK_HINT_WIN_GRAVITY;
1870       geometry->win_gravity = size_hints.win_gravity;
1871     }
1872 }
1873
1874 static gboolean
1875 utf8_is_latin1 (const gchar *str)
1876 {
1877   const char *p = str;
1878
1879   while (*p)
1880     {
1881       gunichar ch = g_utf8_get_char (p);
1882
1883       if (ch > 0xff)
1884         return FALSE;
1885       
1886       p = g_utf8_next_char (p);
1887     }
1888
1889   return TRUE;
1890 }
1891
1892 /* Set the property to @utf8_str as STRING if the @utf8_str is fully
1893  * convertable to STRING, otherwise, set it as compound text
1894  */
1895 static void
1896 set_text_property (GdkWindow   *window,
1897                    Atom         property,
1898                    const gchar *utf8_str)
1899 {
1900   guchar *prop_text = NULL;
1901   Atom prop_type;
1902   gint prop_length;
1903   gint prop_format;
1904   
1905   if (utf8_is_latin1 (utf8_str))
1906     {
1907       prop_type = XA_STRING;
1908       prop_text = gdk_utf8_to_string_target (utf8_str);
1909       prop_length = prop_text ? strlen (prop_text) : 0;
1910       prop_format = 8;
1911     }
1912   else
1913     {
1914       GdkAtom gdk_type;
1915       
1916       gdk_utf8_to_compound_text_for_display (gdk_drawable_get_display (window),
1917                                              utf8_str, &gdk_type, &prop_format,
1918                                              &prop_text, &prop_length);
1919       prop_type = gdk_x11_atom_to_xatom_for_display 
1920         (GDK_WINDOW_DISPLAY (window), gdk_type);
1921     }
1922
1923   if (prop_text)
1924     {
1925       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1926                        GDK_WINDOW_XID (window),
1927                        property,
1928                        prop_type, prop_format,
1929                        PropModeReplace, prop_text,
1930                        prop_length);
1931
1932       g_free (prop_text);
1933     }
1934 }
1935
1936 /**
1937  * gdk_window_set_title:
1938  * @window: a #GdkWindow
1939  * @title: title of @window
1940  *
1941  * Sets the title of a toplevel window, to be displayed in the titlebar.
1942  * If you haven't explicitly set the icon name for the window
1943  * (using gdk_window_set_icon_name()), the icon name will be set to
1944  * @title as well. @title must be in UTF-8 encoding (as with all
1945  * user-readable strings in GDK/GTK+). @title may not be %NULL.
1946  **/
1947 void
1948 gdk_window_set_title (GdkWindow   *window,
1949                       const gchar *title)
1950 {
1951   GdkDisplay *display;
1952   
1953   g_return_if_fail (window != NULL);
1954   g_return_if_fail (GDK_IS_WINDOW (window));
1955   g_return_if_fail (title != NULL);
1956
1957   if (GDK_WINDOW_DESTROYED (window))
1958     return;
1959   
1960   display = gdk_drawable_get_display (window);
1961
1962   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
1963                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"),
1964                    gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
1965                    PropModeReplace, title, strlen (title));
1966   
1967   set_text_property (window,
1968                      gdk_x11_get_xatom_by_name_for_display (display, "WM_NAME"),
1969                      title);
1970   
1971   if (!gdk_window_icon_name_set (window))
1972     {
1973       XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
1974                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
1975                        gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
1976                        PropModeReplace, title, strlen (title));
1977       
1978       set_text_property (window,
1979                          gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
1980                          title);
1981     }
1982 }
1983
1984 /**
1985  * gdk_window_set_role:
1986  * @window: a #GdkWindow
1987  * @role: a string indicating its role
1988  *
1989  * When using GTK+, typically you should use gtk_window_set_role() instead
1990  * of this low-level function.
1991  * 
1992  * The window manager and session manager use a window's role to
1993  * distinguish it from other kinds of window in the same application.
1994  * When an application is restarted after being saved in a previous
1995  * session, all windows with the same title and role are treated as
1996  * interchangeable.  So if you have two windows with the same title
1997  * that should be distinguished for session management purposes, you
1998  * should set the role on those windows. It doesn't matter what string
1999  * you use for the role, as long as you have a different role for each
2000  * non-interchangeable kind of window.
2001  * 
2002  **/
2003 void          
2004 gdk_window_set_role (GdkWindow   *window,
2005                      const gchar *role)
2006 {
2007   GdkDisplay *display;
2008   
2009   g_return_if_fail (window != NULL);
2010   g_return_if_fail (GDK_IS_WINDOW (window));
2011
2012   display = gdk_drawable_get_display (window);
2013
2014   if (!GDK_WINDOW_DESTROYED (window))
2015     {
2016       if (role)
2017         XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
2018                          gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"),
2019                          XA_STRING, 8, PropModeReplace, role, strlen (role));
2020       else
2021         XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
2022                          gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"));
2023     }
2024 }
2025
2026 /**
2027  * gdk_window_set_transient_for:
2028  * @window: a toplevel #GdkWindow
2029  * @parent: another toplevel #GdkWindow
2030  *
2031  * Indicates to the window manager that @window is a transient dialog
2032  * associated with the application window @parent. This allows the
2033  * window manager to do things like center @window on @parent and
2034  * keep @window above @parent.
2035  *
2036  * See gtk_window_set_transient_for() if you're using #GtkWindow or
2037  * #GtkDialog.
2038  * 
2039  **/
2040 void          
2041 gdk_window_set_transient_for (GdkWindow *window, 
2042                               GdkWindow *parent)
2043 {
2044   GdkWindowObject *private;
2045   GdkWindowObject *parent_private;
2046   
2047   g_return_if_fail (window != NULL);
2048   g_return_if_fail (GDK_IS_WINDOW (window));
2049   
2050   private = (GdkWindowObject*) window;
2051   parent_private = (GdkWindowObject*) parent;
2052   
2053   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent))
2054     XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
2055                           GDK_WINDOW_XID (window),
2056                           GDK_WINDOW_XID (parent));
2057 }
2058
2059 /**
2060  * gdk_window_set_background:
2061  * @window: a #GdkWindow
2062  * @color: an allocated #GdkColor
2063  *
2064  * Sets the background color of @window. (However, when using GTK+,
2065  * set the background of a widget with gtk_widget_modify_bg() - if
2066  * you're an application - or gtk_style_set_background() - if you're
2067  * implementing a custom widget.)
2068  *
2069  * The @color must be allocated; gdk_rgb_find_color() is the best way
2070  * to allocate a color.
2071  *
2072  * See also gdk_window_set_back_pixmap().
2073  * 
2074  **/
2075 void
2076 gdk_window_set_background (GdkWindow *window,
2077                            GdkColor  *color)
2078 {
2079   GdkWindowObject *private = (GdkWindowObject *)window;
2080   
2081   g_return_if_fail (window != NULL);
2082   g_return_if_fail (GDK_IS_WINDOW (window));
2083   
2084   if (!GDK_WINDOW_DESTROYED (window))
2085     XSetWindowBackground (GDK_WINDOW_XDISPLAY (window),
2086                           GDK_WINDOW_XID (window), color->pixel);
2087
2088   private->bg_color = *color;
2089
2090   if (private->bg_pixmap &&
2091       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
2092       private->bg_pixmap != GDK_NO_BG)
2093     gdk_pixmap_unref (private->bg_pixmap);
2094   
2095   private->bg_pixmap = NULL;
2096 }
2097
2098 /**
2099  * gdk_window_set_back_pixmap:
2100  * @window: a #GdkWindow
2101  * @pixmap: a #GdkPixmap, or %NULL
2102  * @parent_relative: whether the tiling origin is at the origin of @window's parent
2103  *
2104  * Sets the background pixmap of @window. May also be used to set a background of
2105  * "None" on @window, by setting a background pixmap of %NULL.
2106  * A background pixmap will be tiled, positioning the first tile at the origin of
2107  * @window, or if @parent_relative is %TRUE, the tiling will be done based on the
2108  * origin of the parent window (useful to align tiles in a parent with tiles
2109  * in a child).
2110  *
2111  * A background pixmap of %NULL means that the window will have no
2112  * background.  A window with no background will never have its
2113  * background filled by the windowing system, instead the window will
2114  * contain whatever pixels were already in the corresponding area of
2115  * the display.
2116  *
2117  * The windowing system will normally fill a window with its background
2118  * when the window is obscured then exposed, and when you call
2119  * gdk_window_clear().
2120  * 
2121  **/
2122 void
2123 gdk_window_set_back_pixmap (GdkWindow *window,
2124                             GdkPixmap *pixmap,
2125                             gboolean   parent_relative)
2126 {
2127   GdkWindowObject *private = (GdkWindowObject *)window;
2128   Pixmap xpixmap;
2129   
2130   g_return_if_fail (window != NULL);
2131   g_return_if_fail (GDK_IS_WINDOW (window));
2132   g_return_if_fail (pixmap == NULL || !parent_relative);
2133
2134   if (private->bg_pixmap &&
2135       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
2136       private->bg_pixmap != GDK_NO_BG)
2137     gdk_pixmap_unref (private->bg_pixmap);
2138
2139   if (parent_relative)
2140     {
2141       xpixmap = ParentRelative;
2142       private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
2143     }
2144   else
2145     {
2146       if (pixmap)
2147         {
2148           gdk_pixmap_ref (pixmap);
2149           private->bg_pixmap = pixmap;
2150           xpixmap = GDK_PIXMAP_XID (pixmap);
2151         }
2152       else
2153         {
2154           xpixmap = None;
2155           private->bg_pixmap = GDK_NO_BG;
2156         }
2157     }
2158   
2159   if (!GDK_WINDOW_DESTROYED (window))
2160     XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
2161                                 GDK_WINDOW_XID (window), xpixmap);
2162 }
2163
2164 /**
2165  * gdk_window_set_cursor:
2166  * @window: a #GdkWindow
2167  * @cursor: a cursor
2168  *
2169  * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or
2170  * gdk_cursor_new_from_pixmap() to create the cursor.
2171  * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
2172  * a cursor with no pixels in it. Passing %NULL for the @cursor argument
2173  * to gdk_window_set_cursor() means that @window will use the cursor of
2174  * its parent window. Most windows should use this default.
2175  * 
2176  **/
2177 void
2178 gdk_window_set_cursor (GdkWindow *window,
2179                        GdkCursor *cursor)
2180 {
2181   GdkCursorPrivate *cursor_private;
2182   Cursor xcursor;
2183   
2184   g_return_if_fail (window != NULL);
2185   g_return_if_fail (GDK_IS_WINDOW (window));
2186   
2187   cursor_private = (GdkCursorPrivate*) cursor;
2188   
2189   if (!cursor)
2190     xcursor = None;
2191   else
2192     xcursor = cursor_private->xcursor;
2193   
2194   if (!GDK_WINDOW_DESTROYED (window))
2195     XDefineCursor (GDK_WINDOW_XDISPLAY (window),
2196                    GDK_WINDOW_XID (window),
2197                    xcursor);
2198 }
2199
2200 /**
2201  * gdk_window_get_geometry:
2202  * @window: a #GdkWindow
2203  * @x: return location for X coordinate of window (relative to its parent)
2204  * @y: return location for Y coordinate of window (relative to its parent)
2205  * @width: return location for width of window
2206  * @height: return location for height of window
2207  * @depth: return location for bit depth of window
2208  *
2209  * Any of the return location arguments to this function may be %NULL,
2210  * if you aren't interested in getting the value of that field.
2211  *
2212  * The X and Y coordinates returned are relative to the parent window
2213  * of @window, which for toplevels usually means relative to the
2214  * window decorations (titlebar, etc.) rather than relative to the
2215  * root window (screen-size background window).
2216  *
2217  * On the X11 platform, the geometry is obtained from the X server,
2218  * so reflects the latest position of @window; this may be out-of-sync
2219  * with the position of @window delivered in the most-recently-processed
2220  * #GdkEventConfigure. gdk_window_get_position() in contrast gets the
2221  * position from the most recent configure event.
2222  * 
2223  **/
2224 void
2225 gdk_window_get_geometry (GdkWindow *window,
2226                          gint      *x,
2227                          gint      *y,
2228                          gint      *width,
2229                          gint      *height,
2230                          gint      *depth)
2231 {
2232   Window root;
2233   gint tx;
2234   gint ty;
2235   guint twidth;
2236   guint theight;
2237   guint tborder_width;
2238   guint tdepth;
2239   
2240   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
2241   
2242   if (!window)
2243     {
2244       GDK_NOTE (MULTIHEAD,
2245                 g_message ("gdk_window_get_geometry(): Window needs to be non-NULL to be multi head safe"));
2246       window = gdk_screen_get_root_window ((gdk_get_default_screen ()));
2247     }
2248
2249   if (!GDK_WINDOW_DESTROYED (window))
2250     {
2251       XGetGeometry (GDK_WINDOW_XDISPLAY (window),
2252                     GDK_WINDOW_XID (window),
2253                     &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
2254       
2255       if (x)
2256         *x = tx;
2257       if (y)
2258         *y = ty;
2259       if (width)
2260         *width = twidth;
2261       if (height)
2262         *height = theight;
2263       if (depth)
2264         *depth = tdepth;
2265     }
2266 }
2267
2268 /**
2269  * gdk_window_get_origin:
2270  * @window: a #GdkWindow
2271  * @x: return location for X coordinate
2272  * @y: return location for Y coordinate
2273  * 
2274  * Obtains the position of a window in root window coordinates.
2275  * (Compare with gdk_window_get_position() and
2276  * gdk_window_get_geometry() which return the position of a window
2277  * relative to its parent window.)
2278  * 
2279  * Return value: not meaningful, ignore
2280  **/
2281 gint
2282 gdk_window_get_origin (GdkWindow *window,
2283                        gint      *x,
2284                        gint      *y)
2285 {
2286   gint return_val;
2287   Window child;
2288   gint tx = 0;
2289   gint ty = 0;
2290   
2291   g_return_val_if_fail (window != NULL, 0);
2292   
2293   if (!GDK_WINDOW_DESTROYED (window))
2294     {
2295       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
2296                                           GDK_WINDOW_XID (window),
2297                                           GDK_WINDOW_XROOTWIN (window),
2298                                           0, 0, &tx, &ty,
2299                                           &child);
2300     }
2301   else
2302     return_val = 0;
2303   
2304   if (x)
2305     *x = tx;
2306   if (y)
2307     *y = ty;
2308   
2309   return return_val;
2310 }
2311
2312 /**
2313  * gdk_window_get_deskrelative_origin:
2314  * @window: a #GdkWindow
2315  * @x: return location for X coordinate
2316  * @y: return location for Y coordinate
2317  * 
2318  * This gets the origin of a #GdkWindow relative to
2319  * an Enlightenment-window-manager desktop. As long as you don't
2320  * assume that the user's desktop/workspace covers the entire
2321  * root window (i.e. you don't assume that the desktop begins
2322  * at root window coordinate 0,0) this function is not necessary.
2323  * It's deprecated for that reason.
2324  * 
2325  * Return value: not meaningful
2326  **/
2327 gboolean
2328 gdk_window_get_deskrelative_origin (GdkWindow *window,
2329                                     gint      *x,
2330                                     gint      *y)
2331 {
2332   gboolean return_val = FALSE;
2333   gint num_children, format_return;
2334   Window win, *child, parent, root;
2335   gint tx = 0;
2336   gint ty = 0;
2337   Atom type_return;
2338   Atom atom;
2339   gulong number_return, bytes_after_return;
2340   guchar *data_return;
2341   
2342   g_return_val_if_fail (window != NULL, 0);
2343   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2344   
2345   if (!GDK_WINDOW_DESTROYED (window))
2346     {
2347       atom = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
2348                                                     "ENLIGHTENMENT_DESKTOP");
2349       win = GDK_WINDOW_XID (window);
2350       
2351       while (XQueryTree (GDK_WINDOW_XDISPLAY (window), win, &root, &parent,
2352                          &child, (unsigned int *)&num_children))
2353         {
2354           if ((child) && (num_children > 0))
2355             XFree (child);
2356           
2357           if (!parent)
2358             break;
2359           else
2360             win = parent;
2361           
2362           if (win == root)
2363             break;
2364           
2365           data_return = NULL;
2366           XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), win, atom, 0, 0,
2367                               False, XA_CARDINAL, &type_return, &format_return,
2368                               &number_return, &bytes_after_return, &data_return);
2369
2370           if (type_return == XA_CARDINAL)
2371             {
2372               XFree (data_return);
2373               break;
2374             }
2375         }
2376       
2377       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
2378                                           GDK_WINDOW_XID (window),
2379                                           win,
2380                                           0, 0, &tx, &ty,
2381                                           &root);
2382       if (x)
2383         *x = tx;
2384       if (y)
2385         *y = ty;
2386     }
2387   
2388   
2389   return return_val;
2390 }
2391
2392 /**
2393  * gdk_window_get_root_origin:
2394  * @window: a #GdkWindow
2395  * @x: return location for X position of window frame
2396  * @y: return location for Y position of window frame
2397  *
2398  * Obtains the top-left corner of the window manager frame in root
2399  * window coordinates.
2400  * 
2401  **/
2402 void
2403 gdk_window_get_root_origin (GdkWindow *window,
2404                             gint      *x,
2405                             gint      *y)
2406 {
2407   GdkRectangle rect;
2408
2409   g_return_if_fail (GDK_IS_WINDOW (window));
2410
2411   gdk_window_get_frame_extents (window, &rect);
2412
2413   if (x)
2414     *x = rect.x;
2415
2416   if (y)
2417     *y = rect.y;
2418 }
2419
2420 /**
2421  * gdk_window_get_frame_extents:
2422  * @window: a #GdkWindow
2423  * @rect: rectangle to fill with bounding box of the window frame
2424  *
2425  * Obtains the bounding box of the window, including window manager
2426  * titlebar/borders if any. The frame position is given in root window
2427  * coordinates. To get the position of the window itself (rather than
2428  * the frame) in root window coordinates, use gdk_window_get_origin().
2429  * 
2430  **/
2431 void
2432 gdk_window_get_frame_extents (GdkWindow    *window,
2433                               GdkRectangle *rect)
2434 {
2435   GdkWindowObject *private;
2436   Window xwindow;
2437   Window xparent;
2438   Window root;
2439   Window *children;
2440   unsigned int nchildren;
2441   
2442   g_return_if_fail (GDK_IS_WINDOW (window));
2443   g_return_if_fail (rect != NULL);
2444   
2445   private = (GdkWindowObject*) window;
2446   
2447   rect->x = 0;
2448   rect->y = 0;
2449   rect->width = 1;
2450   rect->height = 1;
2451   
2452   if (GDK_WINDOW_DESTROYED (window))
2453     return;
2454   
2455   while (private->parent && ((GdkWindowObject*) private->parent)->parent)
2456     private = (GdkWindowObject*) private->parent;
2457   if (GDK_WINDOW_DESTROYED (window))
2458     return;
2459   
2460   xparent = GDK_WINDOW_XID (window);
2461   do
2462     {
2463       xwindow = xparent;
2464       if (!XQueryTree (GDK_WINDOW_XDISPLAY (window), xwindow,
2465                        &root, &xparent,
2466                        &children, &nchildren))
2467         return;
2468       
2469       if (children)
2470         XFree (children);
2471     }
2472   while (xparent != root);
2473   
2474   if (xparent == root)
2475     {
2476       unsigned int ww, wh, wb, wd;
2477       int wx, wy;
2478       
2479       if (XGetGeometry (GDK_WINDOW_XDISPLAY (window), xwindow, &root, &wx, &wy, &ww, &wh, &wb, &wd))
2480         {
2481           rect->x = wx;
2482           rect->y = wy;
2483           rect->width = ww;
2484           rect->height = wh;
2485         }
2486     }
2487 }
2488
2489 GdkWindow*
2490 _gdk_windowing_window_get_pointer (GdkWindow       *window,
2491                                    gint            *x,
2492                                    gint            *y,
2493                                    GdkModifierType *mask)
2494 {
2495   GdkWindow *return_val;
2496   Window root;
2497   Window child;
2498   int rootx, rooty;
2499   int winx = 0;
2500   int winy = 0;
2501   unsigned int xmask = 0;
2502   gint xoffset, yoffset;
2503
2504   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
2505   
2506   if (!window)
2507     {
2508       GDK_NOTE (MULTIHEAD,
2509                 g_message ("_gdk_windowing_window_get_pointer(): window arg is need for multihead safe operation"));
2510       window = gdk_screen_get_root_window (gdk_get_default_screen ());
2511     }
2512   
2513   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2514
2515   return_val = NULL;
2516   if (!GDK_WINDOW_DESTROYED (window) &&
2517       XQueryPointer (GDK_WINDOW_XDISPLAY (window),
2518                      GDK_WINDOW_XID (window),
2519                      &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
2520     {
2521       if (child)
2522         return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child);
2523     }
2524   
2525   if (x)
2526     *x = winx + xoffset;
2527   if (y)
2528     *y = winy + yoffset;
2529   if (mask)
2530     *mask = xmask;
2531   
2532   return return_val;
2533 }
2534
2535 GdkWindow*
2536 _gdk_windowing_window_at_pointer (GdkScreen *screen,
2537                                   gint      *win_x,
2538                                   gint      *win_y)
2539 {
2540   return gdk_screen_get_window_at_pointer (screen, win_x, win_y);
2541 }
2542
2543 /**
2544  * gdk_window_get_events:
2545  * @window: a #GdkWindow
2546  * 
2547  * Gets the event mask for @window. See gdk_window_set_events().
2548  * 
2549  * Return value: event mask for @window
2550  **/
2551 GdkEventMask  
2552 gdk_window_get_events (GdkWindow *window)
2553 {
2554   XWindowAttributes attrs;
2555   GdkEventMask event_mask;
2556   
2557   g_return_val_if_fail (window != NULL, 0);
2558   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2559
2560   if (GDK_WINDOW_DESTROYED (window))
2561     return 0;
2562   else
2563     {
2564       XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2565                             GDK_WINDOW_XID (window), 
2566                             &attrs);
2567       
2568       event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
2569       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
2570   
2571       return event_mask;
2572     }
2573 }
2574
2575 /**
2576  * gdk_window_set_events:
2577  * @window: a #GdkWindow
2578  * @event_mask: event mask for @window
2579  *
2580  * The event mask for a window determines which events will be reported
2581  * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK
2582  * means the window should report button press events. The event mask
2583  * is the bitwise OR of values from the #GdkEventMask enumeration.
2584  * 
2585  **/
2586 void          
2587 gdk_window_set_events (GdkWindow       *window,
2588                        GdkEventMask     event_mask)
2589 {
2590   long xevent_mask;
2591   int i;
2592   
2593   g_return_if_fail (window != NULL);
2594   g_return_if_fail (GDK_IS_WINDOW (window));
2595   
2596   if (!GDK_WINDOW_DESTROYED (window))
2597     {
2598       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
2599       xevent_mask = StructureNotifyMask;
2600       for (i = 0; i < _gdk_nenvent_masks; i++)
2601         {
2602           if (event_mask & (1 << (i + 1)))
2603             xevent_mask |= _gdk_event_mask_table[i];
2604         }
2605       
2606       XSelectInput (GDK_WINDOW_XDISPLAY (window),
2607                     GDK_WINDOW_XID (window),
2608                     xevent_mask);
2609     }
2610 }
2611
2612 void
2613 gdk_window_add_colormap_windows (GdkWindow *window)
2614 {
2615   GdkWindow *toplevel;
2616   Window *old_windows;
2617   Window *new_windows;
2618   int i, count;
2619   
2620   g_return_if_fail (window != NULL);
2621   g_return_if_fail (GDK_IS_WINDOW (window));
2622   
2623   toplevel = gdk_window_get_toplevel (window);
2624   if (GDK_WINDOW_DESTROYED (toplevel))
2625     return;
2626   
2627   old_windows = NULL;
2628   if (!XGetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2629                               GDK_WINDOW_XID (toplevel),
2630                               &old_windows, &count))
2631     {
2632       count = 0;
2633     }
2634   
2635   for (i = 0; i < count; i++)
2636     if (old_windows[i] == GDK_WINDOW_XID (window))
2637       {
2638         XFree (old_windows);
2639         return;
2640       }
2641   
2642   new_windows = g_new (Window, count + 1);
2643   
2644   for (i = 0; i < count; i++)
2645     new_windows[i] = old_windows[i];
2646   new_windows[count] = GDK_WINDOW_XID (window);
2647   
2648   XSetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2649                          GDK_WINDOW_XID (toplevel),
2650                          new_windows, count + 1);
2651   
2652   g_free (new_windows);
2653   if (old_windows)
2654     XFree (old_windows);
2655 }
2656
2657 static gboolean
2658 gdk_window_have_shape_ext (GdkDisplay *display)
2659 {
2660   enum { UNKNOWN, NO, YES };
2661   GdkDisplayX11 *display_x11;
2662   
2663   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
2664
2665   display_x11 = GDK_DISPLAY_X11 (display);
2666   
2667   if (display_x11->have_shape == UNKNOWN)
2668     {
2669       int ignore;
2670       if (XQueryExtension (display_x11->xdisplay, "SHAPE", &ignore, &ignore, &ignore))
2671         display_x11->have_shape = YES;
2672       else
2673         display_x11->have_shape = NO;
2674     }
2675   
2676   return (display_x11->have_shape == YES);
2677 }
2678
2679 #define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.")
2680
2681 /*
2682  * This needs the X11 shape extension.
2683  * If not available, shaped windows will look
2684  * ugly, but programs still work.    Stefan Wille
2685  */
2686 /**
2687  * gdk_window_shape_combine_mask:
2688  * @window: a #GdkWindow
2689  * @mask: shape mask
2690  * @x: X position of shape mask with respect to @window
2691  * @y: Y position of shape mask with respect to @window
2692  *
2693  * Applies a shape mask to @window. Pixels in @window corresponding to
2694  * set bits in the @mask will be visible; pixels in @window
2695  * corresponding to unset bits in the @mask will be transparent. This
2696  * gives a non-rectangular window.
2697  *
2698  * If @mask is %NULL, the shape mask will be unset, and the @x/@y
2699  * parameters are not used.
2700  *
2701  * On the X11 platform, this uses an X server extension which is
2702  * widely available on most common platforms, but not available on
2703  * very old X servers, and occasionally the implementation will be
2704  * buggy. On servers without the shape extension, this function
2705  * will do nothing.
2706  * 
2707  **/
2708 void
2709 gdk_window_shape_combine_mask (GdkWindow *window,
2710                                GdkBitmap *mask,
2711                                gint x, gint y)
2712 {
2713   Pixmap pixmap;
2714   gint xoffset, yoffset;
2715   
2716   g_return_if_fail (window != NULL);
2717   g_return_if_fail (GDK_IS_WINDOW (window));
2718   
2719 #ifdef HAVE_SHAPE_EXT
2720   if (GDK_WINDOW_DESTROYED (window))
2721     return;
2722
2723   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2724
2725   if (xoffset != 0 || yoffset != 0)
2726     {
2727       WARN_SHAPE_TOO_BIG ();
2728       return;
2729     }
2730   
2731   if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
2732     {
2733       if (mask)
2734         {
2735           pixmap = GDK_PIXMAP_XID (mask);
2736         }
2737       else
2738         {
2739           x = 0;
2740           y = 0;
2741           pixmap = None;
2742         }
2743       
2744       XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
2745                          GDK_WINDOW_XID (window),
2746                          ShapeBounding,
2747                          x, y,
2748                          pixmap,
2749                          ShapeSet);
2750     }
2751 #endif /* HAVE_SHAPE_EXT */
2752 }
2753
2754 /**
2755  * gdk_window_shape_combine_region:
2756  * @window: a #GdkWindow
2757  * @shape_region: region of window to be non-transparent
2758  * @offset_x: X position of @shape_region in @window coordinates
2759  * @offset_y: Y position of @shape_region in @window coordinates
2760  *
2761  * Makes pixels in @window outside @shape_region be transparent,
2762  * so that the window may be nonrectangular. See also
2763  * gdk_window_shape_combine_mask() to use a bitmap as the mask.
2764  *
2765  * If @shape_region is %NULL, the shape will be unset, so the whole
2766  * window will be opaque again. @offset_x and @offset_y are ignored
2767  * if @shape_region is %NULL.
2768  * 
2769  * On the X11 platform, this uses an X server extension which is
2770  * widely available on most common platforms, but not available on
2771  * very old X servers, and occasionally the implementation will be
2772  * buggy. On servers without the shape extension, this function
2773  * will do nothing.
2774  * 
2775  **/
2776 void
2777 gdk_window_shape_combine_region (GdkWindow *window,
2778                                  GdkRegion *shape_region,
2779                                  gint       offset_x,
2780                                  gint       offset_y)
2781 {
2782   gint xoffset, yoffset;
2783   
2784   g_return_if_fail (GDK_IS_WINDOW (window));
2785   
2786 #ifdef HAVE_SHAPE_EXT
2787   if (GDK_WINDOW_DESTROYED (window))
2788     return;
2789
2790   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2791
2792   if (xoffset != 0 || yoffset != 0)
2793     {
2794       WARN_SHAPE_TOO_BIG ();
2795       return;
2796     }
2797   
2798   if (shape_region == NULL)
2799     {
2800       /* Use NULL mask to unset the shape */
2801       gdk_window_shape_combine_mask (window, NULL, 0, 0);
2802       return;
2803     }
2804   
2805   if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
2806     {
2807       gint n_rects = 0;
2808       XRectangle *xrects = NULL;
2809
2810       _gdk_region_get_xrectangles (shape_region,
2811                                    0, 0,
2812                                    &xrects, &n_rects);
2813       
2814       XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
2815                                GDK_WINDOW_XID (window),
2816                                ShapeBounding,
2817                                offset_x, offset_y,
2818                                xrects, n_rects,
2819                                ShapeSet,
2820                                YXBanded);
2821
2822       g_free (xrects);
2823     }
2824 #endif /* HAVE_SHAPE_EXT */
2825 }
2826
2827
2828 /**
2829  * gdk_window_set_override_redirect:
2830  * @window: a #GdkWindow
2831  * @override_redirect: %TRUE if window should be override redirect
2832  *
2833  * An override redirect window is not under the control of the window manager.
2834  * This means it won't have a titlebar, won't be minimizable, etc. - it will
2835  * be entirely under the control of the application. The window manager
2836  * can't see the override redirect window at all.
2837  *
2838  * Override redirect should only be used for short-lived temporary
2839  * windows, such as popup menus. #GtkMenu uses an override redirect
2840  * window in its implementation, for example.
2841  * 
2842  **/
2843 void
2844 gdk_window_set_override_redirect (GdkWindow *window,
2845                                   gboolean override_redirect)
2846 {
2847   XSetWindowAttributes attr;
2848   
2849   g_return_if_fail (window != NULL);
2850   g_return_if_fail (GDK_IS_WINDOW (window));
2851
2852   if (!GDK_WINDOW_DESTROYED (window))
2853     {
2854       attr.override_redirect = (override_redirect == FALSE)?False:True;
2855       XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2856                                GDK_WINDOW_XID (window),
2857                                CWOverrideRedirect,
2858                                &attr);
2859     }
2860 }
2861
2862
2863 /**
2864  * gdk_window_set_icon_list:
2865  * @window: The #GdkWindow toplevel window to set the icon of.
2866  * @pixbufs: A list of pixbufs, of different sizes.
2867  *
2868  * Sets a list of icons for the window. One of these will be used
2869  * to represent the window when it has been iconified. The icon is
2870  * usually shown in an icon box or some sort of task bar. Which icon
2871  * size is shown depends on the window manager. The window manager
2872  * can scale the icon  but setting several size icons can give better
2873  * image quality since the window manager may only need to scale the
2874  * icon by a small amount or not at all.
2875  *
2876  **/
2877 void
2878 gdk_window_set_icon_list (GdkWindow *window,
2879                           GList     *pixbufs)
2880 {
2881   gulong *data;
2882   guchar *pixels;
2883   gulong *p;
2884   gint size;
2885   GList *l;
2886   GdkPixbuf *pixbuf;
2887   gint width, height, stride;
2888   gint x, y;
2889   gint n_channels;
2890   GdkDisplay *display;
2891   
2892   g_return_if_fail (GDK_IS_WINDOW (window));
2893
2894   if (GDK_WINDOW_DESTROYED (window))
2895     return;
2896
2897   display = gdk_drawable_get_display (window);
2898   
2899   l = pixbufs;
2900   size = 0;
2901   
2902   while (l)
2903     {
2904       pixbuf = l->data;
2905       g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
2906
2907       width = gdk_pixbuf_get_width (pixbuf);
2908       height = gdk_pixbuf_get_height (pixbuf);
2909       
2910       size += 2 + width * height;
2911
2912       l = g_list_next (l);
2913     }
2914
2915   data = g_malloc (size * sizeof (gulong));
2916
2917   l = pixbufs;
2918   p = data;
2919   while (l)
2920     {
2921       pixbuf = l->data;
2922       
2923       width = gdk_pixbuf_get_width (pixbuf);
2924       height = gdk_pixbuf_get_height (pixbuf);
2925       stride = gdk_pixbuf_get_rowstride (pixbuf);
2926       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
2927       
2928       *p++ = width;
2929       *p++ = height;
2930
2931       pixels = gdk_pixbuf_get_pixels (pixbuf);
2932
2933       for (y = 0; y < height; y++)
2934         {
2935           for (x = 0; x < width; x++)
2936             {
2937               guchar r, g, b, a;
2938               
2939               r = pixels[y*stride + x*n_channels + 0];
2940               g = pixels[y*stride + x*n_channels + 1];
2941               b = pixels[y*stride + x*n_channels + 2];
2942               if (n_channels >= 4)
2943                 a = pixels[y*stride + x*n_channels + 3];
2944               else
2945                 a = 255;
2946               
2947               *p++ = a << 24 | r << 16 | g << 8 | b ;
2948             }
2949         }
2950
2951       l = g_list_next (l);
2952     }
2953
2954   if (size > 0)
2955     {
2956       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
2957                        GDK_WINDOW_XID (window),
2958                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"),
2959                        XA_CARDINAL, 32,
2960                        PropModeReplace,
2961                        (guchar*) data, size);
2962     }
2963   else
2964     {
2965       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
2966                        GDK_WINDOW_XID (window),
2967                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"));
2968     }
2969   
2970   g_free (data);
2971 }
2972
2973 /**
2974  * gdk_window_set_icon:
2975  * @window: a #GdkWindow
2976  * @icon_window: a #GdkWindow to use for the icon, or %NULL to unset
2977  * @pixmap: a #GdkPixmap to use as the icon, or %NULL to unset
2978  * @mask: a 1-bit pixmap (#GdkBitmap) to use as mask for @pixmap, or %NULL to have none
2979  *
2980  * Sets the icon of @window as a pixmap or window. If using GTK+, investigate
2981  * gtk_window_set_default_icon_list() first, and then gtk_window_set_icon_list()
2982  * and gtk_window_set_icon(). If those don't meet your needs, look at
2983  * gdk_window_set_icon_list(). Only if all those are too high-level do you
2984  * want to fall back to gdk_window_set_icon().
2985  * 
2986  **/
2987 void          
2988 gdk_window_set_icon (GdkWindow *window, 
2989                      GdkWindow *icon_window,
2990                      GdkPixmap *pixmap,
2991                      GdkBitmap *mask)
2992 {
2993   XWMHints *wm_hints;
2994   
2995   g_return_if_fail (window != NULL);
2996   g_return_if_fail (GDK_IS_WINDOW (window));
2997
2998   if (GDK_WINDOW_DESTROYED (window))
2999     return;
3000
3001   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
3002                           GDK_WINDOW_XID (window));
3003   if (!wm_hints)
3004     wm_hints = XAllocWMHints ();
3005
3006   if (icon_window != NULL)
3007     {
3008       wm_hints->flags |= IconWindowHint;
3009       wm_hints->icon_window = GDK_WINDOW_XID (icon_window);
3010     }
3011   
3012   if (pixmap != NULL)
3013     {
3014       wm_hints->flags |= IconPixmapHint;
3015       wm_hints->icon_pixmap = GDK_PIXMAP_XID (pixmap);
3016     }
3017   
3018   if (mask != NULL)
3019     {
3020       wm_hints->flags |= IconMaskHint;
3021       wm_hints->icon_mask = GDK_PIXMAP_XID (mask);
3022     }
3023
3024   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
3025                GDK_WINDOW_XID (window), wm_hints);
3026   XFree (wm_hints);
3027 }
3028
3029 static gboolean
3030 gdk_window_icon_name_set (GdkWindow *window)
3031 {
3032   return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
3033                                                g_quark_from_static_string ("gdk-icon-name-set")));
3034 }
3035
3036 /**
3037  * gdk_window_set_icon_name:
3038  * @window: a #GdkWindow
3039  * @name: name of window while iconified (minimized)
3040  *
3041  * Windows may have a name used while minimized, distinct from the
3042  * name they display in their titlebar. Most of the time this is a bad
3043  * idea from a user interface standpoint. But you can set such a name
3044  * with this function, if you like.
3045  *
3046  **/
3047 void          
3048 gdk_window_set_icon_name (GdkWindow   *window, 
3049                           const gchar *name)
3050 {
3051   GdkDisplay *display;
3052   
3053   g_return_if_fail (window != NULL);
3054   g_return_if_fail (GDK_IS_WINDOW (window));
3055
3056   if (GDK_WINDOW_DESTROYED (window))
3057     return;
3058
3059   display = gdk_drawable_get_display (window);
3060
3061   g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
3062                       GUINT_TO_POINTER (TRUE));
3063
3064   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
3065                    GDK_WINDOW_XID (window),
3066                    gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
3067                    gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
3068                    PropModeReplace, name, strlen (name));
3069   
3070   set_text_property (window,
3071                      gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
3072                      name);
3073 }
3074
3075 /**
3076  * gdk_window_iconify:
3077  * @window: a #GdkWindow
3078  * 
3079  * Asks to iconify (minimize) @window. The window manager may choose
3080  * to ignore the request, but normally will honor it. Using
3081  * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
3082  * 
3083  **/
3084 void
3085 gdk_window_iconify (GdkWindow *window)
3086 {
3087   GdkWindowObject *private;
3088   
3089   g_return_if_fail (window != NULL);
3090   g_return_if_fail (GDK_IS_WINDOW (window));
3091
3092   if (GDK_WINDOW_DESTROYED (window))
3093     return;
3094
3095   private = (GdkWindowObject*) window;
3096
3097   if (GDK_WINDOW_IS_MAPPED (window))
3098     {  
3099       XIconifyWindow (GDK_WINDOW_XDISPLAY (window),
3100                       GDK_WINDOW_XWINDOW (window),
3101                       gdk_screen_get_number (GDK_WINDOW_SCREEN (window)));
3102     }
3103   else
3104     {
3105       /* Flip our client side flag, the real work happens on map. */
3106       gdk_synthesize_window_state (window,
3107                                    0,
3108                                    GDK_WINDOW_STATE_ICONIFIED);
3109     }
3110 }
3111
3112 /**
3113  * gdk_window_deiconify:
3114  * @window: a #GdkWindow
3115  *
3116  * Attempt to deiconify (unminimize) @window. On X11 the window manager may
3117  * choose to ignore the request to deiconify. When using GTK+,
3118  * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet,
3119  * you probably want to use gtk_window_present(), which raises the window, focuses it,
3120  * unminimizes it, and puts it on the current desktop.
3121  * 
3122  **/
3123 void
3124 gdk_window_deiconify (GdkWindow *window)
3125 {
3126   GdkWindowObject *private;
3127   
3128   g_return_if_fail (window != NULL);
3129   g_return_if_fail (GDK_IS_WINDOW (window));
3130
3131   if (GDK_WINDOW_DESTROYED (window))
3132     return;
3133
3134   private = (GdkWindowObject*) window;
3135
3136   if (GDK_WINDOW_IS_MAPPED (window))
3137     {  
3138       gdk_window_show (window);
3139     }
3140   else
3141     {
3142       /* Flip our client side flag, the real work happens on map. */
3143       gdk_synthesize_window_state (window,
3144                                    GDK_WINDOW_STATE_ICONIFIED,
3145                                    0);
3146     }
3147 }
3148
3149 /**
3150  * gdk_window_stick:
3151  * @window: a toplevel #GdkWindow
3152  *
3153  * "Pins" a window such that it's on all workspaces and does not scroll
3154  * with viewports, for window managers that have scrollable viewports.
3155  * (When using #GtkWindow, gtk_window_stick() may be more useful.)
3156  *
3157  * On the X11 platform, this function depends on window manager
3158  * support, so may have no effect with many window managers. However,
3159  * GDK will do the best it can to convince the window manager to stick
3160  * the window. For window managers that don't support this operation,
3161  * there's nothing you can do to force it to happen.
3162  * 
3163  **/
3164 void
3165 gdk_window_stick (GdkWindow *window)
3166 {
3167   g_return_if_fail (GDK_IS_WINDOW (window));
3168
3169   if (GDK_WINDOW_DESTROYED (window))
3170     return;
3171
3172   if (GDK_WINDOW_IS_MAPPED (window))
3173     {
3174       /* "stick" means stick to all desktops _and_ do not scroll with the
3175        * viewport. i.e. glue to the monitor glass in all cases.
3176        */
3177       
3178       XEvent xev;
3179
3180       /* Request stick during viewport scroll */
3181       gdk_wmspec_change_state (TRUE, window,
3182                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
3183                                0);
3184
3185       /* Request desktop 0xFFFFFFFF */
3186       xev.xclient.type = ClientMessage;
3187       xev.xclient.serial = 0;
3188       xev.xclient.send_event = True;
3189       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
3190       xev.xclient.display = GDK_WINDOW_XDISPLAY (window);
3191       xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), 
3192                                                                         "_NET_WM_DESKTOP");
3193       xev.xclient.format = 32;
3194
3195       xev.xclient.data.l[0] = 0xFFFFFFFF;
3196
3197       XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
3198                   SubstructureRedirectMask | SubstructureNotifyMask,
3199                   &xev);
3200     }
3201   else
3202     {
3203       /* Flip our client side flag, the real work happens on map. */
3204       gdk_synthesize_window_state (window,
3205                                    0,
3206                                    GDK_WINDOW_STATE_STICKY);
3207     }
3208 }
3209
3210 /**
3211  * gdk_window_unstick:
3212  * @window: a toplevel #GdkWindow
3213  *
3214  * Reverse operation for gdk_window_stick(); see gdk_window_stick(),
3215  * and gtk_window_unstick().
3216  * 
3217  **/
3218 void
3219 gdk_window_unstick (GdkWindow *window)
3220 {
3221   g_return_if_fail (GDK_IS_WINDOW (window));
3222
3223   if (GDK_WINDOW_DESTROYED (window))
3224     return;
3225
3226   if (GDK_WINDOW_IS_MAPPED (window))
3227     {
3228       XEvent xev;
3229       Atom type;
3230       gint format;
3231       gulong nitems;
3232       gulong bytes_after;
3233       gulong *current_desktop;
3234       GdkDisplay *display = gdk_drawable_get_display (window);
3235       
3236       /* Request unstick from viewport */
3237       gdk_wmspec_change_state (FALSE, window,
3238                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
3239                                0);
3240
3241       /* Get current desktop, then set it; this is a race, but not
3242        * one that matters much in practice.
3243        */
3244       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window),
3245                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"),
3246                           0, G_MAXLONG,
3247                           False, XA_CARDINAL, &type, &format, &nitems,
3248                           &bytes_after, (guchar **)&current_desktop);
3249
3250       if (type == XA_CARDINAL)
3251         {
3252           xev.xclient.type = ClientMessage;
3253           xev.xclient.serial = 0;
3254           xev.xclient.send_event = True;
3255           xev.xclient.window = GDK_WINDOW_XWINDOW (window);
3256           xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
3257           xev.xclient.format = 32;
3258
3259           xev.xclient.data.l[0] = *current_desktop;
3260       
3261           XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
3262                       SubstructureRedirectMask | SubstructureNotifyMask,
3263                       &xev);
3264
3265           XFree (current_desktop);
3266         }
3267     }
3268   else
3269     {
3270       /* Flip our client side flag, the real work happens on map. */
3271       gdk_synthesize_window_state (window,
3272                                    GDK_WINDOW_STATE_STICKY,
3273                                    0);
3274
3275     }
3276 }
3277
3278 /**
3279  * gdk_window_maximize:
3280  * @window: a #GdkWindow
3281  *
3282  * Asks the window manager to maximize @window, if the window manager supports
3283  * this operation. Not all window managers support this, and some deliberately
3284  * ignore it or don't have a concept of "maximized"; so you can't rely on the
3285  * maximization actually happening. But it will happen with most standard
3286  * window managers, and GDK makes a best effort to get it to happen.
3287  *
3288  * If the window was already maximized, then this function does nothing.
3289  * 
3290  **/
3291 void
3292 gdk_window_maximize (GdkWindow *window)
3293 {
3294   g_return_if_fail (GDK_IS_WINDOW (window));
3295
3296   if (GDK_WINDOW_DESTROYED (window))
3297     return;
3298
3299   if (GDK_WINDOW_IS_MAPPED (window))
3300     gdk_wmspec_change_state (TRUE, window,
3301                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
3302                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
3303   else
3304     gdk_synthesize_window_state (window,
3305                                  0,
3306                                  GDK_WINDOW_STATE_MAXIMIZED);
3307 }
3308
3309 /**
3310  * gdk_window_unmaximize:
3311  * @window: a #GdkWindow
3312  *
3313  * Asks the window manager to unmaximize @window, if the window manager supports
3314  * this operation. Not all window managers support this, and some deliberately
3315  * ignore it or don't have a concept of "maximized"; so you can't rely on the
3316  * unmaximization actually happening. But it will happen with most standard
3317  * window managers, and GDK makes a best effort to get it to happen.
3318  *
3319  * If the window wasn't maximized, then this function does nothing.
3320  * 
3321  **/
3322 void
3323 gdk_window_unmaximize (GdkWindow *window)
3324 {
3325   g_return_if_fail (GDK_IS_WINDOW (window));
3326
3327   if (GDK_WINDOW_DESTROYED (window))
3328     return;
3329
3330   if (GDK_WINDOW_IS_MAPPED (window))
3331     gdk_wmspec_change_state (FALSE, window,
3332                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
3333                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
3334   else
3335     gdk_synthesize_window_state (window,
3336                                  GDK_WINDOW_STATE_MAXIMIZED,
3337                                  0);
3338 }
3339
3340 /**
3341  * gdk_window_set_group:
3342  * @window: a #GdkWindow
3343  * @leader: group leader window
3344  *
3345  * Sets the group leader window for @window. By default,
3346  * GDK sets the group leader for all toplevel windows
3347  * to a global window implicitly created by GDK. With this function
3348  * you can override this default.
3349  *
3350  * The group leader window allows the window manager to distinguish
3351  * all windows that belong to a single application. It may for example
3352  * allow users to minimize/unminimize all windows belonging to an
3353  * application at once. You should only set a non-default group window
3354  * if your application pretends to be multiple applications.
3355  * The group leader window may not be changed after a window has been
3356  * mapped (with gdk_window_show() for example).
3357  * 
3358  **/
3359 void          
3360 gdk_window_set_group (GdkWindow *window, 
3361                       GdkWindow *leader)
3362 {
3363   XWMHints *wm_hints;
3364   
3365   g_return_if_fail (window != NULL);
3366   g_return_if_fail (GDK_IS_WINDOW (window));
3367   g_return_if_fail (leader != NULL);
3368   g_return_if_fail (GDK_IS_WINDOW (leader));
3369
3370   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
3371     return;
3372   
3373   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
3374                           GDK_WINDOW_XID (window));
3375   if (!wm_hints)
3376     wm_hints = XAllocWMHints ();
3377
3378   wm_hints->flags |= WindowGroupHint;
3379   wm_hints->window_group = GDK_WINDOW_XID (leader);
3380
3381   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
3382                GDK_WINDOW_XID (window), wm_hints);
3383   XFree (wm_hints);
3384 }
3385
3386 static MotifWmHints *
3387 gdk_window_get_mwm_hints (GdkWindow *window)
3388 {
3389   GdkDisplay *display;
3390   Atom hints_atom = None;
3391   MotifWmHints *hints;
3392   Atom type;
3393   gint format;
3394   gulong nitems;
3395   gulong bytes_after;
3396   
3397   if (GDK_WINDOW_DESTROYED (window))
3398     return NULL;
3399
3400   display = gdk_drawable_get_display (window);
3401   
3402   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
3403
3404   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
3405                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3406                       False, AnyPropertyType, &type, &format, &nitems,
3407                       &bytes_after, (guchar **)&hints);
3408
3409   if (type == None)
3410     return NULL;
3411   
3412   return hints;
3413 }
3414
3415 static void
3416 gdk_window_set_mwm_hints (GdkWindow *window,
3417                           MotifWmHints *new_hints)
3418 {
3419   GdkDisplay *display;
3420   Atom hints_atom = None;
3421   MotifWmHints *hints;
3422   Atom type;
3423   gint format;
3424   gulong nitems;
3425   gulong bytes_after;
3426   
3427   if (GDK_WINDOW_DESTROYED (window))
3428     return;
3429   
3430   display = gdk_drawable_get_display (window);
3431   
3432   hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
3433
3434   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
3435                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
3436                       False, AnyPropertyType, &type, &format, &nitems,
3437                       &bytes_after, (guchar **)&hints);
3438   
3439   if (type == None)
3440     hints = new_hints;
3441   else
3442     {
3443       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
3444         {
3445           hints->flags |= MWM_HINTS_FUNCTIONS;
3446           hints->functions = new_hints->functions;
3447         }
3448       if (new_hints->flags & MWM_HINTS_DECORATIONS)
3449         {
3450           hints->flags |= MWM_HINTS_DECORATIONS;
3451           hints->decorations = new_hints->decorations;
3452         }
3453     }
3454   
3455   XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
3456                    hints_atom, hints_atom, 32, PropModeReplace,
3457                    (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
3458   
3459   if (hints != new_hints)
3460     XFree (hints);
3461 }
3462
3463 /**
3464  * gdk_window_set_decorations:
3465  * @window: a #GdkWindow
3466  * @decorations: decoration hint mask
3467  *
3468  * "Decorations" are the features the window manager adds to a toplevel #GdkWindow.
3469  * This function sets the traditional Motif window manager hints that tell the
3470  * window manager which decorations you would like your window to have.
3471  * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
3472  * using the GDK function directly.
3473  *
3474  * The @decorations argument is the logical OR of the fields in
3475  * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
3476  * mask, the other bits indicate which decorations should be turned off.
3477  * If #GDK_DECOR_ALL is not included, then the other bits indicate
3478  * which decorations should be turned on.
3479  *
3480  * Most window managers honor a decorations hint of 0 to disable all decorations,
3481  * but very few honor all possible combinations of bits.
3482  * 
3483  **/
3484 void
3485 gdk_window_set_decorations (GdkWindow      *window,
3486                             GdkWMDecoration decorations)
3487 {
3488   MotifWmHints hints;
3489   
3490   g_return_if_fail (window != NULL);
3491   g_return_if_fail (GDK_IS_WINDOW (window));
3492   
3493   hints.flags = MWM_HINTS_DECORATIONS;
3494   hints.decorations = decorations;
3495   
3496   gdk_window_set_mwm_hints (window, &hints);
3497 }
3498
3499 /**
3500  * gdk_window_get_decorations:
3501  * @window: The #GdkWindow to get the decorations from
3502  * @decorations: The window decorations will be written here
3503  *
3504  * Returns the decorations set on the GdkWindow with #gdk_window_set_decorations
3505  * Returns: TRUE if the window has decorations set, FALSE otherwise.
3506  **/
3507 gboolean
3508 gdk_window_get_decorations(GdkWindow *window,
3509                            GdkWMDecoration *decorations)
3510 {
3511   MotifWmHints *hints;
3512   gboolean result = FALSE;
3513
3514   hints = gdk_window_get_mwm_hints (window);
3515   
3516   if (hints)
3517     {
3518       if (hints->flags & MWM_HINTS_DECORATIONS)
3519         {
3520           *decorations = hints->decorations;
3521           result = TRUE;
3522         }
3523       
3524       XFree (hints);
3525     }
3526
3527   return result;
3528 }
3529
3530 /**
3531  * gdk_window_set_functions:
3532  * @window: a #GdkWindow
3533  * @functions: bitmask of operations to allow on @window
3534  *
3535  * This function isn't really good for much. It sets the traditional
3536  * Motif window manager hint for which operations the window manager
3537  * should allow on a toplevel window. However, few window managers do
3538  * anything reliable or interesting with this hint. Many ignore it
3539  * entirely.
3540  *
3541  * The @functions argument is the logical OR of values from the
3542  * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
3543  * then the other bits indicate which functions to disable; if
3544  * it doesn't include #GDK_FUNC_ALL, it indicates which functions to
3545  * enable.
3546  * 
3547  **/
3548 void
3549 gdk_window_set_functions (GdkWindow    *window,
3550                           GdkWMFunction functions)
3551 {
3552   MotifWmHints hints;
3553   
3554   g_return_if_fail (window != NULL);
3555   g_return_if_fail (GDK_IS_WINDOW (window));
3556   
3557   hints.flags = MWM_HINTS_FUNCTIONS;
3558   hints.functions = functions;
3559   
3560   gdk_window_set_mwm_hints (window, &hints);
3561 }
3562
3563 #ifdef HAVE_SHAPE_EXT
3564
3565 /* 
3566  * propagate the shapes from all child windows of a GDK window to the parent 
3567  * window. Shamelessly ripped from Enlightenment's code
3568  * 
3569  * - Raster
3570  */
3571 struct _gdk_span
3572 {
3573   gint                start;
3574   gint                end;
3575   struct _gdk_span    *next;
3576 };
3577
3578 static void
3579 gdk_add_to_span (struct _gdk_span **s,
3580                  gint               x,
3581                  gint               xx)
3582 {
3583   struct _gdk_span *ptr1, *ptr2, *noo, *ss;
3584   gchar             spanning;
3585   
3586   ptr2 = NULL;
3587   ptr1 = *s;
3588   spanning = 0;
3589   ss = NULL;
3590   /* scan the spans for this line */
3591   while (ptr1)
3592     {
3593       /* -- -> new span */
3594       /* == -> existing span */
3595       /* ## -> spans intersect */
3596       /* if we are in the middle of spanning the span into the line */
3597       if (spanning)
3598         {
3599           /* case: ---- ==== */
3600           if (xx < ptr1->start - 1)
3601             {
3602               /* ends before next span - extend to here */
3603               ss->end = xx;
3604               return;
3605             }
3606           /* case: ----##=== */
3607           else if (xx <= ptr1->end)
3608             {
3609               /* crosses into next span - delete next span and append */
3610               ss->end = ptr1->end;
3611               ss->next = ptr1->next;
3612               g_free (ptr1);
3613               return;
3614             }
3615           /* case: ---###--- */
3616           else
3617             {
3618               /* overlaps next span - delete and keep checking */
3619               ss->next = ptr1->next;
3620               g_free (ptr1);
3621               ptr1 = ss;
3622             }
3623         }
3624       /* otherwise havent started spanning it in yet */
3625       else
3626         {
3627           /* case: ---- ==== */
3628           if (xx < ptr1->start - 1)
3629             {
3630               /* insert span here in list */
3631               noo = g_malloc (sizeof (struct _gdk_span));
3632               
3633               if (noo)
3634                 {
3635                   noo->start = x;
3636                   noo->end = xx;
3637                   noo->next = ptr1;
3638                   if (ptr2)
3639                     ptr2->next = noo;
3640                   else
3641                     *s = noo;
3642                 }
3643               return;
3644             }
3645           /* case: ----##=== */
3646           else if ((x < ptr1->start) && (xx <= ptr1->end))
3647             {
3648               /* expand this span to the left point of the new one */
3649               ptr1->start = x;
3650               return;
3651             }
3652           /* case: ===###=== */
3653           else if ((x >= ptr1->start) && (xx <= ptr1->end))
3654             {
3655               /* throw the span away */
3656               return;
3657             }
3658           /* case: ---###--- */
3659           else if ((x < ptr1->start) && (xx > ptr1->end))
3660             {
3661               ss = ptr1;
3662               spanning = 1;
3663               ptr1->start = x;
3664               ptr1->end = xx;
3665             }
3666           /* case: ===##---- */
3667           else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end))
3668             {
3669               ss = ptr1;
3670               spanning = 1;
3671               ptr1->end = xx;
3672             }
3673           /* case: ==== ---- */
3674           /* case handled by next loop iteration - first case */
3675         }
3676       ptr2 = ptr1;
3677       ptr1 = ptr1->next;
3678     }
3679   /* it started in the middle but spans beyond your current list */
3680   if (spanning)
3681     {
3682       ptr2->end = xx;
3683       return;
3684     }
3685   /* it does not start inside a span or in the middle, so add it to the end */
3686   noo = g_malloc (sizeof (struct _gdk_span));
3687   
3688   if (noo)
3689     {
3690       noo->start = x;
3691       noo->end = xx;
3692       if (ptr2)
3693         {
3694           noo->next = ptr2->next;
3695           ptr2->next = noo;
3696         }
3697       else
3698         {
3699           noo->next = NULL;
3700           *s = noo;
3701         }
3702     }
3703   return;
3704 }
3705
3706 static void
3707 gdk_add_rectangles (Display           *disp,
3708                     Window             win,
3709                     struct _gdk_span **spans,
3710                     gint               basew,
3711                     gint               baseh,
3712                     gint               x,
3713                     gint               y)
3714 {
3715   gint a, k;
3716   gint x1, y1, x2, y2;
3717   gint rn, ord;
3718   XRectangle *rl;
3719   
3720   rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord);
3721   if (rl)
3722     {
3723       /* go through all clip rects in this window's shape */
3724       for (k = 0; k < rn; k++)
3725         {
3726           /* for each clip rect, add it to each line's spans */
3727           x1 = x + rl[k].x;
3728           x2 = x + rl[k].x + (rl[k].width - 1);
3729           y1 = y + rl[k].y;
3730           y2 = y + rl[k].y + (rl[k].height - 1);
3731           if (x1 < 0)
3732             x1 = 0;
3733           if (y1 < 0)
3734             y1 = 0;
3735           if (x2 >= basew)
3736             x2 = basew - 1;
3737           if (y2 >= baseh)
3738             y2 = baseh - 1;
3739           for (a = y1; a <= y2; a++)
3740             {
3741               if ((x2 - x1) >= 0)
3742                 gdk_add_to_span (&spans[a], x1, x2);
3743             }
3744         }
3745       XFree (rl);
3746     }
3747 }
3748
3749 static void
3750 gdk_propagate_shapes (Display *disp,
3751                       Window   win,
3752                       gboolean merge)
3753 {
3754   Window              rt, par, *list = NULL;
3755   gint                i, j, num = 0, num_rects = 0;
3756   gint                x, y, contig;
3757   guint               w, h, d;
3758   gint                baseh, basew;
3759   XRectangle         *rects = NULL;
3760   struct _gdk_span  **spans = NULL, *ptr1, *ptr2, *ptr3;
3761   XWindowAttributes   xatt;
3762   
3763   XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d);
3764   if (h <= 0)
3765     return;
3766   basew = w;
3767   baseh = h;
3768   spans = g_malloc (sizeof (struct _gdk_span *) * h);
3769   
3770   for (i = 0; i < h; i++)
3771     spans[i] = NULL;
3772   XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num);
3773   if (list)
3774     {
3775       /* go through all child windows and create/insert spans */
3776       for (i = 0; i < num; i++)
3777         {
3778           if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped))
3779             if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d))
3780               gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y);
3781         }
3782       if (merge)
3783         gdk_add_rectangles (disp, win, spans, basew, baseh, x, y);
3784       
3785       /* go through the spans list and build a list of rects */
3786       rects = g_malloc (sizeof (XRectangle) * 256);
3787       num_rects = 0;
3788       for (i = 0; i < baseh; i++)
3789         {
3790           ptr1 = spans[i];
3791           /* go through the line for all spans */
3792           while (ptr1)
3793             {
3794               rects[num_rects].x = ptr1->start;
3795               rects[num_rects].y = i;
3796               rects[num_rects].width = ptr1->end - ptr1->start + 1;
3797               rects[num_rects].height = 1;
3798               j = i + 1;
3799               /* if there are more lines */
3800               contig = 1;
3801               /* while contigous rects (same start/end coords) exist */
3802               while ((contig) && (j < baseh))
3803                 {
3804                   /* search next line for spans matching this one */
3805                   contig = 0;
3806                   ptr2 = spans[j];
3807                   ptr3 = NULL;
3808                   while (ptr2)
3809                     {
3810                       /* if we have an exact span match set contig */
3811                       if ((ptr2->start == ptr1->start) &&
3812                           (ptr2->end == ptr1->end))
3813                         {
3814                           contig = 1;
3815                           /* remove the span - not needed */
3816                           if (ptr3)
3817                             {
3818                               ptr3->next = ptr2->next;
3819                               g_free (ptr2);
3820                               ptr2 = NULL;
3821                             }
3822                           else
3823                             {
3824                               spans[j] = ptr2->next;
3825                               g_free (ptr2);
3826                               ptr2 = NULL;
3827                             }
3828                           break;
3829                         }
3830                       /* gone past the span point no point looking */
3831                       else if (ptr2->start < ptr1->start)
3832                         break;
3833                       if (ptr2)
3834                         {
3835                           ptr3 = ptr2;
3836                           ptr2 = ptr2->next;
3837                         }
3838                     }
3839                   /* if a contiguous span was found increase the rect h */
3840                   if (contig)
3841                     {
3842                       rects[num_rects].height++;
3843                       j++;
3844                     }
3845                 }
3846               /* up the rect count */
3847               num_rects++;
3848               /* every 256 new rects increase the rect array */
3849               if ((num_rects % 256) == 0)
3850                 rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256));
3851               ptr1 = ptr1->next;
3852             }
3853         }
3854       /* set the rects as the shape mask */
3855       if (rects)
3856         {
3857           XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects,
3858                                    ShapeSet, YXSorted);
3859           g_free (rects);
3860         }
3861       XFree (list);
3862     }
3863   /* free up all the spans we made */
3864   for (i = 0; i < baseh; i++)
3865     {
3866       ptr1 = spans[i];
3867       while (ptr1)
3868         {
3869           ptr2 = ptr1;
3870           ptr1 = ptr1->next;
3871           g_free (ptr2);
3872         }
3873     }
3874   g_free (spans);
3875 }
3876
3877 #endif /* HAVE_SHAPE_EXT */
3878
3879 /**
3880  * gdk_window_set_child_shapes:
3881  * @window: a #GdkWindow
3882  * 
3883  * Sets the shape mask of @window to the union of shape masks
3884  * for all children of @window, ignoring the shape mask of @window
3885  * itself. Contrast with gdk_window_merge_child_shapes() which includes
3886  * the shape mask of @window in the masks to be merged.
3887  **/
3888 void
3889 gdk_window_set_child_shapes (GdkWindow *window)
3890 {
3891   g_return_if_fail (window != NULL);
3892   g_return_if_fail (GDK_IS_WINDOW (window));
3893   
3894 #ifdef HAVE_SHAPE_EXT
3895   if (!GDK_WINDOW_DESTROYED (window) &&
3896       gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
3897     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3898                           GDK_WINDOW_XID (window), FALSE);
3899 #endif   
3900 }
3901
3902 /**
3903  * gdk_window_merge_child_shapes:
3904  * @window: a #GdkWindow
3905  * 
3906  * Merges the shape masks for any child windows into the
3907  * shape mask for @window. i.e. the union of all masks
3908  * for @window and its children will become the new mask
3909  * for @window. See gdk_window_shape_combine_mask().
3910  *
3911  * This function is distinct from gdk_window_set_child_shapes()
3912  * because it includes @window's shape mask in the set of shapes to
3913  * be merged.
3914  * 
3915  **/
3916 void
3917 gdk_window_merge_child_shapes (GdkWindow *window)
3918 {
3919   g_return_if_fail (window != NULL);
3920   g_return_if_fail (GDK_IS_WINDOW (window));
3921   
3922 #ifdef HAVE_SHAPE_EXT
3923   if (!GDK_WINDOW_DESTROYED (window) &&
3924       gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window)))
3925     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3926                           GDK_WINDOW_XID (window), TRUE);
3927 #endif   
3928 }
3929
3930 /* Support for windows that can be guffaw-scrolled
3931  * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
3932  */
3933
3934 static gboolean
3935 gdk_window_gravity_works (GdkWindow *window)
3936 {
3937   enum { UNKNOWN, NO, YES };
3938   static gint gravity_works = UNKNOWN;
3939   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (window);
3940   
3941   if (gravity_works == UNKNOWN)
3942     {
3943       GdkWindowAttr attr;
3944       GdkWindow *parent;
3945       GdkWindow *child;
3946       gint y;
3947       
3948       /* This particular server apparently has a bug so that the test
3949        * works but the actual code crashes it
3950        */
3951       if ((!strcmp (XServerVendor (GDK_DISPLAY_XDISPLAY (display)),
3952                     "Sun Microsystems, Inc.")) &&
3953           (VendorRelease (GDK_DISPLAY_XDISPLAY (display)) == 3400))
3954         {
3955           gravity_works = NO;
3956           return FALSE;
3957         }
3958       
3959       attr.window_type = GDK_WINDOW_TEMP;
3960       attr.wclass = GDK_INPUT_OUTPUT;
3961       attr.x = 0;
3962       attr.y = 0;
3963       attr.width = 100;
3964       attr.height = 100;
3965       attr.event_mask = 0;
3966       
3967       parent = gdk_window_new (gdk_screen_get_root_window (GDK_DRAWABLE_SCREEN (window)),
3968                                &attr, GDK_WA_X | GDK_WA_Y);
3969       
3970       attr.window_type = GDK_WINDOW_CHILD;
3971       child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
3972       
3973       gdk_window_set_static_win_gravity (child, TRUE);
3974       
3975       gdk_window_resize (parent, 100, 110);
3976
3977       gdk_window_move (parent, 0, -10);
3978       gdk_window_move_resize (parent, 0, 0, 100, 100);
3979       
3980       gdk_window_resize (parent, 100, 110);
3981       gdk_window_move (parent, 0, -10);
3982       gdk_window_move_resize (parent, 0, 0, 100, 100);
3983       
3984       gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
3985       
3986       gdk_window_destroy (parent);
3987       gdk_window_destroy (child);
3988       
3989       gravity_works = ((y == -20) ? YES : NO);
3990     }
3991   
3992   return (gravity_works == YES);
3993 }
3994
3995 static void
3996 gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
3997 {
3998   XSetWindowAttributes xattributes;
3999   GdkWindowObject *private;
4000   guint xattributes_mask = 0;
4001   
4002   g_return_if_fail (window != NULL);
4003
4004   private = GDK_WINDOW_OBJECT (window);
4005   if (private->input_only)
4006     return;
4007   
4008   xattributes.bit_gravity = StaticGravity;
4009   xattributes_mask |= CWBitGravity;
4010   xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
4011   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
4012                            GDK_WINDOW_XID (window),
4013                            CWBitGravity,  &xattributes);
4014 }
4015
4016 static void
4017 gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
4018 {
4019   XSetWindowAttributes xattributes;
4020   
4021   g_return_if_fail (window != NULL);
4022   
4023   xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
4024   
4025   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
4026                            GDK_WINDOW_XID (window),
4027                            CWWinGravity,  &xattributes);
4028 }
4029
4030 /**
4031  * gdk_window_set_static_gravities:
4032  * @window: a #GdkWindow
4033  * @use_static: %TRUE to turn on static gravity
4034  *
4035  * Set the bit gravity of the given window to static, and flag it so
4036  * all children get static subwindow gravity. This is used if you are
4037  * implementing scary features that involve deep knowledge of the
4038  * windowing system. Don't worry about it unless you have to.
4039  * 
4040  * Return value: %TRUE if the server supports static gravity
4041  **/
4042 gboolean 
4043 gdk_window_set_static_gravities (GdkWindow *window,
4044                                  gboolean   use_static)
4045 {
4046   GdkWindowObject *private = (GdkWindowObject *)window;
4047   GList *tmp_list;
4048   
4049   g_return_val_if_fail (window != NULL, FALSE);
4050   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
4051
4052   if (!use_static == !private->guffaw_gravity)
4053     return TRUE;
4054   
4055   if (use_static && !gdk_window_gravity_works (window))
4056     return FALSE;
4057   
4058   private->guffaw_gravity = use_static;
4059   
4060   if (!GDK_WINDOW_DESTROYED (window))
4061     {
4062       gdk_window_set_static_bit_gravity (window, use_static);
4063       
4064       tmp_list = private->children;
4065       while (tmp_list)
4066         {
4067           gdk_window_set_static_win_gravity (tmp_list->data, use_static);
4068           
4069           tmp_list = tmp_list->next;
4070         }
4071     }
4072   
4073   return TRUE;
4074 }
4075
4076 static void
4077 wmspec_moveresize (GdkWindow *window,
4078                    gint       direction,
4079                    gint       root_x,
4080                    gint       root_y,
4081                    guint32    timestamp)     
4082 {
4083   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
4084   
4085   XEvent xev;
4086
4087   /* Release passive grab */
4088   gdk_display_pointer_ungrab (display, timestamp);
4089
4090   xev.xclient.type = ClientMessage;
4091   xev.xclient.serial = 0;
4092   xev.xclient.send_event = True;
4093   xev.xclient.window = GDK_WINDOW_XID (window);
4094   xev.xclient.message_type =
4095     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
4096   xev.xclient.format = 32;
4097   xev.xclient.data.l[0] = root_x;
4098   xev.xclient.data.l[1] = root_y;
4099   xev.xclient.data.l[2] = direction;
4100   xev.xclient.data.l[3] = 0;
4101   xev.xclient.data.l[4] = 0;
4102   
4103   XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
4104               SubstructureRedirectMask | SubstructureNotifyMask,
4105               &xev);
4106 }
4107
4108 typedef struct _MoveResizeData MoveResizeData;
4109
4110 struct _MoveResizeData
4111 {
4112   GdkDisplay *display;
4113   
4114   GdkWindow *moveresize_window;
4115   GdkWindow *moveresize_emulation_window;
4116   gboolean is_resize;
4117   GdkWindowEdge resize_edge;
4118   gint moveresize_button;
4119   gint moveresize_x;
4120   gint moveresize_y;
4121   gint moveresize_orig_x;
4122   gint moveresize_orig_y;
4123   gint moveresize_orig_width;
4124   gint moveresize_orig_height;
4125   GdkWindowHints moveresize_geom_mask;
4126   GdkGeometry moveresize_geometry;
4127   Time moveresize_process_time;
4128   XEvent *moveresize_pending_event;
4129 };
4130
4131 /* From the WM spec */
4132 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
4133 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
4134 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
4135 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
4136 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
4137 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
4138 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
4139 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
4140 #define _NET_WM_MOVERESIZE_MOVE              8
4141
4142 static void
4143 wmspec_resize_drag (GdkWindow     *window,
4144                     GdkWindowEdge  edge,
4145                     gint           button,
4146                     gint           root_x,
4147                     gint           root_y,
4148                     guint32        timestamp)
4149 {
4150   gint direction;
4151   
4152   /* Let the compiler turn a switch into a table, instead
4153    * of doing the table manually, this way is easier to verify.
4154    */
4155   switch (edge)
4156     {
4157     case GDK_WINDOW_EDGE_NORTH_WEST:
4158       direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
4159       break;
4160
4161     case GDK_WINDOW_EDGE_NORTH:
4162       direction = _NET_WM_MOVERESIZE_SIZE_TOP;
4163       break;
4164
4165     case GDK_WINDOW_EDGE_NORTH_EAST:
4166       direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
4167       break;
4168
4169     case GDK_WINDOW_EDGE_WEST:
4170       direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
4171       break;
4172
4173     case GDK_WINDOW_EDGE_EAST:
4174       direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
4175       break;
4176
4177     case GDK_WINDOW_EDGE_SOUTH_WEST:
4178       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
4179       break;
4180
4181     case GDK_WINDOW_EDGE_SOUTH:
4182       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
4183       break;
4184
4185     case GDK_WINDOW_EDGE_SOUTH_EAST:
4186       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
4187       break;
4188
4189     default:
4190       g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!",
4191                  edge);
4192       return;
4193       break;
4194     }
4195   
4196   wmspec_moveresize (window, direction, root_x, root_y, timestamp);
4197 }
4198
4199 static MoveResizeData *
4200 get_move_resize_data (GdkDisplay *display)
4201 {
4202   MoveResizeData *mv_resize;
4203   static GQuark move_resize_quark = 0;
4204
4205   if (!move_resize_quark)
4206     move_resize_quark = g_quark_from_static_string ("gdk-window-moveresize");
4207   
4208   mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark);
4209
4210   if (!mv_resize)
4211     {
4212       mv_resize = g_new0 (MoveResizeData, 1);
4213       mv_resize->display = display;
4214       
4215       g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize);
4216     }
4217
4218   return mv_resize;
4219 }
4220
4221 static void
4222 update_pos (MoveResizeData *mv_resize,
4223             gint            new_root_x,
4224             gint            new_root_y)
4225 {
4226   gint dx, dy;
4227
4228   dx = new_root_x - mv_resize->moveresize_x;
4229   dy = new_root_y - mv_resize->moveresize_y;
4230
4231   if (mv_resize->is_resize)
4232     {
4233       gint w, h;
4234
4235       w = mv_resize->moveresize_orig_width;
4236       h = mv_resize->moveresize_orig_height;
4237
4238       switch (mv_resize->resize_edge)
4239         {
4240         case GDK_WINDOW_EDGE_SOUTH_EAST:
4241           w += dx;
4242           h += dy;
4243           break;
4244         }
4245
4246       w = MAX (w, 1);
4247       h = MAX (h, 1);
4248
4249       if (mv_resize->moveresize_geom_mask)
4250         {
4251           gdk_window_constrain_size (&mv_resize->moveresize_geometry,
4252                                      mv_resize->moveresize_geom_mask,
4253                                      w, h, &w, &h);
4254         }
4255
4256       gdk_window_resize (mv_resize->moveresize_window, w, h);
4257     }
4258   else
4259     {
4260       gint x, y;
4261
4262       x = mv_resize->moveresize_orig_x + dx;
4263       y = mv_resize->moveresize_orig_y + dy;
4264
4265       gdk_window_move (mv_resize->moveresize_window, x, y);
4266     }
4267 }
4268
4269 static void
4270 finish_drag (MoveResizeData *mv_resize)
4271 {
4272   gdk_window_destroy (mv_resize->moveresize_emulation_window);
4273   mv_resize->moveresize_emulation_window = NULL;
4274   mv_resize->moveresize_window = NULL;
4275
4276   if (mv_resize->moveresize_pending_event)
4277     {
4278       g_free (mv_resize->moveresize_pending_event);
4279       mv_resize->moveresize_pending_event = NULL;
4280     }
4281 }
4282
4283 static int
4284 lookahead_motion_predicate (Display *xdisplay,
4285                             XEvent  *event,
4286                             XPointer arg)
4287 {
4288   gboolean *seen_release = (gboolean *)arg;
4289   GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
4290   MoveResizeData *mv_resize = get_move_resize_data (display);
4291
4292   if (*seen_release)
4293     return False;
4294
4295   switch (event->xany.type)
4296     {
4297     case ButtonRelease:
4298       *seen_release = TRUE;
4299       break;
4300     case MotionNotify:
4301       mv_resize->moveresize_process_time = event->xmotion.time;
4302       break;
4303     default:
4304       break;
4305     }
4306
4307   return False;
4308 }
4309
4310 static gboolean
4311 moveresize_lookahead (MoveResizeData *mv_resize,
4312                       XEvent         *event)
4313 {
4314   XEvent tmp_event;
4315   gboolean seen_release = FALSE;
4316
4317   if (mv_resize->moveresize_process_time)
4318     {
4319       if (event->xmotion.time == mv_resize->moveresize_process_time)
4320         {
4321           mv_resize->moveresize_process_time = 0;
4322           return TRUE;
4323         }
4324       else
4325         return FALSE;
4326     }
4327
4328   XCheckIfEvent (event->xany.display, &tmp_event,
4329                  lookahead_motion_predicate, (XPointer) & seen_release);
4330
4331   return mv_resize->moveresize_process_time == 0;
4332 }
4333         
4334 gboolean
4335 _gdk_moveresize_handle_event (XEvent *event)
4336 {
4337   guint button_mask = 0;
4338   GdkWindowObject *window_private;
4339   GdkDisplay *display= gdk_x11_lookup_xdisplay (event->xany.display);
4340   MoveResizeData *mv_resize = get_move_resize_data (display);
4341
4342   if (!mv_resize->moveresize_window)
4343     return FALSE;
4344
4345   window_private = (GdkWindowObject *) mv_resize->moveresize_window;
4346
4347   button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
4348
4349   switch (event->xany.type)
4350     {
4351     case MotionNotify:
4352       if (window_private->resize_count > 0)
4353         {
4354           if (mv_resize->moveresize_pending_event)
4355             *mv_resize->moveresize_pending_event = *event;
4356           else
4357             mv_resize->moveresize_pending_event =
4358               g_memdup (event, sizeof (XEvent));
4359
4360           break;
4361         }
4362       if (!moveresize_lookahead (mv_resize, event))
4363         break;
4364
4365       update_pos (mv_resize,
4366                   event->xmotion.x_root,
4367                   event->xmotion.y_root);
4368
4369       /* This should never be triggered in normal cases, but in the
4370        * case where the drag started without an implicit grab being
4371        * in effect, we could miss the release if it occurs before
4372        * we grab the pointer; this ensures that we will never
4373        * get a permanently stuck grab.
4374        */
4375       if ((event->xmotion.state & button_mask) == 0)
4376         finish_drag (mv_resize);
4377       break;
4378
4379     case ButtonRelease:
4380       update_pos (mv_resize,
4381                   event->xbutton.x_root,
4382                   event->xbutton.y_root);
4383
4384       if (event->xbutton.button == mv_resize->moveresize_button)
4385         finish_drag (mv_resize);
4386       break;
4387     }
4388   return TRUE;
4389 }
4390
4391 gboolean 
4392 _gdk_moveresize_configure_done (GdkDisplay *display,
4393                                 GdkWindow  *window)
4394 {
4395   XEvent *tmp_event;
4396   MoveResizeData *mv_resize = get_move_resize_data (display);
4397   
4398   if (window != mv_resize->moveresize_window)
4399     return FALSE;
4400
4401   g_assert (mv_resize != NULL);
4402
4403   if (mv_resize->moveresize_pending_event)
4404     {
4405       tmp_event = mv_resize->moveresize_pending_event;
4406       mv_resize->moveresize_pending_event = NULL;
4407       _gdk_moveresize_handle_event (tmp_event);
4408       g_free (tmp_event);
4409     }
4410   
4411   return TRUE;
4412 }
4413
4414 static void
4415 create_moveresize_window (MoveResizeData *mv_resize,
4416                           guint32         timestamp)
4417 {
4418   GdkWindowAttr attributes;
4419   gint attributes_mask;
4420   GdkGrabStatus status;
4421
4422   g_assert (mv_resize->moveresize_emulation_window == NULL);
4423
4424   attributes.x = -100;
4425   attributes.y = -100;
4426   attributes.width = 10;
4427   attributes.height = 10;
4428   attributes.window_type = GDK_WINDOW_TEMP;
4429   attributes.wclass = GDK_INPUT_ONLY;
4430   attributes.override_redirect = TRUE;
4431   attributes.event_mask = 0;
4432
4433   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
4434
4435   mv_resize->moveresize_emulation_window = 
4436     gdk_window_new (gdk_screen_get_root_window (gdk_display_get_default_screen (mv_resize->display)),
4437                     &attributes,
4438                     attributes_mask);
4439
4440   gdk_window_show (mv_resize->moveresize_emulation_window);
4441
4442   status = gdk_pointer_grab (mv_resize->moveresize_emulation_window,
4443                              FALSE,
4444                              GDK_BUTTON_RELEASE_MASK |
4445                              GDK_POINTER_MOTION_MASK,
4446                              NULL,
4447                              NULL,
4448                              timestamp);
4449
4450   if (status != GDK_GRAB_SUCCESS)
4451     {
4452       /* If this fails, some other client has grabbed the window
4453        * already.
4454        */
4455       gdk_window_destroy (mv_resize->moveresize_emulation_window);
4456       mv_resize->moveresize_emulation_window = NULL;
4457     }
4458
4459   mv_resize->moveresize_process_time = 0;
4460 }
4461
4462 static void
4463 emulate_resize_drag (GdkWindow     *window,
4464                      GdkWindowEdge  edge,
4465                      gint           button,
4466                      gint           root_x,
4467                      gint           root_y,
4468                      guint32        timestamp)
4469 {
4470   MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window));
4471
4472   mv_resize->is_resize = TRUE;
4473   mv_resize->moveresize_button = button;
4474   mv_resize->resize_edge = edge;
4475   mv_resize->moveresize_x = root_x;
4476   mv_resize->moveresize_y = root_y;
4477   mv_resize->moveresize_window = GDK_WINDOW (g_object_ref (G_OBJECT (window)));
4478
4479   gdk_window_get_size (window,
4480                        &mv_resize->moveresize_orig_width,
4481                        &mv_resize->moveresize_orig_height);
4482
4483   mv_resize->moveresize_geom_mask = 0;
4484   gdk_window_get_geometry_hints (window,
4485                                  &mv_resize->moveresize_geometry,
4486                                  &mv_resize->moveresize_geom_mask);
4487
4488   create_moveresize_window (mv_resize, timestamp);
4489 }
4490
4491 static void
4492 emulate_move_drag (GdkWindow     *window,
4493                    gint           button,
4494                    gint           root_x,
4495                    gint           root_y,
4496                    guint32        timestamp)
4497 {
4498   MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window));
4499   
4500   mv_resize->is_resize = FALSE;
4501   mv_resize->moveresize_button = button;
4502   mv_resize->moveresize_x = root_x;
4503   mv_resize->moveresize_y = root_y;
4504
4505   mv_resize->moveresize_window = 
4506     GDK_WINDOW (g_object_ref (G_OBJECT (window)));
4507
4508   gdk_window_get_deskrelative_origin (mv_resize->moveresize_window,
4509                                       &mv_resize->moveresize_orig_x,
4510                                       &mv_resize->moveresize_orig_y);
4511
4512   create_moveresize_window (mv_resize, timestamp);
4513 }
4514
4515 /**
4516  * gdk_window_begin_resize_drag:
4517  * @window: a #GdkWindow
4518  * @edge: the edge or corner from which the drag is started
4519  * @button: the button being used to drag
4520  * @root_x: root window X coordinate of mouse click that began the drag
4521  * @root_y: root window Y coordinate of mouse click that began the drag
4522  * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
4523  *
4524  * Begins a window resize operation (for a toplevel window).
4525  * You might use this function to implement a "window resize grip," for
4526  * example; in fact #GtkStatusbar uses it. The function works best
4527  * with window managers that support the Extended Window Manager Hints spec
4528  * (see http://www.freedesktop.org), but has a fallback implementation
4529  * for other window managers.
4530  * 
4531  **/
4532 void
4533 gdk_window_begin_resize_drag (GdkWindow     *window,
4534                               GdkWindowEdge  edge,
4535                               gint           button,
4536                               gint           root_x,
4537                               gint           root_y,
4538                               guint32        timestamp)
4539 {
4540   g_return_if_fail (GDK_IS_WINDOW (window));
4541
4542   if (GDK_WINDOW_DESTROYED (window))
4543     return;
4544
4545   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
4546                                            gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
4547     wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp);
4548   else
4549     emulate_resize_drag (window, edge, button, root_x, root_y, timestamp);
4550 }
4551
4552 /**
4553  * gdk_window_begin_move_drag:
4554  * @window: a #GdkWindow
4555  * @button: the button being used to drag
4556  * @root_x: root window X coordinate of mouse click that began the drag
4557  * @root_y: root window Y coordinate of mouse click that began the drag
4558  * @timestamp: timestamp of mouse click that began the drag
4559  *
4560  * Begins a window move operation (for a toplevel window).  You might
4561  * use this function to implement a "window move grip," for
4562  * example. The function works best with window managers that support
4563  * the Extended Window Manager Hints spec (see
4564  * http://www.freedesktop.org), but has a fallback implementation for
4565  * other window managers.
4566  * 
4567  **/
4568 void
4569 gdk_window_begin_move_drag (GdkWindow *window,
4570                             gint       button,
4571                             gint       root_x,
4572                             gint       root_y,
4573                             guint32    timestamp)
4574 {
4575   g_return_if_fail (GDK_IS_WINDOW (window));
4576
4577   if (GDK_WINDOW_DESTROYED (window))
4578     return;
4579
4580   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
4581                                            gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
4582     wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE, root_x, root_y,
4583                        timestamp);
4584   else
4585     emulate_move_drag (window, button, root_x, root_y, timestamp);
4586 }