]> Pileus Git - ~andy/gtk/blob - gdk/gdkwindow.c
Typo fix.
[~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 Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gdkwindow.h"
28 #include "gdkinternals.h"
29 #include "gdk.h"                /* For gdk_rectangle_union() */
30 #include "gdkpixmap.h"
31 #include "gdkdrawable.h"
32 #include "gdkpixmap.h"
33
34 #define USE_BACKING_STORE       /* Appears to work on Win32, too, now. */
35
36 typedef struct _GdkWindowPaint GdkWindowPaint;
37
38 struct _GdkWindowPaint
39 {
40   GdkRegion *region;
41   GdkPixmap *pixmap;
42   gint x_offset;
43   gint y_offset;
44 };
45
46 static const GdkPointerHooks default_pointer_hooks = {
47   _gdk_windowing_window_get_pointer,
48   _gdk_windowing_window_at_pointer
49 };
50
51 static const GdkPointerHooks *current_pointer_hooks = &default_pointer_hooks;
52
53 static GdkGC *gdk_window_create_gc      (GdkDrawable     *drawable,
54                                          GdkGCValues     *values,
55                                          GdkGCValuesMask  mask);
56 static void   gdk_window_draw_rectangle (GdkDrawable     *drawable,
57                                          GdkGC           *gc,
58                                          gint             filled,
59                                          gint             x,
60                                          gint             y,
61                                          gint             width,
62                                          gint             height);
63 static void   gdk_window_draw_arc       (GdkDrawable     *drawable,
64                                          GdkGC           *gc,
65                                          gint             filled,
66                                          gint             x,
67                                          gint             y,
68                                          gint             width,
69                                          gint             height,
70                                          gint             angle1,
71                                          gint             angle2);
72 static void   gdk_window_draw_polygon   (GdkDrawable     *drawable,
73                                          GdkGC           *gc,
74                                          gint             filled,
75                                          GdkPoint        *points,
76                                          gint             npoints);
77 static void   gdk_window_draw_text      (GdkDrawable     *drawable,
78                                          GdkFont         *font,
79                                          GdkGC           *gc,
80                                          gint             x,
81                                          gint             y,
82                                          const gchar     *text,
83                                          gint             text_length);
84 static void   gdk_window_draw_text_wc   (GdkDrawable     *drawable,
85                                          GdkFont         *font,
86                                          GdkGC           *gc,
87                                          gint             x,
88                                          gint             y,
89                                          const GdkWChar  *text,
90                                          gint             text_length);
91 static void   gdk_window_draw_drawable  (GdkDrawable     *drawable,
92                                          GdkGC           *gc,
93                                          GdkPixmap       *src,
94                                          gint             xsrc,
95                                          gint             ysrc,
96                                          gint             xdest,
97                                          gint             ydest,
98                                          gint             width,
99                                          gint             height);
100 static void   gdk_window_draw_points    (GdkDrawable     *drawable,
101                                          GdkGC           *gc,
102                                          GdkPoint        *points,
103                                          gint             npoints);
104 static void   gdk_window_draw_segments  (GdkDrawable     *drawable,
105                                          GdkGC           *gc,
106                                          GdkSegment      *segs,
107                                          gint             nsegs);
108 static void   gdk_window_draw_lines     (GdkDrawable     *drawable,
109                                          GdkGC           *gc,
110                                          GdkPoint        *points,
111                                          gint             npoints);
112 static void   gdk_window_draw_glyphs    (GdkDrawable      *drawable,
113                                          GdkGC            *gc,
114                                          PangoFont        *font,
115                                          gint              x,
116                                          gint              y,
117                                          PangoGlyphString *glyphs);
118
119 static void   gdk_window_draw_image     (GdkDrawable     *drawable,
120                                          GdkGC           *gc,
121                                          GdkImage        *image,
122                                          gint             xsrc,
123                                          gint             ysrc,
124                                          gint             xdest,
125                                          gint             ydest,
126                                          gint             width,
127                                          gint             height);
128
129 static GdkImage*  gdk_window_get_image  (GdkDrawable     *drawable,
130                                          gint             x,
131                                          gint             y,
132                                          gint             width,
133                                          gint             height);
134
135
136 static void   gdk_window_real_get_size  (GdkDrawable     *drawable,
137                                          gint            *width,
138                                          gint            *height);
139
140 static GdkVisual*   gdk_window_real_get_visual   (GdkDrawable *drawable);
141 static gint         gdk_window_real_get_depth    (GdkDrawable *drawable);
142 static void         gdk_window_real_set_colormap (GdkDrawable *drawable,
143                                              GdkColormap *cmap);
144 static GdkColormap* gdk_window_real_get_colormap (GdkDrawable *drawable);
145
146 static GdkDrawable* gdk_window_get_composite_drawable (GdkDrawable *drawable,
147                                                        gint         x,
148                                                        gint         y,
149                                                        gint         width,
150                                                        gint         height,
151                                                        gint        *composite_x_offset,
152                                                        gint        *composite_y_offset);
153 static GdkRegion*   gdk_window_get_clip_region        (GdkDrawable *drawable);
154 static GdkRegion*   gdk_window_get_visible_region     (GdkDrawable *drawable);
155
156 static void gdk_window_free_paint_stack (GdkWindow *window);
157
158 static void gdk_window_init       (GdkWindowObject      *window);
159 static void gdk_window_class_init (GdkWindowObjectClass *klass);
160 static void gdk_window_finalize   (GObject              *object);
161
162 static gpointer parent_class = NULL;
163
164 GType
165 gdk_window_object_get_type (void)
166 {
167   static GType object_type = 0;
168
169   if (!object_type)
170     {
171       static const GTypeInfo object_info =
172       {
173         sizeof (GdkWindowObjectClass),
174         (GBaseInitFunc) NULL,
175         (GBaseFinalizeFunc) NULL,
176         (GClassInitFunc) gdk_window_class_init,
177         NULL,           /* class_finalize */
178         NULL,           /* class_data */
179         sizeof (GdkWindowObject),
180         0,              /* n_preallocs */
181         (GInstanceInitFunc) gdk_window_init,
182       };
183       
184       object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
185                                             "GdkWindow",
186                                             &object_info, 0);
187     }
188   
189   return object_type;
190 }
191
192 static void
193 gdk_window_init (GdkWindowObject *window)
194 {
195   /* 0-initialization is good for all other fields. */
196
197   window->window_type = GDK_WINDOW_CHILD;
198
199   window->state = GDK_WINDOW_STATE_WITHDRAWN;
200   
201   window->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
202 }
203
204 static void
205 gdk_window_class_init (GdkWindowObjectClass *klass)
206 {
207   GObjectClass *object_class = G_OBJECT_CLASS (klass);
208   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
209   
210   parent_class = g_type_class_peek_parent (klass);
211
212   object_class->finalize = gdk_window_finalize;
213
214   drawable_class->create_gc = gdk_window_create_gc;
215   drawable_class->draw_rectangle = gdk_window_draw_rectangle;
216   drawable_class->draw_arc = gdk_window_draw_arc;
217   drawable_class->draw_polygon = gdk_window_draw_polygon;
218   drawable_class->draw_text = gdk_window_draw_text;
219   drawable_class->draw_text_wc = gdk_window_draw_text_wc;
220   drawable_class->draw_drawable = gdk_window_draw_drawable;
221   drawable_class->draw_points = gdk_window_draw_points;
222   drawable_class->draw_segments = gdk_window_draw_segments;
223   drawable_class->draw_lines = gdk_window_draw_lines;
224   drawable_class->draw_glyphs = gdk_window_draw_glyphs;
225   drawable_class->draw_image = gdk_window_draw_image;
226   drawable_class->get_depth = gdk_window_real_get_depth;
227   drawable_class->get_size = gdk_window_real_get_size;
228   drawable_class->set_colormap = gdk_window_real_set_colormap;
229   drawable_class->get_colormap = gdk_window_real_get_colormap;
230   drawable_class->get_visual = gdk_window_real_get_visual;
231   drawable_class->get_image = gdk_window_get_image;
232   drawable_class->get_clip_region = gdk_window_get_clip_region;
233   drawable_class->get_visible_region = gdk_window_get_visible_region;
234   drawable_class->get_composite_drawable = gdk_window_get_composite_drawable;
235 }
236
237 static void
238 gdk_window_finalize (GObject *object)
239 {
240   GdkWindow *window = GDK_WINDOW (object);
241   GdkWindowObject *obj = (GdkWindowObject *) object;
242   
243   if (!GDK_WINDOW_DESTROYED (window))
244     {
245       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
246         {
247           g_warning ("losing last reference to undestroyed window\n");
248           _gdk_window_destroy (window, FALSE);
249         }
250       else
251         /* We use TRUE here, to keep us from actually calling
252          * XDestroyWindow() on the window
253          */
254         _gdk_window_destroy (window, TRUE);
255     }
256
257   g_object_unref (G_OBJECT (obj->impl));
258   obj->impl = NULL;
259   
260   G_OBJECT_CLASS (parent_class)->finalize (object);
261 }
262
263 /**
264  * _gdk_window_destroy_hierarchy:
265  * @window: a #GdkWindow
266  * @recursing: If TRUE, then this is being called because a parent
267  *            was destroyed. This generally means that the call to the windowing system
268  *            to destroy the window can be omitted, since it will be destroyed as a result
269  *            of the parent being destroyed. Unless @foreign_destroy
270  *            
271  * foreign_destroy: If TRUE, the window or a parent was destroyed by some external 
272  *            agency. The window has already been destroyed and no windowing
273  *            system calls should be made. (This may never happen for some
274  *            windowing systems.)
275  *
276  * Internal function to destroy a window. Like gdk_window_destroy(), but does not
277  * drop the reference count created by gdk_window_new().
278  **/
279 static void
280 _gdk_window_destroy_hierarchy (GdkWindow *window,
281                                gboolean   recursing,
282                                gboolean   foreign_destroy)
283 {
284   GdkWindowObject *private;
285   GdkWindowObject *temp_private;
286   GdkWindow *temp_window;
287   GList *children;
288   GList *tmp;
289   
290   g_return_if_fail (window != NULL);
291   
292   private = (GdkWindowObject*) window;
293   
294   switch (GDK_WINDOW_TYPE (window))
295     {
296     case GDK_WINDOW_TOPLEVEL:
297     case GDK_WINDOW_CHILD:
298     case GDK_WINDOW_DIALOG:
299     case GDK_WINDOW_TEMP:
300     case GDK_WINDOW_FOREIGN:
301       if (!GDK_WINDOW_DESTROYED (window))
302         {
303           private->state |= GDK_WINDOW_STATE_WITHDRAWN;
304           
305           if (private->parent)
306             {
307               GdkWindowObject *parent_private = (GdkWindowObject *)private->parent;
308               if (parent_private->children)
309                 parent_private->children = g_list_remove (parent_private->children, window);
310             }
311
312           _gdk_window_clear_update_area (window);
313           gdk_window_free_paint_stack (window);
314           
315           if (private->bg_pixmap &&
316               private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
317               private->bg_pixmap != GDK_NO_BG)
318             {
319               gdk_pixmap_unref (private->bg_pixmap);
320               private->bg_pixmap = NULL;
321             }
322           
323           if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN)
324             g_assert (private->children == NULL);
325           else
326             {
327               children = tmp = private->children;
328               private->children = NULL;
329               
330               while (tmp)
331                 {
332                   temp_window = tmp->data;
333                   tmp = tmp->next;
334                   
335                   temp_private = (GdkWindowObject*) temp_window;
336                   if (temp_private)
337                     _gdk_window_destroy_hierarchy (temp_window, TRUE, foreign_destroy);
338                 }
339               
340               g_list_free (children);
341             }
342           
343           _gdk_windowing_window_destroy (window, recursing, foreign_destroy);
344           private->destroyed = TRUE;
345
346           if (private->filters)
347             {
348               tmp = private->filters;
349               
350               while (tmp)
351                 {
352                   g_free (tmp->data);
353                   tmp = tmp->next;
354                 }
355               
356               g_list_free (private->filters);
357               private->filters = NULL;
358             }
359
360           gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
361         }
362       break;
363       
364     case GDK_WINDOW_ROOT:
365       g_error ("attempted to destroy root window");
366       break;
367     }
368 }
369
370 /**
371  * _gdk_window_destroy:
372  * @window: a #GdkWindow
373  * foreign_destroy: If TRUE, the window or a parent was destroyed by some external 
374  *            agency. The window has already been destroyed and no windowing
375  *            system calls should be made. (This may never happen for some
376  *            windowing systems.)
377  *
378  * Internal function to destroy a window. Like gdk_window_destroy(), but does not
379  * drop the reference count created by gdk_window_new().
380  **/
381 void
382 _gdk_window_destroy (GdkWindow *window,
383                      gboolean   foreign_destroy)
384 {
385   _gdk_window_destroy_hierarchy (window, FALSE, foreign_destroy);
386 }
387
388 /**
389  * gdk_window_destroy:
390  * @window: a #GdkWindow
391  *
392  * Destroys @window (destroys the server-side resource associated with @window).
393  * Memory allocated for @window may not be freed until all references
394  * to @window are dropped. All children of @window are also destroyed.
395  *
396  * There's normally no need to use this function, window are automatically
397  * destroyed when their reference count reaches 0.
398  * 
399  **/
400 void
401 gdk_window_destroy (GdkWindow *window)
402 {
403   _gdk_window_destroy_hierarchy (window, FALSE, FALSE);
404   gdk_drawable_unref (window);
405 }
406
407 /**
408  * gdk_window_set_user_data:
409  * @window: a #GdkWindow
410  * @user_data: user data
411  *
412  * For most purposes this function is deprecated in favor of
413  * g_object_set_data(). However, for historical reasons GTK+ stores
414  * the #GtkWidget that owns a #GdkWindow as user data on the
415  * #GdkWindow. So, custom widget implementations should use
416  * this function for that. If GTK+ receives an event for a #GdkWindow,
417  * and the user data for the window is non-%NULL, GTK+ will assume the
418  * user data is a #GtkWidget, and forward the event to that widget.
419  * 
420  **/
421 void
422 gdk_window_set_user_data (GdkWindow *window,
423                           gpointer   user_data)
424 {
425   g_return_if_fail (window != NULL);
426   
427   ((GdkWindowObject*)window)->user_data = user_data;
428 }
429
430 /**
431  * gdk_window_get_user_data:
432  * @window: a #GdkWindow
433  * @data: return location for user data
434  *
435  * Retrieves the user data for @window, which is normally the widget
436  * that @window belongs to. See gdk_window_set_user_data().
437  * 
438  **/
439 void
440 gdk_window_get_user_data (GdkWindow *window,
441                           gpointer  *data)
442 {
443   g_return_if_fail (window != NULL);
444   
445   *data = ((GdkWindowObject*)window)->user_data;
446 }
447
448 /**
449  * gdk_window_get_window_type:
450  * @window: a #GdkWindow
451  * 
452  * Gets the type of the window. See #GdkWindowType.
453  * 
454  * Return value: type of window
455  **/
456 GdkWindowType
457 gdk_window_get_window_type (GdkWindow *window)
458 {
459   g_return_val_if_fail (GDK_IS_WINDOW (window), (GdkWindowType) -1);
460   
461   return GDK_WINDOW_TYPE (window);
462 }
463
464 /**
465  * gdk_window_get_position:
466  * @window: a #GdkWindow
467  * @x: X coordinate of window
468  * @y: Y coordinate of window
469  *
470  * Obtains the position of the window as reported in the most-recently-processed
471  * #GdkEventConfigure. Contrast with gdk_window_get_geometry() which
472  * queries the X server for the current window position, regardless of which
473  * events have been received or processed.
474  *
475  * The position coordinates are relative to the window's parent window.
476  * 
477  **/
478 void
479 gdk_window_get_position (GdkWindow *window,
480                          gint      *x,
481                          gint      *y)
482 {
483   GdkWindowObject *obj;
484   
485   g_return_if_fail (GDK_IS_WINDOW (window));
486   
487   obj = (GdkWindowObject*) window;
488   
489   if (x)
490     *x = obj->x;
491   if (y)
492     *y = obj->y;
493 }
494
495 /**
496  * gdk_window_get_parent:
497  * @window: a #GdkWindow
498  * 
499  * Obtains the parent of @window, as known to GDK. Does not query the
500  * X server; thus this returns the parent as passed to gdk_window_new(),
501  * not the actual parent. This should never matter unless you're using
502  * Xlib calls mixed with GDK calls on the X11 platform. It may also
503  * matter for toplevel windows, because the window manager may choose
504  * to reparent them.
505  * 
506  * Return value: parent of @window
507  **/
508 GdkWindow*
509 gdk_window_get_parent (GdkWindow *window)
510 {
511   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
512   
513   return (GdkWindow*) ((GdkWindowObject*) window)->parent;
514 }
515
516 /**
517  * gdk_window_get_toplevel:
518  * @window: a #GdkWindow
519  * 
520  * Gets the toplevel window that's an ancestor of @window.
521  * 
522  * Return value: the toplevel window containing @window
523  **/
524 GdkWindow*
525 gdk_window_get_toplevel (GdkWindow *window)
526 {
527   GdkWindowObject *obj;
528   
529   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
530
531   obj = (GdkWindowObject *)window;
532   while (GDK_WINDOW_TYPE (obj) == GDK_WINDOW_CHILD)
533     obj = (GdkWindowObject *)obj->parent;
534   
535   return GDK_WINDOW (obj);
536 }
537
538 /**
539  * gdk_window_get_children:
540  * @window: a #GdkWindow
541  * 
542  * Gets the list of children of @window known to GDK.
543  * This function only returns children created via GDK,
544  * so for example it's useless when used with the root window;
545  * it only returns windows an application created itself.
546  *
547  * The returned list must be freed, but the elements in the
548  * list need not be.
549  * 
550  * Return value: list of child windows inside @window
551  **/
552 GList*
553 gdk_window_get_children (GdkWindow *window)
554 {
555   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
556
557   if (GDK_WINDOW_DESTROYED (window))
558     return NULL;
559
560   return g_list_copy (GDK_WINDOW_OBJECT (window)->children);
561 }
562
563 /**
564  * gdk_window_peek_children:
565  * @window: a #GdkWindow
566  * 
567  * Like gdk_window_get_children(), but does not copy the list of
568  * children, so the list does not need to be freed.
569  * 
570  * Return value: a reference to the list of child windows in @window
571  **/
572 GList *
573 gdk_window_peek_children (GdkWindow *window)
574 {
575   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
576
577   if (GDK_WINDOW_DESTROYED (window))
578     return NULL;
579
580   return GDK_WINDOW_OBJECT (window)->children;
581 }
582
583 /**
584  * gdk_window_add_filter:
585  * @window: a #GdkWindow
586  * @function: filter callback
587  * @data: data to pass to filter callback
588  *
589  * Adds an event filter to @window, allowing you to intercept events
590  * before they reach GDK. This is a low-level operation and makes it easy to break
591  * GDK and/or GTK+, so you have to know what you're doing.
592  * 
593  **/
594 void          
595 gdk_window_add_filter (GdkWindow     *window,
596                        GdkFilterFunc  function,
597                        gpointer       data)
598 {
599   GdkWindowObject *private;
600   GList *tmp_list;
601   GdkEventFilter *filter;
602   
603   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
604
605   private = (GdkWindowObject*) window;
606   if (private && GDK_WINDOW_DESTROYED (window))
607     return;
608   
609   if (private)
610     tmp_list = private->filters;
611   else
612     tmp_list = _gdk_default_filters;
613   
614   while (tmp_list)
615     {
616       filter = (GdkEventFilter *)tmp_list->data;
617       if ((filter->function == function) && (filter->data == data))
618         return;
619       tmp_list = tmp_list->next;
620     }
621   
622   filter = g_new (GdkEventFilter, 1);
623   filter->function = function;
624   filter->data = data;
625   
626   if (private)
627     private->filters = g_list_append (private->filters, filter);
628   else
629     _gdk_default_filters = g_list_append (_gdk_default_filters, filter);
630 }
631
632 /**
633  * gdk_window_remove_filter:
634  * @window: a #GdkWindow
635  * @function: previously-added filter function
636  * @data: user data for previously-added filter function
637  *
638  * Remove a filter previously added with gdk_window_add_filter().
639  * 
640  **/
641 void
642 gdk_window_remove_filter (GdkWindow     *window,
643                           GdkFilterFunc  function,
644                           gpointer       data)
645 {
646   GdkWindowObject *private;
647   GList *tmp_list, *node;
648   GdkEventFilter *filter;
649   
650   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
651
652   private = (GdkWindowObject*) window;
653   
654   if (private)
655     tmp_list = private->filters;
656   else
657     tmp_list = _gdk_default_filters;
658   
659   while (tmp_list)
660     {
661       filter = (GdkEventFilter *)tmp_list->data;
662       node = tmp_list;
663       tmp_list = tmp_list->next;
664       
665       if ((filter->function == function) && (filter->data == data))
666         {
667           if (private)
668             private->filters = g_list_remove_link (private->filters, node);
669           else
670             _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node);
671           g_list_free_1 (node);
672           g_free (filter);
673           
674           return;
675         }
676     }
677 }
678
679 /**
680  * gdk_window_get_toplevels:
681  * 
682  * Obtains a list of all toplevel windows known to GDK.
683  * A toplevel window is a child of the root window (see
684  * gdk_get_default_root_window()).
685  *
686  * The returned list should be freed with g_list_free(), but
687  * its elements need not be freed.
688  * 
689  * Return value: list of toplevel windows, free with g_list_free()
690  **/
691 GList *
692 gdk_window_get_toplevels (void)
693 {
694   GList *new_list = NULL;
695   GList *tmp_list;
696   
697   tmp_list = ((GdkWindowObject *)_gdk_parent_root)->children;
698   while (tmp_list)
699     {
700       if (GDK_WINDOW_TYPE (tmp_list->data) != GDK_WINDOW_FOREIGN)
701         new_list = g_list_prepend (new_list, tmp_list->data);
702       tmp_list = tmp_list->next;
703     }
704   
705   return new_list;
706 }
707
708 /**
709  * gdk_window_is_visible:
710  * @window: a #GdkWindow
711  * 
712  * Checks whether the window has been mapped (with gdk_window_show() or
713  * gdk_window_show_unraised()).
714  * 
715  * Return value: %TRUE if the window is mapped
716  **/
717 gboolean 
718 gdk_window_is_visible (GdkWindow *window)
719 {
720   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
721   
722   return GDK_WINDOW_IS_MAPPED (window);
723 }
724
725 /**
726  * gdk_window_is_viewable:
727  * @window: a #GdkWindow
728  * 
729  * Check if the window and all ancestors of the window are
730  * mapped. (This is not necessarily "viewable" in the X sense, since
731  * we only check as far as we have GDK window parents, not to the root
732  * window)
733  * 
734  * 
735  * 
736  * Return value: %TRUE if the window is viewable
737  **/
738 gboolean 
739 gdk_window_is_viewable (GdkWindow *window)
740 {
741   GdkWindowObject *private = (GdkWindowObject *)window;
742   
743   g_return_val_if_fail (window != NULL, FALSE);
744   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
745   
746   while (private && 
747          (private != (GdkWindowObject *)_gdk_parent_root) &&
748          (GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN))
749     {
750       if (!GDK_WINDOW_IS_MAPPED (window))
751         return FALSE;
752       
753       private = (GdkWindowObject *)private->parent;
754     }
755   
756   return TRUE;
757 }
758
759 /**
760  * gdk_window_get_state:
761  * @window: a #GdkWindow
762  * 
763  * Gets the bitwise OR of the currently active window state flags,
764  * from the #GdkWindowState enumeration.
765  * 
766  * Return value: window state bitfield
767  **/
768 GdkWindowState
769 gdk_window_get_state (GdkWindow *window)
770 {
771   GdkWindowObject *private = (GdkWindowObject *)window;
772   
773   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
774   
775   return private->state;
776 }
777
778 /**
779  * gdk_window_begin_paint_rect:
780  * @window: a #GdkWindow
781  * @rectangle: rectangle you intend to draw to
782  *
783  * A convenience wrapper around gdk_window_begin_paint_region() which
784  * creates a rectangular region for you. See
785  * gdk_window_begin_paint_region() for details.
786  * 
787  **/
788 void
789 gdk_window_begin_paint_rect (GdkWindow    *window,
790                              GdkRectangle *rectangle)
791 {
792   GdkRegion *region;
793
794   g_return_if_fail (window != NULL);
795   g_return_if_fail (GDK_IS_WINDOW (window));
796
797   region = gdk_region_rectangle (rectangle);
798   gdk_window_begin_paint_region (window, region);
799   gdk_region_destroy (region);
800 }
801
802 static GdkGC *
803 gdk_window_get_bg_gc (GdkWindow *window, GdkWindowPaint *paint)
804 {
805   GdkWindowObject *private = (GdkWindowObject *)window;
806
807   guint gc_mask = 0;
808   GdkGCValues gc_values;
809
810   if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
811     {
812       GdkWindowPaint tmp_paint = *paint;
813       tmp_paint.x_offset += private->x;
814       tmp_paint.y_offset += private->y;
815       
816       return gdk_window_get_bg_gc (GDK_WINDOW (private->parent), &tmp_paint);
817     }
818   else if (private->bg_pixmap && private->bg_pixmap != GDK_PARENT_RELATIVE_BG && private->bg_pixmap != GDK_NO_BG)
819     {
820       gc_values.fill = GDK_TILED;
821       gc_values.tile = private->bg_pixmap;
822       gc_values.ts_x_origin = - paint->x_offset;
823       gc_values.ts_y_origin = - paint->y_offset;
824       
825       gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN;
826     }
827   else
828     {
829       gc_values.foreground = private->bg_color;
830       gc_mask = GDK_GC_FOREGROUND;
831     }
832
833   return gdk_gc_new_with_values (paint->pixmap, &gc_values, gc_mask);
834 }
835
836 static void
837 gdk_window_paint_init_bg (GdkWindow      *window,
838                           GdkWindowPaint *paint,
839                           GdkRegion      *init_region)
840 {
841   GdkGC *tmp_gc;
842   
843   tmp_gc = gdk_window_get_bg_gc (window, paint);
844
845   gdk_region_offset (init_region,
846                      - paint->x_offset,
847                      - paint->y_offset);
848   gdk_gc_set_clip_region (tmp_gc, init_region);
849
850   gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE, 0, 0, -1, -1);
851   gdk_gc_unref (tmp_gc);
852 }
853
854 #ifdef GDK_WINDOWING_X11
855 #include "x11/gdkx.h"
856 #endif
857
858 /**
859  * gdk_window_begin_paint_region:
860  * @window: a #GdkWindow
861  * @region: region you intend to draw to
862  *
863  * Indicates that you are beginning the process of redrawing @region.
864  * A backing store (offscreen buffer) large enough to contain @region
865  * will be created. The backing store will be initialized with the
866  * background color or background pixmap for @window. Then, all
867  * drawing operations performed on @window will be diverted to the
868  * backing store.  When you call gdk_window_end_paint(), the backing
869  * store will be copied to @window, making it visible onscreen. Only
870  * the part of @window contained in @region will be modified; that is,
871  * drawing operations are clipped to @region.
872  *
873  * The net result of all this is to remove flicker, because the user
874  * sees the finished product appear all at once when you call
875  * gdk_window_end_paint(). If you draw to @window directly without
876  * calling gdk_window_begin_paint_region(), the user may see flicker
877  * as individual drawing operations are performed in sequence.  The
878  * clipping and background-initializing features of
879  * gdk_window_begin_paint_region() are conveniences for the
880  * programmer, so you can avoid doing that work yourself.
881  *
882  * When using GTK+, the widget system automatically places calls to
883  * gdk_window_begin_paint_region() and gdk_window_end_paint() around
884  * emissions of the expose_event signal. That is, if you're writing an
885  * expose event handler, you can assume that the exposed area in
886  * #GdkEventExpose has already been cleared to the window background,
887  * is already set as the clip region, and already has a backing store.
888  * Therefore in most cases, application code need not call
889  * gdk_window_begin_paint_region(). (You can disable the automatic
890  * calls around expose events on a widget-by-widget basis by calling
891  * gtk_widget_set_double_buffered().)
892  *
893  * If you call this function multiple times before calling the
894  * matching gdk_window_end_paint(), the backing stores are pushed onto
895  * a stack. gdk_window_end_paint() copies the topmost backing store
896  * onscreen, subtracts the topmost region from all other regions in
897  * the stack, and pops the stack. All drawing operations affect only
898  * the topmost backing store in the stack. One matching call to
899  * gdk_window_end_paint() is required for each call to
900  * gdk_window_begin_paint_region().
901  * 
902  **/
903 void          
904 gdk_window_begin_paint_region (GdkWindow *window,
905                                GdkRegion *region)
906 {
907 #ifdef USE_BACKING_STORE
908   GdkWindowObject *private = (GdkWindowObject *)window;
909   GdkRectangle clip_box;
910   GdkWindowPaint *paint;
911   GdkRegion *init_region;
912   GdkGC *tmp_gc;
913   
914   g_return_if_fail (window != NULL);
915   g_return_if_fail (GDK_IS_WINDOW (window));
916
917   if (GDK_WINDOW_DESTROYED (window))
918     return;
919   
920   paint = g_new (GdkWindowPaint, 1);
921
922   paint->region = gdk_region_copy (region);
923
924   init_region = gdk_region_copy (region);
925   gdk_region_get_clipbox (paint->region, &clip_box);
926
927   if (private->paint_stack)
928     {
929       gint old_width, old_height;
930       GdkWindowPaint *tmp_paint = private->paint_stack->data;
931       GdkRectangle old_rect, new_rect;
932       GSList *tmp_list;
933
934       gdk_drawable_get_size (tmp_paint->pixmap, &old_width, &old_height);
935       old_rect.x = tmp_paint->x_offset;
936       old_rect.y = tmp_paint->y_offset;
937       old_rect.width = old_width;
938       old_rect.height = old_height;
939
940       gdk_rectangle_union (&clip_box, &old_rect, &new_rect);
941
942       if (new_rect.width > old_rect.width || new_rect.height > old_rect.height)
943         {
944           paint->pixmap = gdk_pixmap_new (window,
945                                           new_rect.width, new_rect.height, -1);
946           tmp_gc = gdk_gc_new (paint->pixmap);
947           gdk_draw_drawable (paint->pixmap, tmp_gc, tmp_paint->pixmap,
948                              0, 0,
949                              old_rect.x - new_rect.x, old_rect.y - new_rect.y,
950                              old_rect.width, old_rect.height);
951           gdk_gc_unref (tmp_gc);
952           gdk_drawable_unref (tmp_paint->pixmap);
953
954           paint->x_offset = new_rect.x;
955           paint->y_offset = new_rect.y;
956           
957           tmp_list = private->paint_stack;
958           while (tmp_list)
959             {
960               tmp_paint = tmp_list->data;
961               gdk_region_subtract (init_region, tmp_paint->region);
962
963               tmp_paint->pixmap = paint->pixmap;
964               tmp_paint->x_offset = paint->x_offset;
965               tmp_paint->y_offset = paint->y_offset;
966               
967               tmp_list = tmp_list->next;
968             }
969         }
970       else
971         {
972           paint->x_offset = tmp_paint->x_offset;
973           paint->y_offset = tmp_paint->y_offset;
974           paint->pixmap = tmp_paint->pixmap;
975
976           tmp_list = private->paint_stack;
977           while (tmp_list)
978             {
979               tmp_paint = tmp_list->data;
980               gdk_region_subtract (init_region, tmp_paint->region);
981
982               tmp_list = tmp_list->next;
983             }
984         }
985     }
986   else
987     {
988       paint->x_offset = clip_box.x;
989       paint->y_offset = clip_box.y;
990       paint->pixmap = gdk_pixmap_new (window, clip_box.width, clip_box.height, -1);
991     }
992
993   if (!gdk_region_empty (init_region))
994     gdk_window_paint_init_bg (window, paint, init_region);
995   
996   gdk_region_destroy (init_region);
997   
998   private->paint_stack = g_slist_prepend (private->paint_stack, paint);
999 #endif /* USE_BACKING_STORE */
1000 }
1001
1002 /**
1003  * gdk_window_end_paint:
1004  * @window: a #GdkWindow
1005  *
1006  * Indicates that the backing store created by the most recent call to
1007  * gdk_window_begin_paint_region() should be copied onscreen and
1008  * deleted, leaving the next-most-recent backing store or no backing
1009  * store at all as the active paint region. See
1010  * gdk_window_begin_paint_region() for full details. It is an error to
1011  * call this function without a matching
1012  * gdk_window_begin_paint_region() first.
1013  * 
1014  **/
1015 void
1016 gdk_window_end_paint (GdkWindow *window)
1017 {
1018 #ifdef USE_BACKING_STORE
1019   GdkWindowObject *private = (GdkWindowObject *)window;
1020   GdkWindowPaint *paint;
1021   GdkGC *tmp_gc;
1022   GdkRectangle clip_box;
1023   gint x_offset, y_offset;
1024
1025   g_return_if_fail (window != NULL);
1026   g_return_if_fail (GDK_IS_WINDOW (window));
1027
1028   if (GDK_WINDOW_DESTROYED (window))
1029     return;
1030
1031   if (private->paint_stack == NULL)
1032     {
1033       g_warning (G_STRLOC": no preceding call to gdk_window_begin_paint_region(), see documentation");
1034       return;
1035     }
1036
1037   paint = private->paint_stack->data;
1038   private->paint_stack = g_slist_delete_link (private->paint_stack, private->paint_stack);
1039
1040   gdk_region_get_clipbox (paint->region, &clip_box);
1041
1042   tmp_gc = gdk_gc_new (window);
1043
1044   _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset);
1045
1046   gdk_gc_set_clip_region (tmp_gc, paint->region);
1047   gdk_gc_set_clip_origin (tmp_gc, -x_offset, -y_offset);
1048
1049   gdk_draw_drawable (private->impl, tmp_gc, paint->pixmap,
1050                      clip_box.x - paint->x_offset,
1051                      clip_box.y - paint->y_offset,
1052                      clip_box.x - x_offset, clip_box.y - y_offset,
1053                      clip_box.width, clip_box.height);
1054   gdk_gc_unref (tmp_gc);
1055
1056   if (private->paint_stack)
1057     {
1058       GSList *tmp_list = private->paint_stack;
1059       while (tmp_list)
1060         {
1061           GdkWindowPaint *tmp_paint = tmp_list->data;
1062           gdk_region_subtract (tmp_paint->region, paint->region);
1063           
1064           tmp_list = tmp_list->next;
1065         }
1066     }
1067   else
1068     gdk_drawable_unref (paint->pixmap);
1069
1070   gdk_region_destroy (paint->region);
1071   g_free (paint);
1072 #endif /* USE_BACKING_STORE */
1073 }
1074
1075 static void
1076 gdk_window_free_paint_stack (GdkWindow *window)
1077 {
1078   GdkWindowObject *private = (GdkWindowObject *)window;
1079   
1080   if (private->paint_stack)
1081     {
1082       GSList *tmp_list = private->paint_stack;
1083
1084       while (tmp_list)
1085         {
1086           GdkWindowPaint *paint = tmp_list->data;
1087
1088           if (tmp_list == private->paint_stack)
1089             gdk_drawable_unref (paint->pixmap);
1090                   
1091           gdk_region_destroy (paint->region);
1092           g_free (paint);
1093
1094           tmp_list = tmp_list->next;
1095         }
1096
1097       g_slist_free (private->paint_stack);
1098       private->paint_stack = NULL;
1099     }
1100 }
1101
1102 static void
1103 gdk_window_get_offsets (GdkWindow *window,
1104                         gint      *x_offset,
1105                         gint      *y_offset)
1106 {
1107   GdkWindowObject *private = (GdkWindowObject *)window;
1108   
1109   if (private->paint_stack)
1110     {
1111       GdkWindowPaint *paint = private->paint_stack->data;
1112       *x_offset = paint->x_offset;
1113       *y_offset = paint->y_offset;
1114     }
1115   else
1116     _gdk_windowing_window_get_offsets (window, x_offset, y_offset);
1117 }
1118
1119 /**
1120  * gdk_window_get_internal_paint_info:
1121  * @window: a #GdkWindow
1122  * @real_drawable: location to store the drawable to which drawing should be done.
1123  * @x_offset: location to store the X offset between coordinates in @window, and
1124  *            the underlying window system primitive coordinates for *@real_drawable.
1125  * @y_offset: location to store the Y offset between coordinates in @window, and
1126  *            the underlying window system primitive coordinates for *@real_drawable.
1127  * 
1128  * If you bypass the GDK layer and use windowing system primitives to
1129  * draw directly onto a #GdkWindow, then you need to deal with two
1130  * details: there may be an offset between GDK coordinates and windowing
1131  * system coordinates, and GDK may have redirected drawing to a offscreen
1132  * pixmap as the result of a gdk_window_begin_paint_region() calls.
1133  * This function allows retrieving the information you need to compensate
1134  * for these effects.
1135  *
1136  * This function exposes details of the GDK implementation, and is thus
1137  * likely to change in future releases of GDK.
1138  **/
1139 void
1140 gdk_window_get_internal_paint_info (GdkWindow    *window,
1141                                     GdkDrawable **real_drawable,
1142                                     gint         *x_offset,
1143                                     gint         *y_offset)
1144 {
1145   gint x_off, y_off;
1146   
1147   GdkWindowObject *private;
1148
1149   g_return_if_fail (GDK_IS_WINDOW (window));
1150
1151   private = (GdkWindowObject *)window;
1152
1153   if (real_drawable)
1154     {
1155       if (private->paint_stack)
1156         {
1157           GdkWindowPaint *paint = private->paint_stack->data;
1158           *real_drawable = paint->pixmap;
1159         }
1160       else
1161         *real_drawable = window;
1162     }
1163
1164   gdk_window_get_offsets (window, &x_off, &y_off);
1165
1166   if (x_offset)
1167     *x_offset = x_off;
1168   if (y_offset)
1169     *y_offset = y_off;
1170 }
1171
1172 #define OFFSET_GC(gc)                                         \
1173     gint x_offset, y_offset;                                  \
1174     gint old_clip_x = gc->clip_x_origin;    \
1175     gint old_clip_y = gc->clip_y_origin;    \
1176     gint old_ts_x = gc->ts_x_origin;        \
1177     gint old_ts_y = gc->ts_y_origin;        \
1178     gdk_window_get_offsets (drawable, &x_offset, &y_offset);  \
1179     if (x_offset != 0 || y_offset != 0)                       \
1180       {                                                       \
1181         gdk_gc_set_clip_origin (gc, old_clip_x - x_offset,    \
1182                                 old_clip_y - y_offset);       \
1183         gdk_gc_set_ts_origin (gc, old_ts_x - x_offset,        \
1184                               old_ts_y - y_offset);           \
1185       }
1186
1187 #define RESTORE_GC(gc)                                      \
1188     if (x_offset != 0 || y_offset != 0)                     \
1189      {                                                      \
1190        gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \
1191        gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y);       \
1192      }
1193
1194 static GdkGC *
1195 gdk_window_create_gc (GdkDrawable     *drawable,
1196                       GdkGCValues     *values,
1197                       GdkGCValuesMask  mask)
1198 {
1199   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
1200   
1201   if (GDK_WINDOW_DESTROYED (drawable))
1202     return NULL;
1203
1204   return gdk_gc_new_with_values (((GdkWindowObject *) drawable)->impl,
1205                                  values, mask);
1206 }
1207
1208 static void
1209 gdk_window_draw_rectangle (GdkDrawable *drawable,
1210                            GdkGC       *gc,
1211                            gint         filled,
1212                            gint         x,
1213                            gint         y,
1214                            gint         width,
1215                            gint         height)
1216 {
1217   GdkWindowObject *private = (GdkWindowObject *)drawable;
1218   OFFSET_GC (gc);
1219
1220   if (GDK_WINDOW_DESTROYED (drawable))
1221     return;
1222   
1223   if (private->paint_stack)
1224     {
1225       GdkWindowPaint *paint = private->paint_stack->data;
1226       gdk_draw_rectangle (paint->pixmap, gc, filled,
1227                           x - x_offset, y - y_offset, width, height);
1228     }
1229   else
1230     gdk_draw_rectangle (private->impl, gc, filled,
1231                         x - x_offset, y - y_offset, width, height);
1232
1233   RESTORE_GC (gc);
1234 }
1235
1236 static void
1237 gdk_window_draw_arc (GdkDrawable *drawable,
1238                      GdkGC       *gc,
1239                      gint         filled,
1240                      gint         x,
1241                      gint         y,
1242                      gint         width,
1243                      gint         height,
1244                      gint         angle1,
1245                      gint         angle2)
1246 {
1247   GdkWindowObject *private = (GdkWindowObject *)drawable;
1248   OFFSET_GC (gc);
1249
1250   if (GDK_WINDOW_DESTROYED (drawable))
1251     return;
1252   
1253   if (private->paint_stack)
1254     {
1255       GdkWindowPaint *paint = private->paint_stack->data;
1256       gdk_draw_arc (paint->pixmap, gc, filled,
1257                     x - x_offset, y - y_offset,
1258                     width, height, angle1, angle2);
1259     }
1260   else
1261     gdk_draw_arc (private->impl, gc, filled,
1262                   x - x_offset, y - y_offset,
1263                   width, height, angle1, angle2);
1264   RESTORE_GC (gc);
1265 }
1266
1267 static void
1268 gdk_window_draw_polygon (GdkDrawable *drawable,
1269                          GdkGC       *gc,
1270                          gint         filled,
1271                          GdkPoint    *points,
1272                          gint         npoints)
1273 {
1274   GdkWindowObject *private = (GdkWindowObject *)drawable;
1275   GdkPoint *new_points;
1276   
1277   OFFSET_GC (gc);
1278
1279   if (GDK_WINDOW_DESTROYED (drawable))
1280     return;
1281   
1282   if (x_offset != 0 || y_offset != 0)
1283     {
1284       int i;
1285       
1286       new_points = g_new (GdkPoint, npoints);
1287       for (i=0; i<npoints; i++)
1288         {
1289           new_points[i].x = points[i].x - x_offset;
1290           new_points[i].y = points[i].y - y_offset;
1291         }
1292     }
1293   else
1294     new_points = points;
1295
1296   if (private->paint_stack)
1297     {
1298       GdkWindowPaint *paint = private->paint_stack->data;
1299       gdk_draw_polygon (paint->pixmap, gc, filled, new_points, npoints);
1300
1301     }
1302   else
1303     gdk_draw_polygon (private->impl, gc, filled, new_points, npoints);
1304   
1305   if (new_points != points)
1306     g_free (new_points);
1307
1308   RESTORE_GC (gc);
1309 }
1310
1311 static void
1312 gdk_window_draw_text (GdkDrawable *drawable,
1313                       GdkFont     *font,
1314                       GdkGC       *gc,
1315                       gint         x,
1316                       gint         y,
1317                       const gchar *text,
1318                       gint         text_length)
1319 {
1320   GdkWindowObject *private = (GdkWindowObject *)drawable;
1321   OFFSET_GC (gc);
1322
1323   if (GDK_WINDOW_DESTROYED (drawable))
1324     return;
1325   
1326   if (private->paint_stack)
1327     {
1328       GdkWindowPaint *paint = private->paint_stack->data;
1329       gdk_draw_text (paint->pixmap, font, gc, 
1330                      x - x_offset, y - y_offset, text, text_length);
1331
1332     }
1333   else
1334     gdk_draw_text (private->impl, font, gc,
1335                    x - x_offset, y - y_offset, text, text_length);
1336
1337   RESTORE_GC (gc);
1338 }
1339
1340 static void
1341 gdk_window_draw_text_wc (GdkDrawable    *drawable,
1342                          GdkFont        *font,
1343                          GdkGC          *gc,
1344                          gint            x,
1345                          gint            y,
1346                          const GdkWChar *text,
1347                          gint            text_length)
1348 {
1349   GdkWindowObject *private = (GdkWindowObject *)drawable;
1350   OFFSET_GC (gc);
1351
1352   if (GDK_WINDOW_DESTROYED (drawable))
1353     return;
1354   
1355   if (private->paint_stack)
1356     {
1357       GdkWindowPaint *paint = private->paint_stack->data;
1358       gdk_draw_text_wc (paint->pixmap, font, gc, 
1359                         x - x_offset, y - y_offset, text, text_length);
1360     }
1361   else
1362     gdk_draw_text_wc (private->impl, font, gc,
1363                       x - x_offset, y - y_offset, text, text_length);
1364   
1365   RESTORE_GC (gc);
1366 }
1367
1368 static GdkDrawable*
1369 gdk_window_get_composite_drawable (GdkDrawable *window,
1370                                    gint         x,
1371                                    gint         y,
1372                                    gint         width,
1373                                    gint         height,
1374                                    gint        *composite_x_offset,
1375                                    gint        *composite_y_offset)
1376 {
1377   GdkWindowObject *private = (GdkWindowObject *)window;
1378   GdkWindowPaint *paint;
1379   GdkRegion *buffered_region;
1380   GSList *tmp_list;
1381   GdkPixmap *buffer;
1382   GdkPixmap *tmp_pixmap;
1383   GdkRectangle rect;
1384   GdkRegion *rect_region;
1385   GdkGC *tmp_gc;
1386   gint windowing_x_offset, windowing_y_offset;
1387   gint buffer_x_offset, buffer_y_offset;
1388
1389   if (GDK_WINDOW_DESTROYED (window) || private->paint_stack == NULL)
1390     {
1391       /* No backing store */
1392       _gdk_windowing_window_get_offsets (window,
1393                                          composite_x_offset,
1394                                          composite_y_offset);
1395       
1396       return GDK_DRAWABLE (g_object_ref (G_OBJECT (window)));
1397     }
1398   
1399   buffered_region = NULL;
1400   buffer = NULL;
1401
1402   /* All GtkWindowPaint structs have the same pixmap and offsets, just
1403    * get the first one. (should probably be cleaned up so that the
1404    * pixmap is stored in the window)
1405    */
1406   paint = private->paint_stack->data;
1407   buffer = paint->pixmap;
1408   buffer_x_offset = paint->x_offset;
1409   buffer_y_offset = paint->y_offset;
1410   
1411   tmp_list = private->paint_stack;
1412   while (tmp_list != NULL)
1413     {
1414       paint = tmp_list->data;
1415       
1416       if (buffered_region == NULL)
1417         buffered_region = gdk_region_copy (paint->region);
1418       else
1419         gdk_region_union (buffered_region, paint->region);
1420
1421       tmp_list = g_slist_next (tmp_list);
1422     }
1423
1424   /* See if the buffered part is overlapping the part we want
1425    * to get
1426    */
1427   rect.x = x;
1428   rect.y = y;
1429   rect.width = width;
1430   rect.height = height;
1431
1432   rect_region = gdk_region_rectangle (&rect);
1433   
1434   gdk_region_intersect (buffered_region, rect_region);
1435
1436   gdk_region_destroy (rect_region);
1437
1438   if (gdk_region_empty (buffered_region))
1439     {
1440       gdk_region_destroy (buffered_region);
1441
1442       _gdk_windowing_window_get_offsets (window,
1443                                          composite_x_offset,
1444                                          composite_y_offset);
1445
1446       return GDK_DRAWABLE (g_object_ref (G_OBJECT (window)));
1447     }
1448   
1449   tmp_pixmap = gdk_pixmap_new (window,
1450                                width, height,
1451                                -1);
1452
1453   tmp_gc = gdk_gc_new (tmp_pixmap);
1454
1455   _gdk_windowing_window_get_offsets (window,
1456                                      &windowing_x_offset,
1457                                      &windowing_y_offset);
1458   
1459   /* Copy the current window contents */
1460   gdk_draw_drawable (tmp_pixmap,
1461                      tmp_gc,
1462                      private->impl,
1463                      x - windowing_x_offset,
1464                      y - windowing_y_offset,
1465                      0, 0,
1466                      width, height);
1467
1468   /* Make buffered_region relative to the tmp_pixmap */
1469   gdk_region_offset (buffered_region,
1470                      - x,
1471                      - y);
1472   
1473   /* Set the clip mask to avoid drawing over non-buffered areas of
1474    * tmp_pixmap. 
1475    */
1476   
1477   gdk_gc_set_clip_region (tmp_gc, buffered_region);
1478   gdk_region_destroy (buffered_region);
1479   
1480   /* Draw backing pixmap onto the tmp_pixmap, offsetting
1481    * appropriately.
1482    */
1483   gdk_draw_drawable (tmp_pixmap,
1484                      tmp_gc,
1485                      buffer,
1486                      x - buffer_x_offset,
1487                      y - buffer_y_offset,
1488                      0, 0,
1489                      width, height);
1490   
1491   /* Set these to location of tmp_pixmap within the window */
1492   *composite_x_offset = x;
1493   *composite_y_offset = y;
1494
1495   g_object_unref (G_OBJECT (tmp_gc));
1496   
1497   return tmp_pixmap;
1498 }
1499
1500 static GdkRegion*
1501 gdk_window_get_clip_region (GdkDrawable *drawable)
1502 {
1503   GdkWindowObject *private = (GdkWindowObject *)drawable;
1504   GdkRegion *result;
1505
1506   result = gdk_drawable_get_clip_region (private->impl);
1507
1508   if (private->paint_stack)
1509     {
1510       GdkRegion *paint_region = gdk_region_new ();
1511       GSList *tmp_list = private->paint_stack;
1512
1513       while (tmp_list)
1514         {
1515           GdkWindowPaint *paint = tmp_list->data;
1516           
1517           gdk_region_union (paint_region, paint->region);
1518
1519           tmp_list = tmp_list->next;
1520         }
1521
1522       gdk_region_intersect (result, paint_region);
1523       gdk_region_destroy (paint_region);
1524     }
1525
1526   return result;
1527 }
1528
1529 static GdkRegion*
1530 gdk_window_get_visible_region (GdkDrawable *drawable)
1531 {
1532   GdkWindowObject *private = (GdkWindowObject*) drawable;
1533   
1534   return gdk_drawable_get_visible_region (private->impl);
1535 }
1536
1537 static void
1538 gdk_window_draw_drawable (GdkDrawable *drawable,
1539                           GdkGC       *gc,
1540                           GdkPixmap   *src,
1541                           gint         xsrc,
1542                           gint         ysrc,
1543                           gint         xdest,
1544                           gint         ydest,
1545                           gint         width,
1546                           gint         height)
1547 {
1548   GdkWindowObject *private = (GdkWindowObject *)drawable;
1549   OFFSET_GC (gc);
1550   
1551   if (GDK_WINDOW_DESTROYED (drawable))
1552     return;
1553
1554   /* If we have a backing pixmap draw to that */
1555   if (private->paint_stack)
1556     {
1557       GdkWindowPaint *paint = private->paint_stack->data;
1558       gdk_draw_drawable (paint->pixmap, gc,
1559                          src, xsrc, ysrc,
1560                          xdest - x_offset, ydest - y_offset, width, height);
1561
1562     }
1563   else
1564     gdk_draw_drawable (private->impl, gc,
1565                        src, xsrc, ysrc,
1566                        xdest - x_offset, ydest - y_offset,
1567                        width, height);
1568
1569   RESTORE_GC (gc);
1570 }
1571
1572 static void
1573 gdk_window_draw_points (GdkDrawable *drawable,
1574                         GdkGC       *gc,
1575                         GdkPoint    *points,
1576                         gint         npoints)
1577 {
1578   GdkWindowObject *private = (GdkWindowObject *)drawable;
1579   GdkPoint *new_points;
1580   
1581   OFFSET_GC (gc);
1582
1583   if (GDK_WINDOW_DESTROYED (drawable))
1584     return;
1585   
1586   if (x_offset != 0 || y_offset != 0)
1587     {
1588       gint i;
1589
1590       new_points = g_new (GdkPoint, npoints);
1591       for (i=0; i<npoints; i++)
1592         {
1593           new_points[i].x = points[i].x - x_offset;
1594           new_points[i].y = points[i].y - y_offset;
1595         }
1596     }
1597   else
1598     new_points = points;
1599
1600   if (private->paint_stack)
1601     {
1602       GdkWindowPaint *paint = private->paint_stack->data;
1603       gdk_draw_points (paint->pixmap, gc, new_points, npoints);
1604     }
1605   else
1606     gdk_draw_points (private->impl, gc, points, npoints);
1607
1608   if (new_points != points)
1609     g_free (new_points);
1610
1611   RESTORE_GC (gc);
1612 }
1613
1614 static void
1615 gdk_window_draw_segments (GdkDrawable *drawable,
1616                           GdkGC       *gc,
1617                           GdkSegment  *segs,
1618                           gint         nsegs)
1619 {
1620   GdkWindowObject *private = (GdkWindowObject *)drawable;
1621   GdkSegment *new_segs;
1622
1623   OFFSET_GC (gc);
1624
1625   if (GDK_WINDOW_DESTROYED (drawable))
1626     return;
1627   
1628   if (x_offset != 0 || y_offset != 0)
1629     {
1630       gint i;
1631
1632       new_segs = g_new (GdkSegment, nsegs);
1633       for (i=0; i<nsegs; i++)
1634         {
1635           new_segs[i].x1 = segs[i].x1 - x_offset;
1636           new_segs[i].y1 = segs[i].y1 - y_offset;
1637           new_segs[i].x2 = segs[i].x2 - x_offset;
1638           new_segs[i].y2 = segs[i].y2 - y_offset;
1639         }
1640     }
1641   else
1642     new_segs = segs;
1643
1644   if (private->paint_stack)
1645     {
1646       GdkWindowPaint *paint = private->paint_stack->data;
1647       gdk_draw_segments (paint->pixmap, gc, new_segs, nsegs);
1648     }
1649   else
1650     gdk_draw_segments (private->impl, gc, new_segs, nsegs);
1651   
1652   if (new_segs != segs)
1653     g_free (new_segs);
1654
1655   RESTORE_GC (gc);
1656 }
1657
1658 static void
1659 gdk_window_draw_lines (GdkDrawable *drawable,
1660                        GdkGC       *gc,
1661                        GdkPoint    *points,
1662                        gint         npoints)
1663 {
1664   GdkWindowObject *private = (GdkWindowObject *)drawable;
1665   GdkPoint *new_points;
1666
1667   OFFSET_GC (gc);
1668
1669   if (GDK_WINDOW_DESTROYED (drawable))
1670     return;
1671   
1672   if (x_offset != 0 || y_offset != 0)
1673     {
1674       gint i;
1675
1676       new_points = g_new (GdkPoint, npoints);
1677       for (i=0; i<npoints; i++)
1678         {
1679           new_points[i].x = points[i].x - x_offset;
1680           new_points[i].y = points[i].y - y_offset;
1681         }
1682     }
1683   else
1684     new_points = points;
1685
1686   if (private->paint_stack)
1687     {
1688       GdkWindowPaint *paint = private->paint_stack->data;
1689       gdk_draw_lines (paint->pixmap, gc, new_points, npoints);
1690     }
1691   else
1692     gdk_draw_lines (private->impl, gc, new_points, npoints);
1693
1694   if (new_points != points)
1695     g_free (new_points);
1696
1697   RESTORE_GC (gc);
1698 }
1699
1700 static void
1701 gdk_window_draw_glyphs (GdkDrawable      *drawable,
1702                         GdkGC            *gc,
1703                         PangoFont        *font,
1704                         gint              x,
1705                         gint              y,
1706                         PangoGlyphString *glyphs)
1707 {
1708   GdkWindowObject *private = (GdkWindowObject *)drawable;
1709
1710   OFFSET_GC (gc);
1711
1712   if (GDK_WINDOW_DESTROYED (drawable))
1713     return;
1714   
1715   if (private->paint_stack)
1716     {
1717       GdkWindowPaint *paint = private->paint_stack->data;
1718
1719       gdk_draw_glyphs (paint->pixmap, gc, font, x - x_offset, y - y_offset, glyphs);
1720     }
1721   else
1722     gdk_draw_glyphs (private->impl, gc, font,
1723                      x - x_offset, y - y_offset, glyphs);
1724
1725   RESTORE_GC (gc);
1726 }
1727
1728 /* Fixme - this is just like gdk_window_paint_init_bg */
1729 static void
1730 gdk_window_clear_backing_rect (GdkWindow *window,
1731                                gint       x,
1732                                gint       y,
1733                                gint       width,
1734                                gint       height)
1735 {
1736   GdkWindowObject *private = (GdkWindowObject *)window;
1737   GdkWindowPaint *paint = private->paint_stack->data;
1738   GdkGC *tmp_gc;
1739
1740   if (GDK_WINDOW_DESTROYED (window))
1741     return;
1742   
1743   tmp_gc = gdk_window_get_bg_gc (window, paint);
1744   gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE,
1745                       x - paint->x_offset, y - paint->y_offset, width, height);
1746   gdk_gc_unref (tmp_gc);
1747 }
1748
1749 /**
1750  * gdk_window_clear:
1751  * @window: a #GdkWindow
1752  * 
1753  * Clears an entire @window to the background color or background pixmap.
1754  **/
1755 void
1756 gdk_window_clear (GdkWindow *window)
1757 {
1758   gint width, height;
1759   
1760   g_return_if_fail (window != NULL);
1761   g_return_if_fail (GDK_IS_WINDOW (window));
1762
1763   gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
1764   
1765   gdk_window_clear_area (window, 0, 0,
1766                          width, height);
1767 }
1768
1769 /**
1770  * gdk_window_clear_area:
1771  * @window: a #GdkWindow
1772  * @x: x coordinate of rectangle to clear
1773  * @y: y coordinate of rectangle to clear
1774  * @width: width of rectangle to clear
1775  * @height: height of rectangle to clear
1776  *
1777  * Clears an area of @window to the background color or background pixmap.
1778  * 
1779  **/
1780 void
1781 gdk_window_clear_area (GdkWindow *window,
1782                        gint       x,
1783                        gint       y,
1784                        gint       width,
1785                        gint       height)
1786 {
1787   GdkWindowObject *private = (GdkWindowObject *)window;
1788
1789   g_return_if_fail (window != NULL);
1790   g_return_if_fail (GDK_IS_WINDOW (window));
1791   
1792   if (private->paint_stack)
1793     gdk_window_clear_backing_rect (window, x, y, width, height);
1794   else
1795     _gdk_windowing_window_clear_area (window, x, y, width, height);
1796 }
1797
1798 /**
1799  * gdk_window_clear_area_e:
1800  * @window: a #GdkWindow
1801  * @x: x coordinate of rectangle to clear
1802  * @y: y coordinate of rectangle to clear
1803  * @width: width of rectangle to clear
1804  * @height: height of rectangle to clear
1805  *
1806  * Like gdk_window_clear_area(), but also generates an expose event for
1807  * the cleared area.
1808  *
1809  * This function has a stupid name because it dates back to the mists
1810  * time, pre-GDK-1.0.
1811  * 
1812  **/
1813 void
1814 gdk_window_clear_area_e (GdkWindow *window,
1815                          gint       x,
1816                          gint       y,
1817                          gint       width,
1818                          gint       height)
1819 {
1820   GdkWindowObject *private = (GdkWindowObject *)window;
1821
1822   g_return_if_fail (window != NULL);
1823   g_return_if_fail (GDK_IS_WINDOW (window));
1824   
1825   if (private->paint_stack)
1826     gdk_window_clear_backing_rect (window, x, y, width, height);
1827
1828   _gdk_windowing_window_clear_area_e (window, x, y, width, height);
1829 }
1830
1831 static void
1832 gdk_window_draw_image (GdkDrawable *drawable,
1833                        GdkGC       *gc,
1834                        GdkImage    *image,
1835                        gint         xsrc,
1836                        gint         ysrc,
1837                        gint         xdest,
1838                        gint         ydest,
1839                        gint         width,
1840                        gint         height)
1841 {
1842   GdkWindowObject *private = (GdkWindowObject *)drawable;
1843
1844   OFFSET_GC (gc);
1845
1846   if (GDK_WINDOW_DESTROYED (drawable))
1847     return;
1848   
1849   if (private->paint_stack)
1850     {
1851       GdkWindowPaint *paint = private->paint_stack->data;
1852       gdk_draw_image (paint->pixmap, gc, image, xsrc, ysrc,
1853                       xdest - x_offset, ydest - y_offset,
1854                       width, height);
1855
1856     }
1857   else
1858     gdk_draw_image (private->impl, gc, image, xsrc, ysrc,
1859                     xdest - x_offset, ydest - y_offset,
1860                     width, height);
1861
1862   RESTORE_GC (gc);
1863 }
1864
1865
1866 static void
1867 gdk_window_real_get_size (GdkDrawable *drawable,
1868                           gint *width,
1869                           gint *height)
1870 {
1871   g_return_if_fail (GDK_IS_WINDOW (drawable));
1872
1873   gdk_drawable_get_size (GDK_WINDOW_OBJECT (drawable)->impl,
1874                          width, height);
1875 }
1876
1877 static GdkVisual*
1878 gdk_window_real_get_visual (GdkDrawable *drawable)
1879 {
1880   GdkColormap *colormap;
1881
1882   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
1883
1884   colormap = gdk_drawable_get_colormap (drawable);
1885   return colormap ? gdk_colormap_get_visual (colormap) : NULL;
1886 }
1887
1888 static gint
1889 gdk_window_real_get_depth (GdkDrawable *drawable)
1890 {
1891   gint depth;
1892   
1893   g_return_val_if_fail (GDK_IS_WINDOW (drawable), 0);
1894
1895   depth = ((GdkWindowObject *)GDK_WINDOW (drawable))->depth;
1896
1897   if (depth == 0)
1898     {
1899       g_print ("0 depth for type %s\n", g_type_name (G_OBJECT_TYPE (drawable)));
1900       G_BREAKPOINT ();
1901     }
1902
1903   return depth;
1904 }
1905
1906 static void
1907 gdk_window_real_set_colormap (GdkDrawable *drawable,
1908                               GdkColormap *cmap)
1909 {
1910   g_return_if_fail (GDK_IS_WINDOW (drawable));  
1911
1912   if (GDK_WINDOW_DESTROYED (drawable))
1913     return;
1914   
1915   gdk_drawable_set_colormap (((GdkWindowObject*)drawable)->impl, cmap);
1916 }
1917
1918 static GdkColormap*
1919 gdk_window_real_get_colormap (GdkDrawable *drawable)
1920 {
1921   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
1922
1923   if (GDK_WINDOW_DESTROYED (drawable))
1924     return NULL;
1925   
1926   return gdk_drawable_get_colormap (((GdkWindowObject*)drawable)->impl);
1927 }
1928                       
1929 static GdkImage*
1930 gdk_window_get_image (GdkDrawable *drawable,
1931                       gint         x,
1932                       gint         y,
1933                       gint         width,
1934                       gint         height)
1935 {
1936   gint x_offset, y_offset;
1937   
1938   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
1939   
1940   if (GDK_WINDOW_DESTROYED (drawable))
1941     return NULL;
1942
1943   /* If we're here, a composite image was not necessary, so
1944    * we can ignore the paint stack.
1945    */
1946   
1947   _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset);
1948   
1949   return gdk_drawable_get_image (((GdkWindowObject*)drawable)->impl,
1950                                  x - x_offset,
1951                                  y - y_offset,
1952                                  width, height);
1953 }
1954
1955 /* Code for dirty-region queueing
1956  */
1957
1958 static GSList *update_windows = NULL;
1959 static guint update_idle = 0;
1960 static gboolean debug_updates = FALSE;
1961
1962 static void
1963 gdk_window_process_updates_internal (GdkWindow *window)
1964 {
1965   GdkWindowObject *private = (GdkWindowObject *)window;
1966   gboolean save_region = FALSE;
1967
1968   /* If an update got queued during update processing, we can get a
1969    * window in the update queue that has an empty update_area.
1970    * just ignore it.
1971    */
1972   if (private->update_area)
1973     {
1974       GdkRegion *update_area = private->update_area;
1975       private->update_area = NULL;
1976       
1977       if (_gdk_event_func && gdk_window_is_viewable (window))
1978         {
1979           GdkEvent event;
1980           GdkRectangle window_rect;
1981           GdkRegion *expose_region;
1982           GdkRegion *window_region;
1983           gint width, height;
1984
1985           if (debug_updates)
1986             {
1987               /* Make sure we see the red invalid area before redrawing. */
1988               gdk_flush ();
1989               g_usleep (70000);
1990             }
1991           
1992           gdk_drawable_get_size (GDK_DRAWABLE (private), &width, &height);
1993           
1994           window_rect.x = 0;
1995           window_rect.y = 0;
1996           window_rect.width = width;
1997           window_rect.height = height;
1998
1999           save_region = _gdk_windowing_window_queue_antiexpose (window, update_area);
2000       
2001           event.expose.type = GDK_EXPOSE;
2002           event.expose.window = gdk_window_ref (window);
2003           event.expose.count = 0;
2004
2005           if (save_region)
2006             expose_region = gdk_region_copy (update_area);
2007           else
2008             expose_region = update_area;
2009           window_region = gdk_region_rectangle (&window_rect);
2010           gdk_region_intersect (expose_region,
2011                                 window_region);
2012           gdk_region_destroy (window_region);
2013           
2014           event.expose.region = expose_region;
2015           gdk_region_get_clipbox (expose_region, &event.expose.area);
2016           
2017           if (!gdk_region_empty (expose_region))
2018             {
2019               (*_gdk_event_func) (&event, _gdk_event_data);
2020             }
2021
2022           if (expose_region != update_area)
2023             gdk_region_destroy (expose_region);
2024           gdk_window_unref (window);
2025         }
2026       if (!save_region)
2027         gdk_region_destroy (update_area);
2028     }
2029 }
2030
2031 /**
2032  * gdk_window_process_all_updates:
2033  *
2034  * Calls gdk_window_process_updates() for all windows (see #GdkWindow)
2035  * in the application.
2036  * 
2037  **/
2038 void
2039 gdk_window_process_all_updates (void)
2040 {
2041   GSList *old_update_windows = update_windows;
2042   GSList *tmp_list = update_windows;
2043
2044   if (update_idle)
2045     g_source_remove (update_idle);
2046   
2047   update_windows = NULL;
2048   update_idle = 0;
2049
2050   while (tmp_list)
2051     {
2052       gdk_window_process_updates_internal (tmp_list->data);
2053       tmp_list = tmp_list->next;
2054     }
2055
2056   g_slist_free (old_update_windows);
2057
2058   gdk_flush();
2059 }
2060
2061 static gboolean
2062 gdk_window_update_idle (gpointer data)
2063 {
2064   gdk_window_process_all_updates ();
2065   
2066   return FALSE;
2067 }
2068
2069 /**
2070  * gdk_window_process_updates:
2071  * @window: a #GdkWindow
2072  * @update_children: whether to also process updates for child windows
2073  *
2074  * Sends one or more expose events to @window. The areas in each 
2075  * expose event will cover the entire update area for the window (see
2076  * gdk_window_invalidate_region() for details). Normally GDK calls
2077  * gdk_window_process_all_updates() on your behalf, so there's no
2078  * need to call this function unless you want to force expose events
2079  * to be delivered immediately and synchronously (vs. the usual
2080  * case, where GDK delivers them in an idle handler). Occasionally
2081  * this is useful to produce nicer scrolling behavior, for example.
2082  * 
2083  **/
2084 void
2085 gdk_window_process_updates (GdkWindow *window,
2086                             gboolean   update_children)
2087 {
2088   GdkWindowObject *private = (GdkWindowObject *)window;
2089
2090   g_return_if_fail (window != NULL);
2091   g_return_if_fail (GDK_IS_WINDOW (window));
2092   
2093   if (private->update_area)
2094     {      
2095       gdk_window_process_updates_internal (window);
2096       update_windows = g_slist_remove (update_windows, window);
2097     }
2098
2099   if (update_children)
2100     {
2101       GList *tmp_list = private->children;
2102       while (tmp_list)
2103         {
2104           gdk_window_process_updates (tmp_list->data, TRUE);
2105           tmp_list = tmp_list->next;
2106         }
2107     }
2108 }
2109
2110 /**
2111  * gdk_window_invalidate_rect:
2112  * @window: a #GdkWindow
2113  * @rect: rectangle to invalidate
2114  * @invalidate_children: whether to also invalidate child windows
2115  *
2116  * A convenience wrapper around gdk_window_invalidate_region() which
2117  * invalidates a rectangular region. See
2118  * gdk_window_invalidate_region() for details.
2119  * 
2120  **/
2121 void
2122 gdk_window_invalidate_rect   (GdkWindow    *window,
2123                               GdkRectangle *rect,
2124                               gboolean      invalidate_children)
2125 {
2126   GdkRectangle window_rect;
2127   GdkRegion *region;
2128   GdkWindowObject *private = (GdkWindowObject *)window;
2129
2130   g_return_if_fail (window != NULL);
2131   g_return_if_fail (GDK_IS_WINDOW (window));
2132
2133   if (GDK_WINDOW_DESTROYED (window))
2134     return;
2135   
2136   if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
2137     return;
2138
2139   if (!rect)
2140     {
2141       window_rect.x = 0;
2142       window_rect.y = 0;
2143       gdk_drawable_get_size (GDK_DRAWABLE (window),
2144                              &window_rect.width,
2145                              &window_rect.height);
2146       rect = &window_rect;
2147     }
2148
2149   region = gdk_region_rectangle (rect);
2150   gdk_window_invalidate_region (window, region, invalidate_children);
2151   gdk_region_destroy (region);
2152 }
2153
2154 /**
2155  * gdk_window_invalidate_maybe_recurse:
2156  * @window: a #GdkWindow
2157  * @region: a #GdkRegion
2158  * @child_func: function to use to decide if to recurse to a child,
2159  *              %NULL means never recurse.
2160  * @child_func_data: data passed to @child_func
2161  *
2162  * Adds @region to the update area for @window. The update area is the
2163  * region that needs to be redrawn, or "dirty region." The call
2164  * gdk_window_process_updates() sends one or more expose events to the
2165  * window, which together cover the entire update area. An
2166  * application would normally redraw the contents of @window in
2167  * response to those expose events.
2168  *
2169  * GDK will call gdk_window_process_all_updates() on your behalf
2170  * whenever your program returns to the main loop and becomes idle, so
2171  * normally there's no need to do that manually, you just need to
2172  * invalidate regions that you know should be redrawn.
2173  *
2174  * The @child_func parameter controls whether the region of
2175  * each child window that intersects @region will also be invalidated.
2176  * Only children for whic @child_func returns TRUE will have the area
2177  * invalidated.
2178  **/
2179 void
2180 gdk_window_invalidate_maybe_recurse (GdkWindow *window,
2181                                      GdkRegion *region,
2182                                      gboolean (*child_func) (GdkWindow *, gpointer),
2183                                      gpointer   user_data)
2184 {
2185   GdkWindowObject *private = (GdkWindowObject *)window;
2186   GdkRegion *visible_region;
2187
2188   g_return_if_fail (window != NULL);
2189   g_return_if_fail (GDK_IS_WINDOW (window));
2190
2191   if (GDK_WINDOW_DESTROYED (window))
2192     return;
2193   
2194   if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
2195     return;
2196
2197   visible_region = gdk_drawable_get_visible_region (window);
2198   gdk_region_intersect (visible_region, region);
2199
2200   if (!gdk_region_empty (visible_region))
2201     {
2202       if (debug_updates)
2203         {
2204           /* Draw ugly color all over the newly-invalid region */
2205           GdkRectangle ugly_rect;
2206           GdkGC *ugly_gc;
2207           GdkColor ugly_color = { 0, 60000, 10000, 10000 };
2208           
2209           ugly_gc = gdk_gc_new (window);
2210
2211           gdk_gc_set_rgb_fg_color (ugly_gc, &ugly_color);
2212           
2213           gdk_region_get_clipbox (visible_region, &ugly_rect);
2214
2215           gdk_draw_rectangle (window,
2216                               ugly_gc,
2217                               TRUE,
2218                               ugly_rect.x, ugly_rect.y,
2219                               ugly_rect.width, ugly_rect.height);
2220           
2221           g_object_unref (G_OBJECT (ugly_gc));
2222         }
2223       
2224       if (private->update_area)
2225         {
2226           gdk_region_union (private->update_area, visible_region);
2227         }
2228       else
2229         {
2230           update_windows = g_slist_prepend (update_windows, window);
2231           private->update_area = gdk_region_copy (visible_region);
2232           
2233           if (!private->update_freeze_count && !update_idle)
2234             update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
2235                                            gdk_window_update_idle, NULL, NULL);
2236         }
2237       
2238       if (child_func)
2239         {
2240           GList *tmp_list;
2241           
2242           tmp_list = private->children;
2243           while (tmp_list)
2244             {
2245               GdkWindowObject *child = tmp_list->data;
2246               tmp_list = tmp_list->next;
2247
2248               if (!child->input_only && (*child_func) ((GdkWindow *)child, user_data))
2249                 {
2250                   GdkRegion *child_region;
2251                   gint x, y;
2252
2253                   gdk_window_get_position ((GdkWindow *)child, &x, &y);
2254
2255                   /* This copy could be saved with a little more complexity */
2256                   child_region = gdk_region_copy (visible_region);
2257                   gdk_region_offset (child_region, -x, -y);
2258                   
2259                   gdk_window_invalidate_maybe_recurse ((GdkWindow *)child, child_region, child_func, user_data);
2260                   
2261                   gdk_region_destroy (child_region);
2262                 }
2263             }
2264         }
2265     }
2266   
2267   gdk_region_destroy (visible_region);
2268 }
2269
2270 static gboolean
2271 true_predicate (GdkWindow *window,
2272                 gpointer   user_data)
2273 {
2274   return TRUE;
2275 }
2276
2277 /**
2278  * gdk_window_invalidate_region:
2279  * @window: a #GdkWindow
2280  * @region: a #GdkRegion
2281  * @invalidate_children: %TRUE to also invalidate child windows 
2282  *
2283  * Adds @region to the update area for @window. The update area is the
2284  * region that needs to be redrawn, or "dirty region." The call
2285  * gdk_window_process_updates() sends one or more expose events to the
2286  * window, which together cover the entire update area. An
2287  * application would normally redraw the contents of @window in
2288  * response to those expose events.
2289  *
2290  * GDK will call gdk_window_process_all_updates() on your behalf
2291  * whenever your program returns to the main loop and becomes idle, so
2292  * normally there's no need to do that manually, you just need to
2293  * invalidate regions that you know should be redrawn.
2294  *
2295  * The @invalidate_children parameter controls whether the region of
2296  * each child window that intersects @region will also be invalidated.
2297  * If %FALSE, then the update area for child windows will remain
2298  * unaffected. See gdk_window_invalidate_maybe_recurse if you need
2299  * fine grained control over which children are invalidated.
2300  **/
2301 void
2302 gdk_window_invalidate_region (GdkWindow *window,
2303                               GdkRegion *region,
2304                               gboolean   invalidate_children)
2305 {
2306   gdk_window_invalidate_maybe_recurse (window, region,
2307                                        invalidate_children ?
2308                                          true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
2309                                        NULL);
2310 }
2311
2312 /**
2313  * gdk_window_get_update_area:
2314  * @window: a #GdkWindow
2315  * 
2316  * Transfers ownership of the update area from @window to the caller
2317  * of the function. That is, after calling this function, @window will
2318  * no longer have an invalid/dirty region; the update area is removed
2319  * from @window and handed to you. If a window has no update area,
2320  * gdk_window_get_update_area() returns %NULL. You are responsible for
2321  * calling gdk_region_destroy() on the returned region if it's non-%NULL.
2322  * 
2323  * Return value: the update area for @window
2324  **/
2325 GdkRegion *
2326 gdk_window_get_update_area (GdkWindow *window)
2327 {
2328   GdkWindowObject *private = (GdkWindowObject *)window;
2329   GdkRegion *tmp_region;
2330
2331   g_return_val_if_fail (window != NULL, NULL);
2332   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2333
2334   if (private->update_area)
2335     {
2336       tmp_region = private->update_area;
2337       private->update_area = NULL;
2338
2339       update_windows = g_slist_remove (update_windows, window);
2340       
2341       return tmp_region;
2342     }
2343   else
2344     return NULL;
2345 }
2346
2347 /**
2348  * _gdk_window_clear_update_area:
2349  * @window: a #GdkWindow.
2350  * 
2351  * Internal function to clear the update area for a window. This
2352  * is called when the window is hidden or destroyed.
2353  **/
2354 void
2355 _gdk_window_clear_update_area (GdkWindow *window)
2356 {
2357   GdkWindowObject *private = (GdkWindowObject *)window;
2358
2359   g_return_if_fail (window != NULL);
2360   g_return_if_fail (GDK_IS_WINDOW (window));
2361
2362   if (private->update_area)
2363     {
2364       update_windows = g_slist_remove (update_windows, window);
2365       
2366       gdk_region_destroy (private->update_area);
2367       private->update_area = NULL;
2368     }
2369 }
2370
2371 /**
2372  * gdk_window_freeze_updates:
2373  * @window: a #GdkWindow
2374  * 
2375  * Temporarily freezes a window such that it won't receive expose
2376  * events.  The window will begin receiving expose events again when
2377  * gdk_window_thaw_updates() is called. If gdk_window_freeze_updates()
2378  * has been called more than once, gdk_window_thaw_updates() must be called
2379  * an equal number of times to begin processing exposes.
2380  **/
2381 void
2382 gdk_window_freeze_updates (GdkWindow *window)
2383 {
2384   GdkWindowObject *private = (GdkWindowObject *)window;
2385
2386   g_return_if_fail (window != NULL);
2387   g_return_if_fail (GDK_IS_WINDOW (window));
2388
2389   private->update_freeze_count++;
2390 }
2391
2392 /**
2393  * gdk_window_thaw_updates:
2394  * @window: a #GdkWindow
2395  * 
2396  * Thaws a window frozen with gdk_window_freeze_updates().
2397  **/
2398 void
2399 gdk_window_thaw_updates (GdkWindow *window)
2400 {
2401   GdkWindowObject *private = (GdkWindowObject *)window;
2402
2403   g_return_if_fail (window != NULL);
2404   g_return_if_fail (GDK_IS_WINDOW (window));
2405   g_return_if_fail (private->update_freeze_count > 0);
2406
2407   private->update_freeze_count--;
2408   if (!private->update_freeze_count && private->update_area && !update_idle)
2409     update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
2410                                    gdk_window_update_idle, NULL, NULL);
2411 }
2412
2413 /**
2414  * gdk_window_set_debug_updates:
2415  * @setting: %TRUE to turn on update debugging
2416  *
2417  * With update debugging enabled, calls to
2418  * gdk_window_invalidate_region() clear the invalidated region of the
2419  * screen to a noticeable color, and GDK pauses for a short time
2420  * before sending exposes to windows during
2421  * gdk_window_process_updates().  The net effect is that you can see
2422  * the invalid region for each window and watch redraws as they
2423  * occur. This allows you to diagnose inefficiencies in your application.
2424  *
2425  * In essence, because the GDK rendering model prevents all flicker,
2426  * if you are redrawing the same region 400 times you may never
2427  * notice, aside from noticing a speed problem. Enabling update
2428  * debugging causes GTK to flicker slowly and noticeably, so you can
2429  * see exactly what's being redrawn when, in what order.
2430  *
2431  * The --gtk-debug=updates command line option passed to GTK+ programs
2432  * enables this debug option at application startup time. That's
2433  * usually more useful than calling gdk_window_set_debug_updates()
2434  * yourself, though you might want to use this function to enable
2435  * updates sometime after application startup time.
2436  * 
2437  **/
2438 void
2439 gdk_window_set_debug_updates (gboolean setting)
2440 {
2441   debug_updates = setting;
2442 }
2443
2444 /**
2445  * gdk_window_constrain_size:
2446  * @geometry: a #GdkGeometry structure
2447  * @flags: a mask indicating what portions of @geometry are set
2448  * @width: desired width of window
2449  * @height: desired height of the window
2450  * @new_width: location to store resulting width
2451  * @new_height: location to store resulting height
2452  * 
2453  * Constrains a desired width and height according to a 
2454  * set of geometry hints (such as minimum and maximum size).
2455  */
2456 void
2457 gdk_window_constrain_size (GdkGeometry *geometry,
2458                            guint        flags,
2459                            gint         width,
2460                            gint         height,
2461                            gint        *new_width,
2462                            gint        *new_height)
2463 {
2464   /* This routine is partially borrowed from fvwm.
2465    *
2466    * Copyright 1993, Robert Nation
2467    *     You may use this code for any purpose, as long as the original
2468    *     copyright remains in the source code and all documentation
2469    *
2470    * which in turn borrows parts of the algorithm from uwm
2471    */
2472   gint min_width = 0;
2473   gint min_height = 0;
2474   gint base_width = 0;
2475   gint base_height = 0;
2476   gint xinc = 1;
2477   gint yinc = 1;
2478   gint max_width = G_MAXINT;
2479   gint max_height = G_MAXINT;
2480   
2481 #define FLOOR(value, base)      ( ((gint) ((value) / (base))) * (base) )
2482
2483   if ((flags & GDK_HINT_BASE_SIZE) && (flags & GDK_HINT_MIN_SIZE))
2484     {
2485       base_width = geometry->base_width;
2486       base_height = geometry->base_height;
2487       min_width = geometry->min_width;
2488       min_height = geometry->min_height;
2489     }
2490   else if (flags & GDK_HINT_BASE_SIZE)
2491     {
2492       base_width = geometry->base_width;
2493       base_height = geometry->base_height;
2494       min_width = geometry->base_width;
2495       min_height = geometry->base_height;
2496     }
2497   else if (flags & GDK_HINT_MIN_SIZE)
2498     {
2499       base_width = geometry->min_width;
2500       base_height = geometry->min_height;
2501       min_width = geometry->min_width;
2502       min_height = geometry->min_height;
2503     }
2504
2505   if (flags & GDK_HINT_MAX_SIZE)
2506     {
2507       max_width = geometry->max_width ;
2508       max_height = geometry->max_height;
2509     }
2510
2511   if (flags & GDK_HINT_RESIZE_INC)
2512     {
2513       xinc = MAX (xinc, geometry->width_inc);
2514       yinc = MAX (yinc, geometry->height_inc);
2515     }
2516   
2517   /* clamp width and height to min and max values
2518    */
2519   width = CLAMP (width, min_width, max_width);
2520   height = CLAMP (height, min_height, max_height);
2521   
2522   /* shrink to base + N * inc
2523    */
2524   width = base_width + FLOOR (width - base_width, xinc);
2525   height = base_height + FLOOR (height - base_height, yinc);
2526
2527   /* constrain aspect ratio, according to:
2528    *
2529    *                width     
2530    * min_aspect <= -------- <= max_aspect
2531    *                height    
2532    */
2533   
2534   if (flags & GDK_HINT_ASPECT &&
2535       geometry->min_aspect > 0 &&
2536       geometry->max_aspect > 0)
2537     {
2538       gint delta;
2539
2540       if (geometry->min_aspect * height > width)
2541         {
2542           delta = FLOOR (height - width * geometry->min_aspect, yinc);
2543           if (height - delta >= min_height)
2544             height -= delta;
2545           else
2546             { 
2547               delta = FLOOR (height * geometry->min_aspect - width, xinc);
2548               if (width + delta <= max_width) 
2549                 width += delta;
2550             }
2551         }
2552       
2553       if (geometry->max_aspect * height < width)
2554         {
2555           delta = FLOOR (width - height * geometry->max_aspect, xinc);
2556           if (width - delta >= min_width) 
2557             width -= delta;
2558           else
2559             {
2560               delta = FLOOR (width / geometry->max_aspect - height, yinc);
2561               if (height + delta <= max_height)
2562                 height += delta;
2563             }
2564         }
2565     }
2566
2567 #undef FLOOR
2568   
2569   *new_width = width;
2570   *new_height = height;
2571 }
2572
2573 /**
2574  * gdk_set_pointer_hooks:
2575  * @new_hooks: a table of pointers to functions for getting
2576  *   quantities related to the current pointer position,
2577  *   or %NULL to restore the default table.
2578  * 
2579  * This function allows for hooking into the operation
2580  * of getting the current location of the pointer. This
2581  * is only useful for such low-level tools as an
2582  * event recorder. Applications should never have any
2583  * reason to use this facility
2584  * 
2585  * Return value: the previous pointer hook table
2586  **/
2587 GdkPointerHooks *
2588 gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
2589 {
2590   const GdkPointerHooks *result = current_pointer_hooks;
2591
2592   if (new_hooks)
2593     current_pointer_hooks = new_hooks;
2594   else
2595     current_pointer_hooks = &default_pointer_hooks;
2596
2597   return (GdkPointerHooks *)result;
2598 }
2599
2600 /**
2601  * gdk_window_get_pointer:
2602  * @window: a #GdkWindow
2603  * @x: return location for X coordinate of pointer
2604  * @y: return location for Y coordinate of pointer
2605  * @mask: return location for modifier mask
2606  *
2607  * Obtains the current pointer position and modifier state.
2608  * The position is given in coordinates relative to @window.
2609  * 
2610  * Return value: the window containing the pointer (as with gdk_window_at_pointer()), or %NULL
2611  *               if the window containing the pointer isn't known to GDK
2612  **/
2613 GdkWindow*
2614 gdk_window_get_pointer (GdkWindow         *window,
2615                         gint              *x,
2616                         gint              *y,
2617                         GdkModifierType *mask)
2618 {
2619   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
2620   
2621   return current_pointer_hooks->get_pointer (window, x, y, mask); 
2622 }
2623
2624 /**
2625  * gdk_window_at_pointer:
2626  * @win_x: return location for origin of the window under the pointer
2627  * @win_y: return location for origin of the window under the pointer
2628  * 
2629  * Obtains the window underneath the mouse pointer, returning the location
2630  * of that window in @win_x, @win_y. Returns %NULL if the window under
2631  * the mouse pointer is not known to GDK (for example, belongs to
2632  * another application).
2633  * 
2634  * Return value: window under the mouse pointer
2635  **/
2636 GdkWindow*
2637 gdk_window_at_pointer (gint *win_x,
2638                        gint *win_y)
2639 {
2640   return current_pointer_hooks->window_at_pointer (NULL, win_x, win_y);
2641 }
2642
2643 /**
2644  * gdk_get_default_root_window:
2645  * 
2646  * Obtains the root window (parent all other windows are inside)
2647  * for the default display and screen.
2648  * 
2649  * Return value: the default root window
2650  **/
2651 GdkWindow *
2652 gdk_get_default_root_window (void)
2653 {
2654   return _gdk_parent_root;
2655 }
2656