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