]> Pileus Git - ~andy/gtk/blob - gdk/gdkoffscreenwindow.c
s/GdkRegion/cairo_region_t/ in all of gtk
[~andy/gtk] / gdk / gdkoffscreenwindow.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2005.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include <config.h>
28 #include <math.h>
29 #include "gdk.h"
30 #include "gdkwindow.h"
31 #include "gdkinternals.h"
32 #include "gdkwindowimpl.h"
33 #include "gdkpixmap.h"
34 #include "gdkdrawable.h"
35 #include "gdktypes.h"
36 #include "gdkscreen.h"
37 #include "gdkgc.h"
38 #include "gdkcolor.h"
39 #include "gdkcursor.h"
40 #include "gdkalias.h"
41
42 /* LIMITATIONS:
43  *
44  * Offscreen windows can't be the child of a foreign window,
45  *   nor contain foreign windows
46  * GDK_POINTER_MOTION_HINT_MASK isn't effective
47  */
48
49 typedef struct _GdkOffscreenWindow      GdkOffscreenWindow;
50 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
51
52 struct _GdkOffscreenWindow
53 {
54   GdkDrawable parent_instance;
55
56   GdkWindow *wrapper;
57   GdkCursor *cursor;
58   GdkColormap *colormap;
59   GdkScreen *screen;
60
61   GdkPixmap *pixmap;
62   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       private->width = width;
877       private->height = height;
878
879       old_pixmap = offscreen->pixmap;
880       offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
881                                           width,
882                                           height,
883                                           private->depth);
884
885       gc = _gdk_drawable_get_scratch_gc (offscreen->pixmap, FALSE);
886       gdk_draw_drawable (offscreen->pixmap,
887                          gc,
888                          old_pixmap,
889                          0,0, 0, 0,
890                          -1, -1);
891       g_object_unref (old_pixmap);
892     }
893
894   if (GDK_WINDOW_IS_MAPPED (private))
895     {
896       // TODO: Only invalidate new area, i.e. for larger windows
897       gdk_window_invalidate_rect (window, NULL, TRUE);
898       _gdk_synthesize_crossing_events_for_geometry_change (window);
899     }
900 }
901
902 static void
903 gdk_offscreen_window_move_resize (GdkWindow *window,
904                                   gboolean   with_move,
905                                   gint       x,
906                                   gint       y,
907                                   gint       width,
908                                   gint       height)
909 {
910   GdkWindowObject *private = (GdkWindowObject *)window;
911   GdkOffscreenWindow *offscreen;
912
913   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
914
915   if (!with_move)
916     {
917       x = private->x;
918       y = private->y;
919     }
920
921   if (width < 0)
922     width = private->width;
923
924   if (height < 0)
925     height = private->height;
926
927   gdk_offscreen_window_move_resize_internal (window, x, y,
928                                              width, height,
929                                              TRUE);
930 }
931
932 static void
933 gdk_offscreen_window_show (GdkWindow *window,
934                            gboolean already_mapped)
935 {
936   GdkWindowObject *private = (GdkWindowObject *)window;
937
938   gdk_window_clear_area_e (window, 0, 0,
939                            private->width, private->height);
940 }
941
942
943 static void
944 gdk_offscreen_window_hide (GdkWindow *window)
945 {
946   GdkWindowObject *private;
947   GdkOffscreenWindow *offscreen;
948   GdkDisplay *display;
949
950   g_return_if_fail (window != NULL);
951
952   private = (GdkWindowObject*) window;
953   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
954
955   /* May need to break grabs on children */
956   display = gdk_drawable_get_display (window);
957
958   /* TODO: This needs updating to the new grab world */
959 #if 0
960   if (display->pointer_grab.window != NULL)
961     {
962       if (is_parent_of (window, display->pointer_grab.window))
963         {
964           /* Call this ourselves, even though gdk_display_pointer_ungrab
965              does so too, since we want to pass implicit == TRUE so the
966              broken grab event is generated */
967           _gdk_display_unset_has_pointer_grab (display,
968                                                TRUE,
969                                                FALSE,
970                                                GDK_CURRENT_TIME);
971           gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
972         }
973     }
974 #endif
975 }
976
977 static void
978 gdk_offscreen_window_withdraw (GdkWindow *window)
979 {
980 }
981
982 static GdkEventMask
983 gdk_offscreen_window_get_events (GdkWindow *window)
984 {
985   return 0;
986 }
987
988 static void
989 gdk_offscreen_window_set_events (GdkWindow       *window,
990                                  GdkEventMask     event_mask)
991 {
992 }
993
994 static void
995 gdk_offscreen_window_set_background (GdkWindow      *window,
996                                      const GdkColor *color)
997 {
998   GdkWindowObject *private = (GdkWindowObject *)window;
999   GdkColormap *colormap = gdk_drawable_get_colormap (window);
1000
1001   private->bg_color = *color;
1002   gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
1003
1004   if (private->bg_pixmap &&
1005       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1006       private->bg_pixmap != GDK_NO_BG)
1007     g_object_unref (private->bg_pixmap);
1008
1009   private->bg_pixmap = NULL;
1010 }
1011
1012 static void
1013 gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
1014                                       GdkPixmap *pixmap)
1015 {
1016   GdkWindowObject *private = (GdkWindowObject *)window;
1017
1018   if (pixmap &&
1019       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1020       private->bg_pixmap != GDK_NO_BG &&
1021       !gdk_drawable_get_colormap (pixmap))
1022     {
1023       g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
1024       return;
1025     }
1026
1027   if (private->bg_pixmap &&
1028       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1029       private->bg_pixmap != GDK_NO_BG)
1030     g_object_unref (private->bg_pixmap);
1031
1032   private->bg_pixmap = pixmap;
1033
1034   if (pixmap &&
1035       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
1036       private->bg_pixmap != GDK_NO_BG)
1037     g_object_ref (pixmap);
1038 }
1039
1040 static void
1041 gdk_offscreen_window_shape_combine_region (GdkWindow       *window,
1042                                            const cairo_region_t *shape_region,
1043                                            gint             offset_x,
1044                                            gint             offset_y)
1045 {
1046 }
1047
1048 static void
1049 gdk_offscreen_window_input_shape_combine_region (GdkWindow       *window,
1050                                                  const cairo_region_t *shape_region,
1051                                                  gint             offset_x,
1052                                                  gint             offset_y)
1053 {
1054 }
1055
1056 static gboolean
1057 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
1058                                            gboolean   use_static)
1059 {
1060   return TRUE;
1061 }
1062
1063 static void
1064 gdk_offscreen_window_get_geometry (GdkWindow *window,
1065                                    gint      *x,
1066                                    gint      *y,
1067                                    gint      *width,
1068                                    gint      *height,
1069                                    gint      *depth)
1070 {
1071   GdkWindowObject *private = (GdkWindowObject *)window;
1072
1073   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
1074
1075   if (!GDK_WINDOW_DESTROYED (window))
1076     {
1077       if (x)
1078         *x = private->x;
1079       if (y)
1080         *y = private->y;
1081       if (width)
1082         *width = private->width;
1083       if (height)
1084         *height = private->height;
1085       if (depth)
1086         *depth = private->depth;
1087     }
1088 }
1089
1090 static gboolean
1091 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
1092                                        cairo_region_t *area)
1093 {
1094   return FALSE;
1095 }
1096
1097 static void
1098 gdk_offscreen_window_queue_translation (GdkWindow *window,
1099                                         GdkGC     *gc,
1100                                         cairo_region_t *area,
1101                                         gint       dx,
1102                                         gint       dy)
1103 {
1104 }
1105
1106 /**
1107  * gdk_offscreen_window_set_embedder:
1108  * @window: a #GdkWindow
1109  * @embedder: the #GdkWindow that @window gets embedded in
1110  *
1111  * Sets @window to be embedded in @embedder.
1112  *
1113  * To fully embed an offscreen window, in addition to calling this
1114  * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
1115  * signal on the @embedder and the #GdkWindow::to-embedder and
1116  * #GdkWindow::from-embedder signals on @window.
1117  *
1118  * Since: 2.18
1119  */
1120 void
1121 gdk_offscreen_window_set_embedder (GdkWindow     *window,
1122                                    GdkWindow     *embedder)
1123 {
1124   GdkWindowObject *private = (GdkWindowObject *)window;
1125   GdkOffscreenWindow *offscreen;
1126
1127   g_return_if_fail (GDK_IS_WINDOW (window));
1128
1129   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
1130     return;
1131
1132   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
1133
1134   if (embedder)
1135     {
1136       g_object_ref (embedder);
1137       GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
1138     }
1139
1140   if (offscreen->embedder)
1141     {
1142       g_object_unref (offscreen->embedder);
1143       GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
1144     }
1145
1146   offscreen->embedder = embedder;
1147 }
1148
1149 /**
1150  * gdk_offscreen_window_get_embedder:
1151  * @window: a #GdkWindow
1152  *
1153  * Gets the window that @window is embedded in.
1154  *
1155  * Returns: the embedding #GdkWindow, or %NULL if @window is not an
1156  *     embedded offscreen window
1157  *
1158  * Since: 2.18
1159  */
1160 GdkWindow *
1161 gdk_offscreen_window_get_embedder (GdkWindow *window)
1162 {
1163   GdkWindowObject *private = (GdkWindowObject *)window;
1164   GdkOffscreenWindow *offscreen;
1165
1166   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
1167
1168   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
1169     return NULL;
1170
1171   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
1172
1173   return offscreen->embedder;
1174 }
1175
1176 static void
1177 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
1178 {
1179   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
1180   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1181
1182   object_class->finalize = gdk_offscreen_window_finalize;
1183
1184   drawable_class->create_gc = gdk_offscreen_window_create_gc;
1185   drawable_class->_copy_to_image = gdk_offscreen_window_copy_to_image;
1186   drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
1187   drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
1188   drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
1189   drawable_class->get_depth = gdk_offscreen_window_get_depth;
1190   drawable_class->get_screen = gdk_offscreen_window_get_screen;
1191   drawable_class->get_visual = gdk_offscreen_window_get_visual;
1192   drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
1193   drawable_class->get_composite_drawable = gdk_offscreen_window_get_composite_drawable;
1194
1195   drawable_class->draw_rectangle = gdk_offscreen_window_draw_rectangle;
1196   drawable_class->draw_arc = gdk_offscreen_window_draw_arc;
1197   drawable_class->draw_polygon = gdk_offscreen_window_draw_polygon;
1198   drawable_class->draw_drawable_with_src = gdk_offscreen_window_draw_drawable;
1199   drawable_class->draw_points = gdk_offscreen_window_draw_points;
1200   drawable_class->draw_segments = gdk_offscreen_window_draw_segments;
1201   drawable_class->draw_lines = gdk_offscreen_window_draw_lines;
1202   drawable_class->draw_image = gdk_offscreen_window_draw_image;
1203   drawable_class->draw_pixbuf = gdk_offscreen_window_draw_pixbuf;
1204 }
1205
1206 static void
1207 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
1208 {
1209   iface->show = gdk_offscreen_window_show;
1210   iface->hide = gdk_offscreen_window_hide;
1211   iface->withdraw = gdk_offscreen_window_withdraw;
1212   iface->raise = gdk_offscreen_window_raise;
1213   iface->lower = gdk_offscreen_window_lower;
1214   iface->move_resize = gdk_offscreen_window_move_resize;
1215   iface->set_background = gdk_offscreen_window_set_background;
1216   iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
1217   iface->get_events = gdk_offscreen_window_get_events;
1218   iface->set_events = gdk_offscreen_window_set_events;
1219   iface->reparent = gdk_offscreen_window_reparent;
1220   iface->get_geometry = gdk_offscreen_window_get_geometry;
1221   iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
1222   iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
1223   iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
1224   iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
1225   iface->queue_translation = gdk_offscreen_window_queue_translation;
1226   iface->get_root_coords = gdk_offscreen_window_get_root_coords;
1227   iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
1228   iface->get_device_state = gdk_offscreen_window_get_device_state;
1229   iface->destroy = gdk_offscreen_window_destroy;
1230 }
1231
1232 #define __GDK_OFFSCREEN_WINDOW_C__
1233 #include "gdkaliasdef.c"