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