]> Pileus Git - ~andy/gtk/blob - gdk/gdkoffscreenwindow.c
API: remove gdk_draw_polygon()
[~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 static GdkDrawable *
277 get_real_drawable (GdkOffscreenWindow *offscreen)
278 {
279   GdkPixmapObject *pixmap;
280   pixmap = (GdkPixmapObject *) offscreen->pixmap;
281   return GDK_DRAWABLE (pixmap->impl);
282 }
283
284 static void
285 gdk_offscreen_window_draw_drawable (GdkDrawable *drawable,
286                                     GdkGC       *gc,
287                                     GdkPixmap   *src,
288                                     gint         xsrc,
289                                     gint         ysrc,
290                                     gint         xdest,
291                                     gint         ydest,
292                                     gint         width,
293                                     gint         height,
294                                     GdkDrawable *original_src)
295 {
296   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
297   GdkDrawable *real_drawable = get_real_drawable (offscreen);
298
299   gdk_draw_drawable (real_drawable, gc,
300                      src, xsrc, ysrc,
301                      xdest, ydest,
302                      width, height);
303
304   add_damage (offscreen, xdest, ydest, width, height, FALSE);
305 }
306
307 static void
308 gdk_offscreen_window_draw_rectangle (GdkDrawable  *drawable,
309                                      GdkGC        *gc,
310                                      gboolean      filled,
311                                      gint          x,
312                                      gint          y,
313                                      gint          width,
314                                      gint          height)
315 {
316   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
317   GdkDrawable *real_drawable = get_real_drawable (offscreen);
318
319   gdk_draw_rectangle (real_drawable,
320                       gc, filled, x, y, width, height);
321
322   add_damage (offscreen, x, y, width, height, !filled);
323
324 }
325
326 static void
327 gdk_offscreen_window_draw_points (GdkDrawable  *drawable,
328                                   GdkGC        *gc,
329                                   GdkPoint     *points,
330                                   gint          npoints)
331 {
332   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
333   GdkDrawable *real_drawable = get_real_drawable (offscreen);
334
335   gdk_draw_points (real_drawable,
336                    gc,
337                    points,
338                    npoints);
339
340
341   if (npoints > 0)
342     {
343       int min_x, min_y, max_x, max_y, i;
344
345       min_x = max_x = points[0].x;
346       min_y = max_y = points[0].y;
347
348         for (i = 1; i < npoints; i++)
349           {
350             min_x = MIN (min_x, points[i].x);
351             max_x = MAX (max_x, points[i].x);
352             min_y = MIN (min_y, points[i].y);
353             max_y = MAX (max_y, points[i].y);
354           }
355
356         add_damage (offscreen, min_x, min_y,
357                     max_x - min_x + 1,
358                     max_y - min_y + 1,
359                     FALSE);
360     }
361 }
362
363 static void
364 gdk_offscreen_window_draw_segments (GdkDrawable  *drawable,
365                                     GdkGC        *gc,
366                                     GdkSegment   *segs,
367                                     gint          nsegs)
368 {
369   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
370   GdkDrawable *real_drawable = get_real_drawable (offscreen);
371
372   gdk_draw_segments (real_drawable,
373                      gc,
374                      segs,
375                      nsegs);
376
377   if (nsegs > 0)
378     {
379       int min_x, min_y, max_x, max_y, i;
380
381       min_x = max_x = segs[0].x1;
382       min_y = max_y = segs[0].y1;
383
384         for (i = 0; i < nsegs; i++)
385           {
386             min_x = MIN (min_x, segs[i].x1);
387             max_x = MAX (max_x, segs[i].x1);
388             min_x = MIN (min_x, segs[i].x2);
389             max_x = MAX (max_x, segs[i].x2);
390             min_y = MIN (min_y, segs[i].y1);
391             max_y = MAX (max_y, segs[i].y1);
392             min_y = MIN (min_y, segs[i].y2);
393             max_y = MAX (max_y, segs[i].y2);
394           }
395
396         add_damage (offscreen, min_x, min_y,
397                     max_x - min_x,
398                     max_y - min_y, TRUE);
399     }
400
401 }
402
403 static void
404 gdk_offscreen_window_draw_lines (GdkDrawable  *drawable,
405                                  GdkGC        *gc,
406                                  GdkPoint     *points,
407                                  gint          npoints)
408 {
409   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
410   GdkDrawable *real_drawable = get_real_drawable (offscreen);
411   GdkWindowObject *private = GDK_WINDOW_OBJECT (offscreen->wrapper);
412
413   gdk_draw_lines (real_drawable,
414                   gc,
415                   points,
416                   npoints);
417
418   /* Hard to compute the minimal size, as we don't know the line
419      width, and since joins are hard to calculate.
420      Its not that often used anyway, damage it all */
421   add_damage (offscreen, 0, 0, private->width, private->height, TRUE);
422 }
423
424 void
425 _gdk_offscreen_window_new (GdkWindow     *window,
426                            GdkScreen     *screen,
427                            GdkVisual     *visual,
428                            GdkWindowAttr *attributes,
429                            gint           attributes_mask)
430 {
431   GdkWindowObject *private;
432   GdkOffscreenWindow *offscreen;
433
434   g_return_if_fail (attributes != NULL);
435
436   if (attributes->wclass != GDK_INPUT_OUTPUT)
437     return; /* Can't support input only offscreens */
438
439   private = (GdkWindowObject *)window;
440
441   if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
442     return;
443
444   private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
445   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
446   offscreen->wrapper = window;
447
448   offscreen->screen = screen;
449
450   if (attributes_mask & GDK_WA_COLORMAP)
451     offscreen->colormap = g_object_ref (attributes->colormap);
452   else
453     {
454       if (gdk_screen_get_system_visual (screen) == visual)
455         {
456           offscreen->colormap = gdk_screen_get_system_colormap (screen);
457           g_object_ref (offscreen->colormap);
458         }
459       else
460         offscreen->colormap = gdk_colormap_new (visual, FALSE);
461     }
462
463   offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent,
464                                       private->width,
465                                       private->height,
466                                       private->depth);
467   gdk_drawable_set_colormap (offscreen->pixmap, offscreen->colormap);
468 }
469
470 static gboolean
471 gdk_offscreen_window_reparent (GdkWindow *window,
472                                GdkWindow *new_parent,
473                                gint       x,
474                                gint       y)
475 {
476   GdkWindowObject *private = (GdkWindowObject *)window;
477   GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
478   GdkWindowObject *old_parent;
479   gboolean was_mapped;
480
481   if (new_parent)
482     {
483       /* No input-output children of input-only windows */
484       if (new_parent_private->input_only && !private->input_only)
485         return FALSE;
486
487       /* Don't create loops in hierarchy */
488       if (is_parent_of (window, new_parent))
489         return FALSE;
490     }
491
492   was_mapped = GDK_WINDOW_IS_MAPPED (window);
493
494   gdk_window_hide (window);
495
496   if (private->parent)
497     private->parent->children = g_list_remove (private->parent->children, window);
498
499   old_parent = private->parent;
500   private->parent = new_parent_private;
501   private->x = x;
502   private->y = y;
503
504   if (new_parent_private)
505     private->parent->children = g_list_prepend (private->parent->children, window);
506
507   _gdk_synthesize_crossing_events_for_geometry_change (window);
508   if (old_parent)
509     _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
510
511   return was_mapped;
512 }
513
514 static void
515 from_embedder (GdkWindow *window,
516                double embedder_x, double embedder_y,
517                double *offscreen_x, double *offscreen_y)
518 {
519   GdkWindowObject *private;
520
521   private = (GdkWindowObject *)window;
522
523   g_signal_emit_by_name (private->impl_window,
524                          "from-embedder",
525                          embedder_x, embedder_y,
526                          offscreen_x, offscreen_y,
527                          NULL);
528 }
529
530 static void
531 to_embedder (GdkWindow *window,
532              double offscreen_x, double offscreen_y,
533              double *embedder_x, double *embedder_y)
534 {
535   GdkWindowObject *private;
536
537   private = (GdkWindowObject *)window;
538
539   g_signal_emit_by_name (private->impl_window,
540                          "to-embedder",
541                          offscreen_x, offscreen_y,
542                          embedder_x, embedder_y,
543                          NULL);
544 }
545
546 static gint
547 gdk_offscreen_window_get_root_coords (GdkWindow *window,
548                                       gint       x,
549                                       gint       y,
550                                       gint      *root_x,
551                                       gint      *root_y)
552 {
553   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
554   GdkOffscreenWindow *offscreen;
555   int tmpx, tmpy;
556
557   tmpx = x;
558   tmpy = y;
559
560   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
561   if (offscreen->embedder)
562     {
563       double dx, dy;
564       to_embedder (window,
565                    x, y,
566                    &dx, &dy);
567       tmpx = floor (dx + 0.5);
568       tmpy = floor (dy + 0.5);
569       gdk_window_get_root_coords (offscreen->embedder,
570                                   tmpx, tmpy,
571                                   &tmpx, &tmpy);
572
573     }
574
575   if (root_x)
576     *root_x = tmpx;
577   if (root_y)
578     *root_y = tmpy;
579
580   return TRUE;
581 }
582
583 static gint
584 gdk_offscreen_window_get_deskrelative_origin (GdkWindow *window,
585                                               gint      *x,
586                                               gint      *y)
587 {
588   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
589   GdkOffscreenWindow *offscreen;
590   int tmpx, tmpy;
591
592   tmpx = 0;
593   tmpy = 0;
594
595   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
596   if (offscreen->embedder)
597     {
598       double dx, dy;
599       gdk_window_get_deskrelative_origin (offscreen->embedder,
600                                           &tmpx, &tmpy);
601
602       to_embedder (window,
603                    0, 0,
604                    &dx, &dy);
605       tmpx = floor (tmpx + dx + 0.5);
606       tmpy = floor (tmpy + dy + 0.5);
607     }
608
609
610   if (x)
611     *x = tmpx;
612   if (y)
613     *y = tmpy;
614
615   return TRUE;
616 }
617
618 static gboolean
619 gdk_offscreen_window_get_device_state (GdkWindow       *window,
620                                        GdkDevice       *device,
621                                        gint            *x,
622                                        gint            *y,
623                                        GdkModifierType *mask)
624 {
625   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
626   GdkOffscreenWindow *offscreen;
627   int tmpx, tmpy;
628   double dtmpx, dtmpy;
629   GdkModifierType tmpmask;
630
631   tmpx = 0;
632   tmpy = 0;
633   tmpmask = 0;
634
635   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
636   if (offscreen->embedder != NULL)
637     {
638       gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
639       from_embedder (window,
640                      tmpx, tmpy,
641                      &dtmpx, &dtmpy);
642       tmpx = floor (dtmpx + 0.5);
643       tmpy = floor (dtmpy + 0.5);
644     }
645
646   if (x)
647     *x = tmpx;
648   if (y)
649     *y = tmpy;
650   if (mask)
651     *mask = tmpmask;
652   return TRUE;
653 }
654
655 /**
656  * gdk_offscreen_window_get_pixmap:
657  * @window: a #GdkWindow
658  *
659  * Gets the offscreen pixmap that an offscreen window renders into.
660  * If you need to keep this around over window resizes, you need to
661  * add a reference to it.
662  *
663  * Returns: The offscreen pixmap, or %NULL if not offscreen
664  *
665  * Since: 2.18
666  */
667 GdkPixmap *
668 gdk_offscreen_window_get_pixmap (GdkWindow *window)
669 {
670   GdkWindowObject *private = (GdkWindowObject *)window;
671   GdkOffscreenWindow *offscreen;
672
673   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
674
675   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
676     return NULL;
677
678   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
679   return offscreen->pixmap;
680 }
681
682 static void
683 gdk_offscreen_window_raise (GdkWindow *window)
684 {
685   /* gdk_window_raise already changed the stacking order */
686   _gdk_synthesize_crossing_events_for_geometry_change (window);
687 }
688
689 static void
690 gdk_offscreen_window_lower (GdkWindow *window)
691 {
692   /* gdk_window_lower already changed the stacking order */
693   _gdk_synthesize_crossing_events_for_geometry_change (window);
694 }
695
696 static void
697 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
698                                            gint       x,
699                                            gint       y,
700                                            gint       width,
701                                            gint       height,
702                                            gboolean   send_expose_events)
703 {
704   GdkWindowObject *private = (GdkWindowObject *)window;
705   GdkOffscreenWindow *offscreen;
706   gint dx, dy, dw, dh;
707   GdkGC *gc;
708   GdkPixmap *old_pixmap;
709
710   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
711
712   if (width < 1)
713     width = 1;
714   if (height < 1)
715     height = 1;
716
717   if (private->destroyed)
718     return;
719
720   dx = x - private->x;
721   dy = y - private->y;
722   dw = width - private->width;
723   dh = height - private->height;
724
725   private->x = x;
726   private->y = y;
727
728   if (private->width != width ||
729       private->height != height)
730     {
731       cairo_t *cr;
732
733       private->width = width;
734       private->height = height;
735
736       old_pixmap = offscreen->pixmap;
737       offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
738                                           width,
739                                           height,
740                                           private->depth);
741
742       cr = gdk_cairo_create (offscreen->pixmap);
743       gdk_cairo_set_source_pixmap (cr, old_pixmap, 0, 0);
744       cairo_paint (cr);
745       cairo_destroy (cr);
746     }
747
748   if (GDK_WINDOW_IS_MAPPED (private))
749     {
750       // TODO: Only invalidate new area, i.e. for larger windows
751       gdk_window_invalidate_rect (window, NULL, TRUE);
752       _gdk_synthesize_crossing_events_for_geometry_change (window);
753     }
754 }
755
756 static void
757 gdk_offscreen_window_move_resize (GdkWindow *window,
758                                   gboolean   with_move,
759                                   gint       x,
760                                   gint       y,
761                                   gint       width,
762                                   gint       height)
763 {
764   GdkWindowObject *private = (GdkWindowObject *)window;
765   GdkOffscreenWindow *offscreen;
766
767   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
768
769   if (!with_move)
770     {
771       x = private->x;
772       y = private->y;
773     }
774
775   if (width < 0)
776     width = private->width;
777
778   if (height < 0)
779     height = private->height;
780
781   gdk_offscreen_window_move_resize_internal (window, x, y,
782                                              width, height,
783                                              TRUE);
784 }
785
786 static void
787 gdk_offscreen_window_show (GdkWindow *window,
788                            gboolean already_mapped)
789 {
790   GdkWindowObject *private = (GdkWindowObject *)window;
791
792   gdk_window_clear_area_e (window, 0, 0,
793                            private->width, private->height);
794 }
795
796
797 static void
798 gdk_offscreen_window_hide (GdkWindow *window)
799 {
800   GdkWindowObject *private;
801   GdkOffscreenWindow *offscreen;
802   GdkDisplay *display;
803
804   g_return_if_fail (window != NULL);
805
806   private = (GdkWindowObject*) window;
807   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
808
809   /* May need to break grabs on children */
810   display = gdk_drawable_get_display (window);
811
812   /* TODO: This needs updating to the new grab world */
813 #if 0
814   if (display->pointer_grab.window != NULL)
815     {
816       if (is_parent_of (window, display->pointer_grab.window))
817         {
818           /* Call this ourselves, even though gdk_display_pointer_ungrab
819              does so too, since we want to pass implicit == TRUE so the
820              broken grab event is generated */
821           _gdk_display_unset_has_pointer_grab (display,
822                                                TRUE,
823                                                FALSE,
824                                                GDK_CURRENT_TIME);
825           gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
826         }
827     }
828 #endif
829 }
830
831 static void
832 gdk_offscreen_window_withdraw (GdkWindow *window)
833 {
834 }
835
836 static GdkEventMask
837 gdk_offscreen_window_get_events (GdkWindow *window)
838 {
839   return 0;
840 }
841
842 static void
843 gdk_offscreen_window_set_events (GdkWindow       *window,
844                                  GdkEventMask     event_mask)
845 {
846 }
847
848 static void
849 gdk_offscreen_window_set_background (GdkWindow      *window,
850                                      const GdkColor *color)
851 {
852   GdkWindowObject *private = (GdkWindowObject *)window;
853   GdkColormap *colormap = gdk_drawable_get_colormap (window);
854
855   private->bg_color = *color;
856   gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
857
858   if (private->bg_pixmap &&
859       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
860       private->bg_pixmap != GDK_NO_BG)
861     g_object_unref (private->bg_pixmap);
862
863   private->bg_pixmap = NULL;
864 }
865
866 static void
867 gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
868                                       GdkPixmap *pixmap)
869 {
870   GdkWindowObject *private = (GdkWindowObject *)window;
871
872   if (pixmap &&
873       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
874       private->bg_pixmap != GDK_NO_BG &&
875       !gdk_drawable_get_colormap (pixmap))
876     {
877       g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
878       return;
879     }
880
881   if (private->bg_pixmap &&
882       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
883       private->bg_pixmap != GDK_NO_BG)
884     g_object_unref (private->bg_pixmap);
885
886   private->bg_pixmap = pixmap;
887
888   if (pixmap &&
889       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
890       private->bg_pixmap != GDK_NO_BG)
891     g_object_ref (pixmap);
892 }
893
894 static void
895 gdk_offscreen_window_shape_combine_region (GdkWindow       *window,
896                                            const cairo_region_t *shape_region,
897                                            gint             offset_x,
898                                            gint             offset_y)
899 {
900 }
901
902 static void
903 gdk_offscreen_window_input_shape_combine_region (GdkWindow       *window,
904                                                  const cairo_region_t *shape_region,
905                                                  gint             offset_x,
906                                                  gint             offset_y)
907 {
908 }
909
910 static gboolean
911 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
912                                            gboolean   use_static)
913 {
914   return TRUE;
915 }
916
917 static void
918 gdk_offscreen_window_get_geometry (GdkWindow *window,
919                                    gint      *x,
920                                    gint      *y,
921                                    gint      *width,
922                                    gint      *height,
923                                    gint      *depth)
924 {
925   GdkWindowObject *private = (GdkWindowObject *)window;
926
927   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
928
929   if (!GDK_WINDOW_DESTROYED (window))
930     {
931       if (x)
932         *x = private->x;
933       if (y)
934         *y = private->y;
935       if (width)
936         *width = private->width;
937       if (height)
938         *height = private->height;
939       if (depth)
940         *depth = private->depth;
941     }
942 }
943
944 static gboolean
945 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
946                                        cairo_region_t *area)
947 {
948   return FALSE;
949 }
950
951 static void
952 gdk_offscreen_window_queue_translation (GdkWindow *window,
953                                         GdkGC     *gc,
954                                         cairo_region_t *area,
955                                         gint       dx,
956                                         gint       dy)
957 {
958 }
959
960 /**
961  * gdk_offscreen_window_set_embedder:
962  * @window: a #GdkWindow
963  * @embedder: the #GdkWindow that @window gets embedded in
964  *
965  * Sets @window to be embedded in @embedder.
966  *
967  * To fully embed an offscreen window, in addition to calling this
968  * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
969  * signal on the @embedder and the #GdkWindow::to-embedder and
970  * #GdkWindow::from-embedder signals on @window.
971  *
972  * Since: 2.18
973  */
974 void
975 gdk_offscreen_window_set_embedder (GdkWindow     *window,
976                                    GdkWindow     *embedder)
977 {
978   GdkWindowObject *private = (GdkWindowObject *)window;
979   GdkOffscreenWindow *offscreen;
980
981   g_return_if_fail (GDK_IS_WINDOW (window));
982
983   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
984     return;
985
986   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
987
988   if (embedder)
989     {
990       g_object_ref (embedder);
991       GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
992     }
993
994   if (offscreen->embedder)
995     {
996       g_object_unref (offscreen->embedder);
997       GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
998     }
999
1000   offscreen->embedder = embedder;
1001 }
1002
1003 /**
1004  * gdk_offscreen_window_get_embedder:
1005  * @window: a #GdkWindow
1006  *
1007  * Gets the window that @window is embedded in.
1008  *
1009  * Returns: the embedding #GdkWindow, or %NULL if @window is not an
1010  *     embedded offscreen window
1011  *
1012  * Since: 2.18
1013  */
1014 GdkWindow *
1015 gdk_offscreen_window_get_embedder (GdkWindow *window)
1016 {
1017   GdkWindowObject *private = (GdkWindowObject *)window;
1018   GdkOffscreenWindow *offscreen;
1019
1020   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
1021
1022   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
1023     return NULL;
1024
1025   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
1026
1027   return offscreen->embedder;
1028 }
1029
1030 static void
1031 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
1032 {
1033   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
1034   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1035
1036   object_class->finalize = gdk_offscreen_window_finalize;
1037
1038   drawable_class->create_gc = gdk_offscreen_window_create_gc;
1039   drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
1040   drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
1041   drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
1042   drawable_class->get_depth = gdk_offscreen_window_get_depth;
1043   drawable_class->get_screen = gdk_offscreen_window_get_screen;
1044   drawable_class->get_visual = gdk_offscreen_window_get_visual;
1045   drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
1046   drawable_class->get_composite_drawable = gdk_offscreen_window_get_composite_drawable;
1047
1048   drawable_class->draw_rectangle = gdk_offscreen_window_draw_rectangle;
1049   drawable_class->draw_drawable_with_src = gdk_offscreen_window_draw_drawable;
1050   drawable_class->draw_points = gdk_offscreen_window_draw_points;
1051   drawable_class->draw_segments = gdk_offscreen_window_draw_segments;
1052   drawable_class->draw_lines = gdk_offscreen_window_draw_lines;
1053 }
1054
1055 static void
1056 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
1057 {
1058   iface->show = gdk_offscreen_window_show;
1059   iface->hide = gdk_offscreen_window_hide;
1060   iface->withdraw = gdk_offscreen_window_withdraw;
1061   iface->raise = gdk_offscreen_window_raise;
1062   iface->lower = gdk_offscreen_window_lower;
1063   iface->move_resize = gdk_offscreen_window_move_resize;
1064   iface->set_background = gdk_offscreen_window_set_background;
1065   iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
1066   iface->get_events = gdk_offscreen_window_get_events;
1067   iface->set_events = gdk_offscreen_window_set_events;
1068   iface->reparent = gdk_offscreen_window_reparent;
1069   iface->get_geometry = gdk_offscreen_window_get_geometry;
1070   iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
1071   iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
1072   iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
1073   iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
1074   iface->queue_translation = gdk_offscreen_window_queue_translation;
1075   iface->get_root_coords = gdk_offscreen_window_get_root_coords;
1076   iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
1077   iface->get_device_state = gdk_offscreen_window_get_device_state;
1078   iface->destroy = gdk_offscreen_window_destroy;
1079 }