]> Pileus Git - ~andy/gtk/blob - gdk/gdkwindow.c
Large changes to the Win32 backend, partially made necessary by the
[~andy/gtk] / gdk / gdkwindow.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gdkwindow.h"
28 #include "gdkinternals.h"
29 #include "gdk.h"                /* For gdk_rectangle_union() */
30 #include "gdkpixmap.h"
31
32 #ifndef USE_BACKING_STORE
33 #ifndef GDK_WINDOWING_WIN32
34 #define USE_BACKING_STORE       /* Doesn't work yet on Win32 */
35 #endif
36 #endif
37
38 typedef struct _GdkWindowPaint GdkWindowPaint;
39
40 struct _GdkWindowPaint
41 {
42   GdkRegion *region;
43   GdkPixmap *pixmap;
44   gint x_offset;
45   gint y_offset;
46 };
47
48 static void   gdk_window_draw_destroy   (GdkDrawable     *drawable);
49 static GdkGC *gdk_window_draw_create_gc (GdkDrawable     *drawable,
50                                          GdkGCValues     *values,
51                                          GdkGCValuesMask  mask);
52 static void   gdk_window_draw_rectangle (GdkDrawable     *drawable,
53                                          GdkGC           *gc,
54                                          gint             filled,
55                                          gint             x,
56                                          gint             y,
57                                          gint             width,
58                                          gint             height);
59 static void   gdk_window_draw_arc       (GdkDrawable     *drawable,
60                                          GdkGC           *gc,
61                                          gint             filled,
62                                          gint             x,
63                                          gint             y,
64                                          gint             width,
65                                          gint             height,
66                                          gint             angle1,
67                                          gint             angle2);
68 static void   gdk_window_draw_polygon   (GdkDrawable     *drawable,
69                                          GdkGC           *gc,
70                                          gint             filled,
71                                          GdkPoint        *points,
72                                          gint             npoints);
73 static void   gdk_window_draw_text      (GdkDrawable     *drawable,
74                                          GdkFont         *font,
75                                          GdkGC           *gc,
76                                          gint             x,
77                                          gint             y,
78                                          const gchar     *text,
79                                          gint             text_length);
80 static void   gdk_window_draw_text_wc   (GdkDrawable     *drawable,
81                                          GdkFont         *font,
82                                          GdkGC           *gc,
83                                          gint             x,
84                                          gint             y,
85                                          const GdkWChar  *text,
86                                          gint             text_length);
87 static void   gdk_window_draw_drawable  (GdkDrawable     *drawable,
88                                          GdkGC           *gc,
89                                          GdkPixmap       *src,
90                                          gint             xsrc,
91                                          gint             ysrc,
92                                          gint             xdest,
93                                          gint             ydest,
94                                          gint             width,
95                                          gint             height);
96 static void   gdk_window_draw_points    (GdkDrawable     *drawable,
97                                          GdkGC           *gc,
98                                          GdkPoint        *points,
99                                          gint             npoints);
100 static void   gdk_window_draw_segments  (GdkDrawable     *drawable,
101                                          GdkGC           *gc,
102                                          GdkSegment      *segs,
103                                          gint             nsegs);
104 static void   gdk_window_draw_lines     (GdkDrawable     *drawable,
105                                          GdkGC           *gc,
106                                          GdkPoint        *points,
107                                          gint             npoints);
108
109
110 /* All drawing operations on windows are forwarded through the following
111  * class to enable the automatic-backing-store feature.
112  */
113 GdkDrawableClass _gdk_window_class = {
114   gdk_window_draw_destroy,
115   gdk_window_draw_create_gc,
116   gdk_window_draw_rectangle,
117   gdk_window_draw_arc,
118   gdk_window_draw_polygon,
119   gdk_window_draw_text,
120   gdk_window_draw_text_wc,
121   gdk_window_draw_drawable,
122   gdk_window_draw_points,
123   gdk_window_draw_segments,
124   gdk_window_draw_lines
125 };
126
127 GdkWindow *
128 _gdk_window_alloc (void)
129 {
130   GdkWindowPrivate *private = g_new (GdkWindowPrivate, 1);
131   GdkWindow *window = (GdkWindow*) private;
132   
133   window->user_data = NULL;
134
135   private->drawable.ref_count = 1;
136   private->drawable.destroyed = FALSE;
137   private->drawable.klass = NULL;
138   private->drawable.klass_data = NULL;
139   private->drawable.window_type = GDK_WINDOW_CHILD;
140
141   private->drawable.width = 1;
142   private->drawable.height = 1;
143
144   private->drawable.colormap = NULL;
145
146   private->parent = NULL;
147   private->x = 0;
148   private->y = 0;
149   private->resize_count = 0;
150
151   private->mapped = FALSE;
152   private->guffaw_gravity = FALSE;
153   private->extension_events = FALSE;
154   
155   private->filters = NULL;
156   private->children = NULL;
157
158   private->bg_color.pixel = 0;
159   private->bg_color.red = 0;
160   private->bg_color.green = 0;
161   private->bg_color.blue = 0;
162
163   private->bg_pixmap = NULL;
164
165   private->paint_stack = NULL;
166
167   private->update_area = NULL;
168   private->update_freeze_count = 0;
169   
170   return window;
171 }
172
173 void
174 gdk_window_set_user_data (GdkWindow *window,
175                           gpointer   user_data)
176 {
177   g_return_if_fail (window != NULL);
178   
179   window->user_data = user_data;
180 }
181
182 void
183 gdk_window_get_user_data (GdkWindow *window,
184                           gpointer  *data)
185 {
186   g_return_if_fail (window != NULL);
187   
188   *data = window->user_data;
189 }
190
191 void
192 gdk_window_get_position (GdkWindow *window,
193                          gint      *x,
194                          gint      *y)
195 {
196   GdkWindowPrivate *window_private;
197   
198   g_return_if_fail (window != NULL);
199   g_return_if_fail (GDK_IS_WINDOW (window));
200   
201   window_private = (GdkWindowPrivate*) window;
202   
203   if (x)
204     *x = window_private->x;
205   if (y)
206     *y = window_private->y;
207 }
208
209 GdkWindow*
210 gdk_window_get_parent (GdkWindow *window)
211 {
212   g_return_val_if_fail (window != NULL, NULL);
213   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
214   
215   return ((GdkWindowPrivate*) window)->parent;
216 }
217
218 GdkWindow*
219 gdk_window_get_toplevel (GdkWindow *window)
220 {
221   GdkWindowPrivate *private;
222   
223   g_return_val_if_fail (window != NULL, NULL);
224   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
225
226   private = (GdkWindowPrivate *)window;
227   while (GDK_DRAWABLE_TYPE (private) == GDK_WINDOW_CHILD)
228     private = (GdkWindowPrivate *)private->parent;
229   
230   return (GdkWindow *)window;
231 }
232
233 void          
234 gdk_window_add_filter (GdkWindow     *window,
235                        GdkFilterFunc  function,
236                        gpointer       data)
237 {
238   GdkWindowPrivate *private;
239   GList *tmp_list;
240   GdkEventFilter *filter;
241   
242   g_return_if_fail (window != NULL);
243   g_return_if_fail (GDK_IS_WINDOW (window));
244
245   private = (GdkWindowPrivate*) window;
246   if (private && GDK_DRAWABLE_DESTROYED (window))
247     return;
248   
249   if (private)
250     tmp_list = private->filters;
251   else
252     tmp_list = gdk_default_filters;
253   
254   while (tmp_list)
255     {
256       filter = (GdkEventFilter *)tmp_list->data;
257       if ((filter->function == function) && (filter->data == data))
258         return;
259       tmp_list = tmp_list->next;
260     }
261   
262   filter = g_new (GdkEventFilter, 1);
263   filter->function = function;
264   filter->data = data;
265   
266   if (private)
267     private->filters = g_list_append (private->filters, filter);
268   else
269     gdk_default_filters = g_list_append (gdk_default_filters, filter);
270 }
271
272 void
273 gdk_window_remove_filter (GdkWindow     *window,
274                           GdkFilterFunc  function,
275                           gpointer       data)
276 {
277   GdkWindowPrivate *private;
278   GList *tmp_list, *node;
279   GdkEventFilter *filter;
280   
281   g_return_if_fail (window != NULL);
282   g_return_if_fail (GDK_IS_WINDOW (window));
283
284   private = (GdkWindowPrivate*) window;
285   
286   if (private)
287     tmp_list = private->filters;
288   else
289     tmp_list = gdk_default_filters;
290   
291   while (tmp_list)
292     {
293       filter = (GdkEventFilter *)tmp_list->data;
294       node = tmp_list;
295       tmp_list = tmp_list->next;
296       
297       if ((filter->function == function) && (filter->data == data))
298         {
299           if (private)
300             private->filters = g_list_remove_link (private->filters, node);
301           else
302             gdk_default_filters = g_list_remove_link (gdk_default_filters, node);
303           g_list_free_1 (node);
304           g_free (filter);
305           
306           return;
307         }
308     }
309 }
310
311 GList *
312 gdk_window_get_toplevels (void)
313 {
314   GList *new_list = NULL;
315   GList *tmp_list;
316   
317   tmp_list = ((GdkWindowPrivate *)gdk_parent_root)->children;
318   while (tmp_list)
319     {
320       new_list = g_list_prepend (new_list, tmp_list->data);
321       tmp_list = tmp_list->next;
322     }
323   
324   return new_list;
325 }
326
327 /*************************************************************
328  * gdk_window_is_visible:
329  *     Check if the given window is mapped.
330  *   arguments:
331  *     window: 
332  *   results:
333  *     is the window mapped
334  *************************************************************/
335
336 gboolean 
337 gdk_window_is_visible (GdkWindow *window)
338 {
339   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
340   
341   g_return_val_if_fail (window != NULL, FALSE);
342   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
343   
344   return private->mapped;
345 }
346
347 /*************************************************************
348  * gdk_window_is_viewable:
349  *     Check if the window and all ancestors of the window
350  *     are mapped. (This is not necessarily "viewable" in
351  *     the X sense, since we only check as far as we have
352  *     GDK window parents, not to the root window)
353  *   arguments:
354  *     window:
355  *   results:
356  *     is the window viewable
357  *************************************************************/
358
359 gboolean 
360 gdk_window_is_viewable (GdkWindow *window)
361 {
362   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
363   
364   g_return_val_if_fail (window != NULL, FALSE);
365   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
366   
367   while (private && 
368          (private != (GdkWindowPrivate *)gdk_parent_root) &&
369          (private->drawable.window_type != GDK_WINDOW_FOREIGN))
370     {
371       if (!private->mapped)
372         return FALSE;
373       
374       private = (GdkWindowPrivate *)private->parent;
375     }
376   
377   return TRUE;
378 }
379
380 void
381 gdk_window_begin_paint_rect (GdkWindow    *window,
382                              GdkRectangle *rectangle)
383 {
384   GdkRegion *region;
385
386   g_return_if_fail (window != NULL);
387   g_return_if_fail (GDK_IS_WINDOW (window));
388
389   region = gdk_region_rectangle (rectangle);
390   gdk_window_begin_paint_region (window, region);
391   gdk_region_destroy (region);
392 }
393
394 static GdkGC *
395 gdk_window_get_bg_gc (GdkWindow *window, GdkWindowPaint *paint)
396 {
397   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
398
399   guint gc_mask = 0;
400   GdkGCValues gc_values;
401
402   if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
403     {
404       GdkWindowPaint tmp_paint = *paint;
405       tmp_paint.x_offset += private->x;
406       tmp_paint.y_offset += private->y;
407       
408       return gdk_window_get_bg_gc (private->parent, &tmp_paint);
409     }
410   else if (private->bg_pixmap && private->bg_pixmap != GDK_PARENT_RELATIVE_BG && private->bg_pixmap != GDK_NO_BG)
411     {
412       gc_values.fill = GDK_TILED;
413       gc_values.tile = private->bg_pixmap;
414       gc_values.ts_x_origin = - paint->x_offset;
415       gc_values.ts_y_origin = - paint->y_offset;
416       
417       gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN;
418     }
419   else
420     {
421       gc_values.foreground = private->bg_color;
422       gc_mask = GDK_GC_FOREGROUND;
423     }
424
425   return gdk_gc_new_with_values (paint->pixmap, &gc_values, gc_mask);
426 }
427
428 static void
429 gdk_window_paint_init_bg (GdkWindow      *window,
430                           GdkWindowPaint *paint,
431                           GdkRegion      *init_region)
432 {
433   GdkGC *tmp_gc;
434
435   tmp_gc = gdk_window_get_bg_gc (window, paint);
436   gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE, 0, 0, -1, -1);
437   gdk_gc_unref (tmp_gc);
438 }
439   
440 void          
441 gdk_window_begin_paint_region (GdkWindow *window,
442                                GdkRegion *region)
443 {
444 #ifdef USE_BACKING_STORE
445   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
446   GdkRectangle clip_box;
447   GdkWindowPaint *paint;
448   GdkRegion *init_region;
449   GdkGC *tmp_gc;
450   
451   g_return_if_fail (window != NULL);
452   g_return_if_fail (GDK_IS_WINDOW (window));
453
454   paint = g_new (GdkWindowPaint, 1);
455
456   paint->region = gdk_region_copy (region);
457
458   init_region = gdk_region_copy (region);
459   gdk_region_get_clipbox (paint->region, &clip_box);
460
461   if (private->paint_stack)
462     {
463       gint old_width, old_height;
464       GdkWindowPaint *tmp_paint = private->paint_stack->data;
465       GdkRectangle old_rect, new_rect;
466       GSList *tmp_list;
467
468       gdk_drawable_get_size (tmp_paint->pixmap, &old_width, &old_height);
469       old_rect.x = tmp_paint->x_offset;
470       old_rect.y = tmp_paint->y_offset;
471       old_rect.width = old_width;
472       old_rect.height = old_height;
473
474       gdk_rectangle_union (&clip_box, &old_rect, &new_rect);
475
476       if (new_rect.width > old_rect.width || new_rect.height > old_rect.height)
477         {
478           paint->pixmap = gdk_pixmap_new (window, new_rect.width, new_rect.height, -1);
479           tmp_gc = gdk_gc_new (paint->pixmap);
480           gdk_draw_drawable (paint->pixmap, tmp_gc, tmp_paint->pixmap,
481                              0, 0, old_rect.width, old_rect.height,
482                              old_rect.x - new_rect.x, old_rect.y - new_rect.y);
483           gdk_gc_unref (tmp_gc);
484           gdk_drawable_unref (tmp_paint->pixmap);
485
486           paint->x_offset = new_rect.x;
487           paint->y_offset = new_rect.y;
488           
489           tmp_list = private->paint_stack;
490           while (tmp_list)
491             {
492               tmp_paint = private->paint_stack->data;
493               gdk_region_subtract (init_region, tmp_paint->region);
494
495               tmp_paint->pixmap = paint->pixmap;
496               tmp_paint->x_offset = paint->x_offset;
497               tmp_paint->y_offset = paint->x_offset;
498
499               tmp_list = tmp_list->next;
500             }
501         }
502       else
503         {
504           paint->x_offset = tmp_paint->x_offset;
505           paint->y_offset = tmp_paint->y_offset;
506           paint->pixmap = tmp_paint->pixmap;
507
508           tmp_list = private->paint_stack;
509           while (tmp_list)
510             {
511               tmp_paint = private->paint_stack->data;
512               gdk_region_subtract (init_region, tmp_paint->region);
513               
514               tmp_list = tmp_list->next;
515             }
516         }
517     }
518   else
519     {
520       paint->x_offset = clip_box.x;
521       paint->y_offset = clip_box.y;
522       paint->pixmap = gdk_pixmap_new (window, clip_box.width, clip_box.height, -1);
523     }
524
525   if (!gdk_region_empty (init_region))
526     gdk_window_paint_init_bg (window, paint, init_region);
527   gdk_region_destroy (init_region);
528   
529   private->paint_stack = g_slist_prepend (private->paint_stack, paint);
530 #endif /* USE_BACKING_STORE */
531 }
532
533 void
534 gdk_window_end_paint (GdkWindow *window)
535 {
536 #ifdef USE_BACKING_STORE
537   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
538   GdkWindowPaint *paint;
539   GdkGC *tmp_gc;
540   GdkRectangle clip_box;
541   gint x_offset, y_offset;
542
543   g_return_if_fail (window != NULL);
544   g_return_if_fail (GDK_IS_WINDOW (window));
545   g_return_if_fail (private->paint_stack != NULL);
546
547   paint = private->paint_stack->data;
548   private->paint_stack = g_slist_delete_link (private->paint_stack, private->paint_stack);
549
550   gdk_region_get_clipbox (paint->region, &clip_box);
551
552   tmp_gc = gdk_gc_new (window);
553
554   _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset);
555
556   gdk_gc_set_clip_region (tmp_gc, paint->region);
557   gdk_gc_set_clip_origin (tmp_gc, -x_offset, -y_offset);
558
559   _gdk_windowing_window_class.draw_drawable (window, tmp_gc, paint->pixmap,
560                                              clip_box.x - paint->x_offset,
561                                              clip_box.y - paint->y_offset,
562                                              clip_box.x - x_offset, clip_box.y - y_offset,
563                                              clip_box.width, clip_box.height);
564   gdk_gc_unref (tmp_gc);
565
566   if (private->paint_stack)
567     {
568       GSList *tmp_list = private->paint_stack;
569       while (tmp_list)
570         {
571           GdkWindowPaint *tmp_paint = tmp_list->data;
572           gdk_region_subtract (tmp_paint->region, paint->region);
573           
574           tmp_list = tmp_list->next;
575         }
576     }
577   else
578     gdk_drawable_unref (paint->pixmap);
579
580   gdk_region_destroy (paint->region);
581   g_free (paint);
582 #endif /* USE_BACKING_STORE */
583 }
584
585 static void
586 gdk_window_get_offsets (GdkWindow *window,
587                         gint      *x_offset,
588                         gint      *y_offset)
589 {
590   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
591   
592   if (private->paint_stack)
593     {
594       GdkWindowPaint *paint = private->paint_stack->data;
595       *x_offset = paint->x_offset;
596       *y_offset = paint->y_offset;
597     }
598   else
599     _gdk_windowing_window_get_offsets (window, x_offset, y_offset);
600 }
601
602 #define OFFSET_GC(gc)                                         \
603     gint x_offset, y_offset;                                  \
604     gint old_clip_x = ((GdkGCPrivate *)gc)->clip_x_origin;    \
605     gint old_clip_y = ((GdkGCPrivate *)gc)->clip_y_origin;    \
606     gint old_ts_x = ((GdkGCPrivate *)gc)->ts_x_origin;        \
607     gint old_ts_y = ((GdkGCPrivate *)gc)->ts_y_origin;        \
608     gdk_window_get_offsets (drawable, &x_offset, &y_offset);  \
609     if (x_offset != 0 || y_offset != 0)                       \
610       {                                                       \
611         gdk_gc_set_clip_origin (gc, old_clip_x - x_offset,    \
612                                 old_clip_y - y_offset);       \
613         gdk_gc_set_ts_origin (gc, old_ts_x - x_offset,        \
614                               old_ts_y - y_offset);           \
615       }
616
617 #define RESTORE_GC(gc)                                      \
618     if (x_offset != 0 || y_offset != 0)                     \
619      {                                                      \
620        gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \
621        gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y);       \
622      }
623
624 static void
625 gdk_window_draw_destroy   (GdkDrawable     *drawable)
626 {
627   _gdk_windowing_window_class.destroy (drawable);
628 }
629
630 static GdkGC *
631 gdk_window_draw_create_gc (GdkDrawable     *drawable,
632                            GdkGCValues     *values,
633                            GdkGCValuesMask  mask)
634 {
635   return _gdk_windowing_window_class.create_gc (drawable, values, mask);
636 }
637
638 static void
639 gdk_window_draw_rectangle (GdkDrawable *drawable,
640                            GdkGC       *gc,
641                            gint         filled,
642                            gint         x,
643                            gint         y,
644                            gint         width,
645                            gint         height)
646 {
647   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
648   OFFSET_GC (gc);
649   
650   if (private->paint_stack)
651     {
652       GdkWindowPaint *paint = private->paint_stack->data;
653       gdk_draw_rectangle (paint->pixmap, gc, filled,
654                           x - x_offset, y - y_offset, width, height);
655     }
656   else
657     _gdk_windowing_window_class.draw_rectangle (drawable, gc, filled,
658                                                 x - x_offset, y - y_offset, width, height);
659
660   RESTORE_GC (gc);
661 }
662
663 static void
664 gdk_window_draw_arc (GdkDrawable *drawable,
665                      GdkGC       *gc,
666                      gint         filled,
667                      gint         x,
668                      gint         y,
669                      gint         width,
670                      gint         height,
671                      gint         angle1,
672                      gint         angle2)
673 {
674   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
675   OFFSET_GC (gc);
676
677   if (private->paint_stack)
678     {
679       GdkWindowPaint *paint = private->paint_stack->data;
680       gdk_draw_arc (paint->pixmap, gc, filled,
681                     x - x_offset, y_offset,
682                     width, height, angle1, angle2);
683     }
684   else
685     _gdk_windowing_window_class.draw_arc (drawable, gc, filled,
686                                           x - x_offset, y - y_offset,
687                                           width, height, angle1, angle2);
688   RESTORE_GC (gc);
689 }
690
691 static void
692 gdk_window_draw_polygon (GdkDrawable *drawable,
693                          GdkGC       *gc,
694                          gint         filled,
695                          GdkPoint    *points,
696                          gint         npoints)
697 {
698   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
699   GdkPoint *new_points;
700   
701   OFFSET_GC (gc);
702
703   if (x_offset != 0 || y_offset != 0)
704     {
705       int i;
706       
707       new_points = g_new (GdkPoint, npoints);
708       for (i=0; i<npoints; i++)
709         {
710           new_points[i].x = points[i].x - x_offset;
711           new_points[i].y = points[i].y - y_offset;
712         }
713     }
714   else
715     new_points = points;
716
717   if (private->paint_stack)
718     {
719       GdkWindowPaint *paint = private->paint_stack->data;
720       gdk_draw_polygon (paint->pixmap, gc, filled, new_points, npoints);
721
722     }
723   else
724     _gdk_windowing_window_class.draw_polygon (drawable, gc, filled, new_points, npoints);
725
726   if (new_points != points)
727     g_free (new_points);
728
729   RESTORE_GC (gc);
730 }
731
732 static void
733 gdk_window_draw_text (GdkDrawable *drawable,
734                       GdkFont     *font,
735                       GdkGC       *gc,
736                       gint         x,
737                       gint         y,
738                       const gchar *text,
739                       gint         text_length)
740 {
741   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
742   OFFSET_GC (gc);
743
744   if (private->paint_stack)
745     {
746       GdkWindowPaint *paint = private->paint_stack->data;
747       gdk_draw_text (paint->pixmap, font, gc, 
748                      x - x_offset, y - y_offset, text, text_length);
749
750     }
751   else
752     _gdk_windowing_window_class.draw_text (drawable, font, gc,
753                                            x - x_offset, y - y_offset, text, text_length);
754
755   RESTORE_GC (gc);
756 }
757
758 static void
759 gdk_window_draw_text_wc (GdkDrawable    *drawable,
760                          GdkFont        *font,
761                          GdkGC          *gc,
762                          gint            x,
763                          gint            y,
764                          const GdkWChar *text,
765                          gint            text_length)
766 {
767   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
768   OFFSET_GC (gc);
769
770   if (private->paint_stack)
771     {
772       GdkWindowPaint *paint = private->paint_stack->data;
773       gdk_draw_text_wc (paint->pixmap, font, gc, 
774                         x - x_offset, y - y_offset, text, text_length);
775     }
776   else
777     _gdk_windowing_window_class.draw_text_wc (drawable, font, gc,
778                                               x - x_offset, y - y_offset, text, text_length);
779
780   RESTORE_GC (gc);
781 }
782
783 static void
784 gdk_window_draw_drawable (GdkDrawable *drawable,
785                           GdkGC       *gc,
786                           GdkPixmap   *src,
787                           gint         xsrc,
788                           gint         ysrc,
789                           gint         xdest,
790                           gint         ydest,
791                           gint         width,
792                           gint         height)
793 {
794   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
795   OFFSET_GC (gc);
796
797   if (private->paint_stack)
798     {
799       GdkWindowPaint *paint = private->paint_stack->data;
800       gdk_draw_drawable (paint->pixmap, gc, src, xsrc, ysrc,
801                          xdest - x_offset, ydest - y_offset, width, height);
802
803     }
804   else
805     _gdk_windowing_window_class.draw_drawable (drawable, gc, src, xsrc, ysrc,
806                                                xdest - x_offset, ydest - y_offset,
807                                                width, height);
808   RESTORE_GC (gc);
809 }
810
811 static void
812 gdk_window_draw_points (GdkDrawable *drawable,
813                         GdkGC       *gc,
814                         GdkPoint    *points,
815                         gint         npoints)
816 {
817   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
818   GdkPoint *new_points;
819   
820   OFFSET_GC (gc);
821
822   if (x_offset != 0 || y_offset != 0)
823     {
824       gint i;
825
826       new_points = g_new (GdkPoint, npoints);
827       for (i=0; i<npoints; i++)
828         {
829           new_points[i].x = points[i].x - x_offset;
830           new_points[i].y = points[i].y - y_offset;
831         }
832     }
833   else
834     new_points = points;
835
836   if (private->paint_stack)
837     {
838       GdkWindowPaint *paint = private->paint_stack->data;
839       gdk_draw_points (paint->pixmap, gc, new_points, npoints);
840     }
841   else
842     _gdk_windowing_window_class.draw_points (drawable, gc, points, npoints);
843
844   if (new_points != points)
845     g_free (new_points);
846
847   RESTORE_GC (gc);
848 }
849
850 static void
851 gdk_window_draw_segments (GdkDrawable *drawable,
852                           GdkGC       *gc,
853                           GdkSegment  *segs,
854                           gint         nsegs)
855 {
856   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
857   GdkSegment *new_segs;
858
859   OFFSET_GC (gc);
860
861   if (x_offset != 0 || y_offset != 0)
862     {
863       gint i;
864
865       new_segs = g_new (GdkSegment, nsegs);
866       for (i=0; i<nsegs; i++)
867         {
868           new_segs[i].x1 = segs[i].x1 - x_offset;
869           new_segs[i].y1 = segs[i].y1 - y_offset;
870           new_segs[i].x2 = segs[i].x2 - x_offset;
871           new_segs[i].y2 = segs[i].y2 - y_offset;
872         }
873     }
874   else
875     new_segs = segs;
876
877   if (private->paint_stack)
878     {
879       GdkWindowPaint *paint = private->paint_stack->data;
880       gdk_draw_segments (paint->pixmap, gc, new_segs, nsegs);
881     }
882   else
883     _gdk_windowing_window_class.draw_segments (drawable, gc, new_segs, nsegs);
884
885   if (new_segs != segs)
886     g_free (new_segs);
887
888   RESTORE_GC (gc);
889 }
890
891 static void
892 gdk_window_draw_lines (GdkDrawable *drawable,
893                        GdkGC       *gc,
894                        GdkPoint    *points,
895                        gint         npoints)
896 {
897   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
898   GdkPoint *new_points;
899
900   OFFSET_GC (gc);
901
902   if (x_offset != 0 || y_offset != 0)
903     {
904       gint i;
905
906       new_points = g_new (GdkPoint, npoints);
907       for (i=0; i<npoints; i++)
908         {
909           new_points[i].x = points[i].x - x_offset;
910           new_points[i].y = points[i].y - y_offset;
911         }
912     }
913   else
914     new_points = points;
915
916   if (private->paint_stack)
917     {
918       GdkWindowPaint *paint = private->paint_stack->data;
919       gdk_draw_lines (paint->pixmap, gc, new_points, npoints);
920     }
921   else
922     _gdk_windowing_window_class.draw_lines (drawable, gc, new_points, npoints);
923
924   if (new_points != points)
925     g_free (new_points);
926
927   RESTORE_GC (gc);
928 }
929
930 /* Fixme - this is just like gdk_window_paint_init_bg */
931 static void
932 gdk_window_clear_backing_rect (GdkWindow *window,
933                                gint       x,
934                                gint       y,
935                                gint       width,
936                                gint       height)
937 {
938   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
939   GdkWindowPaint *paint = private->paint_stack->data;
940   GdkGC *tmp_gc;
941
942   tmp_gc = gdk_window_get_bg_gc (window, paint);
943   gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE,
944                       x - paint->x_offset, y - paint->y_offset, width, height);
945   gdk_gc_unref (tmp_gc);
946 }
947
948 void
949 gdk_window_clear_area (GdkWindow *window,
950                        gint       x,
951                        gint       y,
952                        gint       width,
953                        gint       height)
954 {
955   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
956
957   g_return_if_fail (window != NULL);
958   g_return_if_fail (GDK_IS_WINDOW (window));
959   
960   if (private->paint_stack)
961     gdk_window_clear_backing_rect (window, x, y, width, height);
962   else
963     _gdk_windowing_window_clear_area (window, x, y, width, height);
964 }
965
966 void
967 gdk_window_clear_area_e (GdkWindow *window,
968                          gint       x,
969                          gint       y,
970                          gint       width,
971                          gint       height)
972 {
973   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
974
975   g_return_if_fail (window != NULL);
976   g_return_if_fail (GDK_IS_WINDOW (window));
977   
978   if (private->paint_stack)
979     gdk_window_clear_backing_rect (window, x, y, width, height);
980
981   _gdk_windowing_window_clear_area_e (window, x, y, width, height);
982 }
983
984 void
985 _gdk_window_draw_image (GdkDrawable *drawable,
986                         GdkGC       *gc,
987                         GdkImage    *image,
988                         gint         xsrc,
989                         gint         ysrc,
990                         gint         xdest,
991                         gint         ydest,
992                         gint         width,
993                         gint         height)
994 {
995   GdkImagePrivate *image_private = (GdkImagePrivate*) image;
996   GdkWindowPrivate *private = (GdkWindowPrivate *)drawable;
997
998   OFFSET_GC (gc);
999   
1000   if (private->paint_stack)
1001     {
1002       GdkWindowPaint *paint = private->paint_stack->data;
1003       image_private->klass->image_put (image, paint->pixmap, gc, xsrc, ysrc,
1004                                        xdest - x_offset, ydest - y_offset,
1005                                        width, height);
1006
1007     }
1008   else
1009     image_private->klass->image_put (image, drawable, gc, xsrc, ysrc,
1010                                      xdest - x_offset, ydest - y_offset,
1011                                      width, height);
1012
1013   RESTORE_GC (gc);
1014 }
1015
1016 /* Code for dirty-region queueing
1017  */
1018
1019 static GSList *update_windows = NULL;
1020 static guint update_idle = 0;
1021
1022 #define GDK_PRIORITY_REDRAW     (G_PRIORITY_HIGH_IDLE + 20)
1023
1024 static void
1025 gdk_window_process_updates_internal (GdkWindow *window)
1026 {
1027   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
1028   gboolean save_region = FALSE;
1029   
1030   if (gdk_event_func)
1031     {
1032       GdkEvent event;
1033       GdkRectangle window_rect;
1034
1035       window_rect.x = 0;
1036       window_rect.y = 0;
1037       window_rect.width = private->drawable.width;
1038       window_rect.height = private->drawable.height;
1039
1040       save_region = _gdk_windowing_window_queue_antiexpose (window, private->update_area);
1041       
1042       event.expose.type = GDK_EXPOSE;
1043       event.expose.window = gdk_window_ref ((GdkWindow *)private);
1044       event.expose.count = 0;
1045       
1046       gdk_region_get_clipbox (private->update_area, &event.expose.area);
1047       if (gdk_rectangle_intersect (&event.expose.area, &window_rect, &event.expose.area))
1048         {
1049           (*gdk_event_func) (&event, gdk_event_data);
1050         }
1051     }
1052   
1053   if (!save_region)
1054     gdk_region_destroy (private->update_area);
1055   private->update_area = NULL;
1056 }
1057
1058 void
1059 gdk_window_process_all_updates (void)
1060 {
1061   GSList *old_update_windows = update_windows;
1062   GSList *tmp_list = update_windows;
1063
1064   if (update_idle)
1065     g_source_remove (update_idle);
1066   
1067   update_windows = NULL;
1068   update_idle = 0;
1069
1070   while (tmp_list)
1071     {
1072       gdk_window_process_updates_internal (tmp_list->data);
1073       tmp_list = tmp_list->next;
1074     }
1075
1076   g_slist_free (old_update_windows);
1077
1078   gdk_flush();
1079 }
1080
1081 static gboolean
1082 gdk_window_update_idle (gpointer data)
1083 {
1084   gdk_window_process_all_updates ();
1085   
1086   return FALSE;
1087 }
1088
1089 void
1090 gdk_window_process_updates (GdkWindow *window,
1091                             gboolean   update_children)
1092 {
1093   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
1094
1095   g_return_if_fail (window != NULL);
1096   g_return_if_fail (GDK_IS_WINDOW (window));
1097
1098   if (private->update_area)
1099     {
1100       gdk_window_process_updates_internal (window);
1101       update_windows = g_slist_remove (update_windows, window);
1102     }
1103
1104   if (update_children)
1105     {
1106       GList *tmp_list = private->children;
1107       while (tmp_list)
1108         {
1109           gdk_window_process_updates (tmp_list->data, TRUE);
1110           tmp_list = tmp_list->next;
1111         }
1112     }
1113 }
1114
1115 void
1116 gdk_window_invalidate_rect   (GdkWindow    *window,
1117                               GdkRectangle *rect,
1118                               gboolean      invalidate_children)
1119 {
1120   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
1121
1122   g_return_if_fail (window != NULL);
1123   g_return_if_fail (GDK_IS_WINDOW (window));
1124
1125   if (private->update_area)
1126     {
1127       gdk_region_union_with_rect (private->update_area, rect);
1128     }
1129   else
1130     {
1131       update_windows = g_slist_prepend (update_windows, window);
1132       private->update_area = gdk_region_rectangle (rect);
1133
1134       if (!private->update_freeze_count && !update_idle)
1135         update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
1136                                        gdk_window_update_idle, NULL, NULL);
1137     }
1138
1139
1140   if (invalidate_children)
1141     {
1142       GList *tmp_list;
1143       GdkRectangle child_rect, new_rect;
1144
1145       tmp_list = private->children;
1146       while (tmp_list)
1147         {
1148           GdkWindowPrivate *child = tmp_list->data;
1149           tmp_list = tmp_list->next;
1150
1151           /* FIXME: this is a HACK to figure out if the child is
1152            *        input-only.
1153            */
1154           if (child->drawable.colormap)
1155             {
1156               child_rect.x = child->x;
1157               child_rect.y = child->y;
1158               child_rect.width = child->drawable.width;
1159               child_rect.height = child->drawable.height;
1160               
1161               if (gdk_rectangle_intersect (rect, &child_rect, &new_rect))
1162                 {
1163                   new_rect.x -= child_rect.x;
1164                   new_rect.y -= child_rect.y;
1165                   
1166                   gdk_window_invalidate_rect ((GdkWindow *)child, &new_rect, TRUE);
1167                 }
1168             }
1169         }
1170     }
1171 }
1172
1173 void
1174 gdk_window_invalidate_region (GdkWindow *window,
1175                               GdkRegion *region,
1176                               gboolean   invalidate_children)
1177 {
1178   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
1179
1180   g_return_if_fail (window != NULL);
1181   g_return_if_fail (GDK_IS_WINDOW (window));
1182
1183   if (private->input_only)
1184     return;
1185   
1186   if (private->update_area)
1187     {
1188       gdk_region_union (private->update_area, region);
1189     }
1190   else
1191     {
1192       update_windows = g_slist_prepend (update_windows, window);
1193       private->update_area = gdk_region_copy (region);
1194
1195       if (!private->update_freeze_count && !update_idle)
1196         update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
1197                                        gdk_window_update_idle, NULL, NULL);
1198     }
1199
1200   if (invalidate_children)
1201     {
1202       GList *tmp_list;
1203       GdkRectangle child_rect;
1204       GdkRegion *child_region;
1205
1206       tmp_list = private->children;
1207       while (tmp_list)
1208         {
1209           GdkWindowPrivate *child = tmp_list->data;
1210           tmp_list = tmp_list->next;
1211
1212           if (child->input_only)
1213             {
1214               child_rect.x = child->x;
1215               child_rect.y = child->y;
1216               child_rect.width = child->drawable.width;
1217               child_rect.height = child->drawable.height;
1218               
1219               child_region = gdk_region_rectangle (&child_rect);
1220               gdk_region_intersect (child_region, region);
1221               
1222               if (!gdk_region_empty (child_region))
1223                 {
1224                   gdk_region_offset (child_region, - child_rect.x, - child_rect.y);
1225                   gdk_window_invalidate_region ((GdkWindow *)child, child_region, TRUE);
1226                 }
1227               
1228               gdk_region_destroy (child_region);
1229             }
1230         }
1231     }
1232 }
1233
1234 GdkRegion *
1235 gdk_window_get_update_area (GdkWindow *window)
1236 {
1237   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
1238   GdkRegion *tmp_region;
1239
1240   g_return_val_if_fail (window != NULL, NULL);
1241   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
1242
1243   if (private->update_area)
1244     {
1245       tmp_region = private->update_area;
1246       private->update_area = NULL;
1247
1248       update_windows = g_slist_remove (update_windows, window);
1249       
1250       return tmp_region;
1251     }
1252   else
1253     return NULL;
1254 }
1255
1256 void
1257 gdk_window_freeze_updates (GdkWindow *window)
1258 {
1259   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
1260
1261   g_return_if_fail (window != NULL);
1262   g_return_if_fail (GDK_IS_WINDOW (window));
1263
1264   private->update_freeze_count++;
1265 }
1266
1267 void
1268 gdk_window_thaw_updates (GdkWindow *window)
1269 {
1270   GdkWindowPrivate *private = (GdkWindowPrivate *)window;
1271
1272   g_return_if_fail (window != NULL);
1273   g_return_if_fail (GDK_IS_WINDOW (window));
1274   g_return_if_fail (private->update_freeze_count > 0);
1275
1276   private->update_freeze_count--;
1277   if (!private->update_freeze_count && private->update_area && !update_idle)
1278     update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
1279                                    gdk_window_update_idle, NULL, NULL);
1280 }
1281