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