1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
29 #include "gdkwindow.h"
30 #include "gdkinternals.h"
31 #include "gdkwindowimpl.h"
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
42 typedef struct _GdkOffscreenWindow GdkOffscreenWindow;
43 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
45 struct _GdkOffscreenWindow
47 GdkWindowImpl parent_instance;
51 cairo_surface_t *surface;
55 struct _GdkOffscreenWindowClass
57 GdkWindowImplClass parent_class;
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))
67 static void gdk_offscreen_window_hide (GdkWindow *window);
69 G_DEFINE_TYPE (GdkOffscreenWindow, gdk_offscreen_window, GDK_TYPE_WINDOW_IMPL)
73 gdk_offscreen_window_finalize (GObject *object)
75 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
77 if (offscreen->surface)
78 cairo_surface_destroy (offscreen->surface);
80 G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
84 gdk_offscreen_window_init (GdkOffscreenWindow *window)
89 gdk_offscreen_window_destroy (GdkWindow *window,
91 gboolean foreign_destroy)
93 GdkOffscreenWindow *offscreen;
95 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
97 gdk_offscreen_window_set_embedder (window, NULL);
100 gdk_offscreen_window_hide (window);
103 static cairo_surface_t *
104 get_surface (GdkOffscreenWindow *offscreen)
106 if (! offscreen->surface)
108 GdkWindow *window = offscreen->wrapper;
110 g_signal_emit_by_name (window, "create-surface",
113 &offscreen->surface);
116 return offscreen->surface;
120 is_parent_of (GdkWindow *parent,
131 w = gdk_window_get_parent (w);
137 static cairo_surface_t *
138 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
140 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
142 return cairo_surface_reference (get_surface (offscreen));
146 _gdk_offscreen_window_create_surface (GdkWindow *offscreen,
150 cairo_surface_t *similar;
151 cairo_surface_t *surface;
152 cairo_content_t content = CAIRO_CONTENT_COLOR;
154 g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (offscreen->impl), NULL);
156 similar = _gdk_window_ref_cairo_surface (offscreen->parent);
158 if (gdk_window_get_visual (offscreen) ==
159 gdk_screen_get_rgba_visual (gdk_window_get_screen (offscreen)))
161 content = CAIRO_CONTENT_COLOR_ALPHA;
164 surface = cairo_surface_create_similar (similar, content, width, height);
166 cairo_surface_destroy (similar);
172 _gdk_offscreen_window_new (GdkWindow *window,
173 GdkWindowAttr *attributes,
174 gint attributes_mask)
176 GdkOffscreenWindow *offscreen;
178 g_return_if_fail (attributes != NULL);
180 if (attributes->wclass != GDK_INPUT_OUTPUT)
181 return; /* Can't support input only offscreens */
183 if (window->parent != NULL && GDK_WINDOW_DESTROYED (window->parent))
186 window->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
187 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
188 offscreen->wrapper = window;
192 gdk_offscreen_window_reparent (GdkWindow *window,
193 GdkWindow *new_parent,
197 GdkWindow *old_parent;
202 /* No input-output children of input-only windows */
203 if (new_parent->input_only && !window->input_only)
206 /* Don't create loops in hierarchy */
207 if (is_parent_of (window, new_parent))
211 was_mapped = GDK_WINDOW_IS_MAPPED (window);
213 gdk_window_hide (window);
216 window->parent->children = g_list_remove (window->parent->children, window);
218 old_parent = window->parent;
219 window->parent = new_parent;
224 window->parent->children = g_list_prepend (window->parent->children, window);
226 _gdk_synthesize_crossing_events_for_geometry_change (window);
228 _gdk_synthesize_crossing_events_for_geometry_change (old_parent);
234 from_embedder (GdkWindow *window,
235 double embedder_x, double embedder_y,
236 double *offscreen_x, double *offscreen_y)
238 g_signal_emit_by_name (window->impl_window,
240 embedder_x, embedder_y,
241 offscreen_x, offscreen_y,
246 to_embedder (GdkWindow *window,
247 double offscreen_x, double offscreen_y,
248 double *embedder_x, double *embedder_y)
250 g_signal_emit_by_name (window->impl_window,
252 offscreen_x, offscreen_y,
253 embedder_x, embedder_y,
258 gdk_offscreen_window_get_root_coords (GdkWindow *window,
264 GdkOffscreenWindow *offscreen;
270 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
271 if (offscreen->embedder)
277 tmpx = floor (dx + 0.5);
278 tmpy = floor (dy + 0.5);
279 gdk_window_get_root_coords (offscreen->embedder,
294 gdk_offscreen_window_get_device_state (GdkWindow *window,
298 GdkModifierType *mask)
300 GdkOffscreenWindow *offscreen;
303 GdkModifierType tmpmask;
309 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
310 if (offscreen->embedder != NULL)
312 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
313 from_embedder (window,
316 tmpx = floor (dtmpx + 0.5);
317 tmpy = floor (dtmpy + 0.5);
330 * gdk_offscreen_window_get_surface:
331 * @window: a #GdkWindow
333 * Gets the offscreen surface that an offscreen window renders into.
334 * If you need to keep this around over window resizes, you need to
335 * add a reference to it.
337 * Returns: The offscreen surface, or %NULL if not offscreen
340 gdk_offscreen_window_get_surface (GdkWindow *window)
342 GdkOffscreenWindow *offscreen;
344 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
346 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
349 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
351 return get_surface (offscreen);
355 gdk_offscreen_window_raise (GdkWindow *window)
357 /* gdk_window_raise already changed the stacking order */
358 _gdk_synthesize_crossing_events_for_geometry_change (window);
362 gdk_offscreen_window_lower (GdkWindow *window)
364 /* gdk_window_lower already changed the stacking order */
365 _gdk_synthesize_crossing_events_for_geometry_change (window);
369 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
374 gboolean send_expose_events)
376 GdkOffscreenWindow *offscreen;
379 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
386 if (window->destroyed)
391 dw = width - window->width;
392 dh = height - window->height;
397 if (window->width != width ||
398 window->height != height)
400 window->width = width;
401 window->height = height;
403 if (offscreen->surface)
405 cairo_surface_t *old_surface;
408 old_surface = offscreen->surface;
409 offscreen->surface = NULL;
411 offscreen->surface = get_surface (offscreen);
413 cr = cairo_create (offscreen->surface);
414 cairo_set_source_surface (cr, old_surface, 0, 0);
418 cairo_surface_destroy (old_surface);
422 if (GDK_WINDOW_IS_MAPPED (window))
424 // TODO: Only invalidate new area, i.e. for larger windows
425 gdk_window_invalidate_rect (window, NULL, TRUE);
426 _gdk_synthesize_crossing_events_for_geometry_change (window);
431 gdk_offscreen_window_move_resize (GdkWindow *window,
438 GdkOffscreenWindow *offscreen;
440 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
449 width = window->width;
452 height = window->height;
454 gdk_offscreen_window_move_resize_internal (window, x, y,
460 gdk_offscreen_window_show (GdkWindow *window,
461 gboolean already_mapped)
463 GdkRectangle area = { 0, 0, window->width, window->height };
465 gdk_window_invalidate_rect (window, &area, FALSE);
470 gdk_offscreen_window_hide (GdkWindow *window)
472 GdkOffscreenWindow *offscreen;
475 g_return_if_fail (window != NULL);
477 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
479 /* May need to break grabs on children */
480 display = gdk_window_get_display (window);
482 /* TODO: This needs updating to the new grab world */
484 if (display->pointer_grab.window != NULL)
486 if (is_parent_of (window, display->pointer_grab.window))
488 /* Call this ourselves, even though gdk_display_pointer_ungrab
489 does so too, since we want to pass implicit == TRUE so the
490 broken grab event is generated */
491 _gdk_display_unset_has_pointer_grab (display,
495 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
502 gdk_offscreen_window_withdraw (GdkWindow *window)
507 gdk_offscreen_window_get_events (GdkWindow *window)
513 gdk_offscreen_window_set_events (GdkWindow *window,
514 GdkEventMask event_mask)
519 gdk_offscreen_window_set_background (GdkWindow *window,
520 cairo_pattern_t *pattern)
525 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
526 const cairo_region_t *shape_region,
533 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
534 const cairo_region_t *shape_region,
541 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
548 gdk_offscreen_window_get_geometry (GdkWindow *window,
555 if (!GDK_WINDOW_DESTROYED (window))
562 *width = window->width;
564 *height = window->height;
566 *depth = window->depth;
571 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
572 cairo_region_t *area)
578 gdk_offscreen_window_translate (GdkWindow *window,
579 cairo_region_t *area,
583 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
585 if (offscreen->surface)
589 cr = cairo_create (offscreen->surface);
591 area = cairo_region_copy (area);
593 gdk_cairo_region (cr, area);
596 /* NB: This is a self-copy and Cairo doesn't support that yet.
597 * So we do a litle trick.
599 cairo_push_group (cr);
601 cairo_set_source_surface (cr, offscreen->surface, dx, dy);
604 cairo_pop_group_to_source (cr);
610 _gdk_window_add_damage (window, area);
613 static cairo_surface_t *
614 gdk_offscreen_window_resize_cairo_surface (GdkDrawable *window,
615 cairo_surface_t *surface,
619 /* No-op. The surface gets resized in
620 * gdk_offscreen_window_move_resize_internal().
626 * gdk_offscreen_window_set_embedder:
627 * @window: a #GdkWindow
628 * @embedder: the #GdkWindow that @window gets embedded in
630 * Sets @window to be embedded in @embedder.
632 * To fully embed an offscreen window, in addition to calling this
633 * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
634 * signal on the @embedder and the #GdkWindow::to-embedder and
635 * #GdkWindow::from-embedder signals on @window.
640 gdk_offscreen_window_set_embedder (GdkWindow *window,
643 GdkOffscreenWindow *offscreen;
645 g_return_if_fail (GDK_IS_WINDOW (window));
647 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
650 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
654 g_object_ref (embedder);
655 embedder->num_offscreen_children++;
658 if (offscreen->embedder)
660 g_object_unref (offscreen->embedder);
661 offscreen->embedder->num_offscreen_children--;
664 offscreen->embedder = embedder;
668 * gdk_offscreen_window_get_embedder:
669 * @window: a #GdkWindow
671 * Gets the window that @window is embedded in.
673 * Returns: (transfer none): the embedding #GdkWindow, or %NULL
674 * if @window is not an mbedded offscreen window
679 gdk_offscreen_window_get_embedder (GdkWindow *window)
681 GdkOffscreenWindow *offscreen;
683 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
685 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
688 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
690 return offscreen->embedder;
694 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
696 GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
697 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
698 GObjectClass *object_class = G_OBJECT_CLASS (klass);
700 object_class->finalize = gdk_offscreen_window_finalize;
702 drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
704 impl_class->show = gdk_offscreen_window_show;
705 impl_class->hide = gdk_offscreen_window_hide;
706 impl_class->withdraw = gdk_offscreen_window_withdraw;
707 impl_class->raise = gdk_offscreen_window_raise;
708 impl_class->lower = gdk_offscreen_window_lower;
709 impl_class->move_resize = gdk_offscreen_window_move_resize;
710 impl_class->set_background = gdk_offscreen_window_set_background;
711 impl_class->get_events = gdk_offscreen_window_get_events;
712 impl_class->set_events = gdk_offscreen_window_set_events;
713 impl_class->reparent = gdk_offscreen_window_reparent;
714 impl_class->get_geometry = gdk_offscreen_window_get_geometry;
715 impl_class->shape_combine_region = gdk_offscreen_window_shape_combine_region;
716 impl_class->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
717 impl_class->set_static_gravities = gdk_offscreen_window_set_static_gravities;
718 impl_class->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
719 impl_class->translate = gdk_offscreen_window_translate;
720 impl_class->get_root_coords = gdk_offscreen_window_get_root_coords;
721 impl_class->get_device_state = gdk_offscreen_window_get_device_state;
722 impl_class->destroy = gdk_offscreen_window_destroy;
723 impl_class->resize_cairo_surface = gdk_offscreen_window_resize_cairo_surface;