]> Pileus Git - ~andy/gtk/blob - gdk/gdkoffscreenwindow.c
offscreenwindow: Copy old to new pixmap using Cairo
[~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 GdkImage*
155 gdk_offscreen_window_copy_to_image (GdkDrawable    *drawable,
156                                     GdkImage       *image,
157                                     gint            src_x,
158                                     gint            src_y,
159                                     gint            dest_x,
160                                     gint            dest_y,
161                                     gint            width,
162                                     gint            height)
163 {
164   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
165
166   return gdk_drawable_copy_to_image (offscreen->pixmap,
167                                      image,
168                                      src_x,
169                                      src_y,
170                                      dest_x, dest_y,
171                                      width, height);
172 }
173
174 static cairo_surface_t *
175 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
176 {
177   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
178
179   return _gdk_drawable_ref_cairo_surface (offscreen->pixmap);
180 }
181
182 static GdkColormap*
183 gdk_offscreen_window_get_colormap (GdkDrawable *drawable)
184 {
185   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
186
187   return offscreen->colormap;
188 }
189
190 static void
191 gdk_offscreen_window_set_colormap (GdkDrawable *drawable,
192                                    GdkColormap*colormap)
193 {
194   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
195
196   if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper))
197     return;
198
199   if (offscreen->colormap == colormap)
200     return;
201
202   if (offscreen->colormap)
203     g_object_unref (offscreen->colormap);
204
205   offscreen->colormap = colormap;
206   if (offscreen->colormap)
207     g_object_ref (offscreen->colormap);
208 }
209
210
211 static gint
212 gdk_offscreen_window_get_depth (GdkDrawable *drawable)
213 {
214   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
215
216   return gdk_drawable_get_depth (offscreen->wrapper);
217 }
218
219 static GdkDrawable *
220 gdk_offscreen_window_get_source_drawable (GdkDrawable  *drawable)
221 {
222   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
223
224   return _gdk_drawable_get_source_drawable (offscreen->pixmap);
225 }
226
227 static GdkDrawable *
228 gdk_offscreen_window_get_composite_drawable (GdkDrawable *drawable,
229                                              gint         x,
230                                              gint         y,
231                                              gint         width,
232                                              gint         height,
233                                              gint        *composite_x_offset,
234                                              gint        *composite_y_offset)
235 {
236   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
237
238   return g_object_ref (offscreen->pixmap);
239 }
240
241 static GdkScreen*
242 gdk_offscreen_window_get_screen (GdkDrawable *drawable)
243 {
244   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
245
246   return offscreen->screen;
247 }
248
249 static GdkVisual*
250 gdk_offscreen_window_get_visual (GdkDrawable    *drawable)
251 {
252   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
253
254   return gdk_drawable_get_visual (offscreen->wrapper);
255 }
256
257 static void
258 add_damage (GdkOffscreenWindow *offscreen,
259             int x, int y,
260             int w, int h,
261             gboolean is_line)
262 {
263   GdkRectangle rect;
264   cairo_region_t *damage;
265
266   rect.x = x;
267   rect.y = y;
268   rect.width = w;
269   rect.height = h;
270
271   if (is_line)
272     {
273       /* This should really take into account line width, line
274        * joins (and miter) and line caps. But these are hard
275        * to compute, rarely used and generally a pain. And in
276        * the end a snug damage rectangle is not that important
277        * as multiple damages are generally created anyway.
278        *
279        * So, we just add some padding around the rect.
280        * We use a padding of 3 pixels, plus an extra row
281        * below and on the right for the normal line size. I.E.
282        * line from (0,0) to (2,0) gets h=0 but is really
283        * at least one pixel tall.
284        */
285       rect.x -= 3;
286       rect.y -= 3;
287       rect.width += 7;
288       rect.height += 7;
289     }
290
291   damage = cairo_region_create_rectangle (&rect);
292   _gdk_window_add_damage (offscreen->wrapper, damage);
293   cairo_region_destroy (damage);
294 }
295
296 static GdkDrawable *
297 get_real_drawable (GdkOffscreenWindow *offscreen)
298 {
299   GdkPixmapObject *pixmap;
300   pixmap = (GdkPixmapObject *) offscreen->pixmap;
301   return GDK_DRAWABLE (pixmap->impl);
302 }
303
304 static void
305 gdk_offscreen_window_draw_drawable (GdkDrawable *drawable,
306                                     GdkGC       *gc,
307                                     GdkPixmap   *src,
308                                     gint         xsrc,
309                                     gint         ysrc,
310                                     gint         xdest,
311                                     gint         ydest,
312                                     gint         width,
313                                     gint         height,
314                                     GdkDrawable *original_src)
315 {
316   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
317   GdkDrawable *real_drawable = get_real_drawable (offscreen);
318
319   gdk_draw_drawable (real_drawable, gc,
320                      src, xsrc, ysrc,
321                      xdest, ydest,
322                      width, height);
323
324   add_damage (offscreen, xdest, ydest, width, height, FALSE);
325 }
326
327 static void
328 gdk_offscreen_window_draw_rectangle (GdkDrawable  *drawable,
329                                      GdkGC        *gc,
330                                      gboolean      filled,
331                                      gint          x,
332                                      gint          y,
333                                      gint          width,
334                                      gint          height)
335 {
336   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
337   GdkDrawable *real_drawable = get_real_drawable (offscreen);
338
339   gdk_draw_rectangle (real_drawable,
340                       gc, filled, x, y, width, height);
341
342   add_damage (offscreen, x, y, width, height, !filled);
343
344 }
345
346 static void
347 gdk_offscreen_window_draw_arc (GdkDrawable  *drawable,
348                                GdkGC           *gc,
349                                gboolean filled,
350                                gint             x,
351                                gint             y,
352                                gint             width,
353                                gint             height,
354                                gint             angle1,
355                                gint             angle2)
356 {
357   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
358   GdkDrawable *real_drawable = get_real_drawable (offscreen);
359
360   gdk_draw_arc (real_drawable,
361                 gc,
362                 filled,
363                 x,
364                 y,
365                 width,
366                 height,
367                 angle1,
368                 angle2);
369   add_damage (offscreen, x, y, width, height, !filled);
370 }
371
372 static void
373 gdk_offscreen_window_draw_polygon (GdkDrawable  *drawable,
374                                    GdkGC               *gc,
375                                    gboolean     filled,
376                                    GdkPoint     *points,
377                                    gint         npoints)
378 {
379   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
380   GdkDrawable *real_drawable = get_real_drawable (offscreen);
381
382   gdk_draw_polygon (real_drawable,
383                     gc,
384                     filled,
385                     points,
386                     npoints);
387
388   if (npoints > 0)
389     {
390       int min_x, min_y, max_x, max_y, i;
391
392       min_x = max_x = points[0].x;
393       min_y = max_y = points[0].y;
394
395         for (i = 1; i < npoints; i++)
396           {
397             min_x = MIN (min_x, points[i].x);
398             max_x = MAX (max_x, points[i].x);
399             min_y = MIN (min_y, points[i].y);
400             max_y = MAX (max_y, points[i].y);
401           }
402
403         add_damage (offscreen, min_x, min_y,
404                     max_x - min_x,
405                     max_y - min_y, !filled);
406     }
407 }
408
409 static void
410 gdk_offscreen_window_draw_points (GdkDrawable  *drawable,
411                                   GdkGC        *gc,
412                                   GdkPoint     *points,
413                                   gint          npoints)
414 {
415   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
416   GdkDrawable *real_drawable = get_real_drawable (offscreen);
417
418   gdk_draw_points (real_drawable,
419                    gc,
420                    points,
421                    npoints);
422
423
424   if (npoints > 0)
425     {
426       int min_x, min_y, max_x, max_y, i;
427
428       min_x = max_x = points[0].x;
429       min_y = max_y = points[0].y;
430
431         for (i = 1; i < npoints; i++)
432           {
433             min_x = MIN (min_x, points[i].x);
434             max_x = MAX (max_x, points[i].x);
435             min_y = MIN (min_y, points[i].y);
436             max_y = MAX (max_y, points[i].y);
437           }
438
439         add_damage (offscreen, min_x, min_y,
440                     max_x - min_x + 1,
441                     max_y - min_y + 1,
442                     FALSE);
443     }
444 }
445
446 static void
447 gdk_offscreen_window_draw_segments (GdkDrawable  *drawable,
448                                     GdkGC        *gc,
449                                     GdkSegment   *segs,
450                                     gint          nsegs)
451 {
452   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
453   GdkDrawable *real_drawable = get_real_drawable (offscreen);
454
455   gdk_draw_segments (real_drawable,
456                      gc,
457                      segs,
458                      nsegs);
459
460   if (nsegs > 0)
461     {
462       int min_x, min_y, max_x, max_y, i;
463
464       min_x = max_x = segs[0].x1;
465       min_y = max_y = segs[0].y1;
466
467         for (i = 0; i < nsegs; i++)
468           {
469             min_x = MIN (min_x, segs[i].x1);
470             max_x = MAX (max_x, segs[i].x1);
471             min_x = MIN (min_x, segs[i].x2);
472             max_x = MAX (max_x, segs[i].x2);
473             min_y = MIN (min_y, segs[i].y1);
474             max_y = MAX (max_y, segs[i].y1);
475             min_y = MIN (min_y, segs[i].y2);
476             max_y = MAX (max_y, segs[i].y2);
477           }
478
479         add_damage (offscreen, min_x, min_y,
480                     max_x - min_x,
481                     max_y - min_y, TRUE);
482     }
483
484 }
485
486 static void
487 gdk_offscreen_window_draw_lines (GdkDrawable  *drawable,
488                                  GdkGC        *gc,
489                                  GdkPoint     *points,
490                                  gint          npoints)
491 {
492   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
493   GdkDrawable *real_drawable = get_real_drawable (offscreen);
494   GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper);
495
496   gdk_draw_lines (real_drawable,
497                   gc,
498                   points,
499                   npoints);
500
501   /* Hard to compute the minimal size, as we don't know the line
502      width, and since joins are hard to calculate.
503      Its not that often used anyway, damage it all */
504   add_damage (offscreen, 0, 0, private->width, private->height, TRUE);
505 }
506
507 static void
508 gdk_offscreen_window_draw_image (GdkDrawable *drawable,
509                                  GdkGC        *gc,
510                                  GdkImage    *image,
511                                  gint          xsrc,
512                                  gint          ysrc,
513                                  gint          xdest,
514                                  gint          ydest,
515                                  gint          width,
516                                  gint          height)
517 {
518   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
519   GdkDrawable *real_drawable = get_real_drawable (offscreen);
520
521   gdk_draw_image (real_drawable,
522                   gc,
523                   image,
524                   xsrc,
525                   ysrc,
526                   xdest,
527                   ydest,
528                   width,
529                   height);
530
531   add_damage (offscreen, xdest, ydest, width, height, FALSE);
532 }
533
534
535 static void
536 gdk_offscreen_window_draw_pixbuf (GdkDrawable *drawable,
537                                   GdkGC       *gc,
538                                   GdkPixbuf   *pixbuf,
539                                   gint         src_x,
540                                   gint         src_y,
541                                   gint         dest_x,
542                                   gint         dest_y,
543                                   gint         width,
544                                   gint         height,
545                                   GdkRgbDither dither,
546                                   gint         x_dither,
547                                   gint         y_dither)
548 {
549   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
550   GdkDrawable *real_drawable = get_real_drawable (offscreen);
551
552   gdk_draw_pixbuf (real_drawable,
553                    gc,
554                    pixbuf,
555                    src_x,
556                    src_y,
557                    dest_x,
558                    dest_y,
559                    width,
560                    height,
561                    dither,
562                    x_dither,
563                    y_dither);
564
565   add_damage (offscreen, dest_x, dest_y, width, height, FALSE);
566
567 }
568
569 void
570 _gdk_offscreen_window_new (GdkWindow     *window,
571                            GdkScreen     *screen,
572                            GdkVisual     *visual,
573                            GdkWindowAttr *attributes,
574                            gint           attributes_mask)
575 {
576   GdkWindowObject *private;
577   GdkOffscreenWindow *offscreen;
578
579   g_return_if_fail (attributes != NULL);
580
581   if (attributes->wclass != GDK_INPUT_OUTPUT)
582     return; /* Can't support input only offscreens */
583
584   private = (GdkWindowObject *)window;
585
586   if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
587     return;
588
589   private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
590   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
591   offscreen->wrapper = window;
592
593   offscreen->screen = screen;
594
595   if (attributes_mask & GDK_WA_COLORMAP)
596     offscreen->colormap = g_object_ref (attributes->colormap);
597   else
598     {
599       if (gdk_screen_get_system_visual (screen) == visual)
600         {
601           offscreen->colormap = gdk_screen_get_system_colormap (screen);
602           g_object_ref (offscreen->colormap);
603         }
604       else
605         offscreen->colormap = gdk_colormap_new (visual, FALSE);
606     }
607
608   offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent,
609                                       private->width,
610                                       private->height,
611                                       private->depth);
612   gdk_drawable_set_colormap (offscreen->pixmap, offscreen->colormap);
613 }
614
615 static gboolean
616 gdk_offscreen_window_reparent (GdkWindow *window,
617                                GdkWindow *new_parent,
618                                gint       x,
619                                gint       y)
620 {
621   GdkWindowObject *private = (GdkWindowObject *)window;
622   GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
623   GdkWindowObject *old_parent;
624   gboolean was_mapped;
625
626   if (new_parent)
627     {
628       /* No input-output children of input-only windows */
629       if (new_parent_private->input_only && !private->input_only)
630         return FALSE;
631
632       /* Don't create loops in hierarchy */
633       if (is_parent_of (window, new_parent))
634         return FALSE;
635     }
636
637   was_mapped = GDK_WINDOW_IS_MAPPED (window);
638
639   gdk_window_hide (window);
640
641   if (private->parent)
642     private->parent->children = g_list_remove (private->parent->children, window);
643
644   old_parent = private->parent;
645   private->parent = new_parent_private;
646   private->x = x;
647   private->y = y;
648
649   if (new_parent_private)
650     private->parent->children = g_list_prepend (private->parent->children, window);
651
652   _gdk_synthesize_crossing_events_for_geometry_change (window);
653   if (old_parent)
654     _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
655
656   return was_mapped;
657 }
658
659 static void
660 from_embedder (GdkWindow *window,
661                double embedder_x, double embedder_y,
662                double *offscreen_x, double *offscreen_y)
663 {
664   GdkWindowObject *private;
665
666   private = (GdkWindowObject *)window;
667
668   g_signal_emit_by_name (private->impl_window,
669                          "from-embedder",
670                          embedder_x, embedder_y,
671                          offscreen_x, offscreen_y,
672                          NULL);
673 }
674
675 static void
676 to_embedder (GdkWindow *window,
677              double offscreen_x, double offscreen_y,
678              double *embedder_x, double *embedder_y)
679 {
680   GdkWindowObject *private;
681
682   private = (GdkWindowObject *)window;
683
684   g_signal_emit_by_name (private->impl_window,
685                          "to-embedder",
686                          offscreen_x, offscreen_y,
687                          embedder_x, embedder_y,
688                          NULL);
689 }
690
691 static gint
692 gdk_offscreen_window_get_root_coords (GdkWindow *window,
693                                       gint       x,
694                                       gint       y,
695                                       gint      *root_x,
696                                       gint      *root_y)
697 {
698   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
699   GdkOffscreenWindow *offscreen;
700   int tmpx, tmpy;
701
702   tmpx = x;
703   tmpy = y;
704
705   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
706   if (offscreen->embedder)
707     {
708       double dx, dy;
709       to_embedder (window,
710                    x, y,
711                    &dx, &dy);
712       tmpx = floor (dx + 0.5);
713       tmpy = floor (dy + 0.5);
714       gdk_window_get_root_coords (offscreen->embedder,
715                                   tmpx, tmpy,
716                                   &tmpx, &tmpy);
717
718     }
719
720   if (root_x)
721     *root_x = tmpx;
722   if (root_y)
723     *root_y = tmpy;
724
725   return TRUE;
726 }
727
728 static gint
729 gdk_offscreen_window_get_deskrelative_origin (GdkWindow *window,
730                                               gint      *x,
731                                               gint      *y)
732 {
733   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
734   GdkOffscreenWindow *offscreen;
735   int tmpx, tmpy;
736
737   tmpx = 0;
738   tmpy = 0;
739
740   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
741   if (offscreen->embedder)
742     {
743       double dx, dy;
744       gdk_window_get_deskrelative_origin (offscreen->embedder,
745                                           &tmpx, &tmpy);
746
747       to_embedder (window,
748                    0, 0,
749                    &dx, &dy);
750       tmpx = floor (tmpx + dx + 0.5);
751       tmpy = floor (tmpy + dy + 0.5);
752     }
753
754
755   if (x)
756     *x = tmpx;
757   if (y)
758     *y = tmpy;
759
760   return TRUE;
761 }
762
763 static gboolean
764 gdk_offscreen_window_get_device_state (GdkWindow       *window,
765                                        GdkDevice       *device,
766                                        gint            *x,
767                                        gint            *y,
768                                        GdkModifierType *mask)
769 {
770   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
771   GdkOffscreenWindow *offscreen;
772   int tmpx, tmpy;
773   double dtmpx, dtmpy;
774   GdkModifierType tmpmask;
775
776   tmpx = 0;
777   tmpy = 0;
778   tmpmask = 0;
779
780   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
781   if (offscreen->embedder != NULL)
782     {
783       gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
784       from_embedder (window,
785                      tmpx, tmpy,
786                      &dtmpx, &dtmpy);
787       tmpx = floor (dtmpx + 0.5);
788       tmpy = floor (dtmpy + 0.5);
789     }
790
791   if (x)
792     *x = tmpx;
793   if (y)
794     *y = tmpy;
795   if (mask)
796     *mask = tmpmask;
797   return TRUE;
798 }
799
800 /**
801  * gdk_offscreen_window_get_pixmap:
802  * @window: a #GdkWindow
803  *
804  * Gets the offscreen pixmap that an offscreen window renders into.
805  * If you need to keep this around over window resizes, you need to
806  * add a reference to it.
807  *
808  * Returns: The offscreen pixmap, or %NULL if not offscreen
809  *
810  * Since: 2.18
811  */
812 GdkPixmap *
813 gdk_offscreen_window_get_pixmap (GdkWindow *window)
814 {
815   GdkWindowObject *private = (GdkWindowObject *)window;
816   GdkOffscreenWindow *offscreen;
817
818   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
819
820   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
821     return NULL;
822
823   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
824   return offscreen->pixmap;
825 }
826
827 static void
828 gdk_offscreen_window_raise (GdkWindow *window)
829 {
830   /* gdk_window_raise already changed the stacking order */
831   _gdk_synthesize_crossing_events_for_geometry_change (window);
832 }
833
834 static void
835 gdk_offscreen_window_lower (GdkWindow *window)
836 {
837   /* gdk_window_lower already changed the stacking order */
838   _gdk_synthesize_crossing_events_for_geometry_change (window);
839 }
840
841 static void
842 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
843                                            gint       x,
844                                            gint       y,
845                                            gint       width,
846                                            gint       height,
847                                            gboolean   send_expose_events)
848 {
849   GdkWindowObject *private = (GdkWindowObject *)window;
850   GdkOffscreenWindow *offscreen;
851   gint dx, dy, dw, dh;
852   GdkGC *gc;
853   GdkPixmap *old_pixmap;
854
855   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
856
857   if (width < 1)
858     width = 1;
859   if (height < 1)
860     height = 1;
861
862   if (private->destroyed)
863     return;
864
865   dx = x - private->x;
866   dy = y - private->y;
867   dw = width - private->width;
868   dh = height - private->height;
869
870   private->x = x;
871   private->y = y;
872
873   if (private->width != width ||
874       private->height != height)
875     {
876       cairo_t *cr;
877
878       private->width = width;
879       private->height = height;
880
881       old_pixmap = offscreen->pixmap;
882       offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
883                                           width,
884                                           height,
885                                           private->depth);
886
887       cr = gdk_cairo_create (offscreen->pixmap);
888       gdk_cairo_set_source_pixmap (cr, old_pixmap, 0, 0);
889       cairo_paint (cr);
890       cairo_destroy (cr);
891     }
892
893   if (GDK_WINDOW_IS_MAPPED (private))
894     {
895       // TODO: Only invalidate new area, i.e. for larger windows
896       gdk_window_invalidate_rect (window, NULL, TRUE);
897       _gdk_synthesize_crossing_events_for_geometry_change (window);
898     }
899 }
900
901 static void
902 gdk_offscreen_window_move_resize (GdkWindow *window,
903                                   gboolean   with_move,
904                                   gint       x,
905                                   gint       y,
906                                   gint       width,
907                                   gint       height)
908 {
909   GdkWindowObject *private = (GdkWindowObject *)window;
910   GdkOffscreenWindow *offscreen;
911
912   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
913
914   if (!with_move)
915     {
916       x = private->x;
917       y = private->y;
918     }
919
920   if (width < 0)
921     width = private->width;
922
923   if (height < 0)
924     height = private->height;
925
926   gdk_offscreen_window_move_resize_internal (window, x, y,
927                                              width, height,
928                                              TRUE);
929 }
930
931 static void
932 gdk_offscreen_window_show (GdkWindow *window,
933                            gboolean already_mapped)
934 {
935   GdkWindowObject *private = (GdkWindowObject *)window;
936
937   gdk_window_clear_area_e (window, 0, 0,
938                            private->width, private->height);
939 }
940
941
942 static void
943 gdk_offscreen_window_hide (GdkWindow *window)
944 {
945   GdkWindowObject *private;
946   GdkOffscreenWindow *offscreen;
947   GdkDisplay *display;
948
949   g_return_if_fail (window != NULL);
950
951   private = (GdkWindowObject*) window;
952   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
953
954   /* May need to break grabs on children */
955   display = gdk_drawable_get_display (window);
956
957   /* TODO: This needs updating to the new grab world */
958 #if 0
959   if (display->pointer_grab.window != NULL)
960     {
961       if (is_parent_of (window, display->pointer_grab.window))
962         {
963           /* Call this ourselves, even though gdk_display_pointer_ungrab
964              does so too, since we want to pass implicit == TRUE so the
965              broken grab event is generated */
966           _gdk_display_unset_has_pointer_grab (display,
967                                                TRUE,
968                                                FALSE,
969                                                GDK_CURRENT_TIME);
970           gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
971         }
972     }
973 #endif
974 }
975
976 static void
977 gdk_offscreen_window_withdraw (GdkWindow *window)
978 {
979 }
980
981 static GdkEventMask
982 gdk_offscreen_window_get_events (GdkWindow *window)
983 {
984   return 0;
985 }
986
987 static void
988 gdk_offscreen_window_set_events (GdkWindow       *window,
989                                  GdkEventMask     event_mask)
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_region (GdkWindow       *window,
1041                                            const cairo_region_t *shape_region,
1042                                            gint             offset_x,
1043                                            gint             offset_y)
1044 {
1045 }
1046
1047 static void
1048 gdk_offscreen_window_input_shape_combine_region (GdkWindow       *window,
1049                                                  const cairo_region_t *shape_region,
1050                                                  gint             offset_x,
1051                                                  gint             offset_y)
1052 {
1053 }
1054
1055 static gboolean
1056 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
1057                                            gboolean   use_static)
1058 {
1059   return TRUE;
1060 }
1061
1062 static void
1063 gdk_offscreen_window_get_geometry (GdkWindow *window,
1064                                    gint      *x,
1065                                    gint      *y,
1066                                    gint      *width,
1067                                    gint      *height,
1068                                    gint      *depth)
1069 {
1070   GdkWindowObject *private = (GdkWindowObject *)window;
1071
1072   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
1073
1074   if (!GDK_WINDOW_DESTROYED (window))
1075     {
1076       if (x)
1077         *x = private->x;
1078       if (y)
1079         *y = private->y;
1080       if (width)
1081         *width = private->width;
1082       if (height)
1083         *height = private->height;
1084       if (depth)
1085         *depth = private->depth;
1086     }
1087 }
1088
1089 static gboolean
1090 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
1091                                        cairo_region_t *area)
1092 {
1093   return FALSE;
1094 }
1095
1096 static void
1097 gdk_offscreen_window_queue_translation (GdkWindow *window,
1098                                         GdkGC     *gc,
1099                                         cairo_region_t *area,
1100                                         gint       dx,
1101                                         gint       dy)
1102 {
1103 }
1104
1105 /**
1106  * gdk_offscreen_window_set_embedder:
1107  * @window: a #GdkWindow
1108  * @embedder: the #GdkWindow that @window gets embedded in
1109  *
1110  * Sets @window to be embedded in @embedder.
1111  *
1112  * To fully embed an offscreen window, in addition to calling this
1113  * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
1114  * signal on the @embedder and the #GdkWindow::to-embedder and
1115  * #GdkWindow::from-embedder signals on @window.
1116  *
1117  * Since: 2.18
1118  */
1119 void
1120 gdk_offscreen_window_set_embedder (GdkWindow     *window,
1121                                    GdkWindow     *embedder)
1122 {
1123   GdkWindowObject *private = (GdkWindowObject *)window;
1124   GdkOffscreenWindow *offscreen;
1125
1126   g_return_if_fail (GDK_IS_WINDOW (window));
1127
1128   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
1129     return;
1130
1131   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
1132
1133   if (embedder)
1134     {
1135       g_object_ref (embedder);
1136       GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
1137     }
1138
1139   if (offscreen->embedder)
1140     {
1141       g_object_unref (offscreen->embedder);
1142       GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
1143     }
1144
1145   offscreen->embedder = embedder;
1146 }
1147
1148 /**
1149  * gdk_offscreen_window_get_embedder:
1150  * @window: a #GdkWindow
1151  *
1152  * Gets the window that @window is embedded in.
1153  *
1154  * Returns: the embedding #GdkWindow, or %NULL if @window is not an
1155  *     embedded offscreen window
1156  *
1157  * Since: 2.18
1158  */
1159 GdkWindow *
1160 gdk_offscreen_window_get_embedder (GdkWindow *window)
1161 {
1162   GdkWindowObject *private = (GdkWindowObject *)window;
1163   GdkOffscreenWindow *offscreen;
1164
1165   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
1166
1167   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
1168     return NULL;
1169
1170   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
1171
1172   return offscreen->embedder;
1173 }
1174
1175 static void
1176 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
1177 {
1178   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
1179   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1180
1181   object_class->finalize = gdk_offscreen_window_finalize;
1182
1183   drawable_class->create_gc = gdk_offscreen_window_create_gc;
1184   drawable_class->_copy_to_image = gdk_offscreen_window_copy_to_image;
1185   drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
1186   drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
1187   drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
1188   drawable_class->get_depth = gdk_offscreen_window_get_depth;
1189   drawable_class->get_screen = gdk_offscreen_window_get_screen;
1190   drawable_class->get_visual = gdk_offscreen_window_get_visual;
1191   drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
1192   drawable_class->get_composite_drawable = gdk_offscreen_window_get_composite_drawable;
1193
1194   drawable_class->draw_rectangle = gdk_offscreen_window_draw_rectangle;
1195   drawable_class->draw_arc = gdk_offscreen_window_draw_arc;
1196   drawable_class->draw_polygon = gdk_offscreen_window_draw_polygon;
1197   drawable_class->draw_drawable_with_src = gdk_offscreen_window_draw_drawable;
1198   drawable_class->draw_points = gdk_offscreen_window_draw_points;
1199   drawable_class->draw_segments = gdk_offscreen_window_draw_segments;
1200   drawable_class->draw_lines = gdk_offscreen_window_draw_lines;
1201   drawable_class->draw_image = gdk_offscreen_window_draw_image;
1202   drawable_class->draw_pixbuf = gdk_offscreen_window_draw_pixbuf;
1203 }
1204
1205 static void
1206 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
1207 {
1208   iface->show = gdk_offscreen_window_show;
1209   iface->hide = gdk_offscreen_window_hide;
1210   iface->withdraw = gdk_offscreen_window_withdraw;
1211   iface->raise = gdk_offscreen_window_raise;
1212   iface->lower = gdk_offscreen_window_lower;
1213   iface->move_resize = gdk_offscreen_window_move_resize;
1214   iface->set_background = gdk_offscreen_window_set_background;
1215   iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
1216   iface->get_events = gdk_offscreen_window_get_events;
1217   iface->set_events = gdk_offscreen_window_set_events;
1218   iface->reparent = gdk_offscreen_window_reparent;
1219   iface->get_geometry = gdk_offscreen_window_get_geometry;
1220   iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
1221   iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
1222   iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
1223   iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
1224   iface->queue_translation = gdk_offscreen_window_queue_translation;
1225   iface->get_root_coords = gdk_offscreen_window_get_root_coords;
1226   iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
1227   iface->get_device_state = gdk_offscreen_window_get_device_state;
1228   iface->destroy = gdk_offscreen_window_destroy;
1229 }