]> Pileus Git - ~andy/gtk/blob - gdk/gdkwindow.c
0a703045fd08b4bd5d861d42eb59fec547a385ad
[~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 static GdkGC *gdk_window_create_gc      (GdkDrawable     *drawable,
46                                          GdkGCValues     *values,
47                                          GdkGCValuesMask  mask);
48 static void   gdk_window_draw_rectangle (GdkDrawable     *drawable,
49                                          GdkGC           *gc,
50                                          gint             filled,
51                                          gint             x,
52                                          gint             y,
53                                          gint             width,
54                                          gint             height);
55 static void   gdk_window_draw_arc       (GdkDrawable     *drawable,
56                                          GdkGC           *gc,
57                                          gint             filled,
58                                          gint             x,
59                                          gint             y,
60                                          gint             width,
61                                          gint             height,
62                                          gint             angle1,
63                                          gint             angle2);
64 static void   gdk_window_draw_polygon   (GdkDrawable     *drawable,
65                                          GdkGC           *gc,
66                                          gint             filled,
67                                          GdkPoint        *points,
68                                          gint             npoints);
69 static void   gdk_window_draw_text      (GdkDrawable     *drawable,
70                                          GdkFont         *font,
71                                          GdkGC           *gc,
72                                          gint             x,
73                                          gint             y,
74                                          const gchar     *text,
75                                          gint             text_length);
76 static void   gdk_window_draw_text_wc   (GdkDrawable     *drawable,
77                                          GdkFont         *font,
78                                          GdkGC           *gc,
79                                          gint             x,
80                                          gint             y,
81                                          const GdkWChar  *text,
82                                          gint             text_length);
83 static void   gdk_window_draw_drawable  (GdkDrawable     *drawable,
84                                          GdkGC           *gc,
85                                          GdkPixmap       *src,
86                                          gint             xsrc,
87                                          gint             ysrc,
88                                          gint             xdest,
89                                          gint             ydest,
90                                          gint             width,
91                                          gint             height);
92 static void   gdk_window_draw_points    (GdkDrawable     *drawable,
93                                          GdkGC           *gc,
94                                          GdkPoint        *points,
95                                          gint             npoints);
96 static void   gdk_window_draw_segments  (GdkDrawable     *drawable,
97                                          GdkGC           *gc,
98                                          GdkSegment      *segs,
99                                          gint             nsegs);
100 static void   gdk_window_draw_lines     (GdkDrawable     *drawable,
101                                          GdkGC           *gc,
102                                          GdkPoint        *points,
103                                          gint             npoints);
104 static void   gdk_window_draw_glyphs    (GdkDrawable      *drawable,
105                                          GdkGC            *gc,
106                                          PangoFont        *font,
107                                          gint              x,
108                                          gint              y,
109                                          PangoGlyphString *glyphs);
110
111 static void   gdk_window_draw_image     (GdkDrawable     *drawable,
112                                          GdkGC           *gc,
113                                          GdkImage        *image,
114                                          gint             xsrc,
115                                          gint             ysrc,
116                                          gint             xdest,
117                                          gint             ydest,
118                                          gint             width,
119                                          gint             height);
120
121 static GdkImage*  gdk_window_get_image  (GdkDrawable     *drawable,
122                                          gint             x,
123                                          gint             y,
124                                          gint             width,
125                                          gint             height);
126
127
128 static void   gdk_window_real_get_size  (GdkDrawable     *drawable,
129                                          gint            *width,
130                                          gint            *height);
131
132 static GdkVisual*   gdk_window_real_get_visual   (GdkDrawable *drawable);
133 static gint         gdk_window_real_get_depth    (GdkDrawable *drawable);
134 static void         gdk_window_real_set_colormap (GdkDrawable *drawable,
135                                              GdkColormap *cmap);
136 static GdkColormap* gdk_window_real_get_colormap (GdkDrawable *drawable);
137
138 static GdkDrawable* gdk_window_get_composite_drawable (GdkDrawable *drawable,
139                                                        gint         x,
140                                                        gint         y,
141                                                        gint         width,
142                                                        gint         height,
143                                                        gint        *composite_x_offset,
144                                                        gint        *composite_y_offset);
145 static GdkRegion*   gdk_window_get_clip_region        (GdkDrawable *drawable);
146 static GdkRegion*   gdk_window_get_visible_region     (GdkDrawable *drawable);
147
148 static void gdk_window_free_paint_stack (GdkWindow *window);
149
150 static void gdk_window_init       (GdkWindowObject      *window);
151 static void gdk_window_class_init (GdkWindowObjectClass *klass);
152 static void gdk_window_finalize   (GObject              *object);
153
154 static gpointer parent_class = NULL;
155
156 GType
157 gdk_window_object_get_type (void)
158 {
159   static GType object_type = 0;
160
161   if (!object_type)
162     {
163       static const GTypeInfo object_info =
164       {
165         sizeof (GdkWindowObjectClass),
166         (GBaseInitFunc) NULL,
167         (GBaseFinalizeFunc) NULL,
168         (GClassInitFunc) gdk_window_class_init,
169         NULL,           /* class_finalize */
170         NULL,           /* class_data */
171         sizeof (GdkWindowObject),
172         0,              /* n_preallocs */
173         (GInstanceInitFunc) gdk_window_init,
174       };
175       
176       object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
177                                             "GdkWindow",
178                                             &object_info, 0);
179     }
180   
181   return object_type;
182 }
183
184 static void
185 gdk_window_init (GdkWindowObject *window)
186 {
187   /* 0-initialization is good for all other fields. */
188
189   window->window_type = GDK_WINDOW_CHILD;
190
191   window->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
192 }
193
194 static void
195 gdk_window_class_init (GdkWindowObjectClass *klass)
196 {
197   GObjectClass *object_class = G_OBJECT_CLASS (klass);
198   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
199   
200   parent_class = g_type_class_peek_parent (klass);
201
202   object_class->finalize = gdk_window_finalize;
203
204   drawable_class->create_gc = gdk_window_create_gc;
205   drawable_class->draw_rectangle = gdk_window_draw_rectangle;
206   drawable_class->draw_arc = gdk_window_draw_arc;
207   drawable_class->draw_polygon = gdk_window_draw_polygon;
208   drawable_class->draw_text = gdk_window_draw_text;
209   drawable_class->draw_text_wc = gdk_window_draw_text_wc;
210   drawable_class->draw_drawable = gdk_window_draw_drawable;
211   drawable_class->draw_points = gdk_window_draw_points;
212   drawable_class->draw_segments = gdk_window_draw_segments;
213   drawable_class->draw_lines = gdk_window_draw_lines;
214   drawable_class->draw_glyphs = gdk_window_draw_glyphs;
215   drawable_class->draw_image = gdk_window_draw_image;
216   drawable_class->get_depth = gdk_window_real_get_depth;
217   drawable_class->get_size = gdk_window_real_get_size;
218   drawable_class->set_colormap = gdk_window_real_set_colormap;
219   drawable_class->get_colormap = gdk_window_real_get_colormap;
220   drawable_class->get_visual = gdk_window_real_get_visual;
221   drawable_class->get_image = gdk_window_get_image;
222   drawable_class->get_clip_region = gdk_window_get_clip_region;
223   drawable_class->get_visible_region = gdk_window_get_visible_region;
224   drawable_class->get_composite_drawable = gdk_window_get_composite_drawable;
225 }
226
227 static void
228 gdk_window_finalize (GObject *object)
229 {
230   GdkWindow *window = GDK_WINDOW (object);
231   GdkWindowObject *obj = (GdkWindowObject *) object;
232   
233   if (!GDK_WINDOW_DESTROYED (window))
234     {
235       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
236         {
237           g_warning ("losing last reference to undestroyed window\n");
238           _gdk_window_destroy (window, FALSE);
239         }
240       else
241         /* We use TRUE here, to keep us from actually calling
242          * XDestroyWindow() on the window
243          */
244         _gdk_window_destroy (window, TRUE);
245     }
246
247   g_object_unref (G_OBJECT (obj->impl));
248   obj->impl = NULL;
249   
250   G_OBJECT_CLASS (parent_class)->finalize (object);
251 }
252
253 /**
254  * _gdk_window_destroy_hierarchy:
255  * @window: a #GdkWindow
256  * @recursing: If TRUE, then this is being called because a parent
257  *            was destroyed. This generally means that the call to the windowing system
258  *            to destroy the window can be omitted, since it will be destroyed as a result
259  *            of the parent being destroyed. Unless @foreign_destroy
260  *            
261  * foreign_destroy: If TRUE, the window or a parent was destroyed by some external 
262  *            agency. The window has already been destroyed and no windowing
263  *            system calls should be made. (This may never happen for some
264  *            windowing systems.)
265  *
266  * Internal function to destroy a window. Like gdk_window_destroy(), but does not
267  * drop the reference count created by gdk_window_new().
268  **/
269 static void
270 _gdk_window_destroy_hierarchy (GdkWindow *window,
271                                gboolean   recursing,
272                                gboolean   foreign_destroy)
273 {
274   GdkWindowObject *private;
275   GdkWindowObject *temp_private;
276   GdkWindow *temp_window;
277   GList *children;
278   GList *tmp;
279   
280   g_return_if_fail (window != NULL);
281   
282   private = (GdkWindowObject*) window;
283   
284   switch (GDK_WINDOW_TYPE (window))
285     {
286     case GDK_WINDOW_TOPLEVEL:
287     case GDK_WINDOW_CHILD:
288     case GDK_WINDOW_DIALOG:
289     case GDK_WINDOW_TEMP:
290     case GDK_WINDOW_FOREIGN:
291       if (!GDK_WINDOW_DESTROYED (window))
292         {
293           private->mapped = FALSE;
294           private->destroyed = TRUE;
295           
296           _gdk_windowing_window_destroy (window, recursing, foreign_destroy);
297
298           if (private->parent)
299             {
300               GdkWindowObject *parent_private = (GdkWindowObject *)private->parent;
301               if (parent_private->children)
302                 parent_private->children = g_list_remove (parent_private->children, window);
303             }
304
305           _gdk_window_clear_update_area (window);
306           gdk_window_free_paint_stack (window);
307           
308           if (private->bg_pixmap &&
309               private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
310               private->bg_pixmap != GDK_NO_BG)
311             {
312               gdk_pixmap_unref (private->bg_pixmap);
313               private->bg_pixmap = NULL;
314             }
315           
316           if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
317             {
318               children = tmp = private->children;
319               private->children = NULL;
320               
321               while (tmp)
322                 {
323                   temp_window = tmp->data;
324                   tmp = tmp->next;
325                   
326                   temp_private = (GdkWindowObject*) temp_window;
327                   if (temp_private)
328                     _gdk_window_destroy_hierarchy (temp_window, TRUE, foreign_destroy);
329                 }
330               
331               g_list_free (children);
332             }
333           
334           if (private->filters)
335             {
336               tmp = private->filters;
337               
338               while (tmp)
339                 {
340                   g_free (tmp->data);
341                   tmp = tmp->next;
342                 }
343               
344               g_list_free (private->filters);
345               private->filters = NULL;
346             }
347
348           gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
349         }
350       break;
351       
352     case GDK_WINDOW_ROOT:
353       g_error ("attempted to destroy root window");
354       break;
355     }
356 }
357
358 /**
359  * _gdk_window_destroy:
360  * @window: a #GdkWindow
361  * foreign_destroy: If TRUE, the window or a parent was destroyed by some external 
362  *            agency. The window has already been destroyed and no windowing
363  *            system calls should be made. (This may never happen for some
364  *            windowing systems.)
365  *
366  * Internal function to destroy a window. Like gdk_window_destroy(), but does not
367  * drop the reference count created by gdk_window_new().
368  **/
369 void
370 _gdk_window_destroy (GdkWindow *window,
371                      gboolean   foreign_destroy)
372 {
373   _gdk_window_destroy_hierarchy (window, FALSE, foreign_destroy);
374 }
375
376 void
377 gdk_window_destroy (GdkWindow *window)
378 {
379   _gdk_window_destroy_hierarchy (window, FALSE, FALSE);
380   gdk_drawable_unref (window);
381 }
382
383 void
384 gdk_window_set_user_data (GdkWindow *window,
385                           gpointer   user_data)
386 {
387   g_return_if_fail (window != NULL);
388   
389   ((GdkWindowObject*)window)->user_data = user_data;
390 }
391
392 void
393 gdk_window_get_user_data (GdkWindow *window,
394                           gpointer  *data)
395 {
396   g_return_if_fail (window != NULL);
397   
398   *data = ((GdkWindowObject*)window)->user_data;
399 }
400
401 GdkWindowType
402 gdk_window_get_window_type (GdkWindow *window)
403 {
404   g_return_val_if_fail (GDK_IS_WINDOW (window), (GdkWindowType) -1);
405   
406   return GDK_WINDOW_TYPE (window);
407 }
408
409 void
410 gdk_window_get_position (GdkWindow *window,
411                          gint      *x,
412                          gint      *y)
413 {
414   GdkWindowObject *obj;
415   
416   g_return_if_fail (GDK_IS_WINDOW (window));
417   
418   obj = (GdkWindowObject*) window;
419   
420   if (x)
421     *x = obj->x;
422   if (y)
423     *y = obj->y;
424 }
425
426 GdkWindow*
427 gdk_window_get_parent (GdkWindow *window)
428 {
429   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
430   
431   return (GdkWindow*) ((GdkWindowObject*) window)->parent;
432 }
433
434 GdkWindow*
435 gdk_window_get_toplevel (GdkWindow *window)
436 {
437   GdkWindowObject *obj;
438   
439   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
440
441   obj = (GdkWindowObject *)window;
442   while (GDK_WINDOW_TYPE (obj) == GDK_WINDOW_CHILD)
443     obj = (GdkWindowObject *)obj->parent;
444   
445   return GDK_WINDOW (obj);
446 }
447
448 GList*
449 gdk_window_get_children (GdkWindow *window)
450 {
451   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
452
453   if (GDK_WINDOW_DESTROYED (window))
454     return NULL;
455
456   return g_list_copy (GDK_WINDOW_OBJECT (window)->children);
457 }
458
459 GList *
460 gdk_window_peek_children (GdkWindow       *window)
461 {
462   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
463
464   if (GDK_WINDOW_DESTROYED (window))
465     return NULL;
466
467   return GDK_WINDOW_OBJECT (window)->children;
468 }
469
470 void          
471 gdk_window_add_filter (GdkWindow     *window,
472                        GdkFilterFunc  function,
473                        gpointer       data)
474 {
475   GdkWindowObject *private;
476   GList *tmp_list;
477   GdkEventFilter *filter;
478   
479   g_return_if_fail (window != NULL);
480   g_return_if_fail (GDK_IS_WINDOW (window));
481
482   private = (GdkWindowObject*) window;
483   if (private && GDK_WINDOW_DESTROYED (window))
484     return;
485   
486   if (private)
487     tmp_list = private->filters;
488   else
489     tmp_list = gdk_default_filters;
490   
491   while (tmp_list)
492     {
493       filter = (GdkEventFilter *)tmp_list->data;
494       if ((filter->function == function) && (filter->data == data))
495         return;
496       tmp_list = tmp_list->next;
497     }
498   
499   filter = g_new (GdkEventFilter, 1);
500   filter->function = function;
501   filter->data = data;
502   
503   if (private)
504     private->filters = g_list_append (private->filters, filter);
505   else
506     gdk_default_filters = g_list_append (gdk_default_filters, filter);
507 }
508
509 void
510 gdk_window_remove_filter (GdkWindow     *window,
511                           GdkFilterFunc  function,
512                           gpointer       data)
513 {
514   GdkWindowObject *private;
515   GList *tmp_list, *node;
516   GdkEventFilter *filter;
517   
518   g_return_if_fail (window != NULL);
519   g_return_if_fail (GDK_IS_WINDOW (window));
520
521   private = (GdkWindowObject*) window;
522   
523   if (private)
524     tmp_list = private->filters;
525   else
526     tmp_list = gdk_default_filters;
527   
528   while (tmp_list)
529     {
530       filter = (GdkEventFilter *)tmp_list->data;
531       node = tmp_list;
532       tmp_list = tmp_list->next;
533       
534       if ((filter->function == function) && (filter->data == data))
535         {
536           if (private)
537             private->filters = g_list_remove_link (private->filters, node);
538           else
539             gdk_default_filters = g_list_remove_link (gdk_default_filters, node);
540           g_list_free_1 (node);
541           g_free (filter);
542           
543           return;
544         }
545     }
546 }
547
548 GList *
549 gdk_window_get_toplevels (void)
550 {
551   GList *new_list = NULL;
552   GList *tmp_list;
553   
554   tmp_list = ((GdkWindowObject *)gdk_parent_root)->children;
555   while (tmp_list)
556     {
557       new_list = g_list_prepend (new_list, tmp_list->data);
558       tmp_list = tmp_list->next;
559     }
560   
561   return new_list;
562 }
563
564 /*************************************************************
565  * gdk_window_is_visible:
566  *     Check if the given window is mapped.
567  *   arguments:
568  *     window: 
569  *   results:
570  *     is the window mapped
571  *************************************************************/
572
573 gboolean 
574 gdk_window_is_visible (GdkWindow *window)
575 {
576   GdkWindowObject *private = (GdkWindowObject *)window;
577   
578   g_return_val_if_fail (window != NULL, FALSE);
579   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
580   
581   return private->mapped;
582 }
583
584 /*************************************************************
585  * gdk_window_is_viewable:
586  *     Check if the window and all ancestors of the window
587  *     are mapped. (This is not necessarily "viewable" in
588  *     the X sense, since we only check as far as we have
589  *     GDK window parents, not to the root window)
590  *   arguments:
591  *     window:
592  *   results:
593  *     is the window viewable
594  *************************************************************/
595
596 gboolean 
597 gdk_window_is_viewable (GdkWindow *window)
598 {
599   GdkWindowObject *private = (GdkWindowObject *)window;
600   
601   g_return_val_if_fail (window != NULL, FALSE);
602   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
603   
604   while (private && 
605          (private != (GdkWindowObject *)gdk_parent_root) &&
606          (GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN))
607     {
608       if (!private->mapped)
609         return FALSE;
610       
611       private = (GdkWindowObject *)private->parent;
612     }
613   
614   return TRUE;
615 }
616
617 void
618 gdk_window_begin_paint_rect (GdkWindow    *window,
619                              GdkRectangle *rectangle)
620 {
621   GdkRegion *region;
622
623   g_return_if_fail (window != NULL);
624   g_return_if_fail (GDK_IS_WINDOW (window));
625
626   region = gdk_region_rectangle (rectangle);
627   gdk_window_begin_paint_region (window, region);
628   gdk_region_destroy (region);
629 }
630
631 static GdkGC *
632 gdk_window_get_bg_gc (GdkWindow *window, GdkWindowPaint *paint)
633 {
634   GdkWindowObject *private = (GdkWindowObject *)window;
635
636   guint gc_mask = 0;
637   GdkGCValues gc_values;
638
639   if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
640     {
641       GdkWindowPaint tmp_paint = *paint;
642       tmp_paint.x_offset += private->x;
643       tmp_paint.y_offset += private->y;
644       
645       return gdk_window_get_bg_gc (GDK_WINDOW (private->parent), &tmp_paint);
646     }
647   else if (private->bg_pixmap && private->bg_pixmap != GDK_PARENT_RELATIVE_BG && private->bg_pixmap != GDK_NO_BG)
648     {
649       gc_values.fill = GDK_TILED;
650       gc_values.tile = private->bg_pixmap;
651       gc_values.ts_x_origin = - paint->x_offset;
652       gc_values.ts_y_origin = - paint->y_offset;
653       
654       gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN;
655     }
656   else
657     {
658       gc_values.foreground = private->bg_color;
659       gc_mask = GDK_GC_FOREGROUND;
660     }
661
662   return gdk_gc_new_with_values (paint->pixmap, &gc_values, gc_mask);
663 }
664
665 static void
666 gdk_window_paint_init_bg (GdkWindow      *window,
667                           GdkWindowPaint *paint,
668                           GdkRegion      *init_region)
669 {
670   GdkGC *tmp_gc;
671   
672   tmp_gc = gdk_window_get_bg_gc (window, paint);
673
674   gdk_region_offset (init_region,
675                      - paint->x_offset,
676                      - paint->y_offset);
677   gdk_gc_set_clip_region (tmp_gc, init_region);
678
679   gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE, 0, 0, -1, -1);
680   gdk_gc_unref (tmp_gc);
681 }
682
683 #ifdef GDK_WINDOWING_X11
684 #include "x11/gdkx.h"
685 #endif
686
687 void          
688 gdk_window_begin_paint_region (GdkWindow *window,
689                                GdkRegion *region)
690 {
691 #ifdef USE_BACKING_STORE
692   GdkWindowObject *private = (GdkWindowObject *)window;
693   GdkRectangle clip_box;
694   GdkWindowPaint *paint;
695   GdkRegion *init_region;
696   GdkGC *tmp_gc;
697   
698   g_return_if_fail (window != NULL);
699   g_return_if_fail (GDK_IS_WINDOW (window));
700
701   if (GDK_WINDOW_DESTROYED (window))
702     return;
703   
704   paint = g_new (GdkWindowPaint, 1);
705
706   paint->region = gdk_region_copy (region);
707
708   init_region = gdk_region_copy (region);
709   gdk_region_get_clipbox (paint->region, &clip_box);
710
711   if (private->paint_stack)
712     {
713       gint old_width, old_height;
714       GdkWindowPaint *tmp_paint = private->paint_stack->data;
715       GdkRectangle old_rect, new_rect;
716       GSList *tmp_list;
717
718       gdk_drawable_get_size (tmp_paint->pixmap, &old_width, &old_height);
719       old_rect.x = tmp_paint->x_offset;
720       old_rect.y = tmp_paint->y_offset;
721       old_rect.width = old_width;
722       old_rect.height = old_height;
723
724       gdk_rectangle_union (&clip_box, &old_rect, &new_rect);
725
726       if (new_rect.width > old_rect.width || new_rect.height > old_rect.height)
727         {
728           paint->pixmap = gdk_pixmap_new (window,
729                                           new_rect.width, new_rect.height, -1);
730           tmp_gc = gdk_gc_new (paint->pixmap);
731           gdk_draw_drawable (paint->pixmap, tmp_gc, tmp_paint->pixmap,
732                              0, 0,
733                              old_rect.x - new_rect.x, old_rect.y - new_rect.y,
734                              old_rect.width, old_rect.height);
735           gdk_gc_unref (tmp_gc);
736           gdk_drawable_unref (tmp_paint->pixmap);
737
738           paint->x_offset = new_rect.x;
739           paint->y_offset = new_rect.y;
740           
741           tmp_list = private->paint_stack;
742           while (tmp_list)
743             {
744               tmp_paint = tmp_list->data;
745               gdk_region_subtract (init_region, tmp_paint->region);
746
747               tmp_paint->pixmap = paint->pixmap;
748               tmp_paint->x_offset = paint->x_offset;
749               tmp_paint->y_offset = paint->y_offset;
750               
751               tmp_list = tmp_list->next;
752             }
753         }
754       else
755         {
756           paint->x_offset = tmp_paint->x_offset;
757           paint->y_offset = tmp_paint->y_offset;
758           paint->pixmap = tmp_paint->pixmap;
759
760           tmp_list = private->paint_stack;
761           while (tmp_list)
762             {
763               tmp_paint = tmp_list->data;
764               gdk_region_subtract (init_region, tmp_paint->region);
765
766               tmp_list = tmp_list->next;
767             }
768         }
769     }
770   else
771     {
772       paint->x_offset = clip_box.x;
773       paint->y_offset = clip_box.y;
774       paint->pixmap = gdk_pixmap_new (window, clip_box.width, clip_box.height, -1);
775     }
776
777   if (!gdk_region_empty (init_region))
778     gdk_window_paint_init_bg (window, paint, init_region);
779   
780   gdk_region_destroy (init_region);
781   
782   private->paint_stack = g_slist_prepend (private->paint_stack, paint);
783 #endif /* USE_BACKING_STORE */
784 }
785
786 void
787 gdk_window_end_paint (GdkWindow *window)
788 {
789 #ifdef USE_BACKING_STORE
790   GdkWindowObject *private = (GdkWindowObject *)window;
791   GdkWindowPaint *paint;
792   GdkGC *tmp_gc;
793   GdkRectangle clip_box;
794   gint x_offset, y_offset;
795
796   g_return_if_fail (window != NULL);
797   g_return_if_fail (GDK_IS_WINDOW (window));
798
799   if (GDK_WINDOW_DESTROYED (window))
800     return;
801   
802   g_return_if_fail (private->paint_stack != NULL);
803
804   paint = private->paint_stack->data;
805   private->paint_stack = g_slist_delete_link (private->paint_stack, private->paint_stack);
806
807   gdk_region_get_clipbox (paint->region, &clip_box);
808
809   tmp_gc = gdk_gc_new (window);
810
811   _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset);
812
813   gdk_gc_set_clip_region (tmp_gc, paint->region);
814   gdk_gc_set_clip_origin (tmp_gc, -x_offset, -y_offset);
815
816   gdk_draw_drawable (private->impl, tmp_gc, paint->pixmap,
817                      clip_box.x - paint->x_offset,
818                      clip_box.y - paint->y_offset,
819                      clip_box.x - x_offset, clip_box.y - y_offset,
820                      clip_box.width, clip_box.height);
821   gdk_gc_unref (tmp_gc);
822
823   if (private->paint_stack)
824     {
825       GSList *tmp_list = private->paint_stack;
826       while (tmp_list)
827         {
828           GdkWindowPaint *tmp_paint = tmp_list->data;
829           gdk_region_subtract (tmp_paint->region, paint->region);
830           
831           tmp_list = tmp_list->next;
832         }
833     }
834   else
835     gdk_drawable_unref (paint->pixmap);
836
837   gdk_region_destroy (paint->region);
838   g_free (paint);
839 #endif /* USE_BACKING_STORE */
840 }
841
842 static void
843 gdk_window_free_paint_stack (GdkWindow *window)
844 {
845   GdkWindowObject *private = (GdkWindowObject *)window;
846   
847   if (private->paint_stack)
848     {
849       GSList *tmp_list = private->paint_stack;
850
851       while (tmp_list)
852         {
853           GdkWindowPaint *paint = tmp_list->data;
854
855           if (tmp_list == private->paint_stack)
856             gdk_drawable_unref (paint->pixmap);
857                   
858           gdk_region_destroy (paint->region);
859           g_free (paint);
860
861           tmp_list = tmp_list->next;
862         }
863
864       g_slist_free (private->paint_stack);
865       private->paint_stack = NULL;
866     }
867 }
868
869 static void
870 gdk_window_get_offsets (GdkWindow *window,
871                         gint      *x_offset,
872                         gint      *y_offset)
873 {
874   GdkWindowObject *private = (GdkWindowObject *)window;
875   
876   if (private->paint_stack)
877     {
878       GdkWindowPaint *paint = private->paint_stack->data;
879       *x_offset = paint->x_offset;
880       *y_offset = paint->y_offset;
881     }
882   else
883     _gdk_windowing_window_get_offsets (window, x_offset, y_offset);
884 }
885
886 #define OFFSET_GC(gc)                                         \
887     gint x_offset, y_offset;                                  \
888     gint old_clip_x = gc->clip_x_origin;    \
889     gint old_clip_y = gc->clip_y_origin;    \
890     gint old_ts_x = gc->ts_x_origin;        \
891     gint old_ts_y = gc->ts_y_origin;        \
892     gdk_window_get_offsets (drawable, &x_offset, &y_offset);  \
893     if (x_offset != 0 || y_offset != 0)                       \
894       {                                                       \
895         gdk_gc_set_clip_origin (gc, old_clip_x - x_offset,    \
896                                 old_clip_y - y_offset);       \
897         gdk_gc_set_ts_origin (gc, old_ts_x - x_offset,        \
898                               old_ts_y - y_offset);           \
899       }
900
901 #define RESTORE_GC(gc)                                      \
902     if (x_offset != 0 || y_offset != 0)                     \
903      {                                                      \
904        gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \
905        gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y);       \
906      }
907
908 static GdkGC *
909 gdk_window_create_gc (GdkDrawable     *drawable,
910                       GdkGCValues     *values,
911                       GdkGCValuesMask  mask)
912 {
913   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
914   
915   if (GDK_WINDOW_DESTROYED (drawable))
916     return NULL;
917
918   return gdk_gc_new_with_values (((GdkWindowObject *) drawable)->impl,
919                                  values, mask);
920 }
921
922 static void
923 gdk_window_draw_rectangle (GdkDrawable *drawable,
924                            GdkGC       *gc,
925                            gint         filled,
926                            gint         x,
927                            gint         y,
928                            gint         width,
929                            gint         height)
930 {
931   GdkWindowObject *private = (GdkWindowObject *)drawable;
932   OFFSET_GC (gc);
933
934   if (GDK_WINDOW_DESTROYED (drawable))
935     return;
936   
937   if (private->paint_stack)
938     {
939       GdkWindowPaint *paint = private->paint_stack->data;
940       gdk_draw_rectangle (paint->pixmap, gc, filled,
941                           x - x_offset, y - y_offset, width, height);
942     }
943   else
944     gdk_draw_rectangle (private->impl, gc, filled,
945                         x - x_offset, y - y_offset, width, height);
946
947   RESTORE_GC (gc);
948 }
949
950 static void
951 gdk_window_draw_arc (GdkDrawable *drawable,
952                      GdkGC       *gc,
953                      gint         filled,
954                      gint         x,
955                      gint         y,
956                      gint         width,
957                      gint         height,
958                      gint         angle1,
959                      gint         angle2)
960 {
961   GdkWindowObject *private = (GdkWindowObject *)drawable;
962   OFFSET_GC (gc);
963
964   if (GDK_WINDOW_DESTROYED (drawable))
965     return;
966   
967   if (private->paint_stack)
968     {
969       GdkWindowPaint *paint = private->paint_stack->data;
970       gdk_draw_arc (paint->pixmap, gc, filled,
971                     x - x_offset, y - y_offset,
972                     width, height, angle1, angle2);
973     }
974   else
975     gdk_draw_arc (private->impl, gc, filled,
976                   x - x_offset, y - y_offset,
977                   width, height, angle1, angle2);
978   RESTORE_GC (gc);
979 }
980
981 static void
982 gdk_window_draw_polygon (GdkDrawable *drawable,
983                          GdkGC       *gc,
984                          gint         filled,
985                          GdkPoint    *points,
986                          gint         npoints)
987 {
988   GdkWindowObject *private = (GdkWindowObject *)drawable;
989   GdkPoint *new_points;
990   
991   OFFSET_GC (gc);
992
993   if (GDK_WINDOW_DESTROYED (drawable))
994     return;
995   
996   if (x_offset != 0 || y_offset != 0)
997     {
998       int i;
999       
1000       new_points = g_new (GdkPoint, npoints);
1001       for (i=0; i<npoints; i++)
1002         {
1003           new_points[i].x = points[i].x - x_offset;
1004           new_points[i].y = points[i].y - y_offset;
1005         }
1006     }
1007   else
1008     new_points = points;
1009
1010   if (private->paint_stack)
1011     {
1012       GdkWindowPaint *paint = private->paint_stack->data;
1013       gdk_draw_polygon (paint->pixmap, gc, filled, new_points, npoints);
1014
1015     }
1016   else
1017     gdk_draw_polygon (private->impl, gc, filled, new_points, npoints);
1018   
1019   if (new_points != points)
1020     g_free (new_points);
1021
1022   RESTORE_GC (gc);
1023 }
1024
1025 static void
1026 gdk_window_draw_text (GdkDrawable *drawable,
1027                       GdkFont     *font,
1028                       GdkGC       *gc,
1029                       gint         x,
1030                       gint         y,
1031                       const gchar *text,
1032                       gint         text_length)
1033 {
1034   GdkWindowObject *private = (GdkWindowObject *)drawable;
1035   OFFSET_GC (gc);
1036
1037   if (GDK_WINDOW_DESTROYED (drawable))
1038     return;
1039   
1040   if (private->paint_stack)
1041     {
1042       GdkWindowPaint *paint = private->paint_stack->data;
1043       gdk_draw_text (paint->pixmap, font, gc, 
1044                      x - x_offset, y - y_offset, text, text_length);
1045
1046     }
1047   else
1048     gdk_draw_text (private->impl, font, gc,
1049                    x - x_offset, y - y_offset, text, text_length);
1050
1051   RESTORE_GC (gc);
1052 }
1053
1054 static void
1055 gdk_window_draw_text_wc (GdkDrawable    *drawable,
1056                          GdkFont        *font,
1057                          GdkGC          *gc,
1058                          gint            x,
1059                          gint            y,
1060                          const GdkWChar *text,
1061                          gint            text_length)
1062 {
1063   GdkWindowObject *private = (GdkWindowObject *)drawable;
1064   OFFSET_GC (gc);
1065
1066   if (GDK_WINDOW_DESTROYED (drawable))
1067     return;
1068   
1069   if (private->paint_stack)
1070     {
1071       GdkWindowPaint *paint = private->paint_stack->data;
1072       gdk_draw_text_wc (paint->pixmap, font, gc, 
1073                         x - x_offset, y - y_offset, text, text_length);
1074     }
1075   else
1076     gdk_draw_text_wc (private->impl, font, gc,
1077                       x - x_offset, y - y_offset, text, text_length);
1078   
1079   RESTORE_GC (gc);
1080 }
1081
1082 static GdkDrawable*
1083 gdk_window_get_composite_drawable (GdkDrawable *window,
1084                                    gint         x,
1085                                    gint         y,
1086                                    gint         width,
1087                                    gint         height,
1088                                    gint        *composite_x_offset,
1089                                    gint        *composite_y_offset)
1090 {
1091   GdkWindowObject *private = (GdkWindowObject *)window;
1092   GdkWindowPaint *paint;
1093   GdkRegion *buffered_region;
1094   GSList *tmp_list;
1095   GdkPixmap *buffer;
1096   GdkPixmap *tmp_pixmap;
1097   GdkRectangle rect;
1098   GdkRegion *rect_region;
1099   GdkGC *tmp_gc;
1100   gint windowing_x_offset, windowing_y_offset;
1101   gint buffer_x_offset, buffer_y_offset;
1102
1103   if (GDK_WINDOW_DESTROYED (window) || private->paint_stack == NULL)
1104     {
1105       /* No backing store */
1106       _gdk_windowing_window_get_offsets (window,
1107                                          composite_x_offset,
1108                                          composite_y_offset);
1109       
1110       return GDK_DRAWABLE (g_object_ref (G_OBJECT (window)));
1111     }
1112   
1113   buffered_region = NULL;
1114   buffer = NULL;
1115
1116   /* All GtkWindowPaint structs have the same pixmap and offsets, just
1117    * get the first one. (should probably be cleaned up so that the
1118    * pixmap is stored in the window)
1119    */
1120   paint = private->paint_stack->data;
1121   buffer = paint->pixmap;
1122   buffer_x_offset = paint->x_offset;
1123   buffer_y_offset = paint->y_offset;
1124   
1125   tmp_list = private->paint_stack;
1126   while (tmp_list != NULL)
1127     {
1128       paint = tmp_list->data;
1129       
1130       if (buffered_region == NULL)
1131         buffered_region = gdk_region_copy (paint->region);
1132       else
1133         gdk_region_union (buffered_region, paint->region);
1134
1135       tmp_list = g_slist_next (tmp_list);
1136     }
1137
1138   /* See if the buffered part is overlapping the part we want
1139    * to get
1140    */
1141   rect.x = x;
1142   rect.y = y;
1143   rect.width = width;
1144   rect.height = height;
1145
1146   rect_region = gdk_region_rectangle (&rect);
1147   
1148   gdk_region_intersect (buffered_region, rect_region);
1149
1150   gdk_region_destroy (rect_region);
1151
1152   if (gdk_region_empty (buffered_region))
1153     {
1154       gdk_region_destroy (buffered_region);
1155
1156       _gdk_windowing_window_get_offsets (window,
1157                                          composite_x_offset,
1158                                          composite_y_offset);
1159
1160       return GDK_DRAWABLE (g_object_ref (G_OBJECT (window)));
1161     }
1162   
1163   tmp_pixmap = gdk_pixmap_new (window,
1164                                width, height,
1165                                -1);
1166
1167   tmp_gc = gdk_gc_new (tmp_pixmap);
1168
1169   _gdk_windowing_window_get_offsets (window,
1170                                      &windowing_x_offset,
1171                                      &windowing_y_offset);
1172   
1173   /* Copy the current window contents */
1174   gdk_draw_drawable (tmp_pixmap,
1175                      tmp_gc,
1176                      private->impl,
1177                      x - windowing_x_offset,
1178                      y - windowing_y_offset,
1179                      0, 0,
1180                      width, height);
1181
1182   /* Make buffered_region relative to the tmp_pixmap */
1183   gdk_region_offset (buffered_region,
1184                      - x,
1185                      - y);
1186   
1187   /* Set the clip mask to avoid drawing over non-buffered areas of
1188    * tmp_pixmap. 
1189    */
1190   
1191   gdk_gc_set_clip_region (tmp_gc, buffered_region);
1192   gdk_region_destroy (buffered_region);
1193   
1194   /* Draw backing pixmap onto the tmp_pixmap, offsetting
1195    * appropriately.
1196    */
1197   gdk_draw_drawable (tmp_pixmap,
1198                      tmp_gc,
1199                      buffer,
1200                      x - buffer_x_offset,
1201                      y - buffer_y_offset,
1202                      0, 0,
1203                      width, height);
1204   
1205   /* Set these to location of tmp_pixmap within the window */
1206   *composite_x_offset = x;
1207   *composite_y_offset = y;
1208
1209   g_object_unref (G_OBJECT (tmp_gc));
1210   
1211   return tmp_pixmap;
1212 }
1213
1214 static GdkRegion*
1215 gdk_window_get_clip_region (GdkDrawable *drawable)
1216 {
1217   GdkWindowObject *private = (GdkWindowObject *)drawable;
1218   GdkRegion *result;
1219
1220   result = gdk_drawable_get_clip_region (private->impl);
1221
1222   if (private->paint_stack)
1223     {
1224       GdkRegion *paint_region = gdk_region_new ();
1225       GSList *tmp_list = private->paint_stack;
1226
1227       while (tmp_list)
1228         {
1229           GdkWindowPaint *paint = tmp_list->data;
1230           
1231           gdk_region_union (paint_region, paint->region);
1232         }
1233
1234       gdk_region_intersect (result, paint_region);
1235       gdk_region_destroy (paint_region);
1236     }
1237
1238   return result;
1239 }
1240
1241 static GdkRegion*
1242 gdk_window_get_visible_region (GdkDrawable *drawable)
1243 {
1244   GdkWindowObject *private = (GdkWindowObject*) drawable;
1245   
1246   return gdk_drawable_get_visible_region (private->impl);
1247 }
1248
1249 static void
1250 gdk_window_draw_drawable (GdkDrawable *drawable,
1251                           GdkGC       *gc,
1252                           GdkPixmap   *src,
1253                           gint         xsrc,
1254                           gint         ysrc,
1255                           gint         xdest,
1256                           gint         ydest,
1257                           gint         width,
1258                           gint         height)
1259 {
1260   GdkWindowObject *private = (GdkWindowObject *)drawable;
1261   OFFSET_GC (gc);
1262   
1263   if (GDK_WINDOW_DESTROYED (drawable))
1264     return;
1265
1266   /* If we have a backing pixmap draw to that */
1267   if (private->paint_stack)
1268     {
1269       GdkWindowPaint *paint = private->paint_stack->data;
1270       gdk_draw_drawable (paint->pixmap, gc,
1271                          src, xsrc, ysrc,
1272                          xdest - x_offset, ydest - y_offset, width, height);
1273
1274     }
1275   else
1276     gdk_draw_drawable (private->impl, gc,
1277                        src, xsrc, ysrc,
1278                        xdest - x_offset, ydest - y_offset,
1279                        width, height);
1280
1281   RESTORE_GC (gc);
1282 }
1283
1284 static void
1285 gdk_window_draw_points (GdkDrawable *drawable,
1286                         GdkGC       *gc,
1287                         GdkPoint    *points,
1288                         gint         npoints)
1289 {
1290   GdkWindowObject *private = (GdkWindowObject *)drawable;
1291   GdkPoint *new_points;
1292   
1293   OFFSET_GC (gc);
1294
1295   if (GDK_WINDOW_DESTROYED (drawable))
1296     return;
1297   
1298   if (x_offset != 0 || y_offset != 0)
1299     {
1300       gint i;
1301
1302       new_points = g_new (GdkPoint, npoints);
1303       for (i=0; i<npoints; i++)
1304         {
1305           new_points[i].x = points[i].x - x_offset;
1306           new_points[i].y = points[i].y - y_offset;
1307         }
1308     }
1309   else
1310     new_points = points;
1311
1312   if (private->paint_stack)
1313     {
1314       GdkWindowPaint *paint = private->paint_stack->data;
1315       gdk_draw_points (paint->pixmap, gc, new_points, npoints);
1316     }
1317   else
1318     gdk_draw_points (private->impl, gc, points, npoints);
1319
1320   if (new_points != points)
1321     g_free (new_points);
1322
1323   RESTORE_GC (gc);
1324 }
1325
1326 static void
1327 gdk_window_draw_segments (GdkDrawable *drawable,
1328                           GdkGC       *gc,
1329                           GdkSegment  *segs,
1330                           gint         nsegs)
1331 {
1332   GdkWindowObject *private = (GdkWindowObject *)drawable;
1333   GdkSegment *new_segs;
1334
1335   OFFSET_GC (gc);
1336
1337   if (GDK_WINDOW_DESTROYED (drawable))
1338     return;
1339   
1340   if (x_offset != 0 || y_offset != 0)
1341     {
1342       gint i;
1343
1344       new_segs = g_new (GdkSegment, nsegs);
1345       for (i=0; i<nsegs; i++)
1346         {
1347           new_segs[i].x1 = segs[i].x1 - x_offset;
1348           new_segs[i].y1 = segs[i].y1 - y_offset;
1349           new_segs[i].x2 = segs[i].x2 - x_offset;
1350           new_segs[i].y2 = segs[i].y2 - y_offset;
1351         }
1352     }
1353   else
1354     new_segs = segs;
1355
1356   if (private->paint_stack)
1357     {
1358       GdkWindowPaint *paint = private->paint_stack->data;
1359       gdk_draw_segments (paint->pixmap, gc, new_segs, nsegs);
1360     }
1361   else
1362     gdk_draw_segments (private->impl, gc, new_segs, nsegs);
1363   
1364   if (new_segs != segs)
1365     g_free (new_segs);
1366
1367   RESTORE_GC (gc);
1368 }
1369
1370 static void
1371 gdk_window_draw_lines (GdkDrawable *drawable,
1372                        GdkGC       *gc,
1373                        GdkPoint    *points,
1374                        gint         npoints)
1375 {
1376   GdkWindowObject *private = (GdkWindowObject *)drawable;
1377   GdkPoint *new_points;
1378
1379   OFFSET_GC (gc);
1380
1381   if (GDK_WINDOW_DESTROYED (drawable))
1382     return;
1383   
1384   if (x_offset != 0 || y_offset != 0)
1385     {
1386       gint i;
1387
1388       new_points = g_new (GdkPoint, npoints);
1389       for (i=0; i<npoints; i++)
1390         {
1391           new_points[i].x = points[i].x - x_offset;
1392           new_points[i].y = points[i].y - y_offset;
1393         }
1394     }
1395   else
1396     new_points = points;
1397
1398   if (private->paint_stack)
1399     {
1400       GdkWindowPaint *paint = private->paint_stack->data;
1401       gdk_draw_lines (paint->pixmap, gc, new_points, npoints);
1402     }
1403   else
1404     gdk_draw_lines (private->impl, gc, new_points, npoints);
1405
1406   if (new_points != points)
1407     g_free (new_points);
1408
1409   RESTORE_GC (gc);
1410 }
1411
1412 static void
1413 gdk_window_draw_glyphs (GdkDrawable      *drawable,
1414                         GdkGC            *gc,
1415                         PangoFont        *font,
1416                         gint              x,
1417                         gint              y,
1418                         PangoGlyphString *glyphs)
1419 {
1420   GdkWindowObject *private = (GdkWindowObject *)drawable;
1421
1422   OFFSET_GC (gc);
1423
1424   if (GDK_WINDOW_DESTROYED (drawable))
1425     return;
1426   
1427   if (private->paint_stack)
1428     {
1429       GdkWindowPaint *paint = private->paint_stack->data;
1430
1431       gdk_draw_glyphs (paint->pixmap, gc, font, x - x_offset, y - y_offset, glyphs);
1432     }
1433   else
1434     gdk_draw_glyphs (private->impl, gc, font,
1435                      x - x_offset, y - y_offset, glyphs);
1436
1437   RESTORE_GC (gc);
1438 }
1439
1440 /* Fixme - this is just like gdk_window_paint_init_bg */
1441 static void
1442 gdk_window_clear_backing_rect (GdkWindow *window,
1443                                gint       x,
1444                                gint       y,
1445                                gint       width,
1446                                gint       height)
1447 {
1448   GdkWindowObject *private = (GdkWindowObject *)window;
1449   GdkWindowPaint *paint = private->paint_stack->data;
1450   GdkGC *tmp_gc;
1451
1452   if (GDK_WINDOW_DESTROYED (window))
1453     return;
1454   
1455   tmp_gc = gdk_window_get_bg_gc (window, paint);
1456   gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE,
1457                       x - paint->x_offset, y - paint->y_offset, width, height);
1458   gdk_gc_unref (tmp_gc);
1459 }
1460
1461 void
1462 gdk_window_clear (GdkWindow *window)
1463 {
1464   gint width, height;
1465   
1466   g_return_if_fail (window != NULL);
1467   g_return_if_fail (GDK_IS_WINDOW (window));
1468
1469   gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
1470   
1471   gdk_window_clear_area (window, 0, 0,
1472                          width, height);
1473 }
1474
1475 void
1476 gdk_window_clear_area (GdkWindow *window,
1477                        gint       x,
1478                        gint       y,
1479                        gint       width,
1480                        gint       height)
1481 {
1482   GdkWindowObject *private = (GdkWindowObject *)window;
1483
1484   g_return_if_fail (window != NULL);
1485   g_return_if_fail (GDK_IS_WINDOW (window));
1486   
1487   if (private->paint_stack)
1488     gdk_window_clear_backing_rect (window, x, y, width, height);
1489   else
1490     _gdk_windowing_window_clear_area (window, x, y, width, height);
1491 }
1492
1493 void
1494 gdk_window_clear_area_e (GdkWindow *window,
1495                          gint       x,
1496                          gint       y,
1497                          gint       width,
1498                          gint       height)
1499 {
1500   GdkWindowObject *private = (GdkWindowObject *)window;
1501
1502   g_return_if_fail (window != NULL);
1503   g_return_if_fail (GDK_IS_WINDOW (window));
1504   
1505   if (private->paint_stack)
1506     gdk_window_clear_backing_rect (window, x, y, width, height);
1507
1508   _gdk_windowing_window_clear_area_e (window, x, y, width, height);
1509 }
1510
1511 static void
1512 gdk_window_draw_image (GdkDrawable *drawable,
1513                        GdkGC       *gc,
1514                        GdkImage    *image,
1515                        gint         xsrc,
1516                        gint         ysrc,
1517                        gint         xdest,
1518                        gint         ydest,
1519                        gint         width,
1520                        gint         height)
1521 {
1522   GdkWindowObject *private = (GdkWindowObject *)drawable;
1523
1524   OFFSET_GC (gc);
1525
1526   if (GDK_WINDOW_DESTROYED (drawable))
1527     return;
1528   
1529   if (private->paint_stack)
1530     {
1531       GdkWindowPaint *paint = private->paint_stack->data;
1532       gdk_draw_image (paint->pixmap, gc, image, xsrc, ysrc,
1533                       xdest - x_offset, ydest - y_offset,
1534                       width, height);
1535
1536     }
1537   else
1538     gdk_draw_image (private->impl, gc, image, xsrc, ysrc,
1539                     xdest - x_offset, ydest - y_offset,
1540                     width, height);
1541
1542   RESTORE_GC (gc);
1543 }
1544
1545
1546 static void
1547 gdk_window_real_get_size (GdkDrawable *drawable,
1548                           gint *width,
1549                           gint *height)
1550 {
1551   g_return_if_fail (GDK_IS_WINDOW (drawable));
1552
1553   gdk_drawable_get_size (GDK_WINDOW_OBJECT (drawable)->impl,
1554                          width, height);
1555 }
1556
1557 static GdkVisual*
1558 gdk_window_real_get_visual (GdkDrawable *drawable)
1559 {
1560   GdkColormap *colormap;
1561
1562   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
1563
1564   colormap = gdk_drawable_get_colormap (drawable);
1565   return colormap ? gdk_colormap_get_visual (colormap) : NULL;
1566 }
1567
1568 static gint
1569 gdk_window_real_get_depth (GdkDrawable *drawable)
1570 {
1571   gint depth;
1572   
1573   g_return_val_if_fail (GDK_IS_WINDOW (drawable), 0);
1574
1575   depth = ((GdkWindowObject *)GDK_WINDOW (drawable))->depth;
1576
1577   if (depth == 0)
1578     {
1579       g_print ("0 depth for type %s\n", g_type_name (G_OBJECT_TYPE (drawable)));
1580       G_BREAKPOINT ();
1581     }
1582
1583   return depth;
1584 }
1585
1586 static void
1587 gdk_window_real_set_colormap (GdkDrawable *drawable,
1588                               GdkColormap *cmap)
1589 {
1590   g_return_if_fail (GDK_IS_WINDOW (drawable));  
1591
1592   if (GDK_WINDOW_DESTROYED (drawable))
1593     return;
1594   
1595   gdk_drawable_set_colormap (((GdkWindowObject*)drawable)->impl, cmap);
1596 }
1597
1598 static GdkColormap*
1599 gdk_window_real_get_colormap (GdkDrawable *drawable)
1600 {
1601   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
1602
1603   if (GDK_WINDOW_DESTROYED (drawable))
1604     return NULL;
1605   
1606   return gdk_drawable_get_colormap (((GdkWindowObject*)drawable)->impl);
1607 }
1608                       
1609 static GdkImage*
1610 gdk_window_get_image (GdkDrawable *drawable,
1611                       gint         x,
1612                       gint         y,
1613                       gint         width,
1614                       gint         height)
1615 {
1616   gint x_offset, y_offset;
1617   
1618   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
1619   
1620   if (GDK_WINDOW_DESTROYED (drawable))
1621     return NULL;
1622
1623   /* If we're here, a composite image was not necessary, so
1624    * we can ignore the paint stack.
1625    */
1626   
1627   _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset);
1628   
1629   return gdk_drawable_get_image (((GdkWindowObject*)drawable)->impl,
1630                                  x - x_offset,
1631                                  y - y_offset,
1632                                  width, height);
1633 }
1634
1635 /* Code for dirty-region queueing
1636  */
1637
1638 static GSList *update_windows = NULL;
1639 static guint update_idle = 0;
1640
1641 static void
1642 gdk_window_process_updates_internal (GdkWindow *window)
1643 {
1644   GdkWindowObject *private = (GdkWindowObject *)window;
1645   gboolean save_region = FALSE;
1646
1647   /* If an update got queued during update processing, we can get a
1648    * window in the update queue that has an empty update_area.
1649    * just ignore it.
1650    */
1651   if (private->update_area)
1652     {
1653       GdkRegion *update_area = private->update_area;
1654       private->update_area = NULL;
1655       
1656       if (gdk_event_func && gdk_window_is_viewable (window))
1657         {
1658           GdkEvent event;
1659           GdkRectangle window_rect;
1660           gint width, height;
1661
1662           gdk_drawable_get_size (GDK_DRAWABLE (private), &width, &height);
1663           
1664           window_rect.x = 0;
1665           window_rect.y = 0;
1666           window_rect.width = width;
1667           window_rect.height = height;
1668
1669           save_region = _gdk_windowing_window_queue_antiexpose (window, update_area);
1670       
1671           event.expose.type = GDK_EXPOSE;
1672           event.expose.window = gdk_window_ref (window);
1673           event.expose.count = 0;
1674       
1675           gdk_region_get_clipbox (update_area, &event.expose.area);
1676           if (gdk_rectangle_intersect (&event.expose.area, &window_rect, &event.expose.area))
1677             {
1678               (*gdk_event_func) (&event, gdk_event_data);
1679             }
1680
1681           gdk_window_unref (window);
1682         }
1683       
1684       if (!save_region)
1685         gdk_region_destroy (update_area);
1686     }
1687 }
1688
1689 void
1690 gdk_window_process_all_updates (void)
1691 {
1692   GSList *old_update_windows = update_windows;
1693   GSList *tmp_list = update_windows;
1694
1695   if (update_idle)
1696     g_source_remove (update_idle);
1697   
1698   update_windows = NULL;
1699   update_idle = 0;
1700
1701   while (tmp_list)
1702     {
1703       gdk_window_process_updates_internal (tmp_list->data);
1704       tmp_list = tmp_list->next;
1705     }
1706
1707   g_slist_free (old_update_windows);
1708
1709   gdk_flush();
1710 }
1711
1712 static gboolean
1713 gdk_window_update_idle (gpointer data)
1714 {
1715   gdk_window_process_all_updates ();
1716   
1717   return FALSE;
1718 }
1719
1720 void
1721 gdk_window_process_updates (GdkWindow *window,
1722                             gboolean   update_children)
1723 {
1724   GdkWindowObject *private = (GdkWindowObject *)window;
1725
1726   g_return_if_fail (window != NULL);
1727   g_return_if_fail (GDK_IS_WINDOW (window));
1728
1729   if (private->update_area)
1730     {
1731       gdk_window_process_updates_internal (window);
1732       update_windows = g_slist_remove (update_windows, window);
1733     }
1734
1735   if (update_children)
1736     {
1737       GList *tmp_list = private->children;
1738       while (tmp_list)
1739         {
1740           gdk_window_process_updates (tmp_list->data, TRUE);
1741           tmp_list = tmp_list->next;
1742         }
1743     }
1744 }
1745
1746 void
1747 gdk_window_invalidate_rect   (GdkWindow    *window,
1748                               GdkRectangle *rect,
1749                               gboolean      invalidate_children)
1750 {
1751   GdkRectangle window_rect;
1752   GdkRegion *region;
1753   GdkWindowObject *private = (GdkWindowObject *)window;
1754
1755   g_return_if_fail (window != NULL);
1756   g_return_if_fail (GDK_IS_WINDOW (window));
1757
1758   if (GDK_WINDOW_DESTROYED (window))
1759     return;
1760   
1761   if (private->input_only || !private->mapped)
1762     return;
1763
1764   if (!rect)
1765     {
1766       window_rect.x = 0;
1767       window_rect.y = 0;
1768       gdk_drawable_get_size (GDK_DRAWABLE (window),
1769                              &window_rect.width,
1770                              &window_rect.height);
1771       rect = &window_rect;
1772     }
1773
1774   region = gdk_region_rectangle (rect);
1775   gdk_window_invalidate_region (window, region, invalidate_children);
1776   gdk_region_destroy (region);
1777 }
1778
1779 void
1780 gdk_window_invalidate_region (GdkWindow *window,
1781                               GdkRegion *region,
1782                               gboolean   invalidate_children)
1783 {
1784   GdkWindowObject *private = (GdkWindowObject *)window;
1785   GdkRegion *visible_region;
1786
1787   g_return_if_fail (window != NULL);
1788   g_return_if_fail (GDK_IS_WINDOW (window));
1789
1790   if (GDK_WINDOW_DESTROYED (window))
1791     return;
1792   
1793   if (private->input_only || !private->mapped)
1794     return;
1795
1796   visible_region = gdk_drawable_get_visible_region (window);
1797   gdk_region_intersect (visible_region, region);
1798
1799   if (!gdk_region_empty (visible_region))
1800     {
1801       if (private->update_area)
1802         {
1803           gdk_region_union (private->update_area, visible_region);
1804         }
1805       else
1806         {
1807           update_windows = g_slist_prepend (update_windows, window);
1808           private->update_area = gdk_region_copy (visible_region);
1809           
1810           if (!private->update_freeze_count && !update_idle)
1811             update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
1812                                            gdk_window_update_idle, NULL, NULL);
1813         }
1814       
1815       if (invalidate_children)
1816         {
1817           GList *tmp_list;
1818           
1819           tmp_list = private->children;
1820           while (tmp_list)
1821             {
1822               GdkWindowObject *child = tmp_list->data;
1823               tmp_list = tmp_list->next;
1824               
1825               if (!child->input_only)
1826                 {
1827                   GdkRegion *child_region;
1828                   gint x, y;
1829
1830                   gdk_window_get_position ((GdkWindow *)child, &x, &y);
1831
1832                   /* This copy could be saved with a little more complexity */
1833                   child_region = gdk_region_copy (visible_region);
1834                   gdk_region_offset (child_region, -x, -y);
1835                   
1836                   gdk_window_invalidate_region ((GdkWindow *)child, child_region, TRUE);
1837                   
1838                   gdk_region_destroy (child_region);
1839                 }
1840             }
1841         }
1842     }
1843   
1844   gdk_region_destroy (visible_region);
1845 }
1846
1847 GdkRegion *
1848 gdk_window_get_update_area (GdkWindow *window)
1849 {
1850   GdkWindowObject *private = (GdkWindowObject *)window;
1851   GdkRegion *tmp_region;
1852
1853   g_return_val_if_fail (window != NULL, NULL);
1854   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
1855
1856   if (private->update_area)
1857     {
1858       tmp_region = private->update_area;
1859       private->update_area = NULL;
1860
1861       update_windows = g_slist_remove (update_windows, window);
1862       
1863       return tmp_region;
1864     }
1865   else
1866     return NULL;
1867 }
1868
1869 /**
1870  * _gdk_window_clear_update_area:
1871  * @window: a #GdkWindow.
1872  * 
1873  * Internal function to clear the update area for a window. This
1874  * is called when the window is hidden or destroyed.
1875  **/
1876 void
1877 _gdk_window_clear_update_area (GdkWindow *window)
1878 {
1879   GdkWindowObject *private = (GdkWindowObject *)window;
1880
1881   g_return_if_fail (window != NULL);
1882   g_return_if_fail (GDK_IS_WINDOW (window));
1883
1884   if (private->update_area)
1885     {
1886       update_windows = g_slist_remove (update_windows, window);
1887       
1888       gdk_region_destroy (private->update_area);
1889       private->update_area = NULL;
1890     }
1891 }
1892
1893 void
1894 gdk_window_freeze_updates (GdkWindow *window)
1895 {
1896   GdkWindowObject *private = (GdkWindowObject *)window;
1897
1898   g_return_if_fail (window != NULL);
1899   g_return_if_fail (GDK_IS_WINDOW (window));
1900
1901   private->update_freeze_count++;
1902 }
1903
1904 void
1905 gdk_window_thaw_updates (GdkWindow *window)
1906 {
1907   GdkWindowObject *private = (GdkWindowObject *)window;
1908
1909   g_return_if_fail (window != NULL);
1910   g_return_if_fail (GDK_IS_WINDOW (window));
1911   g_return_if_fail (private->update_freeze_count > 0);
1912
1913   private->update_freeze_count--;
1914   if (!private->update_freeze_count && private->update_area && !update_idle)
1915     update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
1916                                    gdk_window_update_idle, NULL, NULL);
1917 }
1918