]> Pileus Git - ~andy/gtk/blob - gdk/gdkoffscreenwindow.c
Initial client-side-windows work
[~andy/gtk] / gdk / gdkoffscreenwindow.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-2005.  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 <config.h>
28 #include <math.h>
29 #include "gdk.h"
30 #include "gdkwindow.h"
31 #include "gdkinternals.h"
32 #include "gdkwindowimpl.h"
33 #include "gdkpixmap.h"
34 #include "gdkdrawable.h"
35 #include "gdktypes.h"
36 #include "gdkscreen.h"
37 #include "gdkgc.h"
38 #include "gdkcolor.h"
39 #include "gdkcursor.h"
40 #include "gdkalias.h"
41
42 /* LIMITATIONS:
43  *
44  * Offscreen windows can't be the child of a foreign window,
45  *   nor contain foreign windows
46  * GDK_POINTER_MOTION_HINT_MASK isn't effective
47  */
48
49 typedef struct _GdkOffscreenWindow      GdkOffscreenWindow;
50 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
51
52 struct _GdkOffscreenWindow
53 {
54   GdkDrawable parent_instance;
55
56   GdkWindow *wrapper;
57   GdkCursor *cursor;
58   GdkColormap *colormap;
59   GdkScreen *screen;
60
61   GdkPixmap *pixmap;
62 };
63
64 struct _GdkOffscreenWindowClass
65 {
66   GdkDrawableClass parent_class;
67 };
68
69 #define GDK_TYPE_OFFSCREEN_WINDOW            (gdk_offscreen_window_get_type())
70 #define GDK_OFFSCREEN_WINDOW(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow))
71 #define GDK_IS_OFFSCREEN_WINDOW(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW))
72 #define GDK_OFFSCREEN_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
73 #define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW))
74 #define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
75
76 static void       gdk_offscreen_window_impl_iface_init    (GdkWindowImplIface         *iface);
77 static void       gdk_offscreen_window_hide               (GdkWindow                  *window);
78 static void       gdk_offscreen_window_clear_area         (GdkWindow                  *window,
79                                                            gint                        x,
80                                                            gint                        y,
81                                                            gint                        width,
82                                                            gint                        height,
83                                                            gboolean                    send_expose);
84
85
86 G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow,
87                          gdk_offscreen_window,
88                          GDK_TYPE_DRAWABLE,
89                          G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
90                                                 gdk_offscreen_window_impl_iface_init));
91
92
93 static void
94 gdk_offscreen_window_finalize (GObject *object)
95 {
96   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
97
98   if (offscreen->cursor)
99     gdk_cursor_unref (offscreen->cursor);
100
101   offscreen->cursor = NULL;
102
103   gdk_pixmap_unref (offscreen->pixmap);
104   
105   G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
106 }
107
108 static void
109 gdk_offscreen_window_init (GdkOffscreenWindow *window)
110 {
111 }
112
113 void
114 _gdk_offscreen_window_destroy (GdkWindow *window,
115                                gboolean   recursing)
116 {
117   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
118   GdkOffscreenWindow *offscreen;
119
120   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
121
122   if (!recursing)
123     gdk_offscreen_window_hide (window);
124
125   g_object_unref (offscreen->colormap);
126   offscreen->colormap = NULL;
127 }
128
129 static gboolean
130 is_parent_of (GdkWindow *parent,
131               GdkWindow *child)
132 {
133   GdkWindow *w;
134
135   w = child;
136   while (w != NULL)
137     {
138       if (w == parent)
139         return TRUE;
140
141       w = gdk_window_get_parent (w);
142     }
143
144   return FALSE;
145 }
146
147 static GdkGC *
148 gdk_offscreen_window_create_gc (GdkDrawable     *drawable,
149                                 GdkGCValues     *values,
150                                 GdkGCValuesMask  values_mask)
151 {
152   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
153
154   return gdk_gc_new_with_values (offscreen->pixmap, values, values_mask);
155 }
156
157 static GdkImage*
158 gdk_offscreen_window_copy_to_image (GdkDrawable    *drawable,
159                                     GdkImage       *image,
160                                     gint            src_x,
161                                     gint            src_y,
162                                     gint            dest_x,
163                                     gint            dest_y,
164                                     gint            width,
165                                     gint            height)
166 {
167   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
168
169   return gdk_drawable_copy_to_image (offscreen->pixmap,
170                                      image,
171                                      src_x,
172                                      src_y,
173                                      dest_x, dest_y,
174                                      width, height);
175 }
176
177 static cairo_surface_t *
178 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
179 {
180   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
181   
182   return _gdk_drawable_ref_cairo_surface (offscreen->pixmap);
183 }
184
185 static GdkColormap*
186 gdk_offscreen_window_get_colormap (GdkDrawable *drawable)
187 {
188   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
189
190   return offscreen->colormap;
191 }
192
193 static void
194 gdk_offscreen_window_set_colormap (GdkDrawable *drawable,
195                                    GdkColormap*colormap)
196 {
197   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
198
199   if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper))
200     return;
201
202   if (offscreen->colormap == colormap)
203     return;
204
205   if (offscreen->colormap)
206     g_object_unref (offscreen->colormap);
207
208   offscreen->colormap = colormap;
209   if (offscreen->colormap)
210     g_object_ref (offscreen->colormap);
211 }
212
213
214 static gint
215 gdk_offscreen_window_get_depth (GdkDrawable *drawable)
216 {
217   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
218
219   return gdk_drawable_get_depth (offscreen->wrapper);
220 }
221
222 static GdkDrawable *
223 gdk_offscreen_window_get_source_drawable (GdkDrawable  *drawable)
224 {
225   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
226
227   return _gdk_drawable_get_source_drawable (offscreen->pixmap);
228 }
229
230 static GdkDrawable *
231 gdk_offscreen_window_get_composite_drawable (GdkDrawable *drawable,
232                                              gint         x,
233                                              gint         y,
234                                              gint         width,
235                                              gint         height,
236                                              gint        *composite_x_offset,
237                                              gint        *composite_y_offset)
238 {
239   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
240
241   return g_object_ref (offscreen->pixmap);
242 }
243
244 static GdkScreen*
245 gdk_offscreen_window_get_screen (GdkDrawable *drawable)
246 {
247   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
248
249   return offscreen->screen;
250 }
251
252 static GdkVisual*
253 gdk_offscreen_window_get_visual (GdkDrawable    *drawable)
254 {
255   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
256
257   return gdk_drawable_get_visual (offscreen->wrapper);
258 }
259
260 static void
261 add_damage (GdkOffscreenWindow *offscreen,
262             int x, int y,
263             int w, int h)
264 {
265   GdkRectangle rect;
266   GdkRegion *damage;
267   
268   rect.x = x;
269   rect.y = y;
270   rect.width = w;
271   rect.height = h;
272
273   damage = gdk_region_rectangle (&rect);
274   _gdk_window_add_damage (offscreen->wrapper, damage);
275   gdk_region_destroy (damage);
276 }
277
278 static void
279 gdk_offscreen_window_draw_drawable (GdkDrawable *drawable,
280                                     GdkGC       *gc,
281                                     GdkPixmap   *src,
282                                     gint         xsrc,
283                                     gint         ysrc,
284                                     gint         xdest,
285                                     gint         ydest,
286                                     gint         width,
287                                     gint         height)
288 {
289   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
290   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
291   
292   gdk_draw_drawable (real_drawable, gc,
293                      src, xsrc, ysrc,
294                      xdest, ydest,
295                      width, height);
296
297   add_damage (offscreen, xdest, ydest, width, height);
298 }
299
300 static void
301 gdk_offscreen_window_draw_rectangle (GdkDrawable  *drawable,
302                                      GdkGC        *gc,
303                                      gboolean      filled,
304                                      gint          x,
305                                      gint          y,
306                                      gint          width,
307                                      gint          height)
308 {
309   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
310   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
311
312   gdk_draw_rectangle (real_drawable,
313                       gc, filled, x, y, width, height);
314
315   add_damage (offscreen, x, y, width, height);
316   
317 }
318
319 static void
320 gdk_offscreen_window_draw_arc (GdkDrawable  *drawable,
321                                GdkGC           *gc,
322                                gboolean filled,
323                                gint             x,
324                                gint             y,
325                                gint             width,
326                                gint             height,
327                                gint             angle1,
328                                gint             angle2)
329 {
330   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
331   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
332
333   gdk_draw_arc (real_drawable,
334                 gc,
335                 filled,
336                 x,
337                 y,
338                 width,
339                 height,
340                 angle1,
341                 angle2);
342   add_damage (offscreen, x, y, width, height);
343 }
344
345 static void
346 gdk_offscreen_window_draw_polygon (GdkDrawable  *drawable,
347                                    GdkGC               *gc,
348                                    gboolean     filled,
349                                    GdkPoint     *points,
350                                    gint         npoints)
351 {
352   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
353   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
354   
355   gdk_draw_polygon (real_drawable,
356                     gc,
357                     filled,
358                     points,
359                     npoints);
360
361   if (npoints > 0)
362     {
363       int min_x, min_y, max_x, max_y, i;
364       
365       min_x = max_x = points[0].x;
366       min_y = max_y = points[0].y;
367       
368         for (i = 1; i < npoints; i++)
369           {
370             min_x = MIN (min_x, points[i].x);
371             max_x = MAX (max_x, points[i].x);
372             min_y = MIN (min_y, points[i].y);
373             max_y = MAX (max_y, points[i].y);
374           }
375         
376         add_damage (offscreen, min_x, min_y,
377                     max_x - min_x,
378                     max_y - min_y);
379     }
380 }
381
382 static void
383 gdk_offscreen_window_draw_text (GdkDrawable  *drawable,
384                                 GdkFont      *font,
385                                 GdkGC          *gc,
386                                 gint            x,
387                                 gint            y,
388                                 const gchar  *text,
389                                 gint            text_length)
390 {
391   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
392   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
393   GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper);
394
395   gdk_draw_text (real_drawable,
396                  font,
397                  gc,
398                  x,
399                  y,
400                  text,
401                  text_length);
402
403   /* Hard to compute the minimal size, not that often used anyway. */
404   add_damage (offscreen, 0, 0, private->width, private->height);
405 }
406
407 static void
408 gdk_offscreen_window_draw_text_wc (GdkDrawable   *drawable,
409                                    GdkFont       *font,
410                                    GdkGC                 *gc,
411                                    gint           x,
412                                    gint           y,
413                                    const GdkWChar *text,
414                                    gint           text_length)
415 {
416   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
417   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
418   GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper);
419
420   gdk_draw_text_wc (real_drawable,
421                     font,
422                     gc,
423                     x,
424                     y,
425                     text,
426                     text_length);
427
428   /* Hard to compute the minimal size, not that often used anyway. */
429   add_damage (offscreen, 0, 0, private->width, private->height);
430 }
431
432 static void
433 gdk_offscreen_window_draw_points (GdkDrawable  *drawable,
434                                   GdkGC        *gc,
435                                   GdkPoint     *points,
436                                   gint          npoints)
437 {
438   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
439   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
440
441   gdk_draw_points (real_drawable,
442                    gc,
443                    points,
444                    npoints);
445
446
447   if (npoints > 0)
448     {
449       int min_x, min_y, max_x, max_y, i;
450       
451       min_x = max_x = points[0].x;
452       min_y = max_y = points[0].y;
453       
454         for (i = 1; i < npoints; i++)
455           {
456             min_x = MIN (min_x, points[i].x);
457             max_x = MAX (max_x, points[i].x);
458             min_y = MIN (min_y, points[i].y);
459             max_y = MAX (max_y, points[i].y);
460           }
461         
462         add_damage (offscreen, min_x, min_y,
463                     max_x - min_x,
464                     max_y - min_y);
465     }
466 }
467
468 static void
469 gdk_offscreen_window_draw_segments (GdkDrawable  *drawable,
470                                     GdkGC        *gc,
471                                     GdkSegment   *segs,
472                                     gint          nsegs)
473 {
474   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
475   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
476
477   gdk_draw_segments (real_drawable,
478                      gc,
479                      segs,
480                      nsegs);
481
482   if (nsegs > 0)
483     {
484       int min_x, min_y, max_x, max_y, i;
485       
486       min_x = max_x = segs[0].x1;
487       min_y = max_y = segs[0].y1;
488       
489         for (i = 1; i < nsegs; i++)
490           {
491             min_x = MIN (min_x, segs[i].x1);
492             max_x = MAX (max_x, segs[i].x1);
493             min_x = MIN (min_x, segs[i].x2);
494             max_x = MAX (max_x, segs[i].x2);
495             min_y = MIN (min_y, segs[i].y1);
496             max_y = MAX (max_y, segs[i].y1);
497             min_y = MIN (min_y, segs[i].y2);
498             max_y = MAX (max_y, segs[i].y2);
499           }
500         
501         add_damage (offscreen, min_x, min_y,
502                     max_x - min_x,
503                     max_y - min_y);
504     }
505
506 }
507
508 static void
509 gdk_offscreen_window_draw_lines (GdkDrawable  *drawable,
510                                  GdkGC        *gc,
511                                  GdkPoint     *points,
512                                  gint          npoints)
513 {
514   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
515   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
516   GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper);
517
518   gdk_draw_lines (real_drawable,
519                   gc,
520                   points,
521                   npoints);
522
523   /* Hard to compute the minimal size, as we don't know the line
524      width, and since joins are hard to calculate.
525      Its not that often used anyway, damage it all */
526   add_damage (offscreen, 0, 0, private->width, private->height);
527 }
528
529 static void
530 gdk_offscreen_window_draw_image (GdkDrawable *drawable,
531                                  GdkGC        *gc,
532                                  GdkImage    *image,
533                                  gint          xsrc,
534                                  gint          ysrc,
535                                  gint          xdest,
536                                  gint          ydest,
537                                  gint          width,
538                                  gint          height)
539 {
540   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
541   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
542
543   gdk_draw_image (real_drawable,
544                   gc,
545                   image,
546                   xsrc,
547                   ysrc,
548                   xdest,
549                   ydest,
550                   width,
551                   height);
552
553   add_damage (offscreen, xdest, ydest, width, height);
554 }
555
556
557 static void
558 gdk_offscreen_window_draw_pixbuf (GdkDrawable *drawable,
559                                   GdkGC       *gc,
560                                   GdkPixbuf   *pixbuf,
561                                   gint         src_x,
562                                   gint         src_y,
563                                   gint         dest_x,
564                                   gint         dest_y,
565                                   gint         width,
566                                   gint         height,
567                                   GdkRgbDither dither,
568                                   gint         x_dither,
569                                   gint         y_dither)
570 {
571   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
572   GdkDrawable *real_drawable = GDK_DRAWABLE (offscreen->pixmap);
573   
574   gdk_draw_pixbuf (real_drawable,
575                    gc,
576                    pixbuf,
577                    src_x,
578                    src_y,
579                    dest_x,
580                    dest_y,
581                    width,
582                    height,
583                    dither,
584                    x_dither,
585                    y_dither);
586
587   add_damage (offscreen, dest_x, dest_y, width, height);
588
589 }
590
591 void 
592 _gdk_offscreen_window_new (GdkWindow     *window,
593                            GdkScreen     *screen,
594                            GdkVisual     *visual,
595                            GdkWindowAttr *attributes,
596                            gint           attributes_mask)
597 {
598   GdkWindowObject *parent_private;
599   GdkWindowObject *private;
600   GdkOffscreenWindow *offscreen;
601
602   g_return_if_fail (attributes != NULL);
603
604   if (attributes->wclass != GDK_INPUT_OUTPUT)
605     return; /* Can't support input only offscreens */
606   
607   private = (GdkWindowObject *)window;
608
609   if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
610     return;
611
612   parent_private = (GdkWindowObject*) private->parent;
613   private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
614   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
615   offscreen->wrapper = window;
616
617   offscreen->screen = screen;
618
619   if (attributes_mask & GDK_WA_COLORMAP)
620     offscreen->colormap = g_object_ref (attributes->colormap);
621   else
622     {
623       if (gdk_screen_get_system_visual (screen) == visual)
624         {
625           offscreen->colormap = gdk_screen_get_system_colormap (screen);
626           g_object_ref (offscreen->colormap);
627         }
628       else
629         offscreen->colormap = gdk_colormap_new (visual, FALSE);
630     }
631
632   offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent,
633                                       private->width,
634                                       private->height,
635                                       private->depth);
636 }
637
638 static gboolean
639 gdk_offscreen_window_reparent (GdkWindow *window,
640                                GdkWindow *new_parent,
641                                gint       x,
642                                gint       y)
643 {
644   GdkWindowObject *private = (GdkWindowObject *)window;
645   GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
646   GdkWindowObject *old_parent;
647   GdkOffscreenWindow *offscreen;
648   gboolean was_mapped;
649
650   if (new_parent)
651     {
652       /* No input-output children of input-only windows */
653       if (new_parent_private->input_only && !private->input_only)
654         return FALSE;
655       
656       /* Don't create loops in hierarchy */
657       if (is_parent_of (window, new_parent))
658         return FALSE;
659     }
660
661   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
662
663   was_mapped = GDK_WINDOW_IS_MAPPED (window);
664
665   gdk_window_hide (window);
666
667   if (private->parent)
668     private->parent->children = g_list_remove (private->parent->children, window);
669
670   old_parent = private->parent;
671   private->parent = new_parent_private;
672   private->x = x;
673   private->y = y;
674
675   if (new_parent_private)
676     private->parent->children = g_list_prepend (private->parent->children, window);
677
678   _gdk_syntesize_crossing_events_for_geometry_change (window);
679   if (old_parent)
680     _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
681   
682   return was_mapped;
683 }
684
685 static gint
686 gdk_offscreen_window_get_origin (GdkWindow *window,
687                                  gint      *x,
688                                  gint      *y)
689 {
690   if (x)
691     *x = 0;
692   if (y)
693     *y = 0;
694
695   return TRUE;
696 }
697
698 /**
699  * gdk_window_get_offscreen_pixmap:
700  * @window: a #GdkWindow
701  *
702  * Gets the offscreen pixmap that an offscreen window renders into. If
703  * you need to keep this around over window resizes, you need to add a
704  * reference to it.
705  *
706  * Returns: The offscreen pixmap, or NULL if not offscreen
707  **/
708 GdkPixmap *
709 gdk_window_get_offscreen_pixmap (GdkWindow *window)
710 {
711   GdkWindowObject *private = (GdkWindowObject *)window;
712   GdkOffscreenWindow *offscreen;
713   
714   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
715
716   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
717     return NULL;
718   
719   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
720   return offscreen->pixmap;
721 }
722
723 static void
724 gdk_offscreen_window_raise (GdkWindow *window)
725 {
726   /* gdk_window_raise already changed the stacking order */
727   _gdk_syntesize_crossing_events_for_geometry_change (window);
728 }
729
730 static void
731 gdk_offscreen_window_lower (GdkWindow *window)
732 {
733   /* gdk_window_lower already changed the stacking order */
734   _gdk_syntesize_crossing_events_for_geometry_change (window);
735 }
736
737 static void
738 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
739                                            gint       x,
740                                            gint       y,
741                                            gint       width,
742                                            gint       height,
743                                            gboolean   send_expose_events)
744 {
745   GdkWindowObject *private = (GdkWindowObject *)window;
746   GdkOffscreenWindow *offscreen;
747   gint dx, dy, dw, dh;
748   GdkGC *gc;
749   GdkPixmap *old_pixmap;
750
751   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
752
753   if (width < 1)
754     width = 1;
755   if (height < 1)
756     height = 1;
757
758   if (private->destroyed)
759     return;
760
761   dx = x - private->x;
762   dy = y - private->y;
763   dw = width - private->width;
764   dh = height - private->height;
765
766   private->x = x;
767   private->y = y;
768
769   if (private->width != width ||
770       private->height != height)
771     {
772       private->width = width;
773       private->height = height;
774       
775       old_pixmap = offscreen->pixmap;
776       offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
777                                           width,
778                                           height,
779                                           private->depth);
780
781       gc = _gdk_drawable_get_scratch_gc (offscreen->pixmap, FALSE);
782       gdk_draw_drawable (offscreen->pixmap,
783                          gc,
784                          old_pixmap,
785                          0,0, 0, 0,
786                          -1, -1);
787       g_object_unref (old_pixmap);
788     }
789   
790   if (GDK_WINDOW_IS_MAPPED (private))
791     {
792       // TODO: Only invalidate new area, i.e. for larger windows
793       gdk_window_invalidate_rect (window, NULL, TRUE);
794       _gdk_syntesize_crossing_events_for_geometry_change (window);
795     }
796 }
797
798 static void
799 gdk_offscreen_window_move_resize (GdkWindow *window,
800                                   gboolean   with_move,
801                                   gint       x,
802                                   gint       y,
803                                   gint       width,
804                                   gint       height)
805 {
806   GdkWindowObject *private = (GdkWindowObject *)window;
807   GdkOffscreenWindow *offscreen;
808
809   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
810
811   if (!with_move)
812     {
813       x = private->x;
814       y = private->y;
815     }
816
817   if (width < 0)
818     width = private->width;
819
820   if (height < 0)
821     height = private->height;
822
823   gdk_offscreen_window_move_resize_internal (window, x, y,
824                                              width, height,
825                                              TRUE);
826 }
827
828 static void
829 gdk_offscreen_window_show (GdkWindow *window, gboolean raise)
830 {
831   GdkWindowObject *private = (GdkWindowObject *)window;
832   GdkOffscreenWindow *offscreen;
833
834   if (GDK_WINDOW_IS_MAPPED (window))
835     return;
836
837   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
838
839   private->state = 0;
840
841   /* gdk_window_show already changed the stacking order if needed */
842
843   if (private->event_mask & GDK_STRUCTURE_MASK)
844     _gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE);
845   
846   if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
847     _gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE);
848
849   if (gdk_window_is_viewable (window))
850     _gdk_syntesize_crossing_events_for_geometry_change (window);
851   
852   gdk_window_clear_area_e (window, 0, 0,
853                            private->width, private->height);
854 }
855
856
857 static void
858 gdk_offscreen_window_hide (GdkWindow *window)
859 {
860   GdkWindowObject *private;
861   GdkOffscreenWindow *offscreen;
862   GdkDisplay *display;
863
864   g_return_if_fail (window != NULL);
865
866   private = (GdkWindowObject*) window;
867   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
868
869   if (!GDK_WINDOW_IS_MAPPED (private))
870     return;
871   
872   /* May need to break grabs on children */
873   display = gdk_drawable_get_display (window);
874   
875   if (display->pointer_grab.window != NULL)
876     {
877       if (is_parent_of (window, display->pointer_grab.window))
878         {
879           /* Call this ourselves, even though gdk_display_pointer_ungrab
880              does so too, since we want to pass implicit == TRUE so the
881              broken grab event is generated */
882           _gdk_display_unset_has_pointer_grab (display,
883                                                TRUE,
884                                                FALSE,
885                                                GDK_CURRENT_TIME);
886           gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
887         }
888     }
889
890   if (private->event_mask & GDK_STRUCTURE_MASK)
891     _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
892   
893   if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
894     _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
895   
896   private->state = GDK_WINDOW_STATE_WITHDRAWN;
897   
898   _gdk_syntesize_crossing_events_for_geometry_change (window);
899 }
900
901 static void
902 gdk_offscreen_window_withdraw (GdkWindow *window)
903 {
904 }
905
906 static GdkEventMask
907 gdk_offscreen_window_get_events (GdkWindow *window)
908 {
909   return 0;
910 }
911
912 static void
913 gdk_offscreen_window_set_events (GdkWindow       *window,
914                                  GdkEventMask     event_mask)
915 {
916 }
917
918 static GdkGC *
919 setup_backing_rect_gc (GdkWindow *window, int x_offset, int y_offset)
920 {
921   GdkWindowObject *private = (GdkWindowObject *)window;
922   GdkGC *gc;
923
924   if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
925     {
926       x_offset += private->x;
927       y_offset += private->y;
928       
929       return setup_backing_rect_gc (GDK_WINDOW (private->parent), x_offset, y_offset);
930     }
931   else if (private->bg_pixmap &&
932            private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
933            private->bg_pixmap != GDK_NO_BG)
934     {
935       guint gc_mask;
936       GdkGCValues gc_values;
937
938       gc_values.fill = GDK_TILED;
939       gc_values.tile = private->bg_pixmap;
940       gc_values.ts_x_origin = -x_offset;
941       gc_values.ts_y_origin = -y_offset;
942
943       gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN;
944
945       return gdk_gc_new_with_values (window, &gc_values, gc_mask);
946     }
947   else
948     {
949       gc = _gdk_drawable_get_scratch_gc (window, FALSE);
950       g_object_ref (gc);
951       gdk_gc_set_foreground (gc, &private->bg_color);
952       return gc;
953     }
954 }
955
956 static void
957 gdk_offscreen_window_clear_area (GdkWindow *window,
958                                  gint       x,
959                                  gint       y,
960                                  gint       width,
961                                  gint       height,
962                                  gboolean   send_expose)
963 {
964   GdkGC *gc;
965   
966   if (GDK_WINDOW_DESTROYED (window))
967     return;
968
969   /* Actual drawing is done by gdkwindow.c */
970
971   gc = setup_backing_rect_gc (window, 0, 0);
972   gdk_draw_rectangle (window, gc, TRUE, x, y, width, height);
973   g_object_unref (gc);
974   
975   if (send_expose)
976     {
977       GdkRectangle visible, rect;
978
979       visible.x = visible.y = 0;
980       gdk_drawable_get_size (GDK_DRAWABLE (window), &visible.width, &visible.height);
981
982       rect.x = x;
983       rect.y = x;
984       rect.width = width;
985       rect.height = height;
986
987       gdk_rectangle_intersect (&rect, &visible, &rect);
988
989       gdk_window_invalidate_rect (window, &rect, TRUE);
990     }
991 }
992
993 static void
994 gdk_offscreen_window_set_background (GdkWindow      *window,
995                                      const GdkColor *color)
996 {
997   GdkWindowObject *private = (GdkWindowObject *)window;
998   GdkColormap *colormap = gdk_drawable_get_colormap (window);
999
1000   private->bg_color = *color;
1001   gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
1002
1003   if (private->bg_pixmap &&
1004       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1005       private->bg_pixmap != GDK_NO_BG)
1006     g_object_unref (private->bg_pixmap);
1007
1008   private->bg_pixmap = NULL;
1009 }
1010
1011 static void
1012 gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
1013                                       GdkPixmap *pixmap)
1014 {
1015   GdkWindowObject *private = (GdkWindowObject *)window;
1016
1017   if (pixmap &&
1018       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1019       private->bg_pixmap != GDK_NO_BG &&
1020       !gdk_drawable_get_colormap (pixmap))
1021     {
1022       g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
1023       return;
1024     }
1025
1026   if (private->bg_pixmap &&
1027       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1028       private->bg_pixmap != GDK_NO_BG)
1029     g_object_unref (private->bg_pixmap);
1030
1031   private->bg_pixmap = pixmap;
1032
1033   if (pixmap &&
1034       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1035       private->bg_pixmap != GDK_NO_BG)
1036     g_object_ref (pixmap);
1037 }
1038
1039 static void
1040 gdk_offscreen_window_shape_combine_mask (GdkWindow *window,
1041                                          GdkBitmap *mask,
1042                                          gint       x,
1043                                          gint       y)
1044 {
1045 }
1046
1047 static void
1048 gdk_offscreen_window_shape_combine_region (GdkWindow       *window,
1049                                            const GdkRegion *shape_region,
1050                                            gint             offset_x,
1051                                            gint             offset_y)
1052 {
1053 }
1054
1055 static void
1056 gdk_offscreen_window_set_child_shapes (GdkWindow *window)
1057 {
1058 }
1059
1060 static void
1061 gdk_offscreen_window_merge_child_shapes (GdkWindow *window)
1062 {
1063 }
1064
1065 static gboolean
1066 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
1067                                            gboolean   use_static)
1068 {
1069   return TRUE;
1070 }
1071
1072 static void
1073 gdk_offscreen_window_set_cursor (GdkWindow *window,
1074                                  GdkCursor *cursor)
1075 {
1076   GdkWindowObject *private = (GdkWindowObject *)window;
1077   GdkOffscreenWindow *offscreen;
1078
1079   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
1080
1081   if (offscreen->cursor)
1082     {
1083       gdk_cursor_unref (offscreen->cursor);
1084       offscreen->cursor = NULL;
1085     }
1086
1087   if (cursor)
1088     offscreen->cursor = gdk_cursor_ref (cursor);
1089
1090   /* TODO: The cursor is never actually used... */
1091 }
1092
1093 static void
1094 gdk_offscreen_window_get_geometry (GdkWindow *window,
1095                                    gint      *x,
1096                                    gint      *y,
1097                                    gint      *width,
1098                                    gint      *height,
1099                                    gint      *depth)
1100 {
1101   GdkWindowObject *private = (GdkWindowObject *)window;
1102   GdkOffscreenWindow *offscreen;
1103
1104   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
1105
1106   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
1107
1108   if (!GDK_WINDOW_DESTROYED (window))
1109     {
1110       if (x)
1111         *x = private->x;
1112       if (y)
1113         *y = private->y;
1114       if (width)
1115         *width = private->width;
1116       if (height)
1117         *height = private->height;
1118       if (depth)
1119         *depth = private->depth;
1120     }
1121 }
1122
1123 /**
1124  * gdk_window_set_offscreen_hooks:
1125  * @offscreen_window: a offscreen #GdkWindow
1126  * @hooks:  a table of pointers to functions for handling offscreen
1127  *          window coordinates translations
1128  *
1129  * Sets the parent-to-offscreen-child and offscreen-child-to-parent coordinate
1130  * translation functions for offscreen windows.
1131  *
1132  * This function is useful for complex widgets employing
1133  * offscreen windows.
1134  *
1135  * Since: 2.16
1136  */
1137 void
1138 gdk_window_set_offscreen_hooks (GdkWindow  *offscreen_window,
1139                                 const GdkOffscreenChildHooks *hooks)
1140 {
1141   GdkWindowObject *private;
1142
1143   g_return_if_fail (GDK_IS_WINDOW (offscreen_window));
1144   g_return_if_fail (hooks != NULL);
1145
1146   private = (GdkWindowObject *) offscreen_window;
1147
1148   private->offscreen_hooks = hooks;
1149 }
1150
1151 static gboolean
1152 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
1153                                        GdkRegion *area)
1154 {
1155   return FALSE;
1156 }
1157
1158 static void
1159 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
1160 {
1161   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
1162   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1163
1164   object_class->finalize = gdk_offscreen_window_finalize;
1165
1166   drawable_class->create_gc = gdk_offscreen_window_create_gc;
1167   drawable_class->_copy_to_image = gdk_offscreen_window_copy_to_image;
1168   drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
1169   drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
1170   drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
1171   drawable_class->get_depth = gdk_offscreen_window_get_depth;
1172   drawable_class->get_screen = gdk_offscreen_window_get_screen;
1173   drawable_class->get_visual = gdk_offscreen_window_get_visual;
1174   drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
1175   drawable_class->get_composite_drawable = gdk_offscreen_window_get_composite_drawable;
1176
1177   drawable_class->draw_rectangle = gdk_offscreen_window_draw_rectangle;
1178   drawable_class->draw_arc = gdk_offscreen_window_draw_arc;
1179   drawable_class->draw_polygon = gdk_offscreen_window_draw_polygon;
1180   drawable_class->draw_text = gdk_offscreen_window_draw_text;
1181   drawable_class->draw_text_wc = gdk_offscreen_window_draw_text_wc;
1182   drawable_class->draw_drawable = gdk_offscreen_window_draw_drawable;
1183   drawable_class->draw_points = gdk_offscreen_window_draw_points;
1184   drawable_class->draw_segments = gdk_offscreen_window_draw_segments;
1185   drawable_class->draw_lines = gdk_offscreen_window_draw_lines;
1186   drawable_class->draw_image = gdk_offscreen_window_draw_image;
1187   drawable_class->draw_pixbuf = gdk_offscreen_window_draw_pixbuf;
1188 }
1189
1190 static void
1191 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
1192 {
1193   iface->show = gdk_offscreen_window_show;
1194   iface->hide = gdk_offscreen_window_hide;
1195   iface->withdraw = gdk_offscreen_window_withdraw;
1196   iface->raise = gdk_offscreen_window_raise;
1197   iface->lower = gdk_offscreen_window_lower;
1198   iface->move_resize = gdk_offscreen_window_move_resize;
1199   iface->set_background = gdk_offscreen_window_set_background;
1200   iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
1201   iface->get_events = gdk_offscreen_window_get_events;
1202   iface->set_events = gdk_offscreen_window_set_events;
1203   iface->clear_area = gdk_offscreen_window_clear_area;
1204   iface->reparent = gdk_offscreen_window_reparent;
1205   iface->set_cursor = gdk_offscreen_window_set_cursor;
1206   iface->get_geometry = gdk_offscreen_window_get_geometry;
1207   iface->shape_combine_mask = gdk_offscreen_window_shape_combine_mask;
1208   iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
1209   iface->set_child_shapes = gdk_offscreen_window_set_child_shapes;
1210   iface->merge_child_shapes = gdk_offscreen_window_merge_child_shapes;
1211   iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
1212   iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
1213   iface->get_origin = gdk_offscreen_window_get_origin;
1214 }
1215
1216 #define __GDK_OFFSCREEN_WINDOW_C__
1217 #include "gdkaliasdef.c"