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