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