]> Pileus Git - ~andy/gtk/blob - gdk/gdkoffscreenwindow.c
generic damage generation for offscreen windows
[~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 "gdkcolor.h"
38 #include "gdkcursor.h"
39
40
41 /* LIMITATIONS:
42  *
43  * Offscreen windows can't be the child of a foreign window,
44  *   nor contain foreign windows
45  * GDK_POINTER_MOTION_HINT_MASK isn't effective
46  */
47
48 typedef struct _GdkOffscreenWindow      GdkOffscreenWindow;
49 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
50
51 struct _GdkOffscreenWindow
52 {
53   GdkDrawable parent_instance;
54
55   GdkWindow *wrapper;
56   GdkCursor *cursor;
57   GdkColormap *colormap;
58   GdkScreen *screen;
59
60   GdkPixmap *pixmap;
61   GdkWindow *embedder;
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
79 G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow,
80                          gdk_offscreen_window,
81                          GDK_TYPE_DRAWABLE,
82                          G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
83                                                 gdk_offscreen_window_impl_iface_init));
84
85
86 static void
87 gdk_offscreen_window_finalize (GObject *object)
88 {
89   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
90
91   if (offscreen->cursor)
92     gdk_cursor_unref (offscreen->cursor);
93
94   offscreen->cursor = NULL;
95
96   g_object_unref (offscreen->pixmap);
97
98   G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
99 }
100
101 static void
102 gdk_offscreen_window_init (GdkOffscreenWindow *window)
103 {
104 }
105
106 static void
107 gdk_offscreen_window_destroy (GdkWindow *window,
108                               gboolean   recursing,
109                               gboolean   foreign_destroy)
110 {
111   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
112   GdkOffscreenWindow *offscreen;
113
114   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
115
116   gdk_offscreen_window_set_embedder (window, NULL);
117   
118   if (!recursing)
119     gdk_offscreen_window_hide (window);
120
121   g_object_unref (offscreen->colormap);
122   offscreen->colormap = NULL;
123 }
124
125 static gboolean
126 is_parent_of (GdkWindow *parent,
127               GdkWindow *child)
128 {
129   GdkWindow *w;
130
131   w = child;
132   while (w != NULL)
133     {
134       if (w == parent)
135         return TRUE;
136
137       w = gdk_window_get_parent (w);
138     }
139
140   return FALSE;
141 }
142
143 static cairo_surface_t *
144 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
145 {
146   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
147
148   return _gdk_drawable_ref_cairo_surface (offscreen->pixmap);
149 }
150
151 static GdkColormap*
152 gdk_offscreen_window_get_colormap (GdkDrawable *drawable)
153 {
154   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
155
156   return offscreen->colormap;
157 }
158
159 static void
160 gdk_offscreen_window_set_colormap (GdkDrawable *drawable,
161                                    GdkColormap*colormap)
162 {
163   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
164
165   if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper))
166     return;
167
168   if (offscreen->colormap == colormap)
169     return;
170
171   if (offscreen->colormap)
172     g_object_unref (offscreen->colormap);
173
174   offscreen->colormap = colormap;
175   if (offscreen->colormap)
176     g_object_ref (offscreen->colormap);
177 }
178
179
180 static gint
181 gdk_offscreen_window_get_depth (GdkDrawable *drawable)
182 {
183   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
184
185   return gdk_drawable_get_depth (offscreen->wrapper);
186 }
187
188 static GdkDrawable *
189 gdk_offscreen_window_get_source_drawable (GdkDrawable  *drawable)
190 {
191   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
192
193   return _gdk_drawable_get_source_drawable (offscreen->pixmap);
194 }
195
196 static GdkScreen*
197 gdk_offscreen_window_get_screen (GdkDrawable *drawable)
198 {
199   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
200
201   return offscreen->screen;
202 }
203
204 static GdkVisual*
205 gdk_offscreen_window_get_visual (GdkDrawable    *drawable)
206 {
207   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
208
209   return gdk_drawable_get_visual (offscreen->wrapper);
210 }
211
212 void
213 _gdk_offscreen_window_new (GdkWindow     *window,
214                            GdkScreen     *screen,
215                            GdkVisual     *visual,
216                            GdkWindowAttr *attributes,
217                            gint           attributes_mask)
218 {
219   GdkWindowObject *private;
220   GdkOffscreenWindow *offscreen;
221
222   g_return_if_fail (attributes != NULL);
223
224   if (attributes->wclass != GDK_INPUT_OUTPUT)
225     return; /* Can't support input only offscreens */
226
227   private = (GdkWindowObject *)window;
228
229   if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
230     return;
231
232   private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
233   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
234   offscreen->wrapper = window;
235
236   offscreen->screen = screen;
237
238   if (attributes_mask & GDK_WA_COLORMAP)
239     offscreen->colormap = g_object_ref (attributes->colormap);
240   else
241     {
242       if (gdk_screen_get_system_visual (screen) == visual)
243         {
244           offscreen->colormap = gdk_screen_get_system_colormap (screen);
245           g_object_ref (offscreen->colormap);
246         }
247       else
248         offscreen->colormap = gdk_colormap_new (visual, FALSE);
249     }
250
251   offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent,
252                                       private->width,
253                                       private->height,
254                                       private->depth);
255   gdk_drawable_set_colormap (offscreen->pixmap, offscreen->colormap);
256 }
257
258 static gboolean
259 gdk_offscreen_window_reparent (GdkWindow *window,
260                                GdkWindow *new_parent,
261                                gint       x,
262                                gint       y)
263 {
264   GdkWindowObject *private = (GdkWindowObject *)window;
265   GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
266   GdkWindowObject *old_parent;
267   gboolean was_mapped;
268
269   if (new_parent)
270     {
271       /* No input-output children of input-only windows */
272       if (new_parent_private->input_only && !private->input_only)
273         return FALSE;
274
275       /* Don't create loops in hierarchy */
276       if (is_parent_of (window, new_parent))
277         return FALSE;
278     }
279
280   was_mapped = GDK_WINDOW_IS_MAPPED (window);
281
282   gdk_window_hide (window);
283
284   if (private->parent)
285     private->parent->children = g_list_remove (private->parent->children, window);
286
287   old_parent = private->parent;
288   private->parent = new_parent_private;
289   private->x = x;
290   private->y = y;
291
292   if (new_parent_private)
293     private->parent->children = g_list_prepend (private->parent->children, window);
294
295   _gdk_synthesize_crossing_events_for_geometry_change (window);
296   if (old_parent)
297     _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
298
299   return was_mapped;
300 }
301
302 static void
303 from_embedder (GdkWindow *window,
304                double embedder_x, double embedder_y,
305                double *offscreen_x, double *offscreen_y)
306 {
307   GdkWindowObject *private;
308
309   private = (GdkWindowObject *)window;
310
311   g_signal_emit_by_name (private->impl_window,
312                          "from-embedder",
313                          embedder_x, embedder_y,
314                          offscreen_x, offscreen_y,
315                          NULL);
316 }
317
318 static void
319 to_embedder (GdkWindow *window,
320              double offscreen_x, double offscreen_y,
321              double *embedder_x, double *embedder_y)
322 {
323   GdkWindowObject *private;
324
325   private = (GdkWindowObject *)window;
326
327   g_signal_emit_by_name (private->impl_window,
328                          "to-embedder",
329                          offscreen_x, offscreen_y,
330                          embedder_x, embedder_y,
331                          NULL);
332 }
333
334 static gint
335 gdk_offscreen_window_get_root_coords (GdkWindow *window,
336                                       gint       x,
337                                       gint       y,
338                                       gint      *root_x,
339                                       gint      *root_y)
340 {
341   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
342   GdkOffscreenWindow *offscreen;
343   int tmpx, tmpy;
344
345   tmpx = x;
346   tmpy = y;
347
348   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
349   if (offscreen->embedder)
350     {
351       double dx, dy;
352       to_embedder (window,
353                    x, y,
354                    &dx, &dy);
355       tmpx = floor (dx + 0.5);
356       tmpy = floor (dy + 0.5);
357       gdk_window_get_root_coords (offscreen->embedder,
358                                   tmpx, tmpy,
359                                   &tmpx, &tmpy);
360
361     }
362
363   if (root_x)
364     *root_x = tmpx;
365   if (root_y)
366     *root_y = tmpy;
367
368   return TRUE;
369 }
370
371 static gint
372 gdk_offscreen_window_get_deskrelative_origin (GdkWindow *window,
373                                               gint      *x,
374                                               gint      *y)
375 {
376   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
377   GdkOffscreenWindow *offscreen;
378   int tmpx, tmpy;
379
380   tmpx = 0;
381   tmpy = 0;
382
383   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
384   if (offscreen->embedder)
385     {
386       double dx, dy;
387       gdk_window_get_deskrelative_origin (offscreen->embedder,
388                                           &tmpx, &tmpy);
389
390       to_embedder (window,
391                    0, 0,
392                    &dx, &dy);
393       tmpx = floor (tmpx + dx + 0.5);
394       tmpy = floor (tmpy + dy + 0.5);
395     }
396
397
398   if (x)
399     *x = tmpx;
400   if (y)
401     *y = tmpy;
402
403   return TRUE;
404 }
405
406 static gboolean
407 gdk_offscreen_window_get_device_state (GdkWindow       *window,
408                                        GdkDevice       *device,
409                                        gint            *x,
410                                        gint            *y,
411                                        GdkModifierType *mask)
412 {
413   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
414   GdkOffscreenWindow *offscreen;
415   int tmpx, tmpy;
416   double dtmpx, dtmpy;
417   GdkModifierType tmpmask;
418
419   tmpx = 0;
420   tmpy = 0;
421   tmpmask = 0;
422
423   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
424   if (offscreen->embedder != NULL)
425     {
426       gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
427       from_embedder (window,
428                      tmpx, tmpy,
429                      &dtmpx, &dtmpy);
430       tmpx = floor (dtmpx + 0.5);
431       tmpy = floor (dtmpy + 0.5);
432     }
433
434   if (x)
435     *x = tmpx;
436   if (y)
437     *y = tmpy;
438   if (mask)
439     *mask = tmpmask;
440   return TRUE;
441 }
442
443 /**
444  * gdk_offscreen_window_get_pixmap:
445  * @window: a #GdkWindow
446  *
447  * Gets the offscreen pixmap that an offscreen window renders into.
448  * If you need to keep this around over window resizes, you need to
449  * add a reference to it.
450  *
451  * Returns: The offscreen pixmap, or %NULL if not offscreen
452  *
453  * Since: 2.18
454  */
455 GdkPixmap *
456 gdk_offscreen_window_get_pixmap (GdkWindow *window)
457 {
458   GdkWindowObject *private = (GdkWindowObject *)window;
459   GdkOffscreenWindow *offscreen;
460
461   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
462
463   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
464     return NULL;
465
466   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
467   return offscreen->pixmap;
468 }
469
470 static void
471 gdk_offscreen_window_raise (GdkWindow *window)
472 {
473   /* gdk_window_raise already changed the stacking order */
474   _gdk_synthesize_crossing_events_for_geometry_change (window);
475 }
476
477 static void
478 gdk_offscreen_window_lower (GdkWindow *window)
479 {
480   /* gdk_window_lower already changed the stacking order */
481   _gdk_synthesize_crossing_events_for_geometry_change (window);
482 }
483
484 static void
485 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
486                                            gint       x,
487                                            gint       y,
488                                            gint       width,
489                                            gint       height,
490                                            gboolean   send_expose_events)
491 {
492   GdkWindowObject *private = (GdkWindowObject *)window;
493   GdkOffscreenWindow *offscreen;
494   gint dx, dy, dw, dh;
495   GdkPixmap *old_pixmap;
496
497   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
498
499   if (width < 1)
500     width = 1;
501   if (height < 1)
502     height = 1;
503
504   if (private->destroyed)
505     return;
506
507   dx = x - private->x;
508   dy = y - private->y;
509   dw = width - private->width;
510   dh = height - private->height;
511
512   private->x = x;
513   private->y = y;
514
515   if (private->width != width ||
516       private->height != height)
517     {
518       cairo_t *cr;
519
520       private->width = width;
521       private->height = height;
522
523       old_pixmap = offscreen->pixmap;
524       offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
525                                           width,
526                                           height,
527                                           private->depth);
528
529       cr = gdk_cairo_create (offscreen->pixmap);
530       gdk_cairo_set_source_pixmap (cr, old_pixmap, 0, 0);
531       cairo_paint (cr);
532       cairo_destroy (cr);
533     }
534
535   if (GDK_WINDOW_IS_MAPPED (private))
536     {
537       // TODO: Only invalidate new area, i.e. for larger windows
538       gdk_window_invalidate_rect (window, NULL, TRUE);
539       _gdk_synthesize_crossing_events_for_geometry_change (window);
540     }
541 }
542
543 static void
544 gdk_offscreen_window_move_resize (GdkWindow *window,
545                                   gboolean   with_move,
546                                   gint       x,
547                                   gint       y,
548                                   gint       width,
549                                   gint       height)
550 {
551   GdkWindowObject *private = (GdkWindowObject *)window;
552   GdkOffscreenWindow *offscreen;
553
554   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
555
556   if (!with_move)
557     {
558       x = private->x;
559       y = private->y;
560     }
561
562   if (width < 0)
563     width = private->width;
564
565   if (height < 0)
566     height = private->height;
567
568   gdk_offscreen_window_move_resize_internal (window, x, y,
569                                              width, height,
570                                              TRUE);
571 }
572
573 static void
574 gdk_offscreen_window_show (GdkWindow *window,
575                            gboolean already_mapped)
576 {
577   GdkWindowObject *private = (GdkWindowObject *)window;
578
579   gdk_window_clear_area_e (window, 0, 0,
580                            private->width, private->height);
581 }
582
583
584 static void
585 gdk_offscreen_window_hide (GdkWindow *window)
586 {
587   GdkWindowObject *private;
588   GdkOffscreenWindow *offscreen;
589   GdkDisplay *display;
590
591   g_return_if_fail (window != NULL);
592
593   private = (GdkWindowObject*) window;
594   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
595
596   /* May need to break grabs on children */
597   display = gdk_drawable_get_display (window);
598
599   /* TODO: This needs updating to the new grab world */
600 #if 0
601   if (display->pointer_grab.window != NULL)
602     {
603       if (is_parent_of (window, display->pointer_grab.window))
604         {
605           /* Call this ourselves, even though gdk_display_pointer_ungrab
606              does so too, since we want to pass implicit == TRUE so the
607              broken grab event is generated */
608           _gdk_display_unset_has_pointer_grab (display,
609                                                TRUE,
610                                                FALSE,
611                                                GDK_CURRENT_TIME);
612           gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
613         }
614     }
615 #endif
616 }
617
618 static void
619 gdk_offscreen_window_withdraw (GdkWindow *window)
620 {
621 }
622
623 static GdkEventMask
624 gdk_offscreen_window_get_events (GdkWindow *window)
625 {
626   return 0;
627 }
628
629 static void
630 gdk_offscreen_window_set_events (GdkWindow       *window,
631                                  GdkEventMask     event_mask)
632 {
633 }
634
635 static void
636 gdk_offscreen_window_set_background (GdkWindow      *window,
637                                      const GdkColor *color)
638 {
639   GdkWindowObject *private = (GdkWindowObject *)window;
640
641   private->bg_color = *color;
642
643   if (private->bg_pixmap &&
644       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
645       private->bg_pixmap != GDK_NO_BG)
646     g_object_unref (private->bg_pixmap);
647
648   private->bg_pixmap = NULL;
649 }
650
651 static void
652 gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
653                                       GdkPixmap *pixmap)
654 {
655   GdkWindowObject *private = (GdkWindowObject *)window;
656
657   if (pixmap &&
658       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
659       private->bg_pixmap != GDK_NO_BG &&
660       !gdk_drawable_get_colormap (pixmap))
661     {
662       g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
663       return;
664     }
665
666   if (private->bg_pixmap &&
667       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
668       private->bg_pixmap != GDK_NO_BG)
669     g_object_unref (private->bg_pixmap);
670
671   private->bg_pixmap = pixmap;
672
673   if (pixmap &&
674       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
675       private->bg_pixmap != GDK_NO_BG)
676     g_object_ref (pixmap);
677 }
678
679 static void
680 gdk_offscreen_window_shape_combine_region (GdkWindow       *window,
681                                            const cairo_region_t *shape_region,
682                                            gint             offset_x,
683                                            gint             offset_y)
684 {
685 }
686
687 static void
688 gdk_offscreen_window_input_shape_combine_region (GdkWindow       *window,
689                                                  const cairo_region_t *shape_region,
690                                                  gint             offset_x,
691                                                  gint             offset_y)
692 {
693 }
694
695 static gboolean
696 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
697                                            gboolean   use_static)
698 {
699   return TRUE;
700 }
701
702 static void
703 gdk_offscreen_window_get_geometry (GdkWindow *window,
704                                    gint      *x,
705                                    gint      *y,
706                                    gint      *width,
707                                    gint      *height,
708                                    gint      *depth)
709 {
710   GdkWindowObject *private = (GdkWindowObject *)window;
711
712   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
713
714   if (!GDK_WINDOW_DESTROYED (window))
715     {
716       if (x)
717         *x = private->x;
718       if (y)
719         *y = private->y;
720       if (width)
721         *width = private->width;
722       if (height)
723         *height = private->height;
724       if (depth)
725         *depth = private->depth;
726     }
727 }
728
729 static gboolean
730 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
731                                        cairo_region_t *area)
732 {
733   return FALSE;
734 }
735
736 static void
737 gdk_offscreen_window_translate (GdkWindow      *window,
738                                 cairo_region_t *area,
739                                 gint            dx,
740                                 gint            dy)
741 {
742   cairo_surface_t *surface;
743   cairo_t *cr;
744
745   /* Can't use gdk_cairo_create here due to clipping */
746   surface = _gdk_drawable_ref_cairo_surface (window);
747   cr = cairo_create (surface);
748   cairo_surface_destroy (surface);
749
750   area = cairo_region_copy (area);
751
752   gdk_cairo_region (cr, area);
753   cairo_clip (cr);
754   
755   /* NB: This is a self-copy and Cairo doesn't support that yet.
756    * So we do a litle trick.
757    */
758   cairo_push_group (cr);
759
760   gdk_cairo_set_source_pixmap (cr, window, dx, dy);
761   cairo_paint (cr);
762
763   cairo_pop_group_to_source (cr);
764   cairo_paint (cr);
765
766   cairo_destroy (cr);
767
768   _gdk_window_add_damage (window, area);
769 }
770
771 /**
772  * gdk_offscreen_window_set_embedder:
773  * @window: a #GdkWindow
774  * @embedder: the #GdkWindow that @window gets embedded in
775  *
776  * Sets @window to be embedded in @embedder.
777  *
778  * To fully embed an offscreen window, in addition to calling this
779  * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
780  * signal on the @embedder and the #GdkWindow::to-embedder and
781  * #GdkWindow::from-embedder signals on @window.
782  *
783  * Since: 2.18
784  */
785 void
786 gdk_offscreen_window_set_embedder (GdkWindow     *window,
787                                    GdkWindow     *embedder)
788 {
789   GdkWindowObject *private = (GdkWindowObject *)window;
790   GdkOffscreenWindow *offscreen;
791
792   g_return_if_fail (GDK_IS_WINDOW (window));
793
794   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
795     return;
796
797   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
798
799   if (embedder)
800     {
801       g_object_ref (embedder);
802       GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
803     }
804
805   if (offscreen->embedder)
806     {
807       g_object_unref (offscreen->embedder);
808       GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
809     }
810
811   offscreen->embedder = embedder;
812 }
813
814 /**
815  * gdk_offscreen_window_get_embedder:
816  * @window: a #GdkWindow
817  *
818  * Gets the window that @window is embedded in.
819  *
820  * Returns: the embedding #GdkWindow, or %NULL if @window is not an
821  *     embedded offscreen window
822  *
823  * Since: 2.18
824  */
825 GdkWindow *
826 gdk_offscreen_window_get_embedder (GdkWindow *window)
827 {
828   GdkWindowObject *private = (GdkWindowObject *)window;
829   GdkOffscreenWindow *offscreen;
830
831   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
832
833   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
834     return NULL;
835
836   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
837
838   return offscreen->embedder;
839 }
840
841 static void
842 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
843 {
844   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
845   GObjectClass *object_class = G_OBJECT_CLASS (klass);
846
847   object_class->finalize = gdk_offscreen_window_finalize;
848
849   drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
850   drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
851   drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
852   drawable_class->get_depth = gdk_offscreen_window_get_depth;
853   drawable_class->get_screen = gdk_offscreen_window_get_screen;
854   drawable_class->get_visual = gdk_offscreen_window_get_visual;
855   drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
856 }
857
858 static void
859 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
860 {
861   iface->show = gdk_offscreen_window_show;
862   iface->hide = gdk_offscreen_window_hide;
863   iface->withdraw = gdk_offscreen_window_withdraw;
864   iface->raise = gdk_offscreen_window_raise;
865   iface->lower = gdk_offscreen_window_lower;
866   iface->move_resize = gdk_offscreen_window_move_resize;
867   iface->set_background = gdk_offscreen_window_set_background;
868   iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
869   iface->get_events = gdk_offscreen_window_get_events;
870   iface->set_events = gdk_offscreen_window_set_events;
871   iface->reparent = gdk_offscreen_window_reparent;
872   iface->get_geometry = gdk_offscreen_window_get_geometry;
873   iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
874   iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
875   iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
876   iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
877   iface->translate = gdk_offscreen_window_translate;
878   iface->get_root_coords = gdk_offscreen_window_get_root_coords;
879   iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
880   iface->get_device_state = gdk_offscreen_window_get_device_state;
881   iface->destroy = gdk_offscreen_window_destroy;
882 }