]> Pileus Git - ~andy/gtk/blob - gdk/gdkoffscreenwindow.c
API: remove GdkGC
[~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 static void
213 add_damage (GdkOffscreenWindow *offscreen,
214             int x, int y,
215             int w, int h,
216             gboolean is_line)
217 {
218   GdkRectangle rect;
219   cairo_region_t *damage;
220
221   rect.x = x;
222   rect.y = y;
223   rect.width = w;
224   rect.height = h;
225
226   if (is_line)
227     {
228       /* This should really take into account line width, line
229        * joins (and miter) and line caps. But these are hard
230        * to compute, rarely used and generally a pain. And in
231        * the end a snug damage rectangle is not that important
232        * as multiple damages are generally created anyway.
233        *
234        * So, we just add some padding around the rect.
235        * We use a padding of 3 pixels, plus an extra row
236        * below and on the right for the normal line size. I.E.
237        * line from (0,0) to (2,0) gets h=0 but is really
238        * at least one pixel tall.
239        */
240       rect.x -= 3;
241       rect.y -= 3;
242       rect.width += 7;
243       rect.height += 7;
244     }
245
246   damage = cairo_region_create_rectangle (&rect);
247   _gdk_window_add_damage (offscreen->wrapper, damage);
248   cairo_region_destroy (damage);
249 }
250
251 void
252 _gdk_offscreen_window_new (GdkWindow     *window,
253                            GdkScreen     *screen,
254                            GdkVisual     *visual,
255                            GdkWindowAttr *attributes,
256                            gint           attributes_mask)
257 {
258   GdkWindowObject *private;
259   GdkOffscreenWindow *offscreen;
260
261   g_return_if_fail (attributes != NULL);
262
263   if (attributes->wclass != GDK_INPUT_OUTPUT)
264     return; /* Can't support input only offscreens */
265
266   private = (GdkWindowObject *)window;
267
268   if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
269     return;
270
271   private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
272   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
273   offscreen->wrapper = window;
274
275   offscreen->screen = screen;
276
277   if (attributes_mask & GDK_WA_COLORMAP)
278     offscreen->colormap = g_object_ref (attributes->colormap);
279   else
280     {
281       if (gdk_screen_get_system_visual (screen) == visual)
282         {
283           offscreen->colormap = gdk_screen_get_system_colormap (screen);
284           g_object_ref (offscreen->colormap);
285         }
286       else
287         offscreen->colormap = gdk_colormap_new (visual, FALSE);
288     }
289
290   offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent,
291                                       private->width,
292                                       private->height,
293                                       private->depth);
294   gdk_drawable_set_colormap (offscreen->pixmap, offscreen->colormap);
295 }
296
297 static gboolean
298 gdk_offscreen_window_reparent (GdkWindow *window,
299                                GdkWindow *new_parent,
300                                gint       x,
301                                gint       y)
302 {
303   GdkWindowObject *private = (GdkWindowObject *)window;
304   GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
305   GdkWindowObject *old_parent;
306   gboolean was_mapped;
307
308   if (new_parent)
309     {
310       /* No input-output children of input-only windows */
311       if (new_parent_private->input_only && !private->input_only)
312         return FALSE;
313
314       /* Don't create loops in hierarchy */
315       if (is_parent_of (window, new_parent))
316         return FALSE;
317     }
318
319   was_mapped = GDK_WINDOW_IS_MAPPED (window);
320
321   gdk_window_hide (window);
322
323   if (private->parent)
324     private->parent->children = g_list_remove (private->parent->children, window);
325
326   old_parent = private->parent;
327   private->parent = new_parent_private;
328   private->x = x;
329   private->y = y;
330
331   if (new_parent_private)
332     private->parent->children = g_list_prepend (private->parent->children, window);
333
334   _gdk_synthesize_crossing_events_for_geometry_change (window);
335   if (old_parent)
336     _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
337
338   return was_mapped;
339 }
340
341 static void
342 from_embedder (GdkWindow *window,
343                double embedder_x, double embedder_y,
344                double *offscreen_x, double *offscreen_y)
345 {
346   GdkWindowObject *private;
347
348   private = (GdkWindowObject *)window;
349
350   g_signal_emit_by_name (private->impl_window,
351                          "from-embedder",
352                          embedder_x, embedder_y,
353                          offscreen_x, offscreen_y,
354                          NULL);
355 }
356
357 static void
358 to_embedder (GdkWindow *window,
359              double offscreen_x, double offscreen_y,
360              double *embedder_x, double *embedder_y)
361 {
362   GdkWindowObject *private;
363
364   private = (GdkWindowObject *)window;
365
366   g_signal_emit_by_name (private->impl_window,
367                          "to-embedder",
368                          offscreen_x, offscreen_y,
369                          embedder_x, embedder_y,
370                          NULL);
371 }
372
373 static gint
374 gdk_offscreen_window_get_root_coords (GdkWindow *window,
375                                       gint       x,
376                                       gint       y,
377                                       gint      *root_x,
378                                       gint      *root_y)
379 {
380   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
381   GdkOffscreenWindow *offscreen;
382   int tmpx, tmpy;
383
384   tmpx = x;
385   tmpy = y;
386
387   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
388   if (offscreen->embedder)
389     {
390       double dx, dy;
391       to_embedder (window,
392                    x, y,
393                    &dx, &dy);
394       tmpx = floor (dx + 0.5);
395       tmpy = floor (dy + 0.5);
396       gdk_window_get_root_coords (offscreen->embedder,
397                                   tmpx, tmpy,
398                                   &tmpx, &tmpy);
399
400     }
401
402   if (root_x)
403     *root_x = tmpx;
404   if (root_y)
405     *root_y = tmpy;
406
407   return TRUE;
408 }
409
410 static gint
411 gdk_offscreen_window_get_deskrelative_origin (GdkWindow *window,
412                                               gint      *x,
413                                               gint      *y)
414 {
415   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
416   GdkOffscreenWindow *offscreen;
417   int tmpx, tmpy;
418
419   tmpx = 0;
420   tmpy = 0;
421
422   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
423   if (offscreen->embedder)
424     {
425       double dx, dy;
426       gdk_window_get_deskrelative_origin (offscreen->embedder,
427                                           &tmpx, &tmpy);
428
429       to_embedder (window,
430                    0, 0,
431                    &dx, &dy);
432       tmpx = floor (tmpx + dx + 0.5);
433       tmpy = floor (tmpy + dy + 0.5);
434     }
435
436
437   if (x)
438     *x = tmpx;
439   if (y)
440     *y = tmpy;
441
442   return TRUE;
443 }
444
445 static gboolean
446 gdk_offscreen_window_get_device_state (GdkWindow       *window,
447                                        GdkDevice       *device,
448                                        gint            *x,
449                                        gint            *y,
450                                        GdkModifierType *mask)
451 {
452   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
453   GdkOffscreenWindow *offscreen;
454   int tmpx, tmpy;
455   double dtmpx, dtmpy;
456   GdkModifierType tmpmask;
457
458   tmpx = 0;
459   tmpy = 0;
460   tmpmask = 0;
461
462   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
463   if (offscreen->embedder != NULL)
464     {
465       gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
466       from_embedder (window,
467                      tmpx, tmpy,
468                      &dtmpx, &dtmpy);
469       tmpx = floor (dtmpx + 0.5);
470       tmpy = floor (dtmpy + 0.5);
471     }
472
473   if (x)
474     *x = tmpx;
475   if (y)
476     *y = tmpy;
477   if (mask)
478     *mask = tmpmask;
479   return TRUE;
480 }
481
482 /**
483  * gdk_offscreen_window_get_pixmap:
484  * @window: a #GdkWindow
485  *
486  * Gets the offscreen pixmap that an offscreen window renders into.
487  * If you need to keep this around over window resizes, you need to
488  * add a reference to it.
489  *
490  * Returns: The offscreen pixmap, or %NULL if not offscreen
491  *
492  * Since: 2.18
493  */
494 GdkPixmap *
495 gdk_offscreen_window_get_pixmap (GdkWindow *window)
496 {
497   GdkWindowObject *private = (GdkWindowObject *)window;
498   GdkOffscreenWindow *offscreen;
499
500   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
501
502   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
503     return NULL;
504
505   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
506   return offscreen->pixmap;
507 }
508
509 static void
510 gdk_offscreen_window_raise (GdkWindow *window)
511 {
512   /* gdk_window_raise already changed the stacking order */
513   _gdk_synthesize_crossing_events_for_geometry_change (window);
514 }
515
516 static void
517 gdk_offscreen_window_lower (GdkWindow *window)
518 {
519   /* gdk_window_lower already changed the stacking order */
520   _gdk_synthesize_crossing_events_for_geometry_change (window);
521 }
522
523 static void
524 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
525                                            gint       x,
526                                            gint       y,
527                                            gint       width,
528                                            gint       height,
529                                            gboolean   send_expose_events)
530 {
531   GdkWindowObject *private = (GdkWindowObject *)window;
532   GdkOffscreenWindow *offscreen;
533   gint dx, dy, dw, dh;
534   GdkPixmap *old_pixmap;
535
536   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
537
538   if (width < 1)
539     width = 1;
540   if (height < 1)
541     height = 1;
542
543   if (private->destroyed)
544     return;
545
546   dx = x - private->x;
547   dy = y - private->y;
548   dw = width - private->width;
549   dh = height - private->height;
550
551   private->x = x;
552   private->y = y;
553
554   if (private->width != width ||
555       private->height != height)
556     {
557       cairo_t *cr;
558
559       private->width = width;
560       private->height = height;
561
562       old_pixmap = offscreen->pixmap;
563       offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
564                                           width,
565                                           height,
566                                           private->depth);
567
568       cr = gdk_cairo_create (offscreen->pixmap);
569       gdk_cairo_set_source_pixmap (cr, old_pixmap, 0, 0);
570       cairo_paint (cr);
571       cairo_destroy (cr);
572     }
573
574   if (GDK_WINDOW_IS_MAPPED (private))
575     {
576       // TODO: Only invalidate new area, i.e. for larger windows
577       gdk_window_invalidate_rect (window, NULL, TRUE);
578       _gdk_synthesize_crossing_events_for_geometry_change (window);
579     }
580 }
581
582 static void
583 gdk_offscreen_window_move_resize (GdkWindow *window,
584                                   gboolean   with_move,
585                                   gint       x,
586                                   gint       y,
587                                   gint       width,
588                                   gint       height)
589 {
590   GdkWindowObject *private = (GdkWindowObject *)window;
591   GdkOffscreenWindow *offscreen;
592
593   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
594
595   if (!with_move)
596     {
597       x = private->x;
598       y = private->y;
599     }
600
601   if (width < 0)
602     width = private->width;
603
604   if (height < 0)
605     height = private->height;
606
607   gdk_offscreen_window_move_resize_internal (window, x, y,
608                                              width, height,
609                                              TRUE);
610 }
611
612 static void
613 gdk_offscreen_window_show (GdkWindow *window,
614                            gboolean already_mapped)
615 {
616   GdkWindowObject *private = (GdkWindowObject *)window;
617
618   gdk_window_clear_area_e (window, 0, 0,
619                            private->width, private->height);
620 }
621
622
623 static void
624 gdk_offscreen_window_hide (GdkWindow *window)
625 {
626   GdkWindowObject *private;
627   GdkOffscreenWindow *offscreen;
628   GdkDisplay *display;
629
630   g_return_if_fail (window != NULL);
631
632   private = (GdkWindowObject*) window;
633   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
634
635   /* May need to break grabs on children */
636   display = gdk_drawable_get_display (window);
637
638   /* TODO: This needs updating to the new grab world */
639 #if 0
640   if (display->pointer_grab.window != NULL)
641     {
642       if (is_parent_of (window, display->pointer_grab.window))
643         {
644           /* Call this ourselves, even though gdk_display_pointer_ungrab
645              does so too, since we want to pass implicit == TRUE so the
646              broken grab event is generated */
647           _gdk_display_unset_has_pointer_grab (display,
648                                                TRUE,
649                                                FALSE,
650                                                GDK_CURRENT_TIME);
651           gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
652         }
653     }
654 #endif
655 }
656
657 static void
658 gdk_offscreen_window_withdraw (GdkWindow *window)
659 {
660 }
661
662 static GdkEventMask
663 gdk_offscreen_window_get_events (GdkWindow *window)
664 {
665   return 0;
666 }
667
668 static void
669 gdk_offscreen_window_set_events (GdkWindow       *window,
670                                  GdkEventMask     event_mask)
671 {
672 }
673
674 static void
675 gdk_offscreen_window_set_background (GdkWindow      *window,
676                                      const GdkColor *color)
677 {
678   GdkWindowObject *private = (GdkWindowObject *)window;
679   GdkColormap *colormap = gdk_drawable_get_colormap (window);
680
681   private->bg_color = *color;
682   gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
683
684   if (private->bg_pixmap &&
685       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
686       private->bg_pixmap != GDK_NO_BG)
687     g_object_unref (private->bg_pixmap);
688
689   private->bg_pixmap = NULL;
690 }
691
692 static void
693 gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
694                                       GdkPixmap *pixmap)
695 {
696   GdkWindowObject *private = (GdkWindowObject *)window;
697
698   if (pixmap &&
699       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
700       private->bg_pixmap != GDK_NO_BG &&
701       !gdk_drawable_get_colormap (pixmap))
702     {
703       g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
704       return;
705     }
706
707   if (private->bg_pixmap &&
708       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
709       private->bg_pixmap != GDK_NO_BG)
710     g_object_unref (private->bg_pixmap);
711
712   private->bg_pixmap = pixmap;
713
714   if (pixmap &&
715       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
716       private->bg_pixmap != GDK_NO_BG)
717     g_object_ref (pixmap);
718 }
719
720 static void
721 gdk_offscreen_window_shape_combine_region (GdkWindow       *window,
722                                            const cairo_region_t *shape_region,
723                                            gint             offset_x,
724                                            gint             offset_y)
725 {
726 }
727
728 static void
729 gdk_offscreen_window_input_shape_combine_region (GdkWindow       *window,
730                                                  const cairo_region_t *shape_region,
731                                                  gint             offset_x,
732                                                  gint             offset_y)
733 {
734 }
735
736 static gboolean
737 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
738                                            gboolean   use_static)
739 {
740   return TRUE;
741 }
742
743 static void
744 gdk_offscreen_window_get_geometry (GdkWindow *window,
745                                    gint      *x,
746                                    gint      *y,
747                                    gint      *width,
748                                    gint      *height,
749                                    gint      *depth)
750 {
751   GdkWindowObject *private = (GdkWindowObject *)window;
752
753   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
754
755   if (!GDK_WINDOW_DESTROYED (window))
756     {
757       if (x)
758         *x = private->x;
759       if (y)
760         *y = private->y;
761       if (width)
762         *width = private->width;
763       if (height)
764         *height = private->height;
765       if (depth)
766         *depth = private->depth;
767     }
768 }
769
770 static gboolean
771 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
772                                        cairo_region_t *area)
773 {
774   return FALSE;
775 }
776
777 static void
778 gdk_offscreen_window_translate (GdkWindow      *window,
779                                 cairo_region_t *area,
780                                 gint            dx,
781                                 gint            dy)
782 {
783   cairo_surface_t *surface;
784   cairo_t *cr;
785
786   /* Can't use gdk_cairo_create here due to clipping */
787   surface = _gdk_drawable_ref_cairo_surface (window);
788   cr = cairo_create (surface);
789   cairo_surface_destroy (surface);
790
791   area = cairo_region_copy (area);
792
793   gdk_cairo_region (cr, area);
794   cairo_clip (cr);
795   
796   /* NB: This is a self-copy and Cairo doesn't support that yet.
797    * So we do a litle trick.
798    */
799   cairo_push_group (cr);
800
801   gdk_cairo_set_source_pixmap (cr, window, dx, dy);
802   cairo_paint (cr);
803
804   cairo_pop_group_to_source (cr);
805   cairo_paint (cr);
806
807   cairo_destroy (cr);
808
809   _gdk_window_add_damage (window, area);
810 }
811
812 /**
813  * gdk_offscreen_window_set_embedder:
814  * @window: a #GdkWindow
815  * @embedder: the #GdkWindow that @window gets embedded in
816  *
817  * Sets @window to be embedded in @embedder.
818  *
819  * To fully embed an offscreen window, in addition to calling this
820  * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
821  * signal on the @embedder and the #GdkWindow::to-embedder and
822  * #GdkWindow::from-embedder signals on @window.
823  *
824  * Since: 2.18
825  */
826 void
827 gdk_offscreen_window_set_embedder (GdkWindow     *window,
828                                    GdkWindow     *embedder)
829 {
830   GdkWindowObject *private = (GdkWindowObject *)window;
831   GdkOffscreenWindow *offscreen;
832
833   g_return_if_fail (GDK_IS_WINDOW (window));
834
835   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
836     return;
837
838   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
839
840   if (embedder)
841     {
842       g_object_ref (embedder);
843       GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
844     }
845
846   if (offscreen->embedder)
847     {
848       g_object_unref (offscreen->embedder);
849       GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
850     }
851
852   offscreen->embedder = embedder;
853 }
854
855 /**
856  * gdk_offscreen_window_get_embedder:
857  * @window: a #GdkWindow
858  *
859  * Gets the window that @window is embedded in.
860  *
861  * Returns: the embedding #GdkWindow, or %NULL if @window is not an
862  *     embedded offscreen window
863  *
864  * Since: 2.18
865  */
866 GdkWindow *
867 gdk_offscreen_window_get_embedder (GdkWindow *window)
868 {
869   GdkWindowObject *private = (GdkWindowObject *)window;
870   GdkOffscreenWindow *offscreen;
871
872   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
873
874   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
875     return NULL;
876
877   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
878
879   return offscreen->embedder;
880 }
881
882 static void
883 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
884 {
885   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
886   GObjectClass *object_class = G_OBJECT_CLASS (klass);
887
888   object_class->finalize = gdk_offscreen_window_finalize;
889
890   drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
891   drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
892   drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
893   drawable_class->get_depth = gdk_offscreen_window_get_depth;
894   drawable_class->get_screen = gdk_offscreen_window_get_screen;
895   drawable_class->get_visual = gdk_offscreen_window_get_visual;
896   drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
897 }
898
899 static void
900 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
901 {
902   iface->show = gdk_offscreen_window_show;
903   iface->hide = gdk_offscreen_window_hide;
904   iface->withdraw = gdk_offscreen_window_withdraw;
905   iface->raise = gdk_offscreen_window_raise;
906   iface->lower = gdk_offscreen_window_lower;
907   iface->move_resize = gdk_offscreen_window_move_resize;
908   iface->set_background = gdk_offscreen_window_set_background;
909   iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
910   iface->get_events = gdk_offscreen_window_get_events;
911   iface->set_events = gdk_offscreen_window_set_events;
912   iface->reparent = gdk_offscreen_window_reparent;
913   iface->get_geometry = gdk_offscreen_window_get_geometry;
914   iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
915   iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
916   iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
917   iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
918   iface->translate = gdk_offscreen_window_translate;
919   iface->get_root_coords = gdk_offscreen_window_get_root_coords;
920   iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
921   iface->get_device_state = gdk_offscreen_window_get_device_state;
922   iface->destroy = gdk_offscreen_window_destroy;
923 }