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