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