]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkwindow-x11.c
add default icon
[~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 "gdk.h"
32 #include "config.h"
33
34 #include "gdkwindow.h"
35 #include "gdkinputprivate.h"
36 #include "gdkprivate-x11.h"
37 #include "gdkregion.h"
38 #include "gdkinternals.h"
39 #include "MwmUtil.h"
40 #include "gdkwindow-x11.h"
41
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45
46
47 #ifdef HAVE_SHAPE_EXT
48 #include <X11/extensions/shape.h>
49 #endif
50
51 const int gdk_event_mask_table[21] =
52 {
53   ExposureMask,
54   PointerMotionMask,
55   PointerMotionHintMask,
56   ButtonMotionMask,
57   Button1MotionMask,
58   Button2MotionMask,
59   Button3MotionMask,
60   ButtonPressMask,
61   ButtonReleaseMask,
62   KeyPressMask,
63   KeyReleaseMask,
64   EnterWindowMask,
65   LeaveWindowMask,
66   FocusChangeMask,
67   StructureNotifyMask,
68   PropertyChangeMask,
69   VisibilityChangeMask,
70   0,                            /* PROXIMITY_IN */
71   0,                            /* PROXIMTY_OUT */
72   SubstructureNotifyMask,
73   ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
74 };
75 const int gdk_nevent_masks = sizeof (gdk_event_mask_table) / sizeof (int);
76
77 /* Forward declarations */
78 static gboolean gdk_window_gravity_works          (void);
79 static void     gdk_window_set_static_win_gravity (GdkWindow *window,
80                                                    gboolean   on);
81 static gboolean gdk_window_have_shape_ext         (void);
82 static gboolean gdk_window_icon_name_set          (GdkWindow *window);
83
84 static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable);
85 static void         gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
86                                                       GdkColormap *cmap);
87 static void         gdk_window_impl_x11_get_size    (GdkDrawable *drawable,
88                                                      gint *width,
89                                                      gint *height);
90 static GdkRegion*  gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable);
91 static void gdk_window_impl_x11_init       (GdkWindowImplX11      *window);
92 static void gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass);
93 static void gdk_window_impl_x11_finalize   (GObject            *object);
94
95 static gpointer parent_class = NULL;
96
97 GType
98 gdk_window_impl_x11_get_type (void)
99 {
100   static GType object_type = 0;
101
102   if (!object_type)
103     {
104       static const GTypeInfo object_info =
105       {
106         sizeof (GdkWindowImplX11Class),
107         (GBaseInitFunc) NULL,
108         (GBaseFinalizeFunc) NULL,
109         (GClassInitFunc) gdk_window_impl_x11_class_init,
110         NULL,           /* class_finalize */
111         NULL,           /* class_data */
112         sizeof (GdkWindowImplX11),
113         0,              /* n_preallocs */
114         (GInstanceInitFunc) gdk_window_impl_x11_init,
115       };
116       
117       object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_X11,
118                                             "GdkWindowImplX11",
119                                             &object_info, 0);
120     }
121   
122   return object_type;
123 }
124
125 GType
126 _gdk_window_impl_get_type (void)
127 {
128   return gdk_window_impl_x11_get_type ();
129 }
130
131 static void
132 gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
133 {
134   impl->width = 1;
135   impl->height = 1;
136 }
137
138 static void
139 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
140 {
141   GObjectClass *object_class = G_OBJECT_CLASS (klass);
142   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
143   
144   parent_class = g_type_class_peek_parent (klass);
145
146   object_class->finalize = gdk_window_impl_x11_finalize;
147
148   drawable_class->set_colormap = gdk_window_impl_x11_set_colormap;
149   drawable_class->get_colormap = gdk_window_impl_x11_get_colormap;
150   drawable_class->get_size = gdk_window_impl_x11_get_size;
151
152   /* Visible and clip regions are the same */
153   drawable_class->get_clip_region = gdk_window_impl_x11_get_visible_region;
154   drawable_class->get_visible_region = gdk_window_impl_x11_get_visible_region;
155 }
156
157 static void
158 gdk_window_impl_x11_finalize (GObject *object)
159 {
160   GdkWindowObject *wrapper;
161   GdkDrawableImplX11 *draw_impl;
162   GdkWindowImplX11 *window_impl;
163   
164   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));
165
166   draw_impl = GDK_DRAWABLE_IMPL_X11 (object);
167   window_impl = GDK_WINDOW_IMPL_X11 (object);
168   
169   wrapper = (GdkWindowObject*) draw_impl->wrapper;
170
171   if (!GDK_WINDOW_DESTROYED (wrapper))
172     {
173       gdk_xid_table_remove (draw_impl->xid);
174       if (window_impl->focus_window)
175         gdk_xid_table_remove (window_impl->focus_window);
176     }
177
178   G_OBJECT_CLASS (parent_class)->finalize (object);
179 }
180
181 static GdkColormap*
182 gdk_window_impl_x11_get_colormap (GdkDrawable *drawable)
183 {
184   GdkDrawableImplX11 *drawable_impl;
185   GdkWindowImplX11 *window_impl;
186   
187   g_return_val_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable), NULL);
188
189   drawable_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
190   window_impl = GDK_WINDOW_IMPL_X11 (drawable);
191
192   if (!((GdkWindowObject *) drawable_impl->wrapper)->input_only && 
193       drawable_impl->colormap == NULL)
194     {
195       XWindowAttributes window_attributes;
196
197       XGetWindowAttributes (drawable_impl->xdisplay,
198                             drawable_impl->xid,
199                             &window_attributes);
200       drawable_impl->colormap =
201         gdk_colormap_lookup (window_attributes.colormap);
202     }
203   
204   return drawable_impl->colormap;
205 }
206
207 static void
208 gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
209                                   GdkColormap *cmap)
210 {
211   GdkWindowImplX11 *impl;
212   GdkDrawableImplX11 *draw_impl;
213   
214   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
215
216   impl = GDK_WINDOW_IMPL_X11 (drawable);
217   draw_impl = GDK_DRAWABLE_IMPL_X11 (drawable);
218
219   /* chain up */
220   GDK_DRAWABLE_CLASS (parent_class)->set_colormap (drawable, cmap);
221
222   if (cmap)
223     {
224       XSetWindowColormap (draw_impl->xdisplay,
225                           draw_impl->xid,
226                           GDK_COLORMAP_XCOLORMAP (cmap));
227       
228       if (((GdkWindowObject*)draw_impl->wrapper)->window_type !=
229           GDK_WINDOW_TOPLEVEL)
230         gdk_window_add_colormap_windows (GDK_WINDOW (draw_impl->wrapper));
231     }
232 }
233
234
235 static void
236 gdk_window_impl_x11_get_size (GdkDrawable *drawable,
237                               gint        *width,
238                               gint        *height)
239 {
240   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (drawable));
241
242   if (width)
243     *width = GDK_WINDOW_IMPL_X11 (drawable)->width;
244   if (height)
245     *height = GDK_WINDOW_IMPL_X11 (drawable)->height;
246 }
247
248 static GdkRegion*
249 gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable)
250 {
251   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (drawable);
252   GdkRectangle result_rect;
253
254   result_rect.x = 0;
255   result_rect.y = 0;
256   result_rect.width = impl->width;
257   result_rect.height = impl->height;
258
259   gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect);
260
261   return gdk_region_rectangle (&result_rect);
262 }
263
264 void
265 _gdk_windowing_window_init (void)
266 {
267   GdkWindowObject *private;
268   GdkWindowImplX11 *impl;
269   GdkDrawableImplX11 *draw_impl;
270   XWindowAttributes xattributes;
271   unsigned int width;
272   unsigned int height;
273   unsigned int border_width;
274   unsigned int depth;
275   int x, y;
276
277   g_assert (gdk_parent_root == NULL);
278   
279   XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window,
280                 &x, &y, &width, &height, &border_width, &depth);
281   XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes);
282
283   gdk_parent_root = g_object_new (GDK_TYPE_WINDOW, NULL);
284   private = (GdkWindowObject *)gdk_parent_root;
285   impl = GDK_WINDOW_IMPL_X11 (private->impl);
286   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
287   
288   draw_impl->xdisplay = gdk_display;
289   draw_impl->xid = gdk_root_window;
290   draw_impl->wrapper = GDK_DRAWABLE (private);
291   
292   private->window_type = GDK_WINDOW_ROOT;
293   private->depth = depth;
294   impl->width = width;
295   impl->height = height;
296   
297   gdk_xid_table_insert (&gdk_root_window, gdk_parent_root);
298 }
299
300 static GdkAtom wm_client_leader_atom = GDK_NONE;
301
302 GdkWindow*
303 gdk_window_new (GdkWindow     *parent,
304                 GdkWindowAttr *attributes,
305                 gint           attributes_mask)
306 {
307   GdkWindow *window;
308   GdkWindowObject *private;
309   GdkWindowObject *parent_private;
310   GdkWindowImplX11 *impl;
311   GdkDrawableImplX11 *draw_impl;
312   
313   GdkVisual *visual;
314   Window xparent;
315   Visual *xvisual;
316   Display *xdisplay;
317   Window xid;
318
319   XSetWindowAttributes xattributes;
320   long xattributes_mask;
321   XSizeHints size_hints;
322   XWMHints wm_hints;
323   XClassHint *class_hint;
324   int x, y, depth;
325   
326   unsigned int class;
327   char *title;
328   int i;
329   
330   g_return_val_if_fail (attributes != NULL, NULL);
331   
332   if (!parent)
333     parent = gdk_parent_root;
334
335   g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
336   
337   parent_private = (GdkWindowObject*) parent;
338   if (GDK_WINDOW_DESTROYED (parent))
339     return NULL;
340   
341   xparent = GDK_WINDOW_XID (parent);
342   
343   window = g_object_new (GDK_TYPE_WINDOW, NULL);
344   private = (GdkWindowObject *)window;
345   impl = GDK_WINDOW_IMPL_X11 (private->impl);
346   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
347   draw_impl->wrapper = GDK_DRAWABLE (window);
348   
349   xdisplay = draw_impl->xdisplay = GDK_WINDOW_XDISPLAY (parent); 
350   
351   private->parent = (GdkWindowObject *)parent;
352
353   xattributes_mask = 0;
354   
355   if (attributes_mask & GDK_WA_X)
356     x = attributes->x;
357   else
358     x = 0;
359   
360   if (attributes_mask & GDK_WA_Y)
361     y = attributes->y;
362   else
363     y = 0;
364   
365   private->x = x;
366   private->y = y;
367   impl->width = (attributes->width > 1) ? (attributes->width) : (1);
368   impl->height = (attributes->height > 1) ? (attributes->height) : (1);
369
370   if (attributes->wclass == GDK_INPUT_ONLY)
371     {
372       /* Backwards compatiblity - we've always ignored
373        * attributes->window_type for input-only windows
374        * before
375        */
376       if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT &&
377           GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
378         private->window_type = GDK_WINDOW_TEMP;
379       else
380         private->window_type = GDK_WINDOW_CHILD;
381     }
382   else
383     private->window_type = attributes->window_type;
384
385   _gdk_window_init_position (GDK_WINDOW (private));
386   if (impl->position_info.big)
387     private->guffaw_gravity = TRUE;
388   
389   if (attributes_mask & GDK_WA_VISUAL)
390     visual = attributes->visual;
391   else
392     visual = gdk_visual_get_system ();
393   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
394   
395   xattributes.event_mask = StructureNotifyMask;
396   for (i = 0; i < gdk_nevent_masks; i++)
397     {
398       if (attributes->event_mask & (1 << (i + 1)))
399         xattributes.event_mask |= gdk_event_mask_table[i];
400     }
401   
402   if (xattributes.event_mask)
403     xattributes_mask |= CWEventMask;
404   
405   if (attributes_mask & GDK_WA_NOREDIR)
406     {
407       xattributes.override_redirect =
408         (attributes->override_redirect == FALSE)?False:True;
409       xattributes_mask |= CWOverrideRedirect;
410     } 
411   else
412     xattributes.override_redirect = False;
413
414   if (parent_private && parent_private->guffaw_gravity)
415     {
416       xattributes.win_gravity = StaticGravity;
417       xattributes_mask |= CWWinGravity;
418     }
419   
420   /* Sanity checks */
421   switch (private->window_type)
422     {
423     case GDK_WINDOW_TOPLEVEL:
424     case GDK_WINDOW_DIALOG:
425     case GDK_WINDOW_TEMP:
426       if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT &&
427           GDK_WINDOW_TYPE (parent) != GDK_WINDOW_FOREIGN)
428         {
429           g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
430                      "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
431           xparent = gdk_root_window;
432         }
433     case GDK_WINDOW_CHILD:
434       break;
435     default:
436       g_warning (G_STRLOC "cannot make windows of type %d", private->window_type);
437       return NULL;
438     }
439           
440   if (attributes->wclass == GDK_INPUT_OUTPUT)
441     {
442       class = InputOutput;
443       depth = visual->depth;
444
445       private->input_only = FALSE;
446       private->depth = depth;
447       
448       if (attributes_mask & GDK_WA_COLORMAP)
449         {
450           draw_impl->colormap = attributes->colormap;
451           gdk_colormap_ref (attributes->colormap);
452         }
453       else
454         {
455           if ((((GdkVisualPrivate*)gdk_visual_get_system ())->xvisual) == xvisual)
456             {
457               draw_impl->colormap =
458                 gdk_colormap_get_system ();
459               gdk_colormap_ref (draw_impl->colormap);
460             }
461           else
462             {
463               draw_impl->colormap =
464                 gdk_colormap_new (visual, FALSE);
465             }
466         }
467       
468       private->bg_color.pixel = BlackPixel (gdk_display, gdk_screen);
469       xattributes.background_pixel = private->bg_color.pixel;
470
471       private->bg_pixmap = NULL;
472       
473       xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen);
474       xattributes_mask |= CWBorderPixel | CWBackPixel;
475
476       if (private->guffaw_gravity)
477         xattributes.bit_gravity = StaticGravity;
478       else
479         xattributes.bit_gravity = NorthWestGravity;
480       
481       xattributes_mask |= CWBitGravity;
482
483       xattributes.colormap = GDK_COLORMAP_XCOLORMAP (draw_impl->colormap);
484       xattributes_mask |= CWColormap;
485
486       if (private->window_type == GDK_WINDOW_TEMP)
487         {
488           xattributes.save_under = True;
489           xattributes.override_redirect = True;
490           xattributes.cursor = None;
491           xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
492         }
493     }
494   else
495     {
496       depth = 0;
497       private->depth = 0;
498       class = InputOnly;
499       private->input_only = TRUE;
500       draw_impl->colormap = gdk_colormap_get_system ();
501       gdk_colormap_ref (draw_impl->colormap);
502     }
503
504   xid = draw_impl->xid = XCreateWindow (xdisplay, xparent,
505                                         impl->position_info.x, impl->position_info.y,
506                                         impl->position_info.width, impl->position_info.height,
507                                         0, depth, class, xvisual,
508                                         xattributes_mask, &xattributes);
509
510   gdk_drawable_ref (window);
511   gdk_xid_table_insert (&draw_impl->xid, window);
512   
513   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
514                                   (attributes->cursor) :
515                                   NULL));
516   
517   if (parent_private)
518     parent_private->children = g_list_prepend (parent_private->children, window);
519   
520   switch (GDK_WINDOW_TYPE (private))
521     {
522     case GDK_WINDOW_DIALOG:
523       XSetTransientForHint (xdisplay, xid, xparent);
524     case GDK_WINDOW_TOPLEVEL:
525     case GDK_WINDOW_TEMP:
526       XSetWMProtocols (xdisplay, xid,
527                        gdk_wm_window_protocols, 3);
528       break;
529     case GDK_WINDOW_CHILD:
530       if ((attributes->wclass == GDK_INPUT_OUTPUT) &&
531           (draw_impl->colormap != gdk_colormap_get_system ()) &&
532           (draw_impl->colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window))))
533         {
534           GDK_NOTE (MISC, g_message ("adding colormap window\n"));
535           gdk_window_add_colormap_windows (window);
536         }
537       
538       return window;
539     default:
540       
541       return window;
542     }
543
544   if (class != InputOnly)
545     {
546       /* The focus window is off the visible area, and serves to receive key
547        * press events so they don't get sent to child windows.
548        */
549       impl->focus_window = XCreateSimpleWindow (xdisplay, xid,
550                                                 -1, -1, 1, 1, 0,
551                                                 xattributes.background_pixel,
552                                                 xattributes.background_pixel);
553       /* FIXME: probably better to actually track the requested event mask for the toplevel
554        */
555       XSelectInput (xdisplay, impl->focus_window,
556                     KeyPressMask | KeyReleaseMask | FocusChangeMask);
557       
558       XMapWindow (xdisplay, impl->focus_window);
559       gdk_xid_table_insert (&impl->focus_window, window);
560     }
561
562   size_hints.flags = PSize;
563   size_hints.width = impl->width;
564   size_hints.height = impl->height;
565   
566   wm_hints.flags = StateHint | WindowGroupHint;
567   wm_hints.window_group = gdk_leader_window;
568   wm_hints.input = True;
569   wm_hints.initial_state = NormalState;
570   
571   /* FIXME: Is there any point in doing this? Do any WM's pay
572    * attention to PSize, and even if they do, is this the
573    * correct value???
574    */
575   XSetWMNormalHints (xdisplay, xid, &size_hints);
576   
577   XSetWMHints (xdisplay, xid, &wm_hints);
578   
579   if (!wm_client_leader_atom)
580     wm_client_leader_atom = gdk_atom_intern ("WM_CLIENT_LEADER", FALSE);
581   
582   XChangeProperty (xdisplay, xid,
583                    wm_client_leader_atom,
584                    XA_WINDOW, 32, PropModeReplace,
585                    (guchar*) &gdk_leader_window, 1);
586   
587   if (attributes_mask & GDK_WA_TITLE)
588     title = attributes->title;
589   else
590     title = g_get_prgname ();
591
592   gdk_window_set_title (window, title);
593   
594   if (attributes_mask & GDK_WA_WMCLASS)
595     {
596       class_hint = XAllocClassHint ();
597       class_hint->res_name = attributes->wmclass_name;
598       class_hint->res_class = attributes->wmclass_class;
599       XSetClassHint (xdisplay, xid, class_hint);
600       XFree (class_hint);
601     }
602   
603   return window;
604 }
605
606 GdkWindow *
607 gdk_window_foreign_new (GdkNativeWindow anid)
608 {
609   GdkWindow *window;
610   GdkWindowObject *private;
611   GdkWindowObject *parent_private;
612   GdkWindowImplX11 *impl;
613   GdkDrawableImplX11 *draw_impl;
614   XWindowAttributes attrs;
615   Window root, parent;
616   Window *children = NULL;
617   guint nchildren;
618   gboolean result;
619
620   gdk_error_trap_push ();
621   result = XGetWindowAttributes (gdk_display, anid, &attrs);
622   if (gdk_error_trap_pop () || !result)
623     return NULL;
624
625   /* FIXME: This is pretty expensive. Maybe the caller should supply
626    *        the parent */
627   gdk_error_trap_push ();
628   result = XQueryTree (gdk_display, anid, &root, &parent, &children, &nchildren);
629   if (gdk_error_trap_pop () || !result)
630     return NULL;
631
632   if (children)
633     XFree (children);
634   
635   window = g_object_new (GDK_TYPE_WINDOW, NULL);
636   private = (GdkWindowObject *)window;
637   impl = GDK_WINDOW_IMPL_X11 (private->impl);
638   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
639   draw_impl->wrapper = GDK_DRAWABLE (window);
640   
641   private->parent = gdk_xid_table_lookup (parent);
642   
643   parent_private = (GdkWindowObject *)private->parent;
644   
645   if (parent_private)
646     parent_private->children = g_list_prepend (parent_private->children, window);
647
648   draw_impl->xid = anid;
649   draw_impl->xdisplay = gdk_display;
650
651   private->x = attrs.x;
652   private->y = attrs.y;
653   impl->width = attrs.width;
654   impl->height = attrs.height;
655   private->window_type = GDK_WINDOW_FOREIGN;
656   private->destroyed = FALSE;
657
658   if (attrs.map_state == IsUnmapped)
659     private->state = GDK_WINDOW_STATE_WITHDRAWN;
660   else
661     private->state = 0;
662
663   private->depth = attrs.depth;
664   
665   _gdk_window_init_position (GDK_WINDOW (private));
666
667   gdk_drawable_ref (window);
668   gdk_xid_table_insert (&GDK_WINDOW_XID (window), window);
669   
670   return window;
671 }
672
673 void
674 _gdk_windowing_window_destroy (GdkWindow *window,
675                                gboolean   recursing,
676                                gboolean   foreign_destroy)
677 {
678   GdkWindowObject *private = (GdkWindowObject *)window;
679
680   g_return_if_fail (GDK_IS_WINDOW (window));
681
682   _gdk_selection_window_destroyed (window);
683   
684   if (private->extension_events != 0)
685     gdk_input_window_destroy (window);
686
687   if (private->window_type == GDK_WINDOW_FOREIGN)
688     {
689       if (!foreign_destroy && (private->parent != NULL))
690         {
691           /* It's somebody else's window, but in our heirarchy,
692            * so reparent it to the root window, and then send
693            * it a delete event, as if we were a WM
694            */
695           XClientMessageEvent xevent;
696           
697           gdk_error_trap_push ();
698           gdk_window_hide (window);
699           gdk_window_reparent (window, NULL, 0, 0);
700           
701           xevent.type = ClientMessage;
702           xevent.window = GDK_WINDOW_XID (window);
703           xevent.message_type = gdk_wm_protocols;
704           xevent.format = 32;
705           xevent.data.l[0] = gdk_wm_delete_window;
706           xevent.data.l[1] = CurrentTime;
707           
708           XSendEvent (GDK_WINDOW_XDISPLAY (window),
709                       GDK_WINDOW_XID (window),
710                       False, 0, (XEvent *)&xevent);
711           gdk_flush ();
712           gdk_error_trap_pop ();
713         }
714     }
715   else if (!recursing && !foreign_destroy)
716     XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
717 }
718
719 /* This function is called when the XWindow is really gone.
720  */
721 void
722 gdk_window_destroy_notify (GdkWindow *window)
723 {
724   GdkWindowImplX11 *window_impl;
725
726   g_return_if_fail (window != NULL);
727   
728   window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
729
730   if (!GDK_WINDOW_DESTROYED (window))
731     {
732       if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN)
733         g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_WINDOW_XID (window));
734
735       _gdk_window_destroy (window, TRUE);
736     }
737   
738   gdk_xid_table_remove (GDK_WINDOW_XID (window));
739   if (window_impl->focus_window)
740     gdk_xid_table_remove (window_impl->focus_window);
741   
742   gdk_drawable_unref (window);
743 }
744
745 static void
746 set_initial_hints (GdkWindow *window)
747 {
748   GdkWindowObject *private;
749   GdkAtom atoms[5];
750   gint i;
751   
752   private = (GdkWindowObject*) window;
753
754   if (private->state & GDK_WINDOW_STATE_ICONIFIED)
755     {
756       XWMHints *wm_hints;
757       
758       wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
759                               GDK_WINDOW_XID (window));
760       if (!wm_hints)
761         wm_hints = XAllocWMHints ();
762
763       wm_hints->flags |= StateHint;
764       wm_hints->initial_state = IconicState;
765       
766       XSetWMHints (GDK_WINDOW_XDISPLAY (window),
767                    GDK_WINDOW_XID (window), wm_hints);
768       XFree (wm_hints);
769     }
770
771   /* We set the spec hints regardless of whether the spec is supported,
772    * since it can't hurt and it's kind of expensive to check whether
773    * it's supported.
774    */
775   
776   i = 0;
777
778   if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
779     {
780       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
781       ++i;
782       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);
783       ++i;
784     }
785
786   if (private->state & GDK_WINDOW_STATE_STICKY)
787     {
788       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
789       ++i;
790     }
791
792   if (private->modal_hint)
793     {
794       atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MODAL", FALSE);
795       ++i;
796     }
797
798   if (i > 0)
799     {
800       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
801                        GDK_WINDOW_XID (window),
802                        gdk_atom_intern ("_NET_WM_STATE", FALSE),
803                        XA_ATOM, 32, PropModeReplace,
804                        (guchar*) atoms, i);
805     }
806
807   if (private->state & GDK_WINDOW_STATE_STICKY)
808     {
809       atoms[0] = 0xFFFFFFFF;
810       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
811                        GDK_WINDOW_XID (window),
812                        gdk_atom_intern ("_NET_WM_DESKTOP", FALSE),
813                        XA_CARDINAL, 32, PropModeReplace,
814                        (guchar*) atoms, 1);
815     }
816 }
817
818 static void
819 show_window_internal (GdkWindow *window,
820                       gboolean   raise)
821 {
822   GdkWindowObject *private;
823   
824   g_return_if_fail (GDK_IS_WINDOW (window));
825   
826   private = (GdkWindowObject*) window;
827   if (!private->destroyed)
828     {
829       if (raise)
830         XRaiseWindow (GDK_WINDOW_XDISPLAY (window),
831                       GDK_WINDOW_XID (window));
832
833       if (!GDK_WINDOW_IS_MAPPED (window))
834         {
835           set_initial_hints (window);
836           
837           gdk_synthesize_window_state (window,
838                                        GDK_WINDOW_STATE_WITHDRAWN,
839                                        0);
840         }
841       
842       g_assert (GDK_WINDOW_IS_MAPPED (window));
843       
844       if (GDK_WINDOW_IMPL_X11 (private->impl)->position_info.mapped)
845         XMapWindow (GDK_WINDOW_XDISPLAY (window),
846                     GDK_WINDOW_XID (window));
847     }
848 }
849
850 /**
851  * gdk_window_show_unraised:
852  * @window: a #GdkWindow
853  *
854  * Shows a #GdkWindow onscreen, but does not modify its stacking
855  * order. In contrast, gdk_window_show() will raise the window
856  * to the top of the window stack.
857  * 
858  **/
859 void
860 gdk_window_show_unraised (GdkWindow *window)
861 {
862   g_return_if_fail (GDK_IS_WINDOW (window));
863   
864   show_window_internal (window, FALSE);
865 }
866
867 void
868 gdk_window_show (GdkWindow *window)
869 {
870   g_return_if_fail (GDK_IS_WINDOW (window));
871
872   show_window_internal (window, TRUE);
873 }
874
875 void
876 gdk_window_hide (GdkWindow *window)
877 {
878   GdkWindowObject *private;
879   
880   g_return_if_fail (window != NULL);
881
882   private = (GdkWindowObject*) window;
883
884   /* You can't simply unmap toplevel windows. */
885   switch (private->window_type)
886     {
887     case GDK_WINDOW_TOPLEVEL:
888     case GDK_WINDOW_DIALOG:
889     case GDK_WINDOW_TEMP: /* ? */
890       gdk_window_withdraw (window);
891       return;
892       break;
893       
894     case GDK_WINDOW_FOREIGN:
895     case GDK_WINDOW_ROOT:
896     case GDK_WINDOW_CHILD:
897       break;
898     }
899   
900   if (!private->destroyed)
901     {
902       if (GDK_WINDOW_IS_MAPPED (window))
903         gdk_synthesize_window_state (window,
904                                      0,
905                                      GDK_WINDOW_STATE_WITHDRAWN);
906
907       g_assert (!GDK_WINDOW_IS_MAPPED (window));
908       
909       _gdk_window_clear_update_area (window);
910       
911       XUnmapWindow (GDK_WINDOW_XDISPLAY (window),
912                     GDK_WINDOW_XID (window));
913     }
914 }
915
916 void
917 gdk_window_withdraw (GdkWindow *window)
918 {
919   GdkWindowObject *private;
920   
921   g_return_if_fail (window != NULL);
922   
923   private = (GdkWindowObject*) window;
924   if (!private->destroyed)
925     {
926       if (GDK_WINDOW_IS_MAPPED (window))
927         gdk_synthesize_window_state (window,
928                                      0,
929                                      GDK_WINDOW_STATE_WITHDRAWN);
930
931       g_assert (!GDK_WINDOW_IS_MAPPED (window));
932       
933       XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
934                        GDK_WINDOW_XID (window), 0);
935     }
936 }
937
938 void
939 gdk_window_move (GdkWindow *window,
940                  gint       x,
941                  gint       y)
942 {
943   GdkWindowObject *private = (GdkWindowObject *)window;
944   GdkWindowImplX11 *impl;
945
946   g_return_if_fail (window != NULL);
947   g_return_if_fail (GDK_IS_WINDOW (window));
948
949   impl = GDK_WINDOW_IMPL_X11 (private->impl);
950
951   if (!GDK_WINDOW_DESTROYED (window))
952     {
953       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
954         _gdk_window_move_resize_child (window, x, y,
955                                        impl->width, impl->height);
956       else
957         {
958           XMoveWindow (GDK_WINDOW_XDISPLAY (window),
959                        GDK_WINDOW_XID (window),
960                        x, y);
961         }
962     }
963 }
964
965 void
966 gdk_window_resize (GdkWindow *window,
967                    gint       width,
968                    gint       height)
969 {
970   GdkWindowObject *private;
971   
972   g_return_if_fail (window != NULL);
973   g_return_if_fail (GDK_IS_WINDOW (window));
974   
975   if (width < 1)
976     width = 1;
977   if (height < 1)
978     height = 1;
979
980   private = (GdkWindowObject*) window;
981   
982   if (!GDK_WINDOW_DESTROYED (window))
983     {
984       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
985         _gdk_window_move_resize_child (window, private->x, private->y,
986                                        width, height);
987       else
988         {
989           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
990           
991           if (width != impl->width || height != impl->height)
992             private->resize_count += 1;
993
994           XResizeWindow (GDK_WINDOW_XDISPLAY (window),
995                          GDK_WINDOW_XID (window),
996                          width, height);
997         }
998     }
999 }
1000
1001 void
1002 gdk_window_move_resize (GdkWindow *window,
1003                         gint       x,
1004                         gint       y,
1005                         gint       width,
1006                         gint       height)
1007 {
1008   GdkWindowObject *private;
1009   
1010   g_return_if_fail (window != NULL);
1011   g_return_if_fail (GDK_IS_WINDOW (window));
1012
1013   if (width < 1)
1014     width = 1;
1015   if (height < 1)
1016     height = 1;
1017   
1018   private = (GdkWindowObject*) window;
1019
1020   if (!GDK_WINDOW_DESTROYED (window))
1021     {
1022       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
1023         _gdk_window_move_resize_child (window, x, y, width, height);
1024       else
1025         {
1026           GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
1027           
1028           if (width != impl->width || height != impl->height)
1029             private->resize_count += 1;
1030           
1031           XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
1032                              GDK_WINDOW_XID (window),
1033                              x, y, width, height);
1034         }
1035     }
1036 }
1037
1038 void
1039 gdk_window_reparent (GdkWindow *window,
1040                      GdkWindow *new_parent,
1041                      gint       x,
1042                      gint       y)
1043 {
1044   GdkWindowObject *window_private;
1045   GdkWindowObject *parent_private;
1046   GdkWindowObject *old_parent_private;
1047   
1048   g_return_if_fail (window != NULL);
1049   g_return_if_fail (GDK_IS_WINDOW (window));
1050   g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
1051   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
1052   
1053   if (!new_parent)
1054     new_parent = gdk_parent_root;
1055   
1056   window_private = (GdkWindowObject*) window;
1057   old_parent_private = (GdkWindowObject*)window_private->parent;
1058   parent_private = (GdkWindowObject*) new_parent;
1059   
1060   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (new_parent))
1061     XReparentWindow (GDK_WINDOW_XDISPLAY (window),
1062                      GDK_WINDOW_XID (window),
1063                      GDK_WINDOW_XID (new_parent),
1064                      x, y);
1065   
1066   window_private->parent = (GdkWindowObject *)new_parent;
1067
1068   /* Switch the window type as appropriate */
1069
1070   switch (GDK_WINDOW_TYPE (new_parent))
1071     {
1072     case GDK_WINDOW_ROOT:
1073     case GDK_WINDOW_FOREIGN:
1074       /* Now a toplevel */
1075       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1076         {
1077           GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
1078           XSetWMProtocols (GDK_WINDOW_XDISPLAY (window),
1079                            GDK_WINDOW_XID (window),
1080                            gdk_wm_window_protocols, 3);
1081         }
1082     case GDK_WINDOW_TOPLEVEL:
1083     case GDK_WINDOW_CHILD:
1084     case GDK_WINDOW_DIALOG:
1085     case GDK_WINDOW_TEMP:
1086       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
1087           GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
1088         {
1089           /* If we were being sophisticated, we'd save the old window type
1090            * here, and restore it if we were reparented back to the
1091            * toplevel. However, the difference between different types
1092            * of toplevels only really matters on creation anyways.
1093            */
1094           GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
1095         }
1096     }
1097
1098   if (old_parent_private)
1099     old_parent_private->children = g_list_remove (old_parent_private->children, window);
1100   
1101   if ((old_parent_private &&
1102        (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
1103       (!old_parent_private && parent_private->guffaw_gravity))
1104     gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
1105   
1106   parent_private->children = g_list_prepend (parent_private->children, window);
1107   _gdk_window_init_position (GDK_WINDOW (window_private));
1108 }
1109
1110 void
1111 _gdk_windowing_window_clear_area (GdkWindow *window,
1112                                   gint       x,
1113                                   gint       y,
1114                                   gint       width,
1115                                   gint       height)
1116 {
1117   g_return_if_fail (window != NULL);
1118   g_return_if_fail (GDK_IS_WINDOW (window));
1119   
1120   if (!GDK_WINDOW_DESTROYED (window))
1121     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1122                 x, y, width, height, False);
1123 }
1124
1125 void
1126 _gdk_windowing_window_clear_area_e (GdkWindow *window,
1127                                     gint       x,
1128                                     gint       y,
1129                                     gint       width,
1130                                     gint       height)
1131 {
1132   g_return_if_fail (window != NULL);
1133   g_return_if_fail (GDK_IS_WINDOW (window));
1134   
1135   if (!GDK_WINDOW_DESTROYED (window))
1136     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1137                 x, y, width, height, True);
1138 }
1139
1140 void
1141 gdk_window_raise (GdkWindow *window)
1142 {
1143   g_return_if_fail (window != NULL);
1144   g_return_if_fail (GDK_IS_WINDOW (window));
1145   
1146   if (!GDK_WINDOW_DESTROYED (window))
1147     XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1148 }
1149
1150 void
1151 gdk_window_lower (GdkWindow *window)
1152 {
1153   g_return_if_fail (window != NULL);
1154   g_return_if_fail (GDK_IS_WINDOW (window));
1155   
1156   if (!GDK_WINDOW_DESTROYED (window))
1157     XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1158 }
1159
1160 void
1161 gdk_window_focus (GdkWindow *window,
1162                   guint32    timestamp)
1163 {
1164   g_return_if_fail (GDK_IS_WINDOW (window));
1165
1166   if (GDK_WINDOW_DESTROYED (window))
1167     return;
1168   
1169   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE)))
1170     {
1171       XEvent xev;
1172
1173       xev.xclient.type = ClientMessage;
1174       xev.xclient.serial = 0;
1175       xev.xclient.send_event = True;
1176       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
1177       xev.xclient.display = gdk_display;
1178       xev.xclient.message_type = gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE);
1179       xev.xclient.format = 32;
1180       xev.xclient.data.l[0] = 0;
1181       
1182       XSendEvent (gdk_display, gdk_root_window, False,
1183                   SubstructureRedirectMask | SubstructureNotifyMask,
1184                   &xev);
1185     }
1186   else
1187     {
1188       XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
1189
1190       /* There is no way of knowing reliably whether we are viewable so we need
1191        * to trap errors so we don't cause a BadMatch.
1192        */
1193       gdk_error_trap_push ();
1194       XSetInputFocus (GDK_WINDOW_XDISPLAY (window),
1195                       GDK_WINDOW_XWINDOW (window),
1196                       RevertToNone,
1197                       timestamp);
1198       XSync (GDK_WINDOW_XDISPLAY (window), False);
1199       gdk_error_trap_pop ();
1200     }
1201 }
1202
1203 void
1204 gdk_window_set_hints (GdkWindow *window,
1205                       gint       x,
1206                       gint       y,
1207                       gint       min_width,
1208                       gint       min_height,
1209                       gint       max_width,
1210                       gint       max_height,
1211                       gint       flags)
1212 {
1213   XSizeHints size_hints;
1214   
1215   g_return_if_fail (window != NULL);
1216   g_return_if_fail (GDK_IS_WINDOW (window));
1217   
1218   if (GDK_WINDOW_DESTROYED (window))
1219     return;
1220   
1221   size_hints.flags = 0;
1222   
1223   if (flags & GDK_HINT_POS)
1224     {
1225       size_hints.flags |= PPosition;
1226       size_hints.x = x;
1227       size_hints.y = y;
1228     }
1229   
1230   if (flags & GDK_HINT_MIN_SIZE)
1231     {
1232       size_hints.flags |= PMinSize;
1233       size_hints.min_width = min_width;
1234       size_hints.min_height = min_height;
1235     }
1236   
1237   if (flags & GDK_HINT_MAX_SIZE)
1238     {
1239       size_hints.flags |= PMaxSize;
1240       size_hints.max_width = max_width;
1241       size_hints.max_height = max_height;
1242     }
1243   
1244   /* FIXME: Would it be better to delete this property if
1245    *        flags == 0? It would save space on the server
1246    */
1247   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1248                      GDK_WINDOW_XID (window),
1249                      &size_hints);
1250 }
1251
1252 /**
1253  * gdk_window_set_type_hint:
1254  * @window: A #GdkWindow
1255  * @hint: A hint of the function this window will have
1256  *
1257  * The application can use this call to provide a hint to the window
1258  * manager about the functionality of a window. The window manager
1259  * can use this information when determining the decoration and behaviour
1260  * of the window.
1261  *
1262  * The hint must be set before the window is mapped.
1263  **/
1264 void
1265 gdk_window_set_type_hint (GdkWindow        *window,
1266                           GdkWindowTypeHint hint)
1267 {
1268   GdkAtom atom;
1269   
1270   g_return_if_fail (window != NULL);
1271   g_return_if_fail (GDK_IS_WINDOW (window));
1272   
1273   if (GDK_WINDOW_DESTROYED (window))
1274     return;
1275
1276   switch (hint)
1277     {
1278     case GDK_WINDOW_TYPE_HINT_DIALOG:
1279       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DIALOG", FALSE);
1280       break;
1281     case GDK_WINDOW_TYPE_HINT_MENU:
1282       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_MENU", FALSE);
1283       break;
1284     case GDK_WINDOW_TYPE_HINT_TOOLBAR:
1285       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_TOOLBAR", FALSE);
1286       break;
1287     default:
1288       g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint);
1289       /* Fall thru */
1290     case GDK_WINDOW_TYPE_HINT_NORMAL:
1291       atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_NORMAL", FALSE);
1292       break;
1293     }
1294
1295   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1296                    GDK_WINDOW_XID (window),
1297                    gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE),
1298                    XA_ATOM, 32, PropModeReplace,
1299                    (guchar *)&atom, 1);
1300 }
1301
1302
1303 static void
1304 gdk_wmspec_change_state (gboolean add,
1305                          GdkWindow *window,
1306                          GdkAtom state1,
1307                          GdkAtom state2)
1308 {
1309   XEvent xev;
1310
1311 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
1312 #define _NET_WM_STATE_ADD           1    /* add/set property */
1313 #define _NET_WM_STATE_TOGGLE        2    /* toggle property  */  
1314   
1315   xev.xclient.type = ClientMessage;
1316   xev.xclient.serial = 0;
1317   xev.xclient.send_event = True;
1318   xev.xclient.display = gdk_display;
1319   xev.xclient.window = GDK_WINDOW_XID (window);
1320   xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
1321   xev.xclient.format = 32;
1322   xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1323   xev.xclient.data.l[1] = state1;
1324   xev.xclient.data.l[2] = state2;
1325   
1326   XSendEvent (gdk_display, gdk_root_window, False,
1327               SubstructureRedirectMask | SubstructureNotifyMask,
1328               &xev);
1329 }
1330 /**
1331  * gdk_window_set_modal_hint:
1332  * @window: A #GdkWindow
1333  * @modal: TRUE if the window is modal, FALSE otherwise.
1334  *
1335  * The application can use this hint to tell the window manager
1336  * that a certain window has modal behaviour. The window manager
1337  * can use this information to handle modal windows in a special
1338  * way.
1339  *
1340  * You should only use this on windows for which you have
1341  * previously called #gdk_window_set_transient_for()
1342  **/
1343 void
1344 gdk_window_set_modal_hint (GdkWindow *window,
1345                            gboolean   modal)
1346 {
1347   GdkWindowObject *private;
1348
1349   g_return_if_fail (window != NULL);
1350   g_return_if_fail (GDK_IS_WINDOW (window));
1351   
1352   if (GDK_WINDOW_DESTROYED (window))
1353     return;
1354
1355   private = (GdkWindowObject*) window;
1356
1357   private->modal_hint = modal;
1358
1359   if (GDK_WINDOW_IS_MAPPED (window))
1360     gdk_wmspec_change_state (modal, window,
1361                              gdk_atom_intern ("_NET_WM_STATE_MODAL", FALSE),
1362                              0);
1363 }
1364
1365 void 
1366 gdk_window_set_geometry_hints (GdkWindow      *window,
1367                                GdkGeometry    *geometry,
1368                                GdkWindowHints  geom_mask)
1369 {
1370   XSizeHints size_hints;
1371   
1372   g_return_if_fail (window != NULL);
1373   g_return_if_fail (GDK_IS_WINDOW (window));
1374   
1375   if (GDK_WINDOW_DESTROYED (window))
1376     return;
1377   
1378   size_hints.flags = 0;
1379   
1380   if (geom_mask & GDK_HINT_POS)
1381     {
1382       size_hints.flags |= PPosition;
1383       /* We need to initialize the following obsolete fields because KWM 
1384        * apparently uses these fields if they are non-zero.
1385        * #@#!#!$!.
1386        */
1387       size_hints.x = 0;
1388       size_hints.y = 0;
1389     }
1390
1391   if (geom_mask & GDK_HINT_USER_POS)
1392     {
1393       size_hints.flags |= USPosition;
1394     }
1395
1396   if (geom_mask & GDK_HINT_USER_SIZE)
1397     {
1398       size_hints.flags |= USSize;
1399     }
1400   
1401   if (geom_mask & GDK_HINT_MIN_SIZE)
1402     {
1403       size_hints.flags |= PMinSize;
1404       size_hints.min_width = geometry->min_width;
1405       size_hints.min_height = geometry->min_height;
1406     }
1407   
1408   if (geom_mask & GDK_HINT_MAX_SIZE)
1409     {
1410       size_hints.flags |= PMaxSize;
1411       size_hints.max_width = MAX (geometry->max_width, 1);
1412       size_hints.max_height = MAX (geometry->max_height, 1);
1413     }
1414   
1415   if (geom_mask & GDK_HINT_BASE_SIZE)
1416     {
1417       size_hints.flags |= PBaseSize;
1418       size_hints.base_width = geometry->base_width;
1419       size_hints.base_height = geometry->base_height;
1420     }
1421   
1422   if (geom_mask & GDK_HINT_RESIZE_INC)
1423     {
1424       size_hints.flags |= PResizeInc;
1425       size_hints.width_inc = geometry->width_inc;
1426       size_hints.height_inc = geometry->height_inc;
1427     }
1428   
1429   if (geom_mask & GDK_HINT_ASPECT)
1430     {
1431       size_hints.flags |= PAspect;
1432       if (geometry->min_aspect <= 1)
1433         {
1434           size_hints.min_aspect.x = 65536 * geometry->min_aspect;
1435           size_hints.min_aspect.y = 65536;
1436         }
1437       else
1438         {
1439           size_hints.min_aspect.x = 65536;
1440           size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
1441         }
1442       if (geometry->max_aspect <= 1)
1443         {
1444           size_hints.max_aspect.x = 65536 * geometry->max_aspect;
1445           size_hints.max_aspect.y = 65536;
1446         }
1447       else
1448         {
1449           size_hints.max_aspect.x = 65536;
1450           size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
1451         }
1452     }
1453
1454   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1455     {
1456       size_hints.flags |= PWinGravity;
1457       size_hints.win_gravity = geometry->win_gravity;
1458     }
1459   
1460   /* FIXME: Would it be better to delete this property if
1461    *        geom_mask == 0? It would save space on the server
1462    */
1463   XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1464                      GDK_WINDOW_XID (window),
1465                      &size_hints);
1466 }
1467
1468 static void
1469 gdk_window_get_geometry_hints (GdkWindow      *window,
1470                                GdkGeometry    *geometry,
1471                                GdkWindowHints *geom_mask)
1472 {
1473   XSizeHints size_hints;  
1474   glong junk_size_mask = 0;
1475
1476   g_return_if_fail (GDK_IS_WINDOW (window));
1477   g_return_if_fail (geometry != NULL);
1478   g_return_if_fail (geom_mask != NULL);
1479
1480   *geom_mask = 0;
1481   
1482   if (GDK_WINDOW_DESTROYED (window))
1483     return;
1484   
1485   if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
1486                           GDK_WINDOW_XID (window),
1487                           &size_hints,
1488                           &junk_size_mask))
1489     return;                   
1490
1491   if (size_hints.flags & PMinSize)
1492     {
1493       *geom_mask |= GDK_HINT_MIN_SIZE;
1494       geometry->min_width = size_hints.min_width;
1495       geometry->min_height = size_hints.min_height;
1496     }
1497
1498   if (size_hints.flags & PMaxSize)
1499     {
1500       *geom_mask |= GDK_HINT_MAX_SIZE;
1501       geometry->max_width = MAX (size_hints.max_width, 1);
1502       geometry->max_height = MAX (size_hints.max_height, 1);
1503     }
1504
1505   if (size_hints.flags & PResizeInc)
1506     {
1507       *geom_mask |= GDK_HINT_RESIZE_INC;
1508       geometry->width_inc = size_hints.width_inc;
1509       geometry->height_inc = size_hints.height_inc;
1510     }
1511
1512   if (size_hints.flags & PAspect)
1513     {
1514       *geom_mask |= GDK_HINT_ASPECT;
1515
1516       geometry->min_aspect = (gdouble) size_hints.min_aspect.x / (gdouble) size_hints.min_aspect.y;
1517       geometry->max_aspect = (gdouble) size_hints.max_aspect.x / (gdouble) size_hints.max_aspect.y;
1518     }
1519
1520   if (size_hints.flags & PWinGravity)
1521     {
1522       *geom_mask |= GDK_HINT_WIN_GRAVITY;
1523       geometry->win_gravity = size_hints.win_gravity;
1524     }
1525 }
1526
1527 static gboolean
1528 utf8_is_latin1 (const gchar *str)
1529 {
1530   const char *p = str;
1531
1532   while (*p)
1533     {
1534       gunichar ch = g_utf8_get_char (p);
1535
1536       if (ch > 0xff)
1537         return FALSE;
1538       
1539       p = g_utf8_next_char (p);
1540     }
1541
1542   return TRUE;
1543 }
1544
1545 /* Set the property to @utf8_str as STRING if the @utf8_str is fully
1546  * convertable to STRING, otherwise, set it as compound text
1547  */
1548 static void
1549 set_text_property (GdkWindow   *window,
1550                    GdkAtom      property,
1551                    const gchar *utf8_str)
1552 {
1553   guchar *prop_text = NULL;
1554   GdkAtom prop_type;
1555   gint prop_length;
1556   gint prop_format;
1557   
1558   if (utf8_is_latin1 (utf8_str))
1559     {
1560       prop_type = GDK_TARGET_STRING;
1561       prop_text = gdk_utf8_to_string_target (utf8_str);
1562       prop_length = strlen (prop_text);
1563       prop_format = 8;
1564     }
1565   else
1566     {
1567       gdk_utf8_to_compound_text (utf8_str, &prop_type, &prop_format,
1568                                  &prop_text, &prop_length);
1569     }
1570
1571   if (prop_text)
1572     {
1573       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1574                        GDK_WINDOW_XID (window),
1575                        property,
1576                        prop_type, prop_format,
1577                        PropModeReplace, prop_text,
1578                        prop_length);
1579
1580       g_free (prop_text);
1581     }
1582 }
1583
1584 void
1585 gdk_window_set_title (GdkWindow   *window,
1586                       const gchar *title)
1587 {
1588   g_return_if_fail (window != NULL);
1589   g_return_if_fail (GDK_IS_WINDOW (window));
1590
1591   if (GDK_WINDOW_DESTROYED (window))
1592     return;
1593   
1594   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1595                    GDK_WINDOW_XID (window),
1596                    gdk_atom_intern ("_NET_WM_NAME", FALSE),
1597                    gdk_atom_intern ("UTF8_STRING", FALSE), 8,
1598                    PropModeReplace, title,
1599                    strlen (title));
1600
1601   set_text_property (window, gdk_atom_intern ("WM_NAME", FALSE), title);
1602   if (!gdk_window_icon_name_set (window))
1603     {
1604       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
1605                        GDK_WINDOW_XID (window),
1606                        gdk_atom_intern ("_NET_WM_ICON_NAME", FALSE),
1607                        gdk_atom_intern ("UTF8_STRING", FALSE), 8,
1608                        PropModeReplace, title,
1609                        strlen (title));
1610       set_text_property (window, gdk_atom_intern ("WM_ICON_NAME", FALSE), title);
1611     }
1612 }
1613
1614 void          
1615 gdk_window_set_role (GdkWindow   *window,
1616                      const gchar *role)
1617 {
1618   g_return_if_fail (window != NULL);
1619   g_return_if_fail (GDK_IS_WINDOW (window));
1620
1621   if (!GDK_WINDOW_DESTROYED (window))
1622     {
1623       if (role)
1624         XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1625                          gdk_atom_intern ("WM_WINDOW_ROLE", FALSE), XA_STRING,
1626                          8, PropModeReplace, role, strlen (role));
1627       else
1628         XDeleteProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
1629                          gdk_atom_intern ("WM_WINDOW_ROLE", FALSE));
1630     }
1631 }
1632
1633 void          
1634 gdk_window_set_transient_for (GdkWindow *window, 
1635                               GdkWindow *parent)
1636 {
1637   GdkWindowObject *private;
1638   GdkWindowObject *parent_private;
1639   
1640   g_return_if_fail (window != NULL);
1641   g_return_if_fail (GDK_IS_WINDOW (window));
1642   
1643   private = (GdkWindowObject*) window;
1644   parent_private = (GdkWindowObject*) parent;
1645   
1646   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent))
1647     XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
1648                           GDK_WINDOW_XID (window),
1649                           GDK_WINDOW_XID (parent));
1650 }
1651
1652 void
1653 gdk_window_set_background (GdkWindow *window,
1654                            GdkColor  *color)
1655 {
1656   GdkWindowObject *private = (GdkWindowObject *)window;
1657   
1658   g_return_if_fail (window != NULL);
1659   g_return_if_fail (GDK_IS_WINDOW (window));
1660   
1661   if (!GDK_WINDOW_DESTROYED (window))
1662     XSetWindowBackground (GDK_WINDOW_XDISPLAY (window),
1663                           GDK_WINDOW_XID (window), color->pixel);
1664
1665   private->bg_color = *color;
1666
1667   if (private->bg_pixmap &&
1668       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1669       private->bg_pixmap != GDK_NO_BG)
1670     {
1671       gdk_pixmap_unref (private->bg_pixmap);
1672       private->bg_pixmap = NULL;
1673     }
1674 }
1675
1676 void
1677 gdk_window_set_back_pixmap (GdkWindow *window,
1678                             GdkPixmap *pixmap,
1679                             gboolean   parent_relative)
1680 {
1681   GdkWindowObject *private = (GdkWindowObject *)window;
1682   Pixmap xpixmap;
1683   
1684   g_return_if_fail (window != NULL);
1685   g_return_if_fail (GDK_IS_WINDOW (window));
1686   g_return_if_fail (pixmap == NULL || !parent_relative);
1687
1688   if (private->bg_pixmap &&
1689       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1690       private->bg_pixmap != GDK_NO_BG)
1691     gdk_pixmap_unref (private->bg_pixmap);
1692
1693   if (parent_relative)
1694     {
1695       xpixmap = ParentRelative;
1696       private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
1697     }
1698   else
1699     {
1700       if (pixmap)
1701         {
1702           gdk_pixmap_ref (pixmap);
1703           private->bg_pixmap = pixmap;
1704           xpixmap = GDK_PIXMAP_XID (pixmap);
1705         }
1706       else
1707         {
1708           xpixmap = None;
1709           private->bg_pixmap = GDK_NO_BG;
1710         }
1711     }
1712   
1713   if (!GDK_WINDOW_DESTROYED (window))
1714     XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
1715                                 GDK_WINDOW_XID (window), xpixmap);
1716 }
1717
1718 void
1719 gdk_window_set_cursor (GdkWindow *window,
1720                        GdkCursor *cursor)
1721 {
1722   GdkCursorPrivate *cursor_private;
1723   Cursor xcursor;
1724   
1725   g_return_if_fail (window != NULL);
1726   g_return_if_fail (GDK_IS_WINDOW (window));
1727   
1728   cursor_private = (GdkCursorPrivate*) cursor;
1729   
1730   if (!cursor)
1731     xcursor = None;
1732   else
1733     xcursor = cursor_private->xcursor;
1734   
1735   if (!GDK_WINDOW_DESTROYED (window))
1736     XDefineCursor (GDK_WINDOW_XDISPLAY (window),
1737                    GDK_WINDOW_XID (window),
1738                    xcursor);
1739 }
1740
1741 void
1742 gdk_window_get_geometry (GdkWindow *window,
1743                          gint      *x,
1744                          gint      *y,
1745                          gint      *width,
1746                          gint      *height,
1747                          gint      *depth)
1748 {
1749   Window root;
1750   gint tx;
1751   gint ty;
1752   guint twidth;
1753   guint theight;
1754   guint tborder_width;
1755   guint tdepth;
1756   
1757   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
1758   
1759   if (!window)
1760     window = gdk_parent_root;
1761   
1762   if (!GDK_WINDOW_DESTROYED (window))
1763     {
1764       XGetGeometry (GDK_WINDOW_XDISPLAY (window),
1765                     GDK_WINDOW_XID (window),
1766                     &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
1767       
1768       if (x)
1769         *x = tx;
1770       if (y)
1771         *y = ty;
1772       if (width)
1773         *width = twidth;
1774       if (height)
1775         *height = theight;
1776       if (depth)
1777         *depth = tdepth;
1778     }
1779 }
1780
1781 /**
1782  * gdk_window_get_origin:
1783  * @window: a #GdkWindow
1784  * @x: return location for X coordinate
1785  * @y: return location for Y coordinate
1786  * 
1787  * Obtains the position of a window in root window coordinates.
1788  * (Compare with gdk_window_get_position() and
1789  * gdk_window_get_geometry() which return the position of a window
1790  * relative to its parent window.)
1791  * 
1792  * Return value: not meaningful, ignore
1793  **/
1794 gint
1795 gdk_window_get_origin (GdkWindow *window,
1796                        gint      *x,
1797                        gint      *y)
1798 {
1799   gint return_val;
1800   Window child;
1801   gint tx = 0;
1802   gint ty = 0;
1803   
1804   g_return_val_if_fail (window != NULL, 0);
1805   
1806   if (!GDK_WINDOW_DESTROYED (window))
1807     {
1808       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
1809                                           GDK_WINDOW_XID (window),
1810                                           gdk_root_window,
1811                                           0, 0, &tx, &ty,
1812                                           &child);
1813       
1814     }
1815   else
1816     return_val = 0;
1817   
1818   if (x)
1819     *x = tx;
1820   if (y)
1821     *y = ty;
1822   
1823   return return_val;
1824 }
1825
1826 /**
1827  * gdk_window_get_deskrelative_origin:
1828  * @window: a #GdkWindow
1829  * @x: return location for X coordinate
1830  * @y: return location for Y coordinate
1831  * 
1832  * This gets the origin of a #GdkWindow relative to
1833  * an Enlightenment-window-manager desktop. As long as you don't
1834  * assume that the user's desktop/workspace covers the entire
1835  * root window (i.e. you don't assume that the desktop begins
1836  * at root window coordinate 0,0) this function is not necessary.
1837  * It's deprecated for that reason.
1838  * 
1839  * Return value: not meaningful
1840  **/
1841 gboolean
1842 gdk_window_get_deskrelative_origin (GdkWindow *window,
1843                                     gint      *x,
1844                                     gint      *y)
1845 {
1846   gboolean return_val = FALSE;
1847   gint num_children, format_return;
1848   Window win, *child, parent, root;
1849   gint tx = 0;
1850   gint ty = 0;
1851   Atom type_return;
1852   static Atom atom = 0;
1853   gulong number_return, bytes_after_return;
1854   guchar *data_return;
1855   
1856   g_return_val_if_fail (window != NULL, 0);
1857   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1858   
1859   if (!GDK_WINDOW_DESTROYED (window))
1860     {
1861       if (!atom)
1862         atom = gdk_atom_intern ("ENLIGHTENMENT_DESKTOP", FALSE);
1863       win = GDK_WINDOW_XID (window);
1864       
1865       while (XQueryTree (GDK_WINDOW_XDISPLAY (window), win, &root, &parent,
1866                          &child, (unsigned int *)&num_children))
1867         {
1868           if ((child) && (num_children > 0))
1869             XFree (child);
1870           
1871           if (!parent)
1872             break;
1873           else
1874             win = parent;
1875           
1876           if (win == root)
1877             break;
1878           
1879           data_return = NULL;
1880           XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), win, atom, 0, 0,
1881                               False, XA_CARDINAL, &type_return, &format_return,
1882                               &number_return, &bytes_after_return, &data_return);
1883           if (type_return == XA_CARDINAL)
1884             {
1885               XFree (data_return);
1886               break;
1887             }
1888         }
1889       
1890       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
1891                                           GDK_WINDOW_XID (window),
1892                                           win,
1893                                           0, 0, &tx, &ty,
1894                                           &root);
1895       if (x)
1896         *x = tx;
1897       if (y)
1898         *y = ty;
1899     }
1900   
1901   
1902   return return_val;
1903 }
1904
1905 /**
1906  * gdk_window_get_root_origin:
1907  * @window: a #GdkWindow
1908  * @x: return location for X position of window frame
1909  * @y: return location for Y position of window frame
1910  *
1911  * Obtains the top-left corner of the window manager frame in root
1912  * window coordinates.
1913  * 
1914  **/
1915 void
1916 gdk_window_get_root_origin (GdkWindow *window,
1917                             gint      *x,
1918                             gint      *y)
1919 {
1920   GdkRectangle rect;
1921
1922   g_return_if_fail (GDK_IS_WINDOW (window));
1923
1924   gdk_window_get_frame_extents (window, &rect);
1925
1926   if (x)
1927     *x = rect.x;
1928
1929   if (y)
1930     *y = rect.y;
1931 }
1932
1933 /**
1934  * gdk_window_get_frame_extents:
1935  * @window: a #GdkWindow
1936  * @rect: rectangle to fill with bounding box of the window frame
1937  *
1938  * Obtains the bounding box of the window, including window manager
1939  * titlebar/borders if any. The frame position is given in root window
1940  * coordinates. To get the position of the window itself (rather than
1941  * the frame) in root window coordinates, use gdk_window_get_origin().
1942  * 
1943  **/
1944 void
1945 gdk_window_get_frame_extents (GdkWindow    *window,
1946                               GdkRectangle *rect)
1947 {
1948   GdkWindowObject *private;
1949   Window xwindow;
1950   Window xparent;
1951   Window root;
1952   Window *children;
1953   unsigned int nchildren;
1954   
1955   g_return_if_fail (GDK_IS_WINDOW (window));
1956   g_return_if_fail (rect != NULL);
1957   
1958   private = (GdkWindowObject*) window;
1959   
1960   rect->x = 0;
1961   rect->y = 0;
1962   rect->width = 1;
1963   rect->height = 1;
1964   
1965   if (GDK_WINDOW_DESTROYED (window))
1966     return;
1967   
1968   while (private->parent && ((GdkWindowObject*) private->parent)->parent)
1969     private = (GdkWindowObject*) private->parent;
1970   if (GDK_WINDOW_DESTROYED (window))
1971     return;
1972   
1973   xparent = GDK_WINDOW_XID (window);
1974   do
1975     {
1976       xwindow = xparent;
1977       if (!XQueryTree (GDK_WINDOW_XDISPLAY (window), xwindow,
1978                        &root, &xparent,
1979                        &children, &nchildren))
1980         return;
1981       
1982       if (children)
1983         XFree (children);
1984     }
1985   while (xparent != root);
1986   
1987   if (xparent == root)
1988     {
1989       unsigned int ww, wh, wb, wd;
1990       int wx, wy;
1991       
1992       if (XGetGeometry (GDK_WINDOW_XDISPLAY (window), xwindow, &root, &wx, &wy, &ww, &wh, &wb, &wd))
1993         {
1994           rect->x = wx;
1995           rect->y = wy;
1996           rect->width = ww;
1997           rect->height = wh;
1998         }
1999     }
2000 }
2001
2002 GdkWindow*
2003 _gdk_windowing_window_get_pointer (GdkWindow       *window,
2004                                    gint            *x,
2005                                    gint            *y,
2006                                    GdkModifierType *mask)
2007 {
2008   GdkWindow *return_val;
2009   Window root;
2010   Window child;
2011   int rootx, rooty;
2012   int winx = 0;
2013   int winy = 0;
2014   unsigned int xmask = 0;
2015   gint xoffset, yoffset;
2016
2017   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
2018   
2019   if (!window)
2020     window = gdk_parent_root;
2021   
2022   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2023
2024   return_val = NULL;
2025   if (!GDK_WINDOW_DESTROYED (window) &&
2026       XQueryPointer (GDK_WINDOW_XDISPLAY (window),
2027                      GDK_WINDOW_XID (window),
2028                      &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
2029     {
2030       if (child)
2031         return_val = gdk_window_lookup (child);
2032     }
2033   
2034   if (x)
2035     *x = winx + xoffset;
2036   if (y)
2037     *y = winy + yoffset;
2038   if (mask)
2039     *mask = xmask;
2040   
2041   return return_val;
2042 }
2043
2044 GdkWindow*
2045 _gdk_windowing_window_at_pointer (gint *win_x,
2046                                   gint *win_y)
2047 {
2048   GdkWindow *window;
2049   Window root;
2050   Window xwindow;
2051   Window xwindow_last = 0;
2052   Display *xdisplay;
2053   int rootx = -1, rooty = -1;
2054   int winx, winy;
2055   unsigned int xmask;
2056   
2057   xwindow = GDK_ROOT_WINDOW ();
2058   xdisplay = GDK_DISPLAY ();
2059
2060   gdk_x11_grab_server ();
2061   while (xwindow)
2062     {
2063       xwindow_last = xwindow;
2064       XQueryPointer (xdisplay, xwindow,
2065                      &root, &xwindow,
2066                      &rootx, &rooty,
2067                      &winx, &winy,
2068                      &xmask);
2069     }
2070   gdk_x11_ungrab_server ();
2071   
2072   window = gdk_window_lookup (xwindow_last);
2073   
2074   if (win_x)
2075     *win_x = window ? winx : -1;
2076   if (win_y)
2077     *win_y = window ? winy : -1;
2078   
2079   return window;
2080 }
2081
2082 GdkEventMask  
2083 gdk_window_get_events (GdkWindow *window)
2084 {
2085   XWindowAttributes attrs;
2086   GdkEventMask event_mask;
2087   int i;
2088   
2089   g_return_val_if_fail (window != NULL, 0);
2090   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2091
2092   if (GDK_WINDOW_DESTROYED (window))
2093     return 0;
2094   else
2095     {
2096       XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2097                             GDK_WINDOW_XID (window), 
2098                             &attrs);
2099       
2100       event_mask = 0;
2101       for (i = 0; i < gdk_nevent_masks; i++)
2102         {
2103           if (attrs.your_event_mask & gdk_event_mask_table[i])
2104             event_mask |= 1 << (i + 1);
2105         }
2106   
2107       return event_mask;
2108     }
2109 }
2110
2111 void          
2112 gdk_window_set_events (GdkWindow       *window,
2113                        GdkEventMask     event_mask)
2114 {
2115   long xevent_mask;
2116   int i;
2117   
2118   g_return_if_fail (window != NULL);
2119   g_return_if_fail (GDK_IS_WINDOW (window));
2120   
2121   if (!GDK_WINDOW_DESTROYED (window))
2122     {
2123       xevent_mask = StructureNotifyMask;
2124       for (i = 0; i < gdk_nevent_masks; i++)
2125         {
2126           if (event_mask & (1 << (i + 1)))
2127             xevent_mask |= gdk_event_mask_table[i];
2128         }
2129       
2130       XSelectInput (GDK_WINDOW_XDISPLAY (window),
2131                     GDK_WINDOW_XID (window),
2132                     xevent_mask);
2133     }
2134 }
2135
2136 void
2137 gdk_window_add_colormap_windows (GdkWindow *window)
2138 {
2139   GdkWindow *toplevel;
2140   Window *old_windows;
2141   Window *new_windows;
2142   int i, count;
2143   
2144   g_return_if_fail (window != NULL);
2145   g_return_if_fail (GDK_IS_WINDOW (window));
2146   
2147   toplevel = gdk_window_get_toplevel (window);
2148   if (GDK_WINDOW_DESTROYED (toplevel))
2149     return;
2150   
2151   old_windows = NULL;
2152   if (!XGetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2153                               GDK_WINDOW_XID (toplevel),
2154                               &old_windows, &count))
2155     {
2156       count = 0;
2157     }
2158   
2159   for (i = 0; i < count; i++)
2160     if (old_windows[i] == GDK_WINDOW_XID (window))
2161       {
2162         XFree (old_windows);
2163         return;
2164       }
2165   
2166   new_windows = g_new (Window, count + 1);
2167   
2168   for (i = 0; i < count; i++)
2169     new_windows[i] = old_windows[i];
2170   new_windows[count] = GDK_WINDOW_XID (window);
2171   
2172   XSetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel),
2173                          GDK_WINDOW_XID (toplevel),
2174                          new_windows, count + 1);
2175   
2176   g_free (new_windows);
2177   if (old_windows)
2178     XFree (old_windows);
2179 }
2180
2181 static gboolean
2182 gdk_window_have_shape_ext (void)
2183 {
2184   enum { UNKNOWN, NO, YES };
2185   static gint have_shape = UNKNOWN;
2186   
2187   if (have_shape == UNKNOWN)
2188     {
2189       int ignore;
2190       if (XQueryExtension (gdk_display, "SHAPE", &ignore, &ignore, &ignore))
2191         have_shape = YES;
2192       else
2193         have_shape = NO;
2194     }
2195   
2196   return (have_shape == YES);
2197 }
2198
2199 #define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.")
2200
2201 /*
2202  * This needs the X11 shape extension.
2203  * If not available, shaped windows will look
2204  * ugly, but programs still work.    Stefan Wille
2205  */
2206 void
2207 gdk_window_shape_combine_mask (GdkWindow *window,
2208                                GdkBitmap *mask,
2209                                gint x, gint y)
2210 {
2211   Pixmap pixmap;
2212   gint xoffset, yoffset;
2213   
2214   g_return_if_fail (window != NULL);
2215   g_return_if_fail (GDK_IS_WINDOW (window));
2216   
2217 #ifdef HAVE_SHAPE_EXT
2218   if (GDK_WINDOW_DESTROYED (window))
2219     return;
2220
2221   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2222
2223   if (xoffset != 0 || yoffset != 0)
2224     {
2225       WARN_SHAPE_TOO_BIG ();
2226       return;
2227     }
2228   
2229   if (gdk_window_have_shape_ext ())
2230     {
2231       if (mask)
2232         {
2233           pixmap = GDK_PIXMAP_XID (mask);
2234         }
2235       else
2236         {
2237           x = 0;
2238           y = 0;
2239           pixmap = None;
2240         }
2241       
2242       XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
2243                          GDK_WINDOW_XID (window),
2244                          ShapeBounding,
2245                          x, y,
2246                          pixmap,
2247                          ShapeSet);
2248     }
2249 #endif /* HAVE_SHAPE_EXT */
2250 }
2251
2252 void
2253 gdk_window_shape_combine_region (GdkWindow *window,
2254                                  GdkRegion *shape_region,
2255                                  gint       offset_x,
2256                                  gint       offset_y)
2257 {
2258   gint xoffset, yoffset;
2259   
2260   g_return_if_fail (GDK_IS_WINDOW (window));
2261   
2262 #ifdef HAVE_SHAPE_EXT
2263   if (GDK_WINDOW_DESTROYED (window))
2264     return;
2265
2266   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2267
2268   if (xoffset != 0 || yoffset != 0)
2269     {
2270       WARN_SHAPE_TOO_BIG ();
2271       return;
2272     }
2273   
2274   if (shape_region == NULL)
2275     {
2276       /* Use NULL mask to unset the shape */
2277       gdk_window_shape_combine_mask (window, NULL, 0, 0);
2278       return;
2279     }
2280   
2281   if (gdk_window_have_shape_ext ())
2282     {
2283       gint n_rects = 0;
2284       XRectangle *xrects = NULL;
2285
2286       _gdk_region_get_xrectangles (shape_region,
2287                                    0, 0,
2288                                    &xrects, &n_rects);
2289       
2290       XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
2291                                GDK_WINDOW_XID (window),
2292                                ShapeBounding,
2293                                offset_x, offset_y,
2294                                xrects, n_rects,
2295                                ShapeSet,
2296                                YXBanded);
2297
2298       g_free (xrects);
2299     }
2300 #endif /* HAVE_SHAPE_EXT */
2301 }
2302
2303
2304 void
2305 gdk_window_set_override_redirect (GdkWindow *window,
2306                                   gboolean override_redirect)
2307 {
2308   XSetWindowAttributes attr;
2309   
2310   g_return_if_fail (window != NULL);
2311   g_return_if_fail (GDK_IS_WINDOW (window));
2312
2313   if (GDK_WINDOW_DESTROYED (window))
2314     {
2315       attr.override_redirect = (override_redirect == FALSE)?False:True;
2316       XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
2317                                GDK_WINDOW_XID (window),
2318                                CWOverrideRedirect,
2319                                &attr);
2320     }
2321 }
2322
2323
2324 /**
2325  * gdk_window_set_icon_list:
2326  * @window: The #GdkWindow toplevel window to set the icon of.
2327  * @pixbufs: A list of pixbufs, of different sizes.
2328  *
2329  * Sets a list of icons for the window. One of these will be used
2330  * to represent the window when it has been iconified. The icon is
2331  * usually shown in an icon box or some sort of task bar. Which icon
2332  * size is shown depends on the window manager. The window manager
2333  * can scale the icon  but setting several size icons can give better
2334  * image quality since the window manager may only need to scale the
2335  * icon by a small amount or not at all.
2336  *
2337  **/
2338 void
2339 gdk_window_set_icon_list (GdkWindow *window,
2340                           GList     *pixbufs)
2341 {
2342   guint *data;
2343   guchar *pixels;
2344   guint *p;
2345   gint size;
2346   GList *l;
2347   GdkPixbuf *pixbuf;
2348   gint width, height, stride;
2349   gint x, y;
2350   gint n_channels;
2351   
2352   g_return_if_fail (GDK_IS_WINDOW (window));
2353
2354   if (GDK_WINDOW_DESTROYED (window))
2355     return;
2356   
2357   l = pixbufs;
2358   size = 0;
2359   
2360   while (l)
2361     {
2362       pixbuf = l->data;
2363       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
2364
2365       width = gdk_pixbuf_get_width (pixbuf);
2366       height = gdk_pixbuf_get_height (pixbuf);
2367       
2368       size += 2 + width * height;
2369
2370       l = g_list_next (l);
2371     }
2372
2373   data = g_malloc (size*4);
2374
2375   l = pixbufs;
2376   p = data;
2377   while (l)
2378     {
2379       pixbuf = l->data;
2380       
2381       width = gdk_pixbuf_get_width (pixbuf);
2382       height = gdk_pixbuf_get_height (pixbuf);
2383       stride = gdk_pixbuf_get_rowstride (pixbuf);
2384       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
2385       
2386       *p++ = width;
2387       *p++ = height;
2388
2389       pixels = gdk_pixbuf_get_pixels (pixbuf);
2390
2391       for (y = 0; y < height; y++)
2392         {
2393           for (x = 0; x < width; x++)
2394             {
2395               guchar r, g, b, a;
2396               
2397               r = pixels[y*stride + x*n_channels + 0];
2398               g = pixels[y*stride + x*n_channels + 1];
2399               b = pixels[y*stride + x*n_channels + 2];
2400               if (n_channels >= 4)
2401                 a = pixels[y*stride + x*n_channels + 3];
2402               else
2403                 a = 255;
2404               
2405               *p++ = a << 24 | r << 16 | g << 8 | b ;
2406             }
2407         }
2408
2409       l = g_list_next (l);
2410     }
2411
2412   if (size > 0)
2413     {
2414       XChangeProperty (GDK_WINDOW_XDISPLAY (window),
2415                        GDK_WINDOW_XID (window),
2416                        gdk_atom_intern ("_NET_WM_ICON", FALSE),
2417                        XA_CARDINAL, 32,
2418                        PropModeReplace,
2419                        (guchar*) data, size);
2420     }
2421   else
2422     {
2423       XDeleteProperty (GDK_WINDOW_XDISPLAY (window),
2424                        GDK_WINDOW_XID (window),
2425                        gdk_atom_intern ("_NET_WM_ICON", FALSE));
2426     }
2427 }
2428
2429 void          
2430 gdk_window_set_icon (GdkWindow *window, 
2431                      GdkWindow *icon_window,
2432                      GdkPixmap *pixmap,
2433                      GdkBitmap *mask)
2434 {
2435   XWMHints *wm_hints;
2436   
2437   g_return_if_fail (window != NULL);
2438   g_return_if_fail (GDK_IS_WINDOW (window));
2439
2440   if (GDK_WINDOW_DESTROYED (window))
2441     return;
2442
2443   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
2444                           GDK_WINDOW_XID (window));
2445   if (!wm_hints)
2446     wm_hints = XAllocWMHints ();
2447
2448   if (icon_window != NULL)
2449     {
2450       wm_hints->flags |= IconWindowHint;
2451       wm_hints->icon_window = GDK_WINDOW_XID (icon_window);
2452     }
2453   
2454   if (pixmap != NULL)
2455     {
2456       wm_hints->flags |= IconPixmapHint;
2457       wm_hints->icon_pixmap = GDK_PIXMAP_XID (pixmap);
2458     }
2459   
2460   if (mask != NULL)
2461     {
2462       wm_hints->flags |= IconMaskHint;
2463       wm_hints->icon_mask = GDK_PIXMAP_XID (mask);
2464     }
2465
2466   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
2467                GDK_WINDOW_XID (window), wm_hints);
2468   XFree (wm_hints);
2469 }
2470
2471 static gboolean
2472 gdk_window_icon_name_set (GdkWindow *window)
2473 {
2474   return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
2475                                                g_quark_from_static_string ("gdk-icon-name-set")));
2476 }
2477
2478 void          
2479 gdk_window_set_icon_name (GdkWindow   *window, 
2480                           const gchar *name)
2481 {
2482   g_return_if_fail (window != NULL);
2483   g_return_if_fail (GDK_IS_WINDOW (window));
2484
2485   if (GDK_WINDOW_DESTROYED (window))
2486     return;
2487
2488   g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
2489                       GUINT_TO_POINTER (TRUE));
2490
2491   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
2492                    GDK_WINDOW_XID (window),
2493                    gdk_atom_intern ("_NET_WM_ICON_NAME", FALSE),
2494                    gdk_atom_intern ("UTF8_STRING", FALSE), 8,
2495                    PropModeReplace, name,
2496                    strlen (name));
2497   set_text_property (window, gdk_atom_intern ("WM_ICON_NAME", FALSE), name);
2498 }
2499
2500 void
2501 gdk_window_iconify (GdkWindow *window)
2502 {
2503   Display *display;
2504   GdkWindowObject *private;
2505   
2506   g_return_if_fail (window != NULL);
2507   g_return_if_fail (GDK_IS_WINDOW (window));
2508
2509   if (GDK_WINDOW_DESTROYED (window))
2510     return;
2511
2512   display = GDK_WINDOW_XDISPLAY (window);
2513
2514   private = (GdkWindowObject*) window;
2515
2516   if (GDK_WINDOW_IS_MAPPED (window))
2517     {  
2518       XIconifyWindow (display, GDK_WINDOW_XWINDOW (window), DefaultScreen (display));
2519
2520     }
2521   else
2522     {
2523       /* Flip our client side flag, the real work happens on map. */
2524       gdk_synthesize_window_state (window,
2525                                    0,
2526                                    GDK_WINDOW_STATE_ICONIFIED);
2527     }
2528 }
2529
2530 void
2531 gdk_window_deiconify (GdkWindow *window)
2532 {
2533   Display *display;
2534   GdkWindowObject *private;
2535   
2536   g_return_if_fail (window != NULL);
2537   g_return_if_fail (GDK_IS_WINDOW (window));
2538
2539   if (GDK_WINDOW_DESTROYED (window))
2540     return;
2541
2542   display = GDK_WINDOW_XDISPLAY (window);
2543
2544   private = (GdkWindowObject*) window;
2545
2546   if (GDK_WINDOW_IS_MAPPED (window))
2547     {  
2548       gdk_window_show (window);
2549     }
2550   else
2551     {
2552       /* Flip our client side flag, the real work happens on map. */
2553       gdk_synthesize_window_state (window,
2554                                    GDK_WINDOW_STATE_ICONIFIED,
2555                                    0);
2556     }
2557 }
2558
2559 void
2560 gdk_window_stick (GdkWindow *window)
2561 {
2562   g_return_if_fail (GDK_IS_WINDOW (window));
2563
2564   if (GDK_WINDOW_DESTROYED (window))
2565     return;
2566
2567   if (GDK_WINDOW_IS_MAPPED (window))
2568     {
2569       /* "stick" means stick to all desktops _and_ do not scroll with the
2570        * viewport. i.e. glue to the monitor glass in all cases.
2571        */
2572       
2573       XEvent xev;
2574
2575       /* Request stick during viewport scroll */
2576       gdk_wmspec_change_state (TRUE, window,
2577                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
2578                                0);
2579
2580       /* Request desktop 0xFFFFFFFF */
2581       xev.xclient.type = ClientMessage;
2582       xev.xclient.serial = 0;
2583       xev.xclient.send_event = True;
2584       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
2585       xev.xclient.display = gdk_display;
2586       xev.xclient.message_type = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
2587       xev.xclient.format = 32;
2588
2589       xev.xclient.data.l[0] = 0xFFFFFFFF;
2590       
2591       XSendEvent (gdk_display, gdk_root_window, False,
2592                   SubstructureRedirectMask | SubstructureNotifyMask,
2593                   &xev);
2594     }
2595   else
2596     {
2597       /* Flip our client side flag, the real work happens on map. */
2598       gdk_synthesize_window_state (window,
2599                                    0,
2600                                    GDK_WINDOW_STATE_STICKY);
2601     }
2602 }
2603
2604 void
2605 gdk_window_unstick (GdkWindow *window)
2606 {
2607   g_return_if_fail (GDK_IS_WINDOW (window));
2608
2609   if (GDK_WINDOW_DESTROYED (window))
2610     return;
2611
2612   if (GDK_WINDOW_IS_MAPPED (window))
2613     {
2614       XEvent xev;
2615       Atom type;
2616       gint format;
2617       gulong nitems;
2618       gulong bytes_after;
2619       gulong *current_desktop;
2620       
2621       /* Request unstick from viewport */
2622       gdk_wmspec_change_state (FALSE, window,
2623                                gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE),
2624                                0);
2625
2626       /* Get current desktop, then set it; this is a race, but not
2627        * one that matters much in practice.
2628        */
2629       XGetWindowProperty (gdk_display, gdk_root_window,
2630                           gdk_atom_intern ("_NET_CURRENT_DESKTOP", FALSE),
2631                           0, G_MAXLONG,
2632                           False, XA_CARDINAL, &type, &format, &nitems,
2633                           &bytes_after, (guchar **)&current_desktop);
2634
2635       if (type == XA_CARDINAL)
2636         {
2637           xev.xclient.type = ClientMessage;
2638           xev.xclient.serial = 0;
2639           xev.xclient.send_event = True;
2640           xev.xclient.window = GDK_WINDOW_XWINDOW (window);
2641           xev.xclient.display = gdk_display;
2642           xev.xclient.message_type = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
2643           xev.xclient.format = 32;
2644
2645           xev.xclient.data.l[0] = *current_desktop;
2646       
2647           XSendEvent (gdk_display, gdk_root_window, False,
2648                       SubstructureRedirectMask | SubstructureNotifyMask,
2649                       &xev);
2650
2651           XFree (current_desktop);
2652         }
2653     }
2654   else
2655     {
2656       /* Flip our client side flag, the real work happens on map. */
2657       gdk_synthesize_window_state (window,
2658                                    GDK_WINDOW_STATE_STICKY,
2659                                    0);
2660
2661     }
2662 }
2663
2664 void
2665 gdk_window_maximize (GdkWindow *window)
2666 {
2667   g_return_if_fail (GDK_IS_WINDOW (window));
2668
2669   if (GDK_WINDOW_DESTROYED (window))
2670     return;
2671
2672   if (GDK_WINDOW_IS_MAPPED (window))
2673     gdk_wmspec_change_state (TRUE, window,
2674                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
2675                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
2676   else
2677     gdk_synthesize_window_state (window,
2678                                  0,
2679                                  GDK_WINDOW_STATE_MAXIMIZED);
2680 }
2681
2682 void
2683 gdk_window_unmaximize (GdkWindow *window)
2684 {
2685   g_return_if_fail (GDK_IS_WINDOW (window));
2686
2687   if (GDK_WINDOW_DESTROYED (window))
2688     return;
2689
2690   if (GDK_WINDOW_IS_MAPPED (window))
2691     gdk_wmspec_change_state (FALSE, window,
2692                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE),
2693                              gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE));
2694   else
2695     gdk_synthesize_window_state (window,
2696                                  GDK_WINDOW_STATE_MAXIMIZED,
2697                                  0);
2698 }
2699
2700 void          
2701 gdk_window_set_group (GdkWindow *window, 
2702                       GdkWindow *leader)
2703 {
2704   XWMHints *wm_hints;
2705   
2706   g_return_if_fail (window != NULL);
2707   g_return_if_fail (GDK_IS_WINDOW (window));
2708   g_return_if_fail (leader != NULL);
2709   g_return_if_fail (GDK_IS_WINDOW (leader));
2710
2711   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
2712     return;
2713   
2714   wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
2715                           GDK_WINDOW_XID (window));
2716   if (!wm_hints)
2717     wm_hints = XAllocWMHints ();
2718
2719   wm_hints->flags |= WindowGroupHint;
2720   wm_hints->window_group = GDK_WINDOW_XID (leader);
2721
2722   XSetWMHints (GDK_WINDOW_XDISPLAY (window),
2723                GDK_WINDOW_XID (window), wm_hints);
2724   XFree (wm_hints);
2725 }
2726
2727 static MotifWmHints *
2728 gdk_window_get_mwm_hints (GdkWindow *window)
2729 {
2730   static Atom hints_atom = None;
2731   MotifWmHints *hints;
2732   Atom type;
2733   gint format;
2734   gulong nitems;
2735   gulong bytes_after;
2736   
2737   if (GDK_WINDOW_DESTROYED (window))
2738     return NULL;
2739   
2740   if (!hints_atom)
2741     hints_atom = XInternAtom (GDK_WINDOW_XDISPLAY (window), 
2742                               _XA_MOTIF_WM_HINTS, FALSE);
2743   
2744   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
2745                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
2746                       False, AnyPropertyType, &type, &format, &nitems,
2747                       &bytes_after, (guchar **)&hints);
2748
2749   if (type == None)
2750     return NULL;
2751   
2752   return hints;
2753 }
2754
2755 static void
2756 gdk_window_set_mwm_hints (GdkWindow *window,
2757                           MotifWmHints *new_hints)
2758 {
2759   static Atom hints_atom = None;
2760   MotifWmHints *hints;
2761   Atom type;
2762   gint format;
2763   gulong nitems;
2764   gulong bytes_after;
2765   
2766   if (GDK_WINDOW_DESTROYED (window))
2767     return;
2768   
2769   if (!hints_atom)
2770     hints_atom = XInternAtom (GDK_WINDOW_XDISPLAY (window), 
2771                               _XA_MOTIF_WM_HINTS, FALSE);
2772   
2773   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
2774                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
2775                       False, AnyPropertyType, &type, &format, &nitems,
2776                       &bytes_after, (guchar **)&hints);
2777   
2778   if (type == None)
2779     hints = new_hints;
2780   else
2781     {
2782       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
2783         {
2784           hints->flags |= MWM_HINTS_FUNCTIONS;
2785           hints->functions = new_hints->functions;
2786         }
2787       if (new_hints->flags & MWM_HINTS_DECORATIONS)
2788         {
2789           hints->flags |= MWM_HINTS_DECORATIONS;
2790           hints->decorations = new_hints->decorations;
2791         }
2792     }
2793   
2794   XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
2795                    hints_atom, hints_atom, 32, PropModeReplace,
2796                    (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
2797   
2798   if (hints != new_hints)
2799     XFree (hints);
2800 }
2801
2802 void
2803 gdk_window_set_decorations (GdkWindow      *window,
2804                             GdkWMDecoration decorations)
2805 {
2806   MotifWmHints hints;
2807   
2808   g_return_if_fail (window != NULL);
2809   g_return_if_fail (GDK_IS_WINDOW (window));
2810   
2811   hints.flags = MWM_HINTS_DECORATIONS;
2812   hints.decorations = decorations;
2813   
2814   gdk_window_set_mwm_hints (window, &hints);
2815 }
2816
2817 /**
2818  * gdk_window_get_decorations:
2819  * @window: The #GdkWindow to get the decorations from
2820  * @decorations: The window decorations will be written here
2821  *
2822  * Returns the decorations set on the GdkWindow with #gdk_window_set_decorations
2823  * Returns: TRUE if the window has decorations set, FALSE otherwise.
2824  **/
2825 gboolean
2826 gdk_window_get_decorations(GdkWindow *window,
2827                            GdkWMDecoration *decorations)
2828 {
2829   MotifWmHints *hints;
2830   gboolean result = FALSE;
2831
2832   hints = gdk_window_get_mwm_hints (window);
2833   
2834   if (hints)
2835     {
2836       if (hints->flags & MWM_HINTS_DECORATIONS)
2837         {
2838           *decorations = hints->decorations;
2839           result = TRUE;
2840         }
2841       
2842       XFree (hints);
2843     }
2844
2845   return result;
2846 }
2847
2848 void
2849 gdk_window_set_functions (GdkWindow    *window,
2850                           GdkWMFunction functions)
2851 {
2852   MotifWmHints hints;
2853   
2854   g_return_if_fail (window != NULL);
2855   g_return_if_fail (GDK_IS_WINDOW (window));
2856   
2857   hints.flags = MWM_HINTS_FUNCTIONS;
2858   hints.functions = functions;
2859   
2860   gdk_window_set_mwm_hints (window, &hints);
2861 }
2862
2863 #ifdef HAVE_SHAPE_EXT
2864
2865 /* 
2866  * propagate the shapes from all child windows of a GDK window to the parent 
2867  * window. Shamelessly ripped from Enlightenment's code
2868  * 
2869  * - Raster
2870  */
2871 struct _gdk_span
2872 {
2873   gint                start;
2874   gint                end;
2875   struct _gdk_span    *next;
2876 };
2877
2878 static void
2879 gdk_add_to_span (struct _gdk_span **s,
2880                  gint               x,
2881                  gint               xx)
2882 {
2883   struct _gdk_span *ptr1, *ptr2, *noo, *ss;
2884   gchar             spanning;
2885   
2886   ptr2 = NULL;
2887   ptr1 = *s;
2888   spanning = 0;
2889   ss = NULL;
2890   /* scan the spans for this line */
2891   while (ptr1)
2892     {
2893       /* -- -> new span */
2894       /* == -> existing span */
2895       /* ## -> spans intersect */
2896       /* if we are in the middle of spanning the span into the line */
2897       if (spanning)
2898         {
2899           /* case: ---- ==== */
2900           if (xx < ptr1->start - 1)
2901             {
2902               /* ends before next span - extend to here */
2903               ss->end = xx;
2904               return;
2905             }
2906           /* case: ----##=== */
2907           else if (xx <= ptr1->end)
2908             {
2909               /* crosses into next span - delete next span and append */
2910               ss->end = ptr1->end;
2911               ss->next = ptr1->next;
2912               g_free (ptr1);
2913               return;
2914             }
2915           /* case: ---###--- */
2916           else
2917             {
2918               /* overlaps next span - delete and keep checking */
2919               ss->next = ptr1->next;
2920               g_free (ptr1);
2921               ptr1 = ss;
2922             }
2923         }
2924       /* otherwise havent started spanning it in yet */
2925       else
2926         {
2927           /* case: ---- ==== */
2928           if (xx < ptr1->start - 1)
2929             {
2930               /* insert span here in list */
2931               noo = g_malloc (sizeof (struct _gdk_span));
2932               
2933               if (noo)
2934                 {
2935                   noo->start = x;
2936                   noo->end = xx;
2937                   noo->next = ptr1;
2938                   if (ptr2)
2939                     ptr2->next = noo;
2940                   else
2941                     *s = noo;
2942                 }
2943               return;
2944             }
2945           /* case: ----##=== */
2946           else if ((x < ptr1->start) && (xx <= ptr1->end))
2947             {
2948               /* expand this span to the left point of the new one */
2949               ptr1->start = x;
2950               return;
2951             }
2952           /* case: ===###=== */
2953           else if ((x >= ptr1->start) && (xx <= ptr1->end))
2954             {
2955               /* throw the span away */
2956               return;
2957             }
2958           /* case: ---###--- */
2959           else if ((x < ptr1->start) && (xx > ptr1->end))
2960             {
2961               ss = ptr1;
2962               spanning = 1;
2963               ptr1->start = x;
2964               ptr1->end = xx;
2965             }
2966           /* case: ===##---- */
2967           else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end))
2968             {
2969               ss = ptr1;
2970               spanning = 1;
2971               ptr1->end = xx;
2972             }
2973           /* case: ==== ---- */
2974           /* case handled by next loop iteration - first case */
2975         }
2976       ptr2 = ptr1;
2977       ptr1 = ptr1->next;
2978     }
2979   /* it started in the middle but spans beyond your current list */
2980   if (spanning)
2981     {
2982       ptr2->end = xx;
2983       return;
2984     }
2985   /* it does not start inside a span or in the middle, so add it to the end */
2986   noo = g_malloc (sizeof (struct _gdk_span));
2987   
2988   if (noo)
2989     {
2990       noo->start = x;
2991       noo->end = xx;
2992       if (ptr2)
2993         {
2994           noo->next = ptr2->next;
2995           ptr2->next = noo;
2996         }
2997       else
2998         {
2999           noo->next = NULL;
3000           *s = noo;
3001         }
3002     }
3003   return;
3004 }
3005
3006 static void
3007 gdk_add_rectangles (Display           *disp,
3008                     Window             win,
3009                     struct _gdk_span **spans,
3010                     gint               basew,
3011                     gint               baseh,
3012                     gint               x,
3013                     gint               y)
3014 {
3015   gint a, k;
3016   gint x1, y1, x2, y2;
3017   gint rn, ord;
3018   XRectangle *rl;
3019   
3020   rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord);
3021   if (rl)
3022     {
3023       /* go through all clip rects in this window's shape */
3024       for (k = 0; k < rn; k++)
3025         {
3026           /* for each clip rect, add it to each line's spans */
3027           x1 = x + rl[k].x;
3028           x2 = x + rl[k].x + (rl[k].width - 1);
3029           y1 = y + rl[k].y;
3030           y2 = y + rl[k].y + (rl[k].height - 1);
3031           if (x1 < 0)
3032             x1 = 0;
3033           if (y1 < 0)
3034             y1 = 0;
3035           if (x2 >= basew)
3036             x2 = basew - 1;
3037           if (y2 >= baseh)
3038             y2 = baseh - 1;
3039           for (a = y1; a <= y2; a++)
3040             {
3041               if ((x2 - x1) >= 0)
3042                 gdk_add_to_span (&spans[a], x1, x2);
3043             }
3044         }
3045       XFree (rl);
3046     }
3047 }
3048
3049 static void
3050 gdk_propagate_shapes (Display *disp,
3051                       Window   win,
3052                       gboolean merge)
3053 {
3054   Window              rt, par, *list = NULL;
3055   gint                i, j, num = 0, num_rects = 0;
3056   gint                x, y, contig;
3057   guint               w, h, d;
3058   gint                baseh, basew;
3059   XRectangle         *rects = NULL;
3060   struct _gdk_span  **spans = NULL, *ptr1, *ptr2, *ptr3;
3061   XWindowAttributes   xatt;
3062   
3063   XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d);
3064   if (h <= 0)
3065     return;
3066   basew = w;
3067   baseh = h;
3068   spans = g_malloc (sizeof (struct _gdk_span *) * h);
3069   
3070   for (i = 0; i < h; i++)
3071     spans[i] = NULL;
3072   XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num);
3073   if (list)
3074     {
3075       /* go through all child windows and create/insert spans */
3076       for (i = 0; i < num; i++)
3077         {
3078           if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped))
3079             if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d))
3080               gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y);
3081         }
3082       if (merge)
3083         gdk_add_rectangles (disp, win, spans, basew, baseh, x, y);
3084       
3085       /* go through the spans list and build a list of rects */
3086       rects = g_malloc (sizeof (XRectangle) * 256);
3087       num_rects = 0;
3088       for (i = 0; i < baseh; i++)
3089         {
3090           ptr1 = spans[i];
3091           /* go through the line for all spans */
3092           while (ptr1)
3093             {
3094               rects[num_rects].x = ptr1->start;
3095               rects[num_rects].y = i;
3096               rects[num_rects].width = ptr1->end - ptr1->start + 1;
3097               rects[num_rects].height = 1;
3098               j = i + 1;
3099               /* if there are more lines */
3100               contig = 1;
3101               /* while contigous rects (same start/end coords) exist */
3102               while ((contig) && (j < baseh))
3103                 {
3104                   /* search next line for spans matching this one */
3105                   contig = 0;
3106                   ptr2 = spans[j];
3107                   ptr3 = NULL;
3108                   while (ptr2)
3109                     {
3110                       /* if we have an exact span match set contig */
3111                       if ((ptr2->start == ptr1->start) &&
3112                           (ptr2->end == ptr1->end))
3113                         {
3114                           contig = 1;
3115                           /* remove the span - not needed */
3116                           if (ptr3)
3117                             {
3118                               ptr3->next = ptr2->next;
3119                               g_free (ptr2);
3120                               ptr2 = NULL;
3121                             }
3122                           else
3123                             {
3124                               spans[j] = ptr2->next;
3125                               g_free (ptr2);
3126                               ptr2 = NULL;
3127                             }
3128                           break;
3129                         }
3130                       /* gone past the span point no point looking */
3131                       else if (ptr2->start < ptr1->start)
3132                         break;
3133                       if (ptr2)
3134                         {
3135                           ptr3 = ptr2;
3136                           ptr2 = ptr2->next;
3137                         }
3138                     }
3139                   /* if a contiguous span was found increase the rect h */
3140                   if (contig)
3141                     {
3142                       rects[num_rects].height++;
3143                       j++;
3144                     }
3145                 }
3146               /* up the rect count */
3147               num_rects++;
3148               /* every 256 new rects increase the rect array */
3149               if ((num_rects % 256) == 0)
3150                 rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256));
3151               ptr1 = ptr1->next;
3152             }
3153         }
3154       /* set the rects as the shape mask */
3155       if (rects)
3156         {
3157           XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects,
3158                                    ShapeSet, YXSorted);
3159           g_free (rects);
3160         }
3161       XFree (list);
3162     }
3163   /* free up all the spans we made */
3164   for (i = 0; i < baseh; i++)
3165     {
3166       ptr1 = spans[i];
3167       while (ptr1)
3168         {
3169           ptr2 = ptr1;
3170           ptr1 = ptr1->next;
3171           g_free (ptr2);
3172         }
3173     }
3174   g_free (spans);
3175 }
3176
3177 #endif /* HAVE_SHAPE_EXT */
3178
3179 void
3180 gdk_window_set_child_shapes (GdkWindow *window)
3181 {
3182   g_return_if_fail (window != NULL);
3183   g_return_if_fail (GDK_IS_WINDOW (window));
3184   
3185 #ifdef HAVE_SHAPE_EXT
3186   if (!GDK_WINDOW_DESTROYED (window) &&
3187       gdk_window_have_shape_ext ())
3188     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3189                           GDK_WINDOW_XID (window), FALSE);
3190 #endif   
3191 }
3192
3193 void
3194 gdk_window_merge_child_shapes (GdkWindow *window)
3195 {
3196   g_return_if_fail (window != NULL);
3197   g_return_if_fail (GDK_IS_WINDOW (window));
3198   
3199 #ifdef HAVE_SHAPE_EXT
3200   if (!GDK_WINDOW_DESTROYED (window) &&
3201       gdk_window_have_shape_ext ())
3202     gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
3203                           GDK_WINDOW_XID (window), TRUE);
3204 #endif   
3205 }
3206
3207 /* Support for windows that can be guffaw-scrolled
3208  * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
3209  */
3210
3211 static gboolean
3212 gdk_window_gravity_works (void)
3213 {
3214   enum { UNKNOWN, NO, YES };
3215   static gint gravity_works = UNKNOWN;
3216   
3217   if (gravity_works == UNKNOWN)
3218     {
3219       GdkWindowAttr attr;
3220       GdkWindow *parent;
3221       GdkWindow *child;
3222       gint y;
3223       
3224       /* This particular server apparently has a bug so that the test
3225        * works but the actual code crashes it
3226        */
3227       if ((!strcmp (XServerVendor (gdk_display), "Sun Microsystems, Inc.")) &&
3228           (VendorRelease (gdk_display) == 3400))
3229         {
3230           gravity_works = NO;
3231           return FALSE;
3232         }
3233       
3234       attr.window_type = GDK_WINDOW_TEMP;
3235       attr.wclass = GDK_INPUT_OUTPUT;
3236       attr.x = 0;
3237       attr.y = 0;
3238       attr.width = 100;
3239       attr.height = 100;
3240       attr.event_mask = 0;
3241       
3242       parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y);
3243       
3244       attr.window_type = GDK_WINDOW_CHILD;
3245       child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
3246       
3247       gdk_window_set_static_win_gravity (child, TRUE);
3248       
3249       gdk_window_resize (parent, 100, 110);
3250       gdk_window_move (parent, 0, -10);
3251       gdk_window_move_resize (parent, 0, 0, 100, 100);
3252       
3253       gdk_window_resize (parent, 100, 110);
3254       gdk_window_move (parent, 0, -10);
3255       gdk_window_move_resize (parent, 0, 0, 100, 100);
3256       
3257       gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
3258       
3259       gdk_window_destroy (parent);
3260       gdk_window_destroy (child);
3261       
3262       gravity_works = ((y == -20) ? YES : NO);
3263     }
3264   
3265   return (gravity_works == YES);
3266 }
3267
3268 static void
3269 gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
3270 {
3271   XSetWindowAttributes xattributes;
3272   guint xattributes_mask = 0;
3273   
3274   g_return_if_fail (window != NULL);
3275   
3276   xattributes.bit_gravity = StaticGravity;
3277   xattributes_mask |= CWBitGravity;
3278   xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
3279   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3280                            GDK_WINDOW_XID (window),
3281                            CWBitGravity,  &xattributes);
3282 }
3283
3284 static void
3285 gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
3286 {
3287   XSetWindowAttributes xattributes;
3288   
3289   g_return_if_fail (window != NULL);
3290   
3291   xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
3292   
3293   XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window),
3294                            GDK_WINDOW_XID (window),
3295                            CWWinGravity,  &xattributes);
3296 }
3297
3298 /*************************************************************
3299  * gdk_window_set_static_gravities:
3300  *     Set the bit gravity of the given window to static,
3301  *     and flag it so all children get static subwindow
3302  *     gravity.
3303  *   arguments:
3304  *     window: window for which to set static gravity
3305  *     use_static: Whether to turn static gravity on or off.
3306  *   results:
3307  *     Does the XServer support static gravity?
3308  *************************************************************/
3309
3310 gboolean 
3311 gdk_window_set_static_gravities (GdkWindow *window,
3312                                  gboolean   use_static)
3313 {
3314   GdkWindowObject *private = (GdkWindowObject *)window;
3315   GList *tmp_list;
3316   
3317   g_return_val_if_fail (window != NULL, FALSE);
3318   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
3319
3320   if (!use_static == !private->guffaw_gravity)
3321     return TRUE;
3322   
3323   if (use_static && !gdk_window_gravity_works ())
3324     return FALSE;
3325   
3326   private->guffaw_gravity = use_static;
3327   
3328   if (!GDK_WINDOW_DESTROYED (window))
3329     {
3330       gdk_window_set_static_bit_gravity (window, use_static);
3331       
3332       tmp_list = private->children;
3333       while (tmp_list)
3334         {
3335           gdk_window_set_static_win_gravity (window, use_static);
3336           
3337           tmp_list = tmp_list->next;
3338         }
3339     }
3340   
3341   return TRUE;
3342 }
3343
3344 /* internal function created for and used by gdk_window_xid_at_coords */
3345 Window
3346 gdk_window_xid_at (Window   base,
3347                    gint     bx,
3348                    gint     by,
3349                    gint     x,
3350                    gint     y, 
3351                    GList   *excludes,
3352                    gboolean excl_child)
3353 {
3354   Display *xdisplay;
3355   Window *list = NULL;
3356   Window child = 0, parent_win = 0, root_win = 0;
3357   int i;
3358   unsigned int ww, wh, wb, wd, num;
3359   int wx, wy;
3360   
3361   xdisplay = GDK_DISPLAY ();
3362   if (!XGetGeometry (xdisplay, base, &root_win, &wx, &wy, &ww, &wh, &wb, &wd))
3363     return 0;
3364   wx += bx;
3365   wy += by;
3366   
3367   if (!((x >= wx) &&
3368         (y >= wy) &&
3369         (x < (int) (wx + ww)) &&
3370         (y < (int) (wy + wh))))
3371     return 0;
3372   
3373   if (!XQueryTree (xdisplay, base, &root_win, &parent_win, &list, &num))
3374     return base;
3375   
3376   if (list)
3377     {
3378       for (i = num - 1; ; i--)
3379         {
3380           if ((!excl_child) || (!g_list_find (excludes, (gpointer *) list[i])))
3381             {
3382               if ((child = gdk_window_xid_at (list[i], wx, wy, x, y, excludes, excl_child)) != 0)
3383                 {
3384                   XFree (list);
3385                   return child;
3386                 }
3387             }
3388           if (!i)
3389             break;
3390         }
3391       XFree (list);
3392     }
3393   return base;
3394 }
3395
3396 /* 
3397  * The following fucntion by The Rasterman <raster@redhat.com>
3398  * This function returns the X Window ID in which the x y location is in 
3399  * (x and y being relative to the root window), excluding any windows listed
3400  * in the GList excludes (this is a list of X Window ID's - gpointer being
3401  * the Window ID).
3402  * 
3403  * This is primarily designed for internal gdk use - for DND for example
3404  * when using a shaped icon window as the drag object - you exclude the
3405  * X Window ID of the "icon" (perhaps more if excludes may be needed) and
3406  * You can get back an X Window ID as to what X Window ID is infact under
3407  * those X,Y co-ordinates.
3408  */
3409 Window
3410 gdk_window_xid_at_coords (gint     x,
3411                           gint     y,
3412                           GList   *excludes,
3413                           gboolean excl_child)
3414 {
3415   GdkWindow *window;
3416   Display *xdisplay;
3417   Window *list = NULL;
3418   Window root, child = 0, parent_win = 0, root_win = 0;
3419   unsigned int num;
3420   int i;
3421
3422   window = gdk_parent_root;
3423   xdisplay = GDK_WINDOW_XDISPLAY (window);
3424   root = GDK_WINDOW_XID (window);
3425   num = g_list_length (excludes);
3426   
3427   gdk_x11_grab_server ();
3428   if (!XQueryTree (xdisplay, root, &root_win, &parent_win, &list, &num))
3429     {
3430       gdk_x11_ungrab_server ();
3431       return root;
3432     }
3433   if (list)
3434     {
3435       i = num - 1;
3436       do
3437         {
3438           XWindowAttributes xwa;
3439           
3440           XGetWindowAttributes (xdisplay, list [i], &xwa);
3441           
3442           if (xwa.map_state != IsViewable)
3443             continue;
3444           
3445           if (excl_child && g_list_find (excludes, (gpointer *) list[i]))
3446             continue;
3447           
3448           if ((child = gdk_window_xid_at (list[i], 0, 0, x, y, excludes, excl_child)) == 0)
3449             continue;
3450           
3451           if (excludes)
3452             {
3453               if (!g_list_find (excludes, (gpointer *) child))
3454                 {
3455                   XFree (list);
3456                   gdk_x11_ungrab_server ();
3457                   return child;
3458                 }
3459             }
3460           else
3461             {
3462               XFree (list);
3463               gdk_x11_ungrab_server ();
3464               return child;
3465             }
3466         } while (--i > 0);
3467       XFree (list);
3468     }
3469   gdk_x11_ungrab_server ();
3470   return root;
3471 }
3472
3473 static void
3474 wmspec_moveresize (GdkWindow *window,
3475                    gint       direction,
3476                    gint       root_x,
3477                    gint       root_y,
3478                    guint32    timestamp)     
3479 {
3480   XEvent xev;
3481
3482   /* Release passive grab */
3483   gdk_pointer_ungrab (timestamp);
3484   
3485   xev.xclient.type = ClientMessage;
3486   xev.xclient.serial = 0;
3487   xev.xclient.send_event = True;
3488   xev.xclient.display = gdk_display;
3489   xev.xclient.window = GDK_WINDOW_XID (window);
3490   xev.xclient.message_type = gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE);
3491   xev.xclient.format = 32;
3492   xev.xclient.data.l[0] = root_x;
3493   xev.xclient.data.l[1] = root_y;
3494   xev.xclient.data.l[2] = direction;
3495   xev.xclient.data.l[3] = 0;
3496   xev.xclient.data.l[4] = 0;
3497   
3498   XSendEvent (gdk_display, gdk_root_window, False,
3499               SubstructureRedirectMask | SubstructureNotifyMask,
3500               &xev);
3501 }
3502
3503 /* From the WM spec */
3504 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
3505 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
3506 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
3507 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
3508 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
3509 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
3510 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
3511 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
3512 #define _NET_WM_MOVERESIZE_MOVE              8
3513
3514 static void
3515 wmspec_resize_drag (GdkWindow     *window,
3516                     GdkWindowEdge  edge,
3517                     gint           button,
3518                     gint           root_x,
3519                     gint           root_y,
3520                     guint32        timestamp)
3521 {
3522   gint direction;
3523   
3524   /* Let the compiler turn a switch into a table, instead
3525    * of doing the table manually, this way is easier to verify.
3526    */
3527   switch (edge)
3528     {
3529     case GDK_WINDOW_EDGE_NORTH_WEST:
3530       direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
3531       break;
3532
3533     case GDK_WINDOW_EDGE_NORTH:
3534       direction = _NET_WM_MOVERESIZE_SIZE_TOP;
3535       break;
3536
3537     case GDK_WINDOW_EDGE_NORTH_EAST:
3538       direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
3539       break;
3540
3541     case GDK_WINDOW_EDGE_WEST:
3542       direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
3543       break;
3544
3545     case GDK_WINDOW_EDGE_EAST:
3546       direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
3547       break;
3548
3549     case GDK_WINDOW_EDGE_SOUTH_WEST:
3550       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
3551       break;
3552
3553     case GDK_WINDOW_EDGE_SOUTH:
3554       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
3555       break;
3556
3557     case GDK_WINDOW_EDGE_SOUTH_EAST:
3558       direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
3559       break;
3560
3561     default:
3562       g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!",
3563                  edge);
3564       return;
3565       break;
3566     }
3567   
3568   wmspec_moveresize (window, direction, root_x, root_y, timestamp);
3569 }
3570
3571 /* This is global for use in gdkevents-x11.c */
3572 GdkWindow *_gdk_moveresize_window;
3573
3574 static GdkWindow *moveresize_emulation_window = NULL;
3575 static gboolean is_resize = FALSE;
3576 static GdkWindowEdge resize_edge;
3577 static gint moveresize_button;
3578 static gint moveresize_x;
3579 static gint moveresize_y;
3580 static gint moveresize_orig_x;
3581 static gint moveresize_orig_y;
3582 static gint moveresize_orig_width;
3583 static gint moveresize_orig_height;
3584 static GdkWindowHints moveresize_geom_mask = 0;
3585 static GdkGeometry moveresize_geometry;
3586 static Time moveresize_process_time;
3587
3588 static XEvent *moveresize_pending_event;
3589
3590 static void
3591 update_pos (gint new_root_x,
3592             gint new_root_y)
3593 {
3594   gint dx, dy;
3595   
3596   dx = new_root_x - moveresize_x;
3597   dy = new_root_y - moveresize_y;
3598
3599   if (is_resize)
3600     {
3601       gint w, h;
3602
3603       w = moveresize_orig_width;
3604       h = moveresize_orig_height;
3605       
3606       switch (resize_edge)
3607         {
3608         case GDK_WINDOW_EDGE_SOUTH_EAST:
3609           w += dx;
3610           h += dy;
3611           break;
3612         }
3613
3614       w = MAX (w, 1);
3615       h = MAX (h, 1);
3616       
3617       if (moveresize_geom_mask)
3618         {
3619           gdk_window_constrain_size (&moveresize_geometry,
3620                                      moveresize_geom_mask,
3621                                      w, h,
3622                                      &w, &h);
3623         }
3624       
3625       gdk_window_resize (_gdk_moveresize_window, w, h);
3626     }
3627   else
3628     {
3629       gint x, y;
3630
3631       x = moveresize_orig_x + dx;
3632       y = moveresize_orig_y + dy;
3633       
3634       gdk_window_move (_gdk_moveresize_window, x, y);
3635     }
3636 }
3637
3638 static void
3639 finish_drag (void)
3640 {
3641   gdk_window_destroy (moveresize_emulation_window);
3642   moveresize_emulation_window = NULL;
3643   _gdk_moveresize_window = NULL;
3644
3645   if (moveresize_pending_event)
3646     {
3647       g_free (moveresize_pending_event);
3648       moveresize_pending_event = NULL;
3649     }
3650 }
3651
3652 static int
3653 lookahead_motion_predicate (Display *display,
3654                             XEvent  *event,
3655                             XPointer arg)
3656 {
3657   gboolean *seen_release = (gboolean *)arg;
3658   
3659   if (*seen_release)
3660     return False;
3661
3662   switch (event->xany.type)
3663     {
3664     case ButtonRelease:
3665       *seen_release = TRUE;
3666       break;
3667     case MotionNotify:
3668       moveresize_process_time = event->xmotion.time;
3669       break;
3670     default:
3671       break;
3672     }
3673
3674   return False;
3675 }
3676
3677 static gboolean
3678 moveresize_lookahead (XEvent *event)
3679 {
3680   XEvent tmp_event;
3681   gboolean seen_release = FALSE;
3682
3683   if (moveresize_process_time)
3684     {
3685       if (event->xmotion.time == moveresize_process_time)
3686         {
3687           moveresize_process_time = 0;
3688           return TRUE;
3689         }
3690       else
3691         return FALSE;
3692     }
3693
3694   XCheckIfEvent (gdk_display, &tmp_event,
3695                  lookahead_motion_predicate, (XPointer)&seen_release);
3696
3697   return moveresize_process_time == 0;
3698 }
3699         
3700 void
3701 _gdk_moveresize_handle_event (XEvent *event)
3702 {
3703   guint button_mask = 0;
3704   GdkWindowObject *window_private = (GdkWindowObject *) _gdk_moveresize_window;
3705   
3706   button_mask = GDK_BUTTON1_MASK << (moveresize_button - 1);
3707   
3708   switch (event->xany.type)
3709     {
3710     case MotionNotify:
3711       if (window_private->resize_count > 0)
3712         {
3713           if (moveresize_pending_event)
3714             *moveresize_pending_event = *event;
3715           else
3716             moveresize_pending_event = g_memdup (event, sizeof (XEvent));
3717
3718           break;
3719         }
3720       if (!moveresize_lookahead (event))
3721         break;
3722       
3723       update_pos (event->xmotion.x_root,
3724                   event->xmotion.y_root);
3725       
3726       /* This should never be triggered in normal cases, but in the
3727        * case where the drag started without an implicit grab being
3728        * in effect, we could miss the release if it occurs before
3729        * we grab the pointer; this ensures that we will never
3730        * get a permanently stuck grab.
3731        */
3732       if ((event->xmotion.state & button_mask) == 0)
3733         finish_drag ();
3734       break;
3735
3736     case ButtonRelease:
3737       update_pos (event->xbutton.x_root,
3738                   event->xbutton.y_root);
3739       
3740       if (event->xbutton.button == moveresize_button)
3741         finish_drag ();
3742       break;
3743     }
3744 }
3745
3746 void
3747 _gdk_moveresize_configure_done (void)
3748 {
3749   XEvent *tmp_event;
3750   
3751   if (moveresize_pending_event)
3752     {
3753       tmp_event = moveresize_pending_event;
3754       moveresize_pending_event = NULL;
3755       _gdk_moveresize_handle_event (tmp_event);
3756       g_free (tmp_event);
3757     }
3758 }
3759
3760 static void
3761 create_moveresize_window (guint32 timestamp)
3762 {
3763   GdkWindowAttr attributes;
3764   gint attributes_mask;
3765   GdkGrabStatus status;
3766
3767   g_assert (moveresize_emulation_window == NULL);
3768   
3769   attributes.x = -100;
3770   attributes.y = -100;
3771   attributes.width = 10;
3772   attributes.height = 10;
3773   attributes.window_type = GDK_WINDOW_TEMP;
3774   attributes.wclass = GDK_INPUT_ONLY;
3775   attributes.override_redirect = TRUE;
3776   attributes.event_mask = 0;
3777
3778   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
3779
3780   moveresize_emulation_window =
3781     gdk_window_new (NULL, &attributes, attributes_mask);
3782
3783   gdk_window_show (moveresize_emulation_window);
3784
3785   status = gdk_pointer_grab (moveresize_emulation_window,
3786                              FALSE,
3787                              GDK_BUTTON_RELEASE_MASK |
3788                              GDK_POINTER_MOTION_MASK,
3789                              FALSE,
3790                              NULL,
3791                              timestamp);
3792
3793   if (status != GDK_GRAB_SUCCESS)
3794     {
3795       /* If this fails, some other client has grabbed the window
3796        * already.
3797        */
3798       gdk_window_destroy (moveresize_emulation_window);
3799       moveresize_emulation_window = NULL;
3800     }
3801
3802   moveresize_process_time = 0;
3803 }
3804
3805 static void
3806 emulate_resize_drag (GdkWindow     *window,
3807                      GdkWindowEdge  edge,
3808                      gint           button,
3809                      gint           root_x,
3810                      gint           root_y,
3811                      guint32        timestamp)
3812 {
3813   is_resize = TRUE;
3814   moveresize_button = button;
3815   resize_edge = edge;
3816   moveresize_x = root_x;
3817   moveresize_y = root_y;
3818   _gdk_moveresize_window = GDK_WINDOW (g_object_ref (G_OBJECT (window)));
3819
3820   gdk_window_get_size (window, &moveresize_orig_width, &moveresize_orig_height);
3821   
3822   moveresize_geom_mask = 0;
3823   gdk_window_get_geometry_hints (window,
3824                                  &moveresize_geometry,
3825                                  &moveresize_geom_mask);
3826   
3827   create_moveresize_window (timestamp);
3828 }
3829
3830 static void
3831 emulate_move_drag (GdkWindow     *window,
3832                    gint           button,
3833                    gint           root_x,
3834                    gint           root_y,
3835                    guint32        timestamp)
3836 {
3837   is_resize = FALSE;
3838   moveresize_button = button;
3839   moveresize_x = root_x;
3840   moveresize_y = root_y;
3841   _gdk_moveresize_window = GDK_WINDOW (g_object_ref (G_OBJECT (window)));
3842
3843   gdk_window_get_deskrelative_origin (_gdk_moveresize_window,
3844                                       &moveresize_orig_x,
3845                                       &moveresize_orig_y);
3846   
3847   create_moveresize_window (timestamp);
3848 }
3849
3850 void
3851 gdk_window_begin_resize_drag (GdkWindow     *window,
3852                               GdkWindowEdge  edge,
3853                               gint           button,
3854                               gint           root_x,
3855                               gint           root_y,
3856                               guint32        timestamp)
3857 {
3858   g_return_if_fail (GDK_IS_WINDOW (window));
3859   g_return_if_fail (moveresize_emulation_window == NULL);
3860   
3861   if (GDK_WINDOW_DESTROYED (window))
3862     return;
3863
3864   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
3865     wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp);
3866   else
3867     emulate_resize_drag (window, edge, button, root_x, root_y, timestamp);
3868 }
3869
3870 void
3871 gdk_window_begin_move_drag (GdkWindow *window,
3872                             gint       button,
3873                             gint       root_x,
3874                             gint       root_y,
3875                             guint32    timestamp)
3876 {
3877   g_return_if_fail (GDK_IS_WINDOW (window));
3878   g_return_if_fail (moveresize_emulation_window == NULL);
3879   
3880   if (GDK_WINDOW_DESTROYED (window))
3881     return;
3882
3883   if (gdk_net_wm_supports (gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE)))
3884     wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE,
3885                        root_x, root_y, timestamp);
3886   else
3887     emulate_move_drag (window, button, root_x, root_y, timestamp);
3888 }