]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkwindow-x11.c
A bit of editing.
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <netinet/in.h>
31 #include "gdk.h"
32 #include "config.h"
33
34 #include "gdkwindow.h"
35 #include "gdkinputprivate.h"
36 #include "gdkprivate-x11.h"
37 #include "gdkregion.h"
38 #include "gdkinternals.h"
39 #include "MwmUtil.h"
40
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44
45
46 #ifdef HAVE_SHAPE_EXT
47 #include <X11/extensions/shape.h>
48 #endif
49
50 const int gdk_event_mask_table[21] =
51 {
52   ExposureMask,
53   PointerMotionMask,
54   PointerMotionHintMask,
55   ButtonMotionMask,
56   Button1MotionMask,
57   Button2MotionMask,
58   Button3MotionMask,
59   ButtonPressMask,
60   ButtonReleaseMask,
61   KeyPressMask,
62   KeyReleaseMask,
63   EnterWindowMask,
64   LeaveWindowMask,
65   FocusChangeMask,
66   StructureNotifyMask,
67   PropertyChangeMask,
68   VisibilityChangeMask,
69   0,                            /* PROXIMITY_IN */
70   0,                            /* PROXIMTY_OUT */
71   SubstructureNotifyMask,
72   ButtonPressMask      /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
73 };
74 const int gdk_nevent_masks = sizeof (gdk_event_mask_table) / sizeof (int);
75
76 /* Forward declarations */
77 static gboolean gdk_window_gravity_works (void);
78 static void     gdk_window_set_static_win_gravity (GdkWindow *window, 
79                                                    gboolean   on);
80 static gboolean gdk_window_have_shape_ext (void);
81
82 GdkDrawableClass _gdk_windowing_window_class;
83
84 static void
85 gdk_x11_window_destroy (GdkDrawable *drawable)
86 {
87   if (!GDK_DRAWABLE_DESTROYED (drawable))
88     {
89       if (GDK_DRAWABLE_TYPE (drawable) != GDK_WINDOW_FOREIGN)
90         {
91           g_warning ("losing last reference to undestroyed window\n");
92           _gdk_window_destroy (drawable, FALSE);
93         }
94       else
95         /* We use TRUE here, to keep us from actually calling
96          * XDestroyWindow() on the window
97          */
98         _gdk_window_destroy (drawable, TRUE);
99       
100       gdk_xid_table_remove (GDK_DRAWABLE_XID (drawable));
101     }
102
103   g_free (GDK_DRAWABLE_XDATA (drawable));
104 }
105
106 static GdkWindow *
107 gdk_x11_window_alloc (void)
108 {
109   GdkWindow *window;
110   GdkWindowPrivate *private;
111   
112   static gboolean initialized = FALSE;
113
114   if (!initialized)
115     {
116       initialized = TRUE;
117
118       _gdk_windowing_window_class = _gdk_x11_drawable_class;
119       _gdk_windowing_window_class.destroy = gdk_x11_window_destroy;
120     }
121
122   window = _gdk_window_alloc ();
123   private = (GdkWindowPrivate *)window;
124
125   private->drawable.klass = &_gdk_window_class;
126   private->drawable.klass_data = g_new (GdkWindowXData, 1);
127
128   return window;
129 }
130
131 void
132 gdk_window_init (void)
133 {
134   GdkWindowPrivate *private;
135   XWindowAttributes xattributes;
136   unsigned int width;
137   unsigned int height;
138   unsigned int border_width;
139   unsigned int depth;
140   int x, y;
141   
142   XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window,
143                 &x, &y, &width, &height, &border_width, &depth);
144   XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes);
145
146   gdk_parent_root = gdk_x11_window_alloc ();
147   private = (GdkWindowPrivate *)gdk_parent_root;
148   
149   GDK_DRAWABLE_XDATA (gdk_parent_root)->xdisplay = gdk_display;
150   GDK_DRAWABLE_XDATA (gdk_parent_root)->xid = gdk_root_window;
151
152   private->drawable.window_type = GDK_WINDOW_ROOT;
153   private->drawable.width = width;
154   private->drawable.height = height;
155   
156   gdk_xid_table_insert (&gdk_root_window, gdk_parent_root);
157 }
158
159 static GdkAtom wm_client_leader_atom = GDK_NONE;
160
161 GdkWindow*
162 gdk_window_new (GdkWindow     *parent,
163                 GdkWindowAttr *attributes,
164                 gint           attributes_mask)
165 {
166   GdkWindow *window;
167   GdkWindowPrivate *private;
168   GdkWindowPrivate *parent_private;
169   
170   GdkVisual *visual;
171   Window xparent;
172   Visual *xvisual;
173
174   XSetWindowAttributes xattributes;
175   long xattributes_mask;
176   XSizeHints size_hints;
177   XWMHints wm_hints;
178   XClassHint *class_hint;
179   int x, y, depth;
180   
181   unsigned int class;
182   char *title;
183   int i;
184   
185   g_return_val_if_fail (attributes != NULL, NULL);
186   
187   if (!parent)
188     parent = gdk_parent_root;
189   
190   parent_private = (GdkWindowPrivate*) parent;
191   if (GDK_DRAWABLE_DESTROYED (parent))
192     return NULL;
193   
194   xparent = GDK_DRAWABLE_XID (parent);
195   
196   window = gdk_x11_window_alloc ();
197   private = (GdkWindowPrivate *)window;
198
199   GDK_DRAWABLE_XDATA (window)->xdisplay = GDK_DRAWABLE_XDISPLAY (parent);
200   
201   private->parent = parent;
202
203   xattributes_mask = 0;
204   
205   if (attributes_mask & GDK_WA_X)
206     x = attributes->x;
207   else
208     x = 0;
209   
210   if (attributes_mask & GDK_WA_Y)
211     y = attributes->y;
212   else
213     y = 0;
214   
215   private->x = x;
216   private->y = y;
217   private->drawable.width = (attributes->width > 1) ? (attributes->width) : (1);
218   private->drawable.height = (attributes->height > 1) ? (attributes->height) : (1);
219   private->drawable.window_type = attributes->window_type;
220
221   _gdk_window_init_position (window);
222   if (GDK_WINDOW_XDATA (window)->position_info.big)
223     private->guffaw_gravity = TRUE;
224   
225   if (attributes_mask & GDK_WA_VISUAL)
226     visual = attributes->visual;
227   else
228     visual = gdk_visual_get_system ();
229   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
230   
231   xattributes.event_mask = StructureNotifyMask;
232   for (i = 0; i < gdk_nevent_masks; i++)
233     {
234       if (attributes->event_mask & (1 << (i + 1)))
235         xattributes.event_mask |= gdk_event_mask_table[i];
236     }
237   
238   if (xattributes.event_mask)
239     xattributes_mask |= CWEventMask;
240   
241   if (attributes_mask & GDK_WA_NOREDIR)
242     {
243       xattributes.override_redirect =
244         (attributes->override_redirect == FALSE)?False:True;
245       xattributes_mask |= CWOverrideRedirect;
246     } 
247   else
248     xattributes.override_redirect = False;
249
250   if (parent_private && parent_private->guffaw_gravity)
251     {
252       xattributes.win_gravity = StaticGravity;
253       xattributes_mask |= CWWinGravity;
254     }
255   
256   if (attributes->wclass == GDK_INPUT_OUTPUT)
257     {
258       class = InputOutput;
259       depth = visual->depth;
260
261       private->input_only = FALSE;
262       private->drawable.depth = depth;
263       
264       if (attributes_mask & GDK_WA_COLORMAP)
265         private->drawable.colormap = attributes->colormap;
266       else
267         {
268           if ((((GdkVisualPrivate*)gdk_visual_get_system ())->xvisual) == xvisual)
269             private->drawable.colormap = gdk_colormap_get_system ();
270           else
271             private->drawable.colormap = gdk_colormap_new (visual, False);
272         }
273       
274       private->bg_color.pixel = BlackPixel (gdk_display, gdk_screen);
275       xattributes.background_pixel = private->bg_color.pixel;
276
277       private->bg_pixmap = NULL;
278       
279       xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen);
280       xattributes_mask |= CWBorderPixel | CWBackPixel;
281
282       if (private->guffaw_gravity)
283         xattributes.bit_gravity = StaticGravity;
284       else
285         xattributes.bit_gravity = NorthWestGravity;
286       
287       xattributes_mask |= CWBitGravity;
288   
289       switch (private->drawable.window_type)
290         {
291         case GDK_WINDOW_TOPLEVEL:
292           xattributes.colormap = GDK_COLORMAP_XCOLORMAP (private->drawable.colormap);
293           xattributes_mask |= CWColormap;
294           
295           xparent = gdk_root_window;
296           break;
297           
298         case GDK_WINDOW_CHILD:
299           xattributes.colormap = GDK_COLORMAP_XCOLORMAP (private->drawable.colormap);
300           xattributes_mask |= CWColormap;
301           break;
302           
303         case GDK_WINDOW_DIALOG:
304           xattributes.colormap = GDK_COLORMAP_XCOLORMAP (private->drawable.colormap);
305           xattributes_mask |= CWColormap;
306           
307           xparent = gdk_root_window;
308           break;
309           
310         case GDK_WINDOW_TEMP:
311           xattributes.colormap = GDK_COLORMAP_XCOLORMAP (private->drawable.colormap);
312           xattributes_mask |= CWColormap;
313           
314           xparent = gdk_root_window;
315           
316           xattributes.save_under = True;
317           xattributes.override_redirect = True;
318           xattributes.cursor = None;
319           xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
320           break;
321         case GDK_WINDOW_ROOT:
322           g_error ("cannot make windows of type GDK_WINDOW_ROOT");
323           break;
324         case GDK_WINDOW_PIXMAP:
325           g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)");
326           break;
327         }
328     }
329   else
330     {
331       depth = 0;
332       class = InputOnly;
333       private->input_only = TRUE;
334       private->drawable.colormap = NULL;
335     }
336
337   GDK_DRAWABLE_XDATA (private)->xid = XCreateWindow (GDK_DRAWABLE_XDISPLAY (parent),
338                                                      xparent,
339                                                      x, y, private->drawable.width, private->drawable.height,
340                                                      0, depth, class, xvisual,
341                                                      xattributes_mask, &xattributes);
342   gdk_drawable_ref (window);
343   gdk_xid_table_insert (&GDK_DRAWABLE_XID (window), window);
344   
345   if (private->drawable.colormap)
346     gdk_colormap_ref (private->drawable.colormap);
347   
348   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
349                                   (attributes->cursor) :
350                                   NULL));
351   
352   if (parent_private)
353     parent_private->children = g_list_prepend (parent_private->children, window);
354   
355   switch (private->drawable.window_type)
356     {
357     case GDK_WINDOW_DIALOG:
358       XSetTransientForHint (GDK_DRAWABLE_XDISPLAY (window),
359                             GDK_DRAWABLE_XID (window),
360                             xparent);
361     case GDK_WINDOW_TOPLEVEL:
362     case GDK_WINDOW_TEMP:
363       XSetWMProtocols (GDK_DRAWABLE_XDISPLAY (window),
364                        GDK_DRAWABLE_XID (window),
365                        gdk_wm_window_protocols, 2);
366       break;
367     case GDK_WINDOW_CHILD:
368       if ((attributes->wclass == GDK_INPUT_OUTPUT) &&
369           (private->drawable.colormap != gdk_colormap_get_system ()) &&
370           (private->drawable.colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window))))
371         {
372           GDK_NOTE (MISC, g_message ("adding colormap window\n"));
373           gdk_window_add_colormap_windows (window);
374         }
375       
376       return window;
377     default:
378       
379       return window;
380     }
381   
382   size_hints.flags = PSize;
383   size_hints.width = private->drawable.width;
384   size_hints.height = private->drawable.height;
385   
386   wm_hints.flags = InputHint | StateHint | WindowGroupHint;
387   wm_hints.window_group = gdk_leader_window;
388   wm_hints.input = True;
389   wm_hints.initial_state = NormalState;
390   
391   /* FIXME: Is there any point in doing this? Do any WM's pay
392    * attention to PSize, and even if they do, is this the
393    * correct value???
394    */
395   XSetWMNormalHints (GDK_DRAWABLE_XDISPLAY (window),
396                      GDK_DRAWABLE_XID (window),
397                      &size_hints);
398   
399   XSetWMHints (GDK_DRAWABLE_XDISPLAY (window),
400                GDK_DRAWABLE_XID (window),
401                &wm_hints);
402   
403   if (!wm_client_leader_atom)
404     wm_client_leader_atom = gdk_atom_intern ("WM_CLIENT_LEADER", FALSE);
405   
406   XChangeProperty (GDK_DRAWABLE_XDISPLAY (window),
407                    GDK_DRAWABLE_XID (window),
408                    wm_client_leader_atom,
409                    XA_WINDOW, 32, PropModeReplace,
410                    (guchar*) &gdk_leader_window, 1);
411   
412   if (attributes_mask & GDK_WA_TITLE)
413     title = attributes->title;
414   else
415     title = g_get_prgname ();
416   
417   XmbSetWMProperties (GDK_DRAWABLE_XDISPLAY (window),
418                       GDK_DRAWABLE_XID (window),
419                       title, title,
420                       NULL, 0,
421                       NULL, NULL, NULL);
422   
423   if (attributes_mask & GDK_WA_WMCLASS)
424     {
425       class_hint = XAllocClassHint ();
426       class_hint->res_name = attributes->wmclass_name;
427       class_hint->res_class = attributes->wmclass_class;
428       XSetClassHint (GDK_DRAWABLE_XDISPLAY (window),
429                      GDK_DRAWABLE_XID (window),
430                      class_hint);
431       XFree (class_hint);
432     }
433   
434   return window;
435 }
436
437 GdkWindow *
438 gdk_window_foreign_new (guint32 anid)
439 {
440   GdkWindow *window;
441   GdkWindowPrivate *private;
442   GdkWindowPrivate *parent_private;
443   XWindowAttributes attrs;
444   Window root, parent;
445   Window *children = NULL;
446   guint nchildren;
447   gboolean result;
448
449   gdk_error_trap_push ();
450   result = XGetWindowAttributes (gdk_display, anid, &attrs);
451   if (gdk_error_trap_pop () || !result)
452     return NULL;
453
454   /* FIXME: This is pretty expensive. Maybe the caller should supply
455    *        the parent */
456   gdk_error_trap_push ();
457   result = XQueryTree (gdk_display, anid, &root, &parent, &children, &nchildren);
458   if (gdk_error_trap_pop () || !result)
459     return NULL;
460
461   if (children)
462     XFree (children);
463   
464   window = gdk_x11_window_alloc ();
465   private = (GdkWindowPrivate *)window;
466
467   private->parent = gdk_xid_table_lookup (parent);
468   
469   parent_private = (GdkWindowPrivate *)private->parent;
470   
471   if (parent_private)
472     parent_private->children = g_list_prepend (parent_private->children, window);
473   
474   GDK_DRAWABLE_XDATA (window)->xid = anid;
475   GDK_DRAWABLE_XDATA (window)->xdisplay = gdk_display;
476
477   private->x = attrs.x;
478   private->y = attrs.y;
479   private->drawable.width = attrs.width;
480   private->drawable.height = attrs.height;
481   private->drawable.window_type = GDK_WINDOW_FOREIGN;
482   private->drawable.destroyed = FALSE;
483   private->mapped = (attrs.map_state != IsUnmapped);
484   
485   gdk_drawable_ref (window);
486   gdk_xid_table_insert (&GDK_DRAWABLE_XID (window), window);
487   
488   return window;
489 }
490
491 void
492 _gdk_windowing_window_destroy (GdkWindow *window,
493                                gboolean   recursing,
494                                gboolean   foreign_destroy)
495 {
496   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
497
498   if (private->extension_events != 0)
499     gdk_input_window_destroy (window);
500
501   if (private->drawable.window_type == GDK_WINDOW_FOREIGN)
502     {
503       if (!foreign_destroy && (private->parent != NULL))
504         {
505           /* It's somebody else's window, but in our heirarchy,
506            * so reparent it to the root window, and then send
507            * it a delete event, as if we were a WM
508            */
509           XClientMessageEvent xevent;
510           
511           gdk_error_trap_push ();
512           gdk_window_hide (window);
513           gdk_window_reparent (window, NULL, 0, 0);
514           
515           xevent.type = ClientMessage;
516           xevent.window = GDK_DRAWABLE_XID (window);
517           xevent.message_type = gdk_wm_protocols;
518           xevent.format = 32;
519           xevent.data.l[0] = gdk_wm_delete_window;
520           xevent.data.l[1] = CurrentTime;
521           
522           XSendEvent (GDK_DRAWABLE_XDISPLAY (window),
523                       GDK_DRAWABLE_XID (window),
524                       False, 0, (XEvent *)&xevent);
525           gdk_flush ();
526           gdk_error_trap_pop ();
527         }
528     }
529   else if (!recursing && !foreign_destroy)
530     XDestroyWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
531 }
532
533 /* This function is called when the XWindow is really gone.
534  */
535 void
536 gdk_window_destroy_notify (GdkWindow *window)
537 {
538   g_return_if_fail (window != NULL);
539   
540   if (!GDK_DRAWABLE_DESTROYED (window))
541     {
542       if (GDK_DRAWABLE_TYPE(window) != GDK_WINDOW_FOREIGN)
543         g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_DRAWABLE_XID (window));
544
545       _gdk_window_destroy (window, TRUE);
546     }
547   
548   gdk_xid_table_remove (GDK_DRAWABLE_XID (window));
549   gdk_drawable_unref (window);
550 }
551
552 void
553 gdk_window_show (GdkWindow *window)
554 {
555   GdkWindowPrivate *private;
556   
557   g_return_if_fail (window != NULL);
558   
559   private = (GdkWindowPrivate*) window;
560   if (!private->drawable.destroyed)
561     {
562       private->mapped = TRUE;
563       XRaiseWindow (GDK_DRAWABLE_XDISPLAY (window),
564                     GDK_DRAWABLE_XID (window));
565       
566       if (GDK_WINDOW_XDATA (window)->position_info.mapped)
567         XMapWindow (GDK_DRAWABLE_XDISPLAY (window),
568                     GDK_DRAWABLE_XID (window));
569     }
570 }
571
572 void
573 gdk_window_hide (GdkWindow *window)
574 {
575   GdkWindowPrivate *private;
576   
577   g_return_if_fail (window != NULL);
578
579   private = (GdkWindowPrivate*) window;
580   if (!private->drawable.destroyed)
581     {
582       private->mapped = FALSE;
583
584       _gdk_window_clear_update_area (window);
585       
586       XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window),
587                     GDK_DRAWABLE_XID (window));
588     }
589 }
590
591 void
592 gdk_window_withdraw (GdkWindow *window)
593 {
594   GdkWindowPrivate *private;
595   
596   g_return_if_fail (window != NULL);
597   
598   private = (GdkWindowPrivate*) window;
599   if (!private->drawable.destroyed)
600     XWithdrawWindow (GDK_DRAWABLE_XDISPLAY (window),
601                      GDK_DRAWABLE_XID (window), 0);
602 }
603
604 void
605 gdk_window_move (GdkWindow *window,
606                  gint       x,
607                  gint       y)
608 {
609   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
610   
611   g_return_if_fail (window != NULL);
612   g_return_if_fail (GDK_IS_WINDOW (window));
613
614   gdk_window_move_resize (window, x, y,
615                           private->drawable.width, private->drawable.height);
616 }
617
618 void
619 gdk_window_resize (GdkWindow *window,
620                    gint       width,
621                    gint       height)
622 {
623   GdkWindowPrivate *private;
624   
625   g_return_if_fail (window != NULL);
626   g_return_if_fail (GDK_IS_WINDOW (window));
627   
628   if (width < 1)
629     width = 1;
630   if (height < 1)
631     height = 1;
632
633   private = (GdkWindowPrivate*) window;
634   
635   if (!GDK_DRAWABLE_DESTROYED (window))
636     {
637       if (GDK_DRAWABLE_TYPE (private) == GDK_WINDOW_CHILD)
638         _gdk_window_move_resize_child (window, private->x, private->y,
639                                        width, height);
640       else
641         {
642           XResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
643                          GDK_DRAWABLE_XID (window),
644                          width, height);
645           private->resize_count += 1;
646         }
647     }
648 }
649
650 void
651 gdk_window_move_resize (GdkWindow *window,
652                         gint       x,
653                         gint       y,
654                         gint       width,
655                         gint       height)
656 {
657   GdkWindowPrivate *private;
658   
659   g_return_if_fail (window != NULL);
660   g_return_if_fail (GDK_IS_WINDOW (window));
661
662   if (width < 1)
663     width = 1;
664   if (height < 1)
665     height = 1;
666   
667   private = (GdkWindowPrivate*) window;
668
669   if (!GDK_DRAWABLE_DESTROYED (window))
670     {
671       if (GDK_DRAWABLE_TYPE (private) == GDK_WINDOW_CHILD)
672         _gdk_window_move_resize_child (window, x, y, width, height);
673       else
674         {
675           XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
676                              GDK_DRAWABLE_XID (window),
677                              x, y, width, height);
678         }
679     }
680 }
681
682 void
683 gdk_window_reparent (GdkWindow *window,
684                      GdkWindow *new_parent,
685                      gint       x,
686                      gint       y)
687 {
688   GdkWindowPrivate *window_private;
689   GdkWindowPrivate *parent_private;
690   GdkWindowPrivate *old_parent_private;
691   
692   g_return_if_fail (window != NULL);
693   g_return_if_fail (GDK_IS_WINDOW (window));
694   g_return_if_fail (new_parent != NULL);
695   g_return_if_fail (GDK_IS_WINDOW (new_parent));
696   
697   if (!new_parent)
698     new_parent = gdk_parent_root;
699   
700   window_private = (GdkWindowPrivate*) window;
701   old_parent_private = (GdkWindowPrivate*)window_private->parent;
702   parent_private = (GdkWindowPrivate*) new_parent;
703   
704   if (!GDK_DRAWABLE_DESTROYED (window) && !GDK_DRAWABLE_DESTROYED (new_parent))
705     XReparentWindow (GDK_DRAWABLE_XDISPLAY (window),
706                      GDK_DRAWABLE_XID (window),
707                      GDK_DRAWABLE_XID (new_parent),
708                      x, y);
709   
710   window_private->parent = new_parent;
711   
712   if (old_parent_private)
713     old_parent_private->children = g_list_remove (old_parent_private->children, window);
714   
715   if ((old_parent_private &&
716        (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
717       (!old_parent_private && parent_private->guffaw_gravity))
718     gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
719   
720   parent_private->children = g_list_prepend (parent_private->children, window);
721 }
722
723 void
724 _gdk_windowing_window_clear_area (GdkWindow *window,
725                                   gint       x,
726                                   gint       y,
727                                   gint       width,
728                                   gint       height)
729 {
730   g_return_if_fail (window != NULL);
731   g_return_if_fail (GDK_IS_WINDOW (window));
732   
733   if (!GDK_DRAWABLE_DESTROYED (window))
734     XClearArea (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window),
735                 x, y, width, height, False);
736 }
737
738 void
739 _gdk_windowing_window_clear_area_e (GdkWindow *window,
740                                     gint       x,
741                                     gint       y,
742                                     gint       width,
743                                     gint       height)
744 {
745   g_return_if_fail (window != NULL);
746   g_return_if_fail (GDK_IS_WINDOW (window));
747   
748   if (!GDK_DRAWABLE_DESTROYED (window))
749     XClearArea (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window),
750                 x, y, width, height, True);
751 }
752
753 void
754 gdk_window_raise (GdkWindow *window)
755 {
756   g_return_if_fail (window != NULL);
757   g_return_if_fail (GDK_IS_WINDOW (window));
758   
759   if (!GDK_DRAWABLE_DESTROYED (window))
760     XRaiseWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
761 }
762
763 void
764 gdk_window_lower (GdkWindow *window)
765 {
766   g_return_if_fail (window != NULL);
767   g_return_if_fail (GDK_IS_WINDOW (window));
768   
769   if (!GDK_DRAWABLE_DESTROYED (window))
770     XLowerWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
771 }
772
773 void
774 gdk_window_set_hints (GdkWindow *window,
775                       gint       x,
776                       gint       y,
777                       gint       min_width,
778                       gint       min_height,
779                       gint       max_width,
780                       gint       max_height,
781                       gint       flags)
782 {
783   XSizeHints size_hints;
784   
785   g_return_if_fail (window != NULL);
786   g_return_if_fail (GDK_IS_WINDOW (window));
787   
788   if (GDK_DRAWABLE_DESTROYED (window))
789     return;
790   
791   size_hints.flags = 0;
792   
793   if (flags & GDK_HINT_POS)
794     {
795       size_hints.flags |= PPosition;
796       size_hints.x = x;
797       size_hints.y = y;
798     }
799   
800   if (flags & GDK_HINT_MIN_SIZE)
801     {
802       size_hints.flags |= PMinSize;
803       size_hints.min_width = min_width;
804       size_hints.min_height = min_height;
805     }
806   
807   if (flags & GDK_HINT_MAX_SIZE)
808     {
809       size_hints.flags |= PMaxSize;
810       size_hints.max_width = max_width;
811       size_hints.max_height = max_height;
812     }
813   
814   /* FIXME: Would it be better to delete this property of
815    *        flags == 0? It would save space on the server
816    */
817   XSetWMNormalHints (GDK_DRAWABLE_XDISPLAY (window),
818                      GDK_DRAWABLE_XID (window),
819                      &size_hints);
820 }
821
822 void 
823 gdk_window_set_geometry_hints (GdkWindow      *window,
824                                GdkGeometry    *geometry,
825                                GdkWindowHints  geom_mask)
826 {
827   XSizeHints size_hints;
828   
829   g_return_if_fail (window != NULL);
830   g_return_if_fail (GDK_IS_WINDOW (window));
831   
832   if (GDK_DRAWABLE_DESTROYED (window))
833     return;
834   
835   size_hints.flags = 0;
836   
837   if (geom_mask & GDK_HINT_POS)
838     {
839       size_hints.flags |= PPosition;
840       /* We need to initialize the following obsolete fields because KWM 
841        * apparently uses these fields if they are non-zero.
842        * #@#!#!$!.
843        */
844       size_hints.x = 0;
845       size_hints.y = 0;
846     }
847   
848   if (geom_mask & GDK_HINT_MIN_SIZE)
849     {
850       size_hints.flags |= PMinSize;
851       size_hints.min_width = geometry->min_width;
852       size_hints.min_height = geometry->min_height;
853     }
854   
855   if (geom_mask & GDK_HINT_MAX_SIZE)
856     {
857       size_hints.flags |= PMaxSize;
858       size_hints.max_width = MAX (geometry->max_width, 1);
859       size_hints.max_height = MAX (geometry->max_height, 1);
860     }
861   
862   if (geom_mask & GDK_HINT_BASE_SIZE)
863     {
864       size_hints.flags |= PBaseSize;
865       size_hints.base_width = geometry->base_width;
866       size_hints.base_height = geometry->base_height;
867     }
868   
869   if (geom_mask & GDK_HINT_RESIZE_INC)
870     {
871       size_hints.flags |= PResizeInc;
872       size_hints.width_inc = geometry->width_inc;
873       size_hints.height_inc = geometry->height_inc;
874     }
875   
876   if (geom_mask & GDK_HINT_ASPECT)
877     {
878       size_hints.flags |= PAspect;
879       if (geometry->min_aspect <= 1)
880         {
881           size_hints.min_aspect.x = 65536 * geometry->min_aspect;
882           size_hints.min_aspect.y = 65536;
883         }
884       else
885         {
886           size_hints.min_aspect.x = 65536;
887           size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
888         }
889       if (geometry->max_aspect <= 1)
890         {
891           size_hints.max_aspect.x = 65536 * geometry->max_aspect;
892           size_hints.max_aspect.y = 65536;
893         }
894       else
895         {
896           size_hints.max_aspect.x = 65536;
897           size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
898         }
899     }
900
901   /* FIXME: Would it be better to delete this property of
902    *        geom_mask == 0? It would save space on the server
903    */
904   XSetWMNormalHints (GDK_DRAWABLE_XDISPLAY (window),
905                      GDK_DRAWABLE_XID (window),
906                      &size_hints);
907 }
908
909 void
910 gdk_window_set_title (GdkWindow   *window,
911                       const gchar *title)
912 {
913   g_return_if_fail (window != NULL);
914   g_return_if_fail (GDK_IS_WINDOW (window));
915   
916   if (!GDK_DRAWABLE_DESTROYED (window))
917     XmbSetWMProperties (GDK_DRAWABLE_XDISPLAY (window),
918                         GDK_DRAWABLE_XID (window),
919                         title, title, NULL, 0, NULL, NULL, NULL);
920 }
921
922 void          
923 gdk_window_set_role (GdkWindow   *window,
924                      const gchar *role)
925 {
926   g_return_if_fail (window != NULL);
927   g_return_if_fail (GDK_IS_WINDOW (window));
928
929   if (!GDK_DRAWABLE_DESTROYED (window))
930     {
931       if (role)
932         XChangeProperty (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window),
933                          gdk_atom_intern ("WM_WINDOW_ROLE", FALSE), XA_STRING,
934                          8, PropModeReplace, role, strlen (role));
935       else
936         XDeleteProperty (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window),
937                          gdk_atom_intern ("WM_WINDOW_ROLE", FALSE));
938     }
939 }
940
941 void          
942 gdk_window_set_transient_for (GdkWindow *window, 
943                               GdkWindow *parent)
944 {
945   GdkWindowPrivate *private;
946   GdkWindowPrivate *parent_private;
947   
948   g_return_if_fail (window != NULL);
949   g_return_if_fail (GDK_IS_WINDOW (window));
950   
951   private = (GdkWindowPrivate*) window;
952   parent_private = (GdkWindowPrivate*) parent;
953   
954   if (!GDK_DRAWABLE_DESTROYED (window) && !GDK_DRAWABLE_DESTROYED (parent))
955     XSetTransientForHint (GDK_DRAWABLE_XDISPLAY (window), 
956                           GDK_DRAWABLE_XID (window),
957                           GDK_DRAWABLE_XID (parent));
958 }
959
960 void
961 gdk_window_set_background (GdkWindow *window,
962                            GdkColor  *color)
963 {
964   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
965   
966   g_return_if_fail (window != NULL);
967   g_return_if_fail (GDK_IS_WINDOW (window));
968   
969   if (!GDK_DRAWABLE_DESTROYED (window))
970     XSetWindowBackground (GDK_DRAWABLE_XDISPLAY (window),
971                           GDK_DRAWABLE_XID (window), color->pixel);
972
973   private->bg_color = *color;
974
975   if (private->bg_pixmap &&
976       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
977       private->bg_pixmap != GDK_NO_BG)
978     {
979       gdk_pixmap_unref (private->bg_pixmap);
980       private->bg_pixmap = NULL;
981     }
982 }
983
984 void
985 gdk_window_set_back_pixmap (GdkWindow *window,
986                             GdkPixmap *pixmap,
987                             gboolean   parent_relative)
988 {
989   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
990   Pixmap xpixmap;
991   
992   g_return_if_fail (window != NULL);
993   g_return_if_fail (GDK_IS_WINDOW (window));
994   g_return_if_fail (pixmap == NULL || !parent_relative);
995
996   if (private->bg_pixmap &&
997       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
998       private->bg_pixmap != GDK_NO_BG)
999     gdk_pixmap_unref (private->bg_pixmap);
1000
1001   if (parent_relative)
1002     {
1003       xpixmap = ParentRelative;
1004       private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
1005     }
1006   else
1007     {
1008       if (pixmap)
1009         {
1010           gdk_pixmap_ref (pixmap);
1011           private->bg_pixmap = pixmap;
1012           xpixmap = GDK_DRAWABLE_XID (pixmap);
1013         }
1014       else
1015         {
1016           xpixmap = None;
1017           private->bg_pixmap = GDK_NO_BG;
1018         }
1019     }
1020   
1021   if (!GDK_DRAWABLE_DESTROYED (window))
1022     XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
1023                                 GDK_DRAWABLE_XID (window), xpixmap);
1024 }
1025
1026 void
1027 gdk_window_set_cursor (GdkWindow *window,
1028                        GdkCursor *cursor)
1029 {
1030   GdkCursorPrivate *cursor_private;
1031   Cursor xcursor;
1032   
1033   g_return_if_fail (window != NULL);
1034   g_return_if_fail (GDK_IS_WINDOW (window));
1035   
1036   cursor_private = (GdkCursorPrivate*) cursor;
1037   
1038   if (!cursor)
1039     xcursor = None;
1040   else
1041     xcursor = cursor_private->xcursor;
1042   
1043   if (!GDK_DRAWABLE_DESTROYED (window))
1044     XDefineCursor (GDK_DRAWABLE_XDISPLAY (window),
1045                    GDK_DRAWABLE_XID (window),
1046                    xcursor);
1047 }
1048
1049 void
1050 gdk_window_get_geometry (GdkWindow *window,
1051                          gint      *x,
1052                          gint      *y,
1053                          gint      *width,
1054                          gint      *height,
1055                          gint      *depth)
1056 {
1057   Window root;
1058   gint tx;
1059   gint ty;
1060   guint twidth;
1061   guint theight;
1062   guint tborder_width;
1063   guint tdepth;
1064   
1065   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
1066   
1067   if (!window)
1068     window = gdk_parent_root;
1069   
1070   if (!GDK_DRAWABLE_DESTROYED (window))
1071     {
1072       XGetGeometry (GDK_DRAWABLE_XDISPLAY (window),
1073                     GDK_DRAWABLE_XID (window),
1074                     &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
1075       
1076       if (x)
1077         *x = tx;
1078       if (y)
1079         *y = ty;
1080       if (width)
1081         *width = twidth;
1082       if (height)
1083         *height = theight;
1084       if (depth)
1085         *depth = tdepth;
1086     }
1087 }
1088
1089 gint
1090 gdk_window_get_origin (GdkWindow *window,
1091                        gint      *x,
1092                        gint      *y)
1093 {
1094   gint return_val;
1095   Window child;
1096   gint tx = 0;
1097   gint ty = 0;
1098   
1099   g_return_val_if_fail (window != NULL, 0);
1100   
1101   if (!GDK_DRAWABLE_DESTROYED (window))
1102     {
1103       return_val = XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
1104                                           GDK_DRAWABLE_XID (window),
1105                                           gdk_root_window,
1106                                           0, 0, &tx, &ty,
1107                                           &child);
1108       
1109     }
1110   else
1111     return_val = 0;
1112   
1113   if (x)
1114     *x = tx;
1115   if (y)
1116     *y = ty;
1117   
1118   return return_val;
1119 }
1120
1121 gboolean
1122 gdk_window_get_deskrelative_origin (GdkWindow *window,
1123                                     gint      *x,
1124                                     gint      *y)
1125 {
1126   gboolean return_val = FALSE;
1127   gint num_children, format_return;
1128   Window win, *child, parent, root;
1129   gint tx = 0;
1130   gint ty = 0;
1131   Atom type_return;
1132   static Atom atom = 0;
1133   gulong number_return, bytes_after_return;
1134   guchar *data_return;
1135   
1136   g_return_val_if_fail (window != NULL, 0);
1137   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1138   
1139   if (!GDK_DRAWABLE_DESTROYED (window))
1140     {
1141       if (!atom)
1142         atom = gdk_atom_intern ("ENLIGHTENMENT_DESKTOP", FALSE);
1143       win = GDK_DRAWABLE_XID (window);
1144       
1145       while (XQueryTree (GDK_DRAWABLE_XDISPLAY (window), win, &root, &parent,
1146                          &child, (unsigned int *)&num_children))
1147         {
1148           if ((child) && (num_children > 0))
1149             XFree (child);
1150           
1151           if (!parent)
1152             break;
1153           else
1154             win = parent;
1155           
1156           if (win == root)
1157             break;
1158           
1159           data_return = NULL;
1160           XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (window), win, atom, 0, 0,
1161                               False, XA_CARDINAL, &type_return, &format_return,
1162                               &number_return, &bytes_after_return, &data_return);
1163           if (type_return == XA_CARDINAL)
1164             {
1165               XFree (data_return);
1166               break;
1167             }
1168         }
1169       
1170       return_val = XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
1171                                           GDK_DRAWABLE_XID (window),
1172                                           win,
1173                                           0, 0, &tx, &ty,
1174                                           &root);
1175       if (x)
1176         *x = tx;
1177       if (y)
1178         *y = ty;
1179     }
1180   
1181   
1182   return return_val;
1183 }
1184
1185 void
1186 gdk_window_get_root_origin (GdkWindow *window,
1187                             gint      *x,
1188                             gint      *y)
1189 {
1190   GdkWindowPrivate *private;
1191   Window xwindow;
1192   Window xparent;
1193   Window root;
1194   Window *children;
1195   unsigned int nchildren;
1196   
1197   g_return_if_fail (window != NULL);
1198   g_return_if_fail (GDK_IS_WINDOW (window));
1199   
1200   private = (GdkWindowPrivate*) window;
1201   if (x)
1202     *x = 0;
1203   if (y)
1204     *y = 0;
1205
1206   if (GDK_DRAWABLE_DESTROYED (window))
1207     return;
1208   
1209   while (private->parent && ((GdkWindowPrivate*) private->parent)->parent)
1210     private = (GdkWindowPrivate*) private->parent;
1211   if (GDK_DRAWABLE_DESTROYED (window))
1212     return;
1213   
1214   xparent = GDK_DRAWABLE_XID (window);
1215   do
1216     {
1217       xwindow = xparent;
1218       if (!XQueryTree (GDK_DRAWABLE_XDISPLAY (window), xwindow,
1219                        &root, &xparent,
1220                        &children, &nchildren))
1221         return;
1222       
1223       if (children)
1224         XFree (children);
1225     }
1226   while (xparent != root);
1227   
1228   if (xparent == root)
1229     {
1230       unsigned int ww, wh, wb, wd;
1231       int wx, wy;
1232       
1233       if (XGetGeometry (GDK_DRAWABLE_XDISPLAY (window), xwindow, &root, &wx, &wy, &ww, &wh, &wb, &wd))
1234         {
1235           if (x)
1236             *x = wx;
1237           if (y)
1238             *y = wy;
1239         }
1240     }
1241 }
1242
1243 GdkWindow*
1244 gdk_window_get_pointer (GdkWindow       *window,
1245                         gint            *x,
1246                         gint            *y,
1247                         GdkModifierType *mask)
1248 {
1249   GdkWindow *return_val;
1250   Window root;
1251   Window child;
1252   int rootx, rooty;
1253   int winx = 0;
1254   int winy = 0;
1255   unsigned int xmask = 0;
1256   gint xoffset, yoffset;
1257
1258   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
1259   
1260   if (!window)
1261     window = gdk_parent_root;
1262   
1263   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
1264
1265   return_val = NULL;
1266   if (!GDK_DRAWABLE_DESTROYED (window) &&
1267       XQueryPointer (GDK_DRAWABLE_XDISPLAY (window),
1268                      GDK_DRAWABLE_XID (window),
1269                      &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
1270     {
1271       if (child)
1272         return_val = gdk_window_lookup (child);
1273     }
1274   
1275   if (x)
1276     *x = winx + xoffset;
1277   if (y)
1278     *y = winy + yoffset;
1279   if (mask)
1280     *mask = xmask;
1281   
1282   return return_val;
1283 }
1284
1285 GdkWindow*
1286 gdk_window_at_pointer (gint *win_x,
1287                        gint *win_y)
1288 {
1289   GdkWindow *window;
1290   Window root;
1291   Window xwindow;
1292   Window xwindow_last = 0;
1293   Display *xdisplay;
1294   int rootx = -1, rooty = -1;
1295   int winx, winy;
1296   unsigned int xmask;
1297   
1298   xwindow = GDK_ROOT_WINDOW ();
1299   xdisplay = GDK_DISPLAY ();
1300   
1301   XGrabServer (xdisplay);
1302   while (xwindow)
1303     {
1304       xwindow_last = xwindow;
1305       XQueryPointer (xdisplay, xwindow,
1306                      &root, &xwindow,
1307                      &rootx, &rooty,
1308                      &winx, &winy,
1309                      &xmask);
1310     }
1311   XUngrabServer (xdisplay);
1312   
1313   window = gdk_window_lookup (xwindow_last);
1314   
1315   if (win_x)
1316     *win_x = window ? winx : -1;
1317   if (win_y)
1318     *win_y = window ? winy : -1;
1319   
1320   return window;
1321 }
1322
1323 GList*
1324 gdk_window_get_children (GdkWindow *window)
1325 {
1326   GdkWindow *child;
1327   GList *children;
1328   Window root;
1329   Window parent;
1330   Window *xchildren;
1331   unsigned int nchildren;
1332   unsigned int i;
1333   
1334   g_return_val_if_fail (window != NULL, NULL);
1335   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
1336
1337   if (GDK_DRAWABLE_DESTROYED (window))
1338     return NULL;
1339   
1340   XQueryTree (GDK_DRAWABLE_XDISPLAY (window),
1341               GDK_DRAWABLE_XID (window),
1342               &root, &parent, &xchildren, &nchildren);
1343   
1344   children = NULL;
1345   
1346   if (nchildren > 0)
1347     {
1348       for (i = 0; i < nchildren; i++)
1349         {
1350           child = gdk_window_lookup (xchildren[i]);
1351           if (child)
1352             children = g_list_prepend (children, child);
1353         }
1354       
1355       if (xchildren)
1356         XFree (xchildren);
1357     }
1358   
1359   return children;
1360 }
1361
1362 GdkEventMask  
1363 gdk_window_get_events (GdkWindow *window)
1364 {
1365   XWindowAttributes attrs;
1366   GdkEventMask event_mask;
1367   int i;
1368   
1369   g_return_val_if_fail (window != NULL, 0);
1370   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1371
1372   if (GDK_DRAWABLE_DESTROYED (window))
1373     return 0;
1374   else
1375     {
1376       XGetWindowAttributes (GDK_DRAWABLE_XDISPLAY (window),
1377                             GDK_DRAWABLE_XID (window), 
1378                             &attrs);
1379       
1380       event_mask = 0;
1381       for (i = 0; i < gdk_nevent_masks; i++)
1382         {
1383           if (attrs.your_event_mask & gdk_event_mask_table[i])
1384             event_mask |= 1 << (i + 1);
1385         }
1386   
1387       return event_mask;
1388     }
1389 }
1390
1391 void          
1392 gdk_window_set_events (GdkWindow       *window,
1393                        GdkEventMask     event_mask)
1394 {
1395   long xevent_mask;
1396   int i;
1397   
1398   g_return_if_fail (window != NULL);
1399   g_return_if_fail (GDK_IS_WINDOW (window));
1400   
1401   if (!GDK_DRAWABLE_DESTROYED (window))
1402     {
1403       xevent_mask = StructureNotifyMask;
1404       for (i = 0; i < gdk_nevent_masks; i++)
1405         {
1406           if (event_mask & (1 << (i + 1)))
1407             xevent_mask |= gdk_event_mask_table[i];
1408         }
1409       
1410       XSelectInput (GDK_DRAWABLE_XDISPLAY (window),
1411                     GDK_DRAWABLE_XID (window),
1412                     xevent_mask);
1413     }
1414 }
1415
1416 void
1417 gdk_window_add_colormap_windows (GdkWindow *window)
1418 {
1419   GdkWindow *toplevel;
1420   Window *old_windows;
1421   Window *new_windows;
1422   int i, count;
1423   
1424   g_return_if_fail (window != NULL);
1425   g_return_if_fail (GDK_IS_WINDOW (window));
1426   
1427   toplevel = gdk_window_get_toplevel (window);
1428   if (GDK_DRAWABLE_DESTROYED (toplevel))
1429     return;
1430   
1431   old_windows = NULL;
1432   if (!XGetWMColormapWindows (GDK_DRAWABLE_XDISPLAY (toplevel),
1433                               GDK_DRAWABLE_XID (toplevel),
1434                               &old_windows, &count))
1435     {
1436       count = 0;
1437     }
1438   
1439   for (i = 0; i < count; i++)
1440     if (old_windows[i] == GDK_DRAWABLE_XID (window))
1441       {
1442         XFree (old_windows);
1443         return;
1444       }
1445   
1446   new_windows = g_new (Window, count + 1);
1447   
1448   for (i = 0; i < count; i++)
1449     new_windows[i] = old_windows[i];
1450   new_windows[count] = GDK_DRAWABLE_XID (window);
1451   
1452   XSetWMColormapWindows (GDK_DRAWABLE_XDISPLAY (toplevel),
1453                          GDK_DRAWABLE_XID (toplevel),
1454                          new_windows, count + 1);
1455   
1456   g_free (new_windows);
1457   if (old_windows)
1458     XFree (old_windows);
1459 }
1460
1461 static gboolean
1462 gdk_window_have_shape_ext (void)
1463 {
1464   enum { UNKNOWN, NO, YES };
1465   static gint have_shape = UNKNOWN;
1466   
1467   if (have_shape == UNKNOWN)
1468     {
1469       int ignore;
1470       if (XQueryExtension (gdk_display, "SHAPE", &ignore, &ignore, &ignore))
1471         have_shape = YES;
1472       else
1473         have_shape = NO;
1474     }
1475   
1476   return (have_shape == YES);
1477 }
1478
1479 /*
1480  * This needs the X11 shape extension.
1481  * If not available, shaped windows will look
1482  * ugly, but programs still work.    Stefan Wille
1483  */
1484 void
1485 gdk_window_shape_combine_mask (GdkWindow *window,
1486                                GdkBitmap *mask,
1487                                gint x, gint y)
1488 {
1489   Pixmap pixmap;
1490   
1491   g_return_if_fail (window != NULL);
1492   g_return_if_fail (GDK_IS_WINDOW (window));
1493   
1494 #ifdef HAVE_SHAPE_EXT
1495   if (GDK_DRAWABLE_DESTROYED (window))
1496     return;
1497   
1498   if (gdk_window_have_shape_ext ())
1499     {
1500       if (mask)
1501         {
1502           pixmap = GDK_DRAWABLE_XID (mask);
1503         }
1504       else
1505         {
1506           x = 0;
1507           y = 0;
1508           pixmap = None;
1509         }
1510       
1511       XShapeCombineMask (GDK_DRAWABLE_XDISPLAY (window),
1512                          GDK_DRAWABLE_XID (window),
1513                          ShapeBounding,
1514                          x, y,
1515                          pixmap,
1516                          ShapeSet);
1517     }
1518 #endif /* HAVE_SHAPE_EXT */
1519 }
1520
1521 void
1522 gdk_window_set_override_redirect (GdkWindow *window,
1523                                   gboolean override_redirect)
1524 {
1525   XSetWindowAttributes attr;
1526   
1527   g_return_if_fail (window != NULL);
1528   g_return_if_fail (GDK_IS_WINDOW (window));
1529
1530   if (GDK_DRAWABLE_DESTROYED (window))
1531     {
1532       attr.override_redirect = (override_redirect == FALSE)?False:True;
1533       XChangeWindowAttributes (GDK_DRAWABLE_XDISPLAY (window),
1534                                GDK_DRAWABLE_XID (window),
1535                                CWOverrideRedirect,
1536                                &attr);
1537     }
1538 }
1539
1540 void          
1541 gdk_window_set_icon (GdkWindow *window, 
1542                      GdkWindow *icon_window,
1543                      GdkPixmap *pixmap,
1544                      GdkBitmap *mask)
1545 {
1546   XWMHints *wm_hints;
1547   
1548   g_return_if_fail (window != NULL);
1549   g_return_if_fail (GDK_IS_WINDOW (window));
1550
1551   if (GDK_DRAWABLE_DESTROYED (window))
1552     return;
1553
1554   wm_hints = XGetWMHints (GDK_DRAWABLE_XDISPLAY (window),
1555                           GDK_DRAWABLE_XID (window));
1556   if (!wm_hints)
1557     wm_hints = XAllocWMHints ();
1558
1559   if (icon_window != NULL)
1560     {
1561       wm_hints->flags |= IconWindowHint;
1562       wm_hints->icon_window = GDK_DRAWABLE_XID (icon_window);
1563     }
1564   
1565   if (pixmap != NULL)
1566     {
1567       wm_hints->flags |= IconPixmapHint;
1568       wm_hints->icon_pixmap = GDK_DRAWABLE_XID (pixmap);
1569     }
1570   
1571   if (mask != NULL)
1572     {
1573       wm_hints->flags |= IconMaskHint;
1574       wm_hints->icon_mask = GDK_DRAWABLE_XID (mask);
1575     }
1576
1577   XSetWMHints (GDK_DRAWABLE_XDISPLAY (window),
1578                GDK_DRAWABLE_XID (window), wm_hints);
1579   XFree (wm_hints);
1580 }
1581
1582 void          
1583 gdk_window_set_icon_name (GdkWindow   *window, 
1584                           const gchar *name)
1585 {
1586   XTextProperty property;
1587   gint res;
1588   
1589   g_return_if_fail (window != NULL);
1590   g_return_if_fail (GDK_IS_WINDOW (window));
1591
1592   if (GDK_DRAWABLE_DESTROYED (window))
1593     return;
1594   
1595   res = XmbTextListToTextProperty (GDK_DRAWABLE_XDISPLAY (window),
1596                                    &name, 1, XStdICCTextStyle,
1597                                    &property);
1598   if (res < 0)
1599     {
1600       g_warning ("Error converting icon name to text property: %d\n", res);
1601       return;
1602     }
1603   
1604   XSetWMIconName (GDK_DRAWABLE_XDISPLAY (window),
1605                   GDK_DRAWABLE_XID (window),
1606                   &property);
1607   
1608   if (property.value)
1609     XFree (property.value);
1610 }
1611
1612 void          
1613 gdk_window_set_group (GdkWindow *window, 
1614                       GdkWindow *leader)
1615 {
1616   XWMHints *wm_hints;
1617   
1618   g_return_if_fail (window != NULL);
1619   g_return_if_fail (GDK_IS_WINDOW (window));
1620   g_return_if_fail (leader != NULL);
1621   g_return_if_fail (GDK_IS_WINDOW (leader));
1622
1623   if (GDK_DRAWABLE_DESTROYED (window) || GDK_DRAWABLE_DESTROYED (leader))
1624     return;
1625   
1626   wm_hints = XGetWMHints (GDK_DRAWABLE_XDISPLAY (window),
1627                           GDK_DRAWABLE_XID (window));
1628   if (!wm_hints)
1629     wm_hints = XAllocWMHints ();
1630
1631   wm_hints->flags |= WindowGroupHint;
1632   wm_hints->window_group = GDK_DRAWABLE_XID (leader);
1633
1634   XSetWMHints (GDK_DRAWABLE_XDISPLAY (window),
1635                GDK_DRAWABLE_XID (window), wm_hints);
1636   XFree (wm_hints);
1637 }
1638
1639 static void
1640 gdk_window_set_mwm_hints (GdkWindow *window,
1641                           MotifWmHints *new_hints)
1642 {
1643   static Atom hints_atom = None;
1644   MotifWmHints *hints;
1645   Atom type;
1646   gint format;
1647   gulong nitems;
1648   gulong bytes_after;
1649   
1650   if (GDK_DRAWABLE_DESTROYED (window))
1651     return;
1652   
1653   if (!hints_atom)
1654     hints_atom = XInternAtom (GDK_DRAWABLE_XDISPLAY (window), 
1655                               _XA_MOTIF_WM_HINTS, FALSE);
1656   
1657   XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window),
1658                       hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
1659                       False, AnyPropertyType, &type, &format, &nitems,
1660                       &bytes_after, (guchar **)&hints);
1661   
1662   if (type == None)
1663     hints = new_hints;
1664   else
1665     {
1666       if (new_hints->flags & MWM_HINTS_FUNCTIONS)
1667         {
1668           hints->flags |= MWM_HINTS_FUNCTIONS;
1669           hints->functions = new_hints->functions;
1670         }
1671       if (new_hints->flags & MWM_HINTS_DECORATIONS)
1672         {
1673           hints->flags |= MWM_HINTS_DECORATIONS;
1674           hints->decorations = new_hints->decorations;
1675         }
1676     }
1677   
1678   XChangeProperty (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window),
1679                    hints_atom, hints_atom, 32, PropModeReplace,
1680                    (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
1681   
1682   if (hints != new_hints)
1683     XFree (hints);
1684 }
1685
1686 void
1687 gdk_window_set_decorations (GdkWindow      *window,
1688                             GdkWMDecoration decorations)
1689 {
1690   MotifWmHints hints;
1691   
1692   g_return_if_fail (window != NULL);
1693   g_return_if_fail (GDK_IS_WINDOW (window));
1694   
1695   hints.flags = MWM_HINTS_DECORATIONS;
1696   hints.decorations = decorations;
1697   
1698   gdk_window_set_mwm_hints (window, &hints);
1699 }
1700
1701 void
1702 gdk_window_set_functions (GdkWindow    *window,
1703                           GdkWMFunction functions)
1704 {
1705   MotifWmHints hints;
1706   
1707   g_return_if_fail (window != NULL);
1708   g_return_if_fail (GDK_IS_WINDOW (window));
1709   
1710   hints.flags = MWM_HINTS_FUNCTIONS;
1711   hints.functions = functions;
1712   
1713   gdk_window_set_mwm_hints (window, &hints);
1714 }
1715
1716 /* 
1717  * propagate the shapes from all child windows of a GDK window to the parent 
1718  * window. Shamelessly ripped from Enlightenment's code
1719  * 
1720  * - Raster
1721  */
1722 struct _gdk_span
1723 {
1724   gint                start;
1725   gint                end;
1726   struct _gdk_span    *next;
1727 };
1728
1729 static void
1730 gdk_add_to_span (struct _gdk_span **s,
1731                  gint               x,
1732                  gint               xx)
1733 {
1734   struct _gdk_span *ptr1, *ptr2, *noo, *ss;
1735   gchar             spanning;
1736   
1737   ptr2 = NULL;
1738   ptr1 = *s;
1739   spanning = 0;
1740   ss = NULL;
1741   /* scan the spans for this line */
1742   while (ptr1)
1743     {
1744       /* -- -> new span */
1745       /* == -> existing span */
1746       /* ## -> spans intersect */
1747       /* if we are in the middle of spanning the span into the line */
1748       if (spanning)
1749         {
1750           /* case: ---- ==== */
1751           if (xx < ptr1->start - 1)
1752             {
1753               /* ends before next span - extend to here */
1754               ss->end = xx;
1755               return;
1756             }
1757           /* case: ----##=== */
1758           else if (xx <= ptr1->end)
1759             {
1760               /* crosses into next span - delete next span and append */
1761               ss->end = ptr1->end;
1762               ss->next = ptr1->next;
1763               g_free (ptr1);
1764               return;
1765             }
1766           /* case: ---###--- */
1767           else
1768             {
1769               /* overlaps next span - delete and keep checking */
1770               ss->next = ptr1->next;
1771               g_free (ptr1);
1772               ptr1 = ss;
1773             }
1774         }
1775       /* otherwise havent started spanning it in yet */
1776       else
1777         {
1778           /* case: ---- ==== */
1779           if (xx < ptr1->start - 1)
1780             {
1781               /* insert span here in list */
1782               noo = g_malloc (sizeof (struct _gdk_span));
1783               
1784               if (noo)
1785                 {
1786                   noo->start = x;
1787                   noo->end = xx;
1788                   noo->next = ptr1;
1789                   if (ptr2)
1790                     ptr2->next = noo;
1791                   else
1792                     *s = noo;
1793                 }
1794               return;
1795             }
1796           /* case: ----##=== */
1797           else if ((x < ptr1->start) && (xx <= ptr1->end))
1798             {
1799               /* expand this span to the left point of the new one */
1800               ptr1->start = x;
1801               return;
1802             }
1803           /* case: ===###=== */
1804           else if ((x >= ptr1->start) && (xx <= ptr1->end))
1805             {
1806               /* throw the span away */
1807               return;
1808             }
1809           /* case: ---###--- */
1810           else if ((x < ptr1->start) && (xx > ptr1->end))
1811             {
1812               ss = ptr1;
1813               spanning = 1;
1814               ptr1->start = x;
1815               ptr1->end = xx;
1816             }
1817           /* case: ===##---- */
1818           else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end))
1819             {
1820               ss = ptr1;
1821               spanning = 1;
1822               ptr1->end = xx;
1823             }
1824           /* case: ==== ---- */
1825           /* case handled by next loop iteration - first case */
1826         }
1827       ptr2 = ptr1;
1828       ptr1 = ptr1->next;
1829     }
1830   /* it started in the middle but spans beyond your current list */
1831   if (spanning)
1832     {
1833       ptr2->end = xx;
1834       return;
1835     }
1836   /* it does not start inside a span or in the middle, so add it to the end */
1837   noo = g_malloc (sizeof (struct _gdk_span));
1838   
1839   if (noo)
1840     {
1841       noo->start = x;
1842       noo->end = xx;
1843       if (ptr2)
1844         {
1845           noo->next = ptr2->next;
1846           ptr2->next = noo;
1847         }
1848       else
1849         {
1850           noo->next = NULL;
1851           *s = noo;
1852         }
1853     }
1854   return;
1855 }
1856
1857 static void
1858 gdk_add_rectangles (Display           *disp,
1859                     Window             win,
1860                     struct _gdk_span **spans,
1861                     gint               basew,
1862                     gint               baseh,
1863                     gint               x,
1864                     gint               y)
1865 {
1866   gint a, k;
1867   gint x1, y1, x2, y2;
1868   gint rn, ord;
1869   XRectangle *rl;
1870   
1871   rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord);
1872   if (rl)
1873     {
1874       /* go through all clip rects in this window's shape */
1875       for (k = 0; k < rn; k++)
1876         {
1877           /* for each clip rect, add it to each line's spans */
1878           x1 = x + rl[k].x;
1879           x2 = x + rl[k].x + (rl[k].width - 1);
1880           y1 = y + rl[k].y;
1881           y2 = y + rl[k].y + (rl[k].height - 1);
1882           if (x1 < 0)
1883             x1 = 0;
1884           if (y1 < 0)
1885             y1 = 0;
1886           if (x2 >= basew)
1887             x2 = basew - 1;
1888           if (y2 >= baseh)
1889             y2 = baseh - 1;
1890           for (a = y1; a <= y2; a++)
1891             {
1892               if ((x2 - x1) >= 0)
1893                 gdk_add_to_span (&spans[a], x1, x2);
1894             }
1895         }
1896       XFree (rl);
1897     }
1898 }
1899
1900 static void
1901 gdk_propagate_shapes (Display *disp,
1902                       Window   win,
1903                       gboolean merge)
1904 {
1905   Window              rt, par, *list = NULL;
1906   gint                i, j, num = 0, num_rects = 0;
1907   gint                x, y, contig;
1908   guint               w, h, d;
1909   gint                baseh, basew;
1910   XRectangle         *rects = NULL;
1911   struct _gdk_span  **spans = NULL, *ptr1, *ptr2, *ptr3;
1912   XWindowAttributes   xatt;
1913   
1914   XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d);
1915   if (h <= 0)
1916     return;
1917   basew = w;
1918   baseh = h;
1919   spans = g_malloc (sizeof (struct _gdk_span *) * h);
1920   
1921   for (i = 0; i < h; i++)
1922     spans[i] = NULL;
1923   XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num);
1924   if (list)
1925     {
1926       /* go through all child windows and create/insert spans */
1927       for (i = 0; i < num; i++)
1928         {
1929           if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped))
1930             if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d))
1931               gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y);
1932         }
1933       if (merge)
1934         gdk_add_rectangles (disp, win, spans, basew, baseh, x, y);
1935       
1936       /* go through the spans list and build a list of rects */
1937       rects = g_malloc (sizeof (XRectangle) * 256);
1938       num_rects = 0;
1939       for (i = 0; i < baseh; i++)
1940         {
1941           ptr1 = spans[i];
1942           /* go through the line for all spans */
1943           while (ptr1)
1944             {
1945               rects[num_rects].x = ptr1->start;
1946               rects[num_rects].y = i;
1947               rects[num_rects].width = ptr1->end - ptr1->start + 1;
1948               rects[num_rects].height = 1;
1949               j = i + 1;
1950               /* if there are more lines */
1951               contig = 1;
1952               /* while contigous rects (same start/end coords) exist */
1953               while ((contig) && (j < baseh))
1954                 {
1955                   /* search next line for spans matching this one */
1956                   contig = 0;
1957                   ptr2 = spans[j];
1958                   ptr3 = NULL;
1959                   while (ptr2)
1960                     {
1961                       /* if we have an exact span match set contig */
1962                       if ((ptr2->start == ptr1->start) &&
1963                           (ptr2->end == ptr1->end))
1964                         {
1965                           contig = 1;
1966                           /* remove the span - not needed */
1967                           if (ptr3)
1968                             {
1969                               ptr3->next = ptr2->next;
1970                               g_free (ptr2);
1971                               ptr2 = NULL;
1972                             }
1973                           else
1974                             {
1975                               spans[j] = ptr2->next;
1976                               g_free (ptr2);
1977                               ptr2 = NULL;
1978                             }
1979                           break;
1980                         }
1981                       /* gone past the span point no point looking */
1982                       else if (ptr2->start < ptr1->start)
1983                         break;
1984                       if (ptr2)
1985                         {
1986                           ptr3 = ptr2;
1987                           ptr2 = ptr2->next;
1988                         }
1989                     }
1990                   /* if a contiguous span was found increase the rect h */
1991                   if (contig)
1992                     {
1993                       rects[num_rects].height++;
1994                       j++;
1995                     }
1996                 }
1997               /* up the rect count */
1998               num_rects++;
1999               /* every 256 new rects increase the rect array */
2000               if ((num_rects % 256) == 0)
2001                 rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256));
2002               ptr1 = ptr1->next;
2003             }
2004         }
2005       /* set the rects as the shape mask */
2006       if (rects)
2007         {
2008           XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects,
2009                                    ShapeSet, YXSorted);
2010           g_free (rects);
2011         }
2012       XFree (list);
2013     }
2014   /* free up all the spans we made */
2015   for (i = 0; i < baseh; i++)
2016     {
2017       ptr1 = spans[i];
2018       while (ptr1)
2019         {
2020           ptr2 = ptr1;
2021           ptr1 = ptr1->next;
2022           g_free (ptr2);
2023         }
2024     }
2025   g_free (spans);
2026 }
2027
2028 void
2029 gdk_window_set_child_shapes (GdkWindow *window)
2030 {
2031   g_return_if_fail (window != NULL);
2032   g_return_if_fail (GDK_IS_WINDOW (window));
2033   
2034 #ifdef HAVE_SHAPE_EXT
2035   if (!GDK_DRAWABLE_DESTROYED (window) &&
2036       gdk_window_have_shape_ext ())
2037     gdk_propagate_shapes (GDK_DRAWABLE_XDISPLAY (window),
2038                           GDK_DRAWABLE_XID (window), FALSE);
2039 #endif   
2040 }
2041
2042 void
2043 gdk_window_merge_child_shapes (GdkWindow *window)
2044 {
2045   g_return_if_fail (window != NULL);
2046   g_return_if_fail (GDK_IS_WINDOW (window));
2047   
2048 #ifdef HAVE_SHAPE_EXT
2049   if (!GDK_DRAWABLE_DESTROYED (window) &&
2050       gdk_window_have_shape_ext ())
2051     gdk_propagate_shapes (GDK_DRAWABLE_XDISPLAY (window),
2052                           GDK_DRAWABLE_XID (window), TRUE);
2053 #endif   
2054 }
2055
2056 /* Support for windows that can be guffaw-scrolled
2057  * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
2058  */
2059
2060 static gboolean
2061 gdk_window_gravity_works (void)
2062 {
2063   enum { UNKNOWN, NO, YES };
2064   static gint gravity_works = UNKNOWN;
2065   
2066   if (gravity_works == UNKNOWN)
2067     {
2068       GdkWindowAttr attr;
2069       GdkWindow *parent;
2070       GdkWindow *child;
2071       gint y;
2072       
2073       /* This particular server apparently has a bug so that the test
2074        * works but the actual code crashes it
2075        */
2076       if ((!strcmp (XServerVendor (gdk_display), "Sun Microsystems, Inc.")) &&
2077           (VendorRelease (gdk_display) == 3400))
2078         {
2079           gravity_works = NO;
2080           return FALSE;
2081         }
2082       
2083       attr.window_type = GDK_WINDOW_TEMP;
2084       attr.wclass = GDK_INPUT_OUTPUT;
2085       attr.x = 0;
2086       attr.y = 0;
2087       attr.width = 100;
2088       attr.height = 100;
2089       attr.event_mask = 0;
2090       
2091       parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y);
2092       
2093       attr.window_type = GDK_WINDOW_CHILD;
2094       child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
2095       
2096       gdk_window_set_static_win_gravity (child, TRUE);
2097       
2098       gdk_window_resize (parent, 100, 110);
2099       gdk_window_move (parent, 0, -10);
2100       gdk_window_move_resize (parent, 0, 0, 100, 100);
2101       
2102       gdk_window_resize (parent, 100, 110);
2103       gdk_window_move (parent, 0, -10);
2104       gdk_window_move_resize (parent, 0, 0, 100, 100);
2105       
2106       gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
2107       
2108       gdk_window_destroy (parent);
2109       gdk_window_destroy (child);
2110       
2111       gravity_works = ((y == -20) ? YES : NO);
2112     }
2113   
2114   return (gravity_works == YES);
2115 }
2116
2117 static void
2118 gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
2119 {
2120   XSetWindowAttributes xattributes;
2121   guint xattributes_mask = 0;
2122   
2123   g_return_if_fail (window != NULL);
2124   
2125   xattributes.bit_gravity = StaticGravity;
2126   xattributes_mask |= CWBitGravity;
2127   xattributes.bit_gravity = on ? StaticGravity : ForgetGravity;
2128   XChangeWindowAttributes (GDK_DRAWABLE_XDISPLAY (window),
2129                            GDK_DRAWABLE_XID (window),
2130                            CWBitGravity,  &xattributes);
2131 }
2132
2133 static void
2134 gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
2135 {
2136   XSetWindowAttributes xattributes;
2137   
2138   g_return_if_fail (window != NULL);
2139   
2140   xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
2141   
2142   XChangeWindowAttributes (GDK_DRAWABLE_XDISPLAY (window),
2143                            GDK_DRAWABLE_XID (window),
2144                            CWWinGravity,  &xattributes);
2145 }
2146
2147 /*************************************************************
2148  * gdk_window_set_static_gravities:
2149  *     Set the bit gravity of the given window to static,
2150  *     and flag it so all children get static subwindow
2151  *     gravity.
2152  *   arguments:
2153  *     window: window for which to set static gravity
2154  *     use_static: Whether to turn static gravity on or off.
2155  *   results:
2156  *     Does the XServer support static gravity?
2157  *************************************************************/
2158
2159 gboolean 
2160 gdk_window_set_static_gravities (GdkWindow *window,
2161                                  gboolean   use_static)
2162 {
2163   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
2164   GList *tmp_list;
2165   
2166   g_return_val_if_fail (window != NULL, FALSE);
2167   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2168
2169   if (!use_static == !private->guffaw_gravity)
2170     return TRUE;
2171   
2172   if (use_static && !gdk_window_gravity_works ())
2173     return FALSE;
2174   
2175   private->guffaw_gravity = use_static;
2176   
2177   if (!GDK_DRAWABLE_DESTROYED (window))
2178     {
2179       gdk_window_set_static_bit_gravity (window, use_static);
2180       
2181       tmp_list = private->children;
2182       while (tmp_list)
2183         {
2184           gdk_window_set_static_win_gravity (window, use_static);
2185           
2186           tmp_list = tmp_list->next;
2187         }
2188     }
2189   
2190   return TRUE;
2191 }
2192
2193 /* internal function created for and used by gdk_window_xid_at_coords */
2194 Window
2195 gdk_window_xid_at (Window   base,
2196                    gint     bx,
2197                    gint     by,
2198                    gint     x,
2199                    gint     y, 
2200                    GList   *excludes,
2201                    gboolean excl_child)
2202 {
2203   Display *xdisplay;
2204   Window *list = NULL;
2205   Window child = 0, parent_win = 0, root_win = 0;
2206   int i;
2207   unsigned int ww, wh, wb, wd, num;
2208   int wx, wy;
2209   
2210   xdisplay = GDK_DISPLAY ();
2211   if (!XGetGeometry (xdisplay, base, &root_win, &wx, &wy, &ww, &wh, &wb, &wd))
2212     return 0;
2213   wx += bx;
2214   wy += by;
2215   
2216   if (!((x >= wx) &&
2217         (y >= wy) &&
2218         (x < (int) (wx + ww)) &&
2219         (y < (int) (wy + wh))))
2220     return 0;
2221   
2222   if (!XQueryTree (xdisplay, base, &root_win, &parent_win, &list, &num))
2223     return base;
2224   
2225   if (list)
2226     {
2227       for (i = num - 1; ; i--)
2228         {
2229           if ((!excl_child) || (!g_list_find (excludes, (gpointer *) list[i])))
2230             {
2231               if ((child = gdk_window_xid_at (list[i], wx, wy, x, y, excludes, excl_child)) != 0)
2232                 {
2233                   XFree (list);
2234                   return child;
2235                 }
2236             }
2237           if (!i)
2238             break;
2239         }
2240       XFree (list);
2241     }
2242   return base;
2243 }
2244
2245 /* 
2246  * The following fucntion by The Rasterman <raster@redhat.com>
2247  * This function returns the X Window ID in which the x y location is in 
2248  * (x and y being relative to the root window), excluding any windows listed
2249  * in the GList excludes (this is a list of X Window ID's - gpointer being
2250  * the Window ID).
2251  * 
2252  * This is primarily designed for internal gdk use - for DND for example
2253  * when using a shaped icon window as the drag object - you exclude the
2254  * X Window ID of the "icon" (perhaps more if excludes may be needed) and
2255  * You can get back an X Window ID as to what X Window ID is infact under
2256  * those X,Y co-ordinates.
2257  */
2258 Window
2259 gdk_window_xid_at_coords (gint     x,
2260                           gint     y,
2261                           GList   *excludes,
2262                           gboolean excl_child)
2263 {
2264   GdkWindow *window;
2265   GdkDrawablePrivate *private;
2266   Display *xdisplay;
2267   Window *list = NULL;
2268   Window root, child = 0, parent_win = 0, root_win = 0;
2269   unsigned int num;
2270   int i;
2271
2272   window = gdk_parent_root;
2273   private = (GdkDrawablePrivate*) window;
2274   xdisplay = GDK_DRAWABLE_XDISPLAY (private);
2275   root = GDK_DRAWABLE_XID (private);
2276   num = g_list_length (excludes);
2277   
2278   XGrabServer (xdisplay);
2279   if (!XQueryTree (xdisplay, root, &root_win, &parent_win, &list, &num))
2280     {
2281       XUngrabServer (xdisplay);
2282       return root;
2283     }
2284   if (list)
2285     {
2286       i = num - 1;
2287       do
2288         {
2289           XWindowAttributes xwa;
2290           
2291           XGetWindowAttributes (xdisplay, list [i], &xwa);
2292           
2293           if (xwa.map_state != IsViewable)
2294             continue;
2295           
2296           if (excl_child && g_list_find (excludes, (gpointer *) list[i]))
2297             continue;
2298           
2299           if ((child = gdk_window_xid_at (list[i], 0, 0, x, y, excludes, excl_child)) == 0)
2300             continue;
2301           
2302           if (excludes)
2303             {
2304               if (!g_list_find (excludes, (gpointer *) child))
2305                 {
2306                   XFree (list);
2307                   XUngrabServer (xdisplay);
2308                   return child;
2309                 }
2310             }
2311           else
2312             {
2313               XFree (list);
2314               XUngrabServer (xdisplay);
2315               return child;
2316             }
2317         } while (--i > 0);
2318       XFree (list);
2319     }
2320   XUngrabServer (xdisplay);
2321   return root;
2322 }
2323