]> Pileus Git - ~andy/gtk/blob - gdk/gdkoffscreenwindow.c
gdk: Make GdkWindowImpl a class, not an interface
[~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
29 #include "gdkwindow.h"
30 #include "gdkinternals.h"
31 #include "gdkwindowimpl.h"
32
33 #include <math.h>
34
35 /* LIMITATIONS:
36  *
37  * Offscreen windows can't be the child of a foreign window,
38  *   nor contain foreign windows
39  * GDK_POINTER_MOTION_HINT_MASK isn't effective
40  */
41
42 typedef struct _GdkOffscreenWindow      GdkOffscreenWindow;
43 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
44
45 struct _GdkOffscreenWindow
46 {
47   GdkWindowImpl parent_instance;
48
49   GdkWindow *wrapper;
50
51   cairo_surface_t *surface;
52   GdkWindow *embedder;
53 };
54
55 struct _GdkOffscreenWindowClass
56 {
57   GdkWindowImplClass parent_class;
58 };
59
60 #define GDK_TYPE_OFFSCREEN_WINDOW            (gdk_offscreen_window_get_type())
61 #define GDK_OFFSCREEN_WINDOW(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow))
62 #define GDK_IS_OFFSCREEN_WINDOW(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW))
63 #define GDK_OFFSCREEN_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
64 #define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW))
65 #define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
66
67 static void       gdk_offscreen_window_hide               (GdkWindow                  *window);
68
69 G_DEFINE_TYPE (GdkOffscreenWindow, gdk_offscreen_window, GDK_TYPE_WINDOW_IMPL)
70
71
72 static void
73 gdk_offscreen_window_finalize (GObject *object)
74 {
75   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
76
77   if (offscreen->surface)
78     cairo_surface_destroy (offscreen->surface);
79
80   G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
81 }
82
83 static void
84 gdk_offscreen_window_init (GdkOffscreenWindow *window)
85 {
86 }
87
88 static void
89 gdk_offscreen_window_destroy (GdkWindow *window,
90                               gboolean   recursing,
91                               gboolean   foreign_destroy)
92 {
93   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
94   GdkOffscreenWindow *offscreen;
95
96   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
97
98   gdk_offscreen_window_set_embedder (window, NULL);
99   
100   if (!recursing)
101     gdk_offscreen_window_hide (window);
102 }
103
104 static cairo_surface_t *
105 get_surface (GdkOffscreenWindow *offscreen)
106 {
107   if (! offscreen->surface)
108     {
109       GdkWindowObject *private = (GdkWindowObject *) offscreen->wrapper;
110
111       g_signal_emit_by_name (private, "create-surface",
112                              private->width,
113                              private->height,
114                              &offscreen->surface);
115     }
116
117   return offscreen->surface;
118 }
119
120 static gboolean
121 is_parent_of (GdkWindow *parent,
122               GdkWindow *child)
123 {
124   GdkWindow *w;
125
126   w = child;
127   while (w != NULL)
128     {
129       if (w == parent)
130         return TRUE;
131
132       w = gdk_window_get_parent (w);
133     }
134
135   return FALSE;
136 }
137
138 static cairo_surface_t *
139 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
140 {
141   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
142
143   return cairo_surface_reference (get_surface (offscreen));
144 }
145
146 cairo_surface_t *
147 _gdk_offscreen_window_create_surface (GdkWindow *offscreen,
148                                       gint       width,
149                                       gint       height)
150 {
151   GdkWindowObject *private = (GdkWindowObject *) offscreen;
152   cairo_surface_t *similar;
153   cairo_surface_t *surface;
154   cairo_content_t  content = CAIRO_CONTENT_COLOR;
155
156   g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (private->impl), NULL);
157
158   similar = _gdk_window_ref_cairo_surface ((GdkWindow *)private->parent);
159
160   if (gdk_window_get_visual (offscreen) ==
161       gdk_screen_get_rgba_visual (gdk_window_get_screen (offscreen)))
162     {
163       content = CAIRO_CONTENT_COLOR_ALPHA;
164     }
165
166   surface = cairo_surface_create_similar (similar, content, width, height);
167
168   cairo_surface_destroy (similar);
169
170   return surface;
171 }
172
173 void
174 _gdk_offscreen_window_new (GdkWindow     *window,
175                            GdkWindowAttr *attributes,
176                            gint           attributes_mask)
177 {
178   GdkWindowObject *private;
179   GdkOffscreenWindow *offscreen;
180
181   g_return_if_fail (attributes != NULL);
182
183   if (attributes->wclass != GDK_INPUT_OUTPUT)
184     return; /* Can't support input only offscreens */
185
186   private = (GdkWindowObject *)window;
187
188   if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
189     return;
190
191   private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
192   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
193   offscreen->wrapper = window;
194 }
195
196 static gboolean
197 gdk_offscreen_window_reparent (GdkWindow *window,
198                                GdkWindow *new_parent,
199                                gint       x,
200                                gint       y)
201 {
202   GdkWindowObject *private = (GdkWindowObject *)window;
203   GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
204   GdkWindowObject *old_parent;
205   gboolean was_mapped;
206
207   if (new_parent)
208     {
209       /* No input-output children of input-only windows */
210       if (new_parent_private->input_only && !private->input_only)
211         return FALSE;
212
213       /* Don't create loops in hierarchy */
214       if (is_parent_of (window, new_parent))
215         return FALSE;
216     }
217
218   was_mapped = GDK_WINDOW_IS_MAPPED (window);
219
220   gdk_window_hide (window);
221
222   if (private->parent)
223     private->parent->children = g_list_remove (private->parent->children, window);
224
225   old_parent = private->parent;
226   private->parent = new_parent_private;
227   private->x = x;
228   private->y = y;
229
230   if (new_parent_private)
231     private->parent->children = g_list_prepend (private->parent->children, window);
232
233   _gdk_synthesize_crossing_events_for_geometry_change (window);
234   if (old_parent)
235     _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
236
237   return was_mapped;
238 }
239
240 static void
241 from_embedder (GdkWindow *window,
242                double embedder_x, double embedder_y,
243                double *offscreen_x, double *offscreen_y)
244 {
245   GdkWindowObject *private;
246
247   private = (GdkWindowObject *)window;
248
249   g_signal_emit_by_name (private->impl_window,
250                          "from-embedder",
251                          embedder_x, embedder_y,
252                          offscreen_x, offscreen_y,
253                          NULL);
254 }
255
256 static void
257 to_embedder (GdkWindow *window,
258              double offscreen_x, double offscreen_y,
259              double *embedder_x, double *embedder_y)
260 {
261   GdkWindowObject *private;
262
263   private = (GdkWindowObject *)window;
264
265   g_signal_emit_by_name (private->impl_window,
266                          "to-embedder",
267                          offscreen_x, offscreen_y,
268                          embedder_x, embedder_y,
269                          NULL);
270 }
271
272 static gint
273 gdk_offscreen_window_get_root_coords (GdkWindow *window,
274                                       gint       x,
275                                       gint       y,
276                                       gint      *root_x,
277                                       gint      *root_y)
278 {
279   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
280   GdkOffscreenWindow *offscreen;
281   int tmpx, tmpy;
282
283   tmpx = x;
284   tmpy = y;
285
286   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
287   if (offscreen->embedder)
288     {
289       double dx, dy;
290       to_embedder (window,
291                    x, y,
292                    &dx, &dy);
293       tmpx = floor (dx + 0.5);
294       tmpy = floor (dy + 0.5);
295       gdk_window_get_root_coords (offscreen->embedder,
296                                   tmpx, tmpy,
297                                   &tmpx, &tmpy);
298
299     }
300
301   if (root_x)
302     *root_x = tmpx;
303   if (root_y)
304     *root_y = tmpy;
305
306   return TRUE;
307 }
308
309 static gboolean
310 gdk_offscreen_window_get_device_state (GdkWindow       *window,
311                                        GdkDevice       *device,
312                                        gint            *x,
313                                        gint            *y,
314                                        GdkModifierType *mask)
315 {
316   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
317   GdkOffscreenWindow *offscreen;
318   int tmpx, tmpy;
319   double dtmpx, dtmpy;
320   GdkModifierType tmpmask;
321
322   tmpx = 0;
323   tmpy = 0;
324   tmpmask = 0;
325
326   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
327   if (offscreen->embedder != NULL)
328     {
329       gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
330       from_embedder (window,
331                      tmpx, tmpy,
332                      &dtmpx, &dtmpy);
333       tmpx = floor (dtmpx + 0.5);
334       tmpy = floor (dtmpy + 0.5);
335     }
336
337   if (x)
338     *x = tmpx;
339   if (y)
340     *y = tmpy;
341   if (mask)
342     *mask = tmpmask;
343   return TRUE;
344 }
345
346 /**
347  * gdk_offscreen_window_get_surface:
348  * @window: a #GdkWindow
349  *
350  * Gets the offscreen surface that an offscreen window renders into.
351  * If you need to keep this around over window resizes, you need to
352  * add a reference to it.
353  *
354  * Returns: The offscreen surface, or %NULL if not offscreen
355  */
356 cairo_surface_t *
357 gdk_offscreen_window_get_surface (GdkWindow *window)
358 {
359   GdkWindowObject *private = (GdkWindowObject *)window;
360   GdkOffscreenWindow *offscreen;
361
362   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
363
364   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
365     return NULL;
366
367   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
368
369   return get_surface (offscreen);
370 }
371
372 static void
373 gdk_offscreen_window_raise (GdkWindow *window)
374 {
375   /* gdk_window_raise already changed the stacking order */
376   _gdk_synthesize_crossing_events_for_geometry_change (window);
377 }
378
379 static void
380 gdk_offscreen_window_lower (GdkWindow *window)
381 {
382   /* gdk_window_lower already changed the stacking order */
383   _gdk_synthesize_crossing_events_for_geometry_change (window);
384 }
385
386 static void
387 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
388                                            gint       x,
389                                            gint       y,
390                                            gint       width,
391                                            gint       height,
392                                            gboolean   send_expose_events)
393 {
394   GdkWindowObject *private = (GdkWindowObject *)window;
395   GdkOffscreenWindow *offscreen;
396   gint dx, dy, dw, dh;
397
398   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
399
400   if (width < 1)
401     width = 1;
402   if (height < 1)
403     height = 1;
404
405   if (private->destroyed)
406     return;
407
408   dx = x - private->x;
409   dy = y - private->y;
410   dw = width - private->width;
411   dh = height - private->height;
412
413   private->x = x;
414   private->y = y;
415
416   if (private->width != width ||
417       private->height != height)
418     {
419       private->width = width;
420       private->height = height;
421
422       if (offscreen->surface)
423         {
424           cairo_surface_t *old_surface;
425           cairo_t *cr;
426
427           old_surface = offscreen->surface;
428           offscreen->surface = NULL;
429
430           offscreen->surface = get_surface (offscreen);
431
432           cr = cairo_create (offscreen->surface);
433           cairo_set_source_surface (cr, old_surface, 0, 0);
434           cairo_paint (cr);
435           cairo_destroy (cr);
436
437           cairo_surface_destroy (old_surface);
438         }
439     }
440
441   if (GDK_WINDOW_IS_MAPPED (private))
442     {
443       // TODO: Only invalidate new area, i.e. for larger windows
444       gdk_window_invalidate_rect (window, NULL, TRUE);
445       _gdk_synthesize_crossing_events_for_geometry_change (window);
446     }
447 }
448
449 static void
450 gdk_offscreen_window_move_resize (GdkWindow *window,
451                                   gboolean   with_move,
452                                   gint       x,
453                                   gint       y,
454                                   gint       width,
455                                   gint       height)
456 {
457   GdkWindowObject *private = (GdkWindowObject *)window;
458   GdkOffscreenWindow *offscreen;
459
460   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
461
462   if (!with_move)
463     {
464       x = private->x;
465       y = private->y;
466     }
467
468   if (width < 0)
469     width = private->width;
470
471   if (height < 0)
472     height = private->height;
473
474   gdk_offscreen_window_move_resize_internal (window, x, y,
475                                              width, height,
476                                              TRUE);
477 }
478
479 static void
480 gdk_offscreen_window_show (GdkWindow *window,
481                            gboolean already_mapped)
482 {
483   GdkWindowObject *private = (GdkWindowObject *)window;
484   GdkRectangle area = { 0, 0, private->width, private->height };
485
486   gdk_window_invalidate_rect (window, &area, FALSE);
487 }
488
489
490 static void
491 gdk_offscreen_window_hide (GdkWindow *window)
492 {
493   GdkWindowObject *private;
494   GdkOffscreenWindow *offscreen;
495   GdkDisplay *display;
496
497   g_return_if_fail (window != NULL);
498
499   private = (GdkWindowObject*) window;
500   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
501
502   /* May need to break grabs on children */
503   display = gdk_window_get_display (window);
504
505   /* TODO: This needs updating to the new grab world */
506 #if 0
507   if (display->pointer_grab.window != NULL)
508     {
509       if (is_parent_of (window, display->pointer_grab.window))
510         {
511           /* Call this ourselves, even though gdk_display_pointer_ungrab
512              does so too, since we want to pass implicit == TRUE so the
513              broken grab event is generated */
514           _gdk_display_unset_has_pointer_grab (display,
515                                                TRUE,
516                                                FALSE,
517                                                GDK_CURRENT_TIME);
518           gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
519         }
520     }
521 #endif
522 }
523
524 static void
525 gdk_offscreen_window_withdraw (GdkWindow *window)
526 {
527 }
528
529 static GdkEventMask
530 gdk_offscreen_window_get_events (GdkWindow *window)
531 {
532   return 0;
533 }
534
535 static void
536 gdk_offscreen_window_set_events (GdkWindow       *window,
537                                  GdkEventMask     event_mask)
538 {
539 }
540
541 static void
542 gdk_offscreen_window_set_background (GdkWindow      *window,
543                                      cairo_pattern_t *pattern)
544 {
545 }
546
547 static void
548 gdk_offscreen_window_shape_combine_region (GdkWindow       *window,
549                                            const cairo_region_t *shape_region,
550                                            gint             offset_x,
551                                            gint             offset_y)
552 {
553 }
554
555 static void
556 gdk_offscreen_window_input_shape_combine_region (GdkWindow       *window,
557                                                  const cairo_region_t *shape_region,
558                                                  gint             offset_x,
559                                                  gint             offset_y)
560 {
561 }
562
563 static gboolean
564 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
565                                            gboolean   use_static)
566 {
567   return TRUE;
568 }
569
570 static void
571 gdk_offscreen_window_get_geometry (GdkWindow *window,
572                                    gint      *x,
573                                    gint      *y,
574                                    gint      *width,
575                                    gint      *height,
576                                    gint      *depth)
577 {
578   GdkWindowObject *private = (GdkWindowObject *)window;
579
580   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
581
582   if (!GDK_WINDOW_DESTROYED (window))
583     {
584       if (x)
585         *x = private->x;
586       if (y)
587         *y = private->y;
588       if (width)
589         *width = private->width;
590       if (height)
591         *height = private->height;
592       if (depth)
593         *depth = private->depth;
594     }
595 }
596
597 static gboolean
598 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
599                                        cairo_region_t *area)
600 {
601   return FALSE;
602 }
603
604 static void
605 gdk_offscreen_window_translate (GdkWindow      *window,
606                                 cairo_region_t *area,
607                                 gint            dx,
608                                 gint            dy)
609 {
610   GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (((GdkWindowObject *) window)->impl);
611
612   if (offscreen->surface)
613     {
614       cairo_t *cr;
615
616       cr = cairo_create (offscreen->surface);
617
618       area = cairo_region_copy (area);
619
620       gdk_cairo_region (cr, area);
621       cairo_clip (cr);
622
623       /* NB: This is a self-copy and Cairo doesn't support that yet.
624        * So we do a litle trick.
625        */
626       cairo_push_group (cr);
627
628       cairo_set_source_surface (cr, offscreen->surface, dx, dy);
629       cairo_paint (cr);
630
631       cairo_pop_group_to_source (cr);
632       cairo_paint (cr);
633
634       cairo_destroy (cr);
635     }
636
637   _gdk_window_add_damage (window, area);
638 }
639
640 static cairo_surface_t *
641 gdk_offscreen_window_resize_cairo_surface (GdkDrawable     *window,
642                                            cairo_surface_t *surface,
643                                            gint             width,
644                                            gint             height)
645 {
646   /* No-op.  The surface gets resized in
647    * gdk_offscreen_window_move_resize_internal().
648    */
649   return surface;
650 }
651
652 /**
653  * gdk_offscreen_window_set_embedder:
654  * @window: a #GdkWindow
655  * @embedder: the #GdkWindow that @window gets embedded in
656  *
657  * Sets @window to be embedded in @embedder.
658  *
659  * To fully embed an offscreen window, in addition to calling this
660  * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
661  * signal on the @embedder and the #GdkWindow::to-embedder and
662  * #GdkWindow::from-embedder signals on @window.
663  *
664  * Since: 2.18
665  */
666 void
667 gdk_offscreen_window_set_embedder (GdkWindow     *window,
668                                    GdkWindow     *embedder)
669 {
670   GdkWindowObject *private = (GdkWindowObject *)window;
671   GdkOffscreenWindow *offscreen;
672
673   g_return_if_fail (GDK_IS_WINDOW (window));
674
675   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
676     return;
677
678   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
679
680   if (embedder)
681     {
682       g_object_ref (embedder);
683       GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
684     }
685
686   if (offscreen->embedder)
687     {
688       g_object_unref (offscreen->embedder);
689       GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
690     }
691
692   offscreen->embedder = embedder;
693 }
694
695 /**
696  * gdk_offscreen_window_get_embedder:
697  * @window: a #GdkWindow
698  *
699  * Gets the window that @window is embedded in.
700  *
701  * Returns: (transfer none): the embedding #GdkWindow, or %NULL
702  *     if @window is not an mbedded offscreen window
703  *
704  * Since: 2.18
705  */
706 GdkWindow *
707 gdk_offscreen_window_get_embedder (GdkWindow *window)
708 {
709   GdkWindowObject *private = (GdkWindowObject *)window;
710   GdkOffscreenWindow *offscreen;
711
712   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
713
714   if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
715     return NULL;
716
717   offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
718
719   return offscreen->embedder;
720 }
721
722 static void
723 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
724 {
725   GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
726   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
727   GObjectClass *object_class = G_OBJECT_CLASS (klass);
728
729   object_class->finalize = gdk_offscreen_window_finalize;
730
731   drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
732
733   impl_class->show = gdk_offscreen_window_show;
734   impl_class->hide = gdk_offscreen_window_hide;
735   impl_class->withdraw = gdk_offscreen_window_withdraw;
736   impl_class->raise = gdk_offscreen_window_raise;
737   impl_class->lower = gdk_offscreen_window_lower;
738   impl_class->move_resize = gdk_offscreen_window_move_resize;
739   impl_class->set_background = gdk_offscreen_window_set_background;
740   impl_class->get_events = gdk_offscreen_window_get_events;
741   impl_class->set_events = gdk_offscreen_window_set_events;
742   impl_class->reparent = gdk_offscreen_window_reparent;
743   impl_class->get_geometry = gdk_offscreen_window_get_geometry;
744   impl_class->shape_combine_region = gdk_offscreen_window_shape_combine_region;
745   impl_class->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
746   impl_class->set_static_gravities = gdk_offscreen_window_set_static_gravities;
747   impl_class->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
748   impl_class->translate = gdk_offscreen_window_translate;
749   impl_class->get_root_coords = gdk_offscreen_window_get_root_coords;
750   impl_class->get_device_state = gdk_offscreen_window_get_device_state;
751   impl_class->destroy = gdk_offscreen_window_destroy;
752   impl_class->resize_cairo_surface = gdk_offscreen_window_resize_cairo_surface;
753 }