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