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