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/.
31 #include "gdkwindow.h"
32 #include "gdkinternals.h"
33 #include "gdkwindowimpl.h"
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
43 typedef struct _GdkOffscreenWindow GdkOffscreenWindow;
44 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
46 struct _GdkOffscreenWindow
48 GdkDrawable parent_instance;
52 cairo_surface_t *surface;
56 struct _GdkOffscreenWindowClass
58 GdkDrawableClass parent_class;
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))
68 static void gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface);
69 static void gdk_offscreen_window_hide (GdkWindow *window);
71 G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow,
74 G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
75 gdk_offscreen_window_impl_iface_init));
79 gdk_offscreen_window_finalize (GObject *object)
81 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
83 if (offscreen->surface)
84 cairo_surface_destroy (offscreen->surface);
86 G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
90 gdk_offscreen_window_init (GdkOffscreenWindow *window)
95 gdk_offscreen_window_destroy (GdkWindow *window,
97 gboolean foreign_destroy)
99 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
100 GdkOffscreenWindow *offscreen;
102 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
104 gdk_offscreen_window_set_embedder (window, NULL);
107 gdk_offscreen_window_hide (window);
110 static cairo_surface_t *
111 get_surface (GdkOffscreenWindow *offscreen)
113 if (! offscreen->surface)
115 GdkWindowObject *private = (GdkWindowObject *) offscreen->wrapper;
117 g_signal_emit_by_name (private, "create-surface",
120 &offscreen->surface);
123 return offscreen->surface;
127 is_parent_of (GdkWindow *parent,
138 w = gdk_window_get_parent (w);
144 static cairo_surface_t *
145 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
147 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
149 return cairo_surface_reference (get_surface (offscreen));
153 _gdk_offscreen_window_create_surface (GdkWindow *offscreen,
157 GdkWindowObject *private = (GdkWindowObject *) offscreen;
158 cairo_surface_t *similar;
159 cairo_surface_t *surface;
161 g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (private->impl), NULL);
163 similar = _gdk_drawable_ref_cairo_surface ((GdkWindow *)private->parent);
165 surface = cairo_surface_create_similar (similar,
166 /* FIXME: use visual */
171 cairo_surface_destroy (similar);
177 _gdk_offscreen_window_new (GdkWindow *window,
178 GdkWindowAttr *attributes,
179 gint attributes_mask)
181 GdkWindowObject *private;
182 GdkOffscreenWindow *offscreen;
184 g_return_if_fail (attributes != NULL);
186 if (attributes->wclass != GDK_INPUT_OUTPUT)
187 return; /* Can't support input only offscreens */
189 private = (GdkWindowObject *)window;
191 if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
194 private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
195 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
196 offscreen->wrapper = window;
200 gdk_offscreen_window_reparent (GdkWindow *window,
201 GdkWindow *new_parent,
205 GdkWindowObject *private = (GdkWindowObject *)window;
206 GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
207 GdkWindowObject *old_parent;
212 /* No input-output children of input-only windows */
213 if (new_parent_private->input_only && !private->input_only)
216 /* Don't create loops in hierarchy */
217 if (is_parent_of (window, new_parent))
221 was_mapped = GDK_WINDOW_IS_MAPPED (window);
223 gdk_window_hide (window);
226 private->parent->children = g_list_remove (private->parent->children, window);
228 old_parent = private->parent;
229 private->parent = new_parent_private;
233 if (new_parent_private)
234 private->parent->children = g_list_prepend (private->parent->children, window);
236 _gdk_synthesize_crossing_events_for_geometry_change (window);
238 _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
244 from_embedder (GdkWindow *window,
245 double embedder_x, double embedder_y,
246 double *offscreen_x, double *offscreen_y)
248 GdkWindowObject *private;
250 private = (GdkWindowObject *)window;
252 g_signal_emit_by_name (private->impl_window,
254 embedder_x, embedder_y,
255 offscreen_x, offscreen_y,
260 to_embedder (GdkWindow *window,
261 double offscreen_x, double offscreen_y,
262 double *embedder_x, double *embedder_y)
264 GdkWindowObject *private;
266 private = (GdkWindowObject *)window;
268 g_signal_emit_by_name (private->impl_window,
270 offscreen_x, offscreen_y,
271 embedder_x, embedder_y,
276 gdk_offscreen_window_get_root_coords (GdkWindow *window,
282 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
283 GdkOffscreenWindow *offscreen;
289 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
290 if (offscreen->embedder)
296 tmpx = floor (dx + 0.5);
297 tmpy = floor (dy + 0.5);
298 gdk_window_get_root_coords (offscreen->embedder,
313 gdk_offscreen_window_get_device_state (GdkWindow *window,
317 GdkModifierType *mask)
319 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
320 GdkOffscreenWindow *offscreen;
323 GdkModifierType tmpmask;
329 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
330 if (offscreen->embedder != NULL)
332 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
333 from_embedder (window,
336 tmpx = floor (dtmpx + 0.5);
337 tmpy = floor (dtmpy + 0.5);
350 * gdk_offscreen_window_get_surface:
351 * @window: a #GdkWindow
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.
357 * Returns: The offscreen surface, or %NULL if not offscreen
360 gdk_offscreen_window_get_surface (GdkWindow *window)
362 GdkWindowObject *private = (GdkWindowObject *)window;
363 GdkOffscreenWindow *offscreen;
365 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
367 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
370 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
372 return get_surface (offscreen);
376 gdk_offscreen_window_raise (GdkWindow *window)
378 /* gdk_window_raise already changed the stacking order */
379 _gdk_synthesize_crossing_events_for_geometry_change (window);
383 gdk_offscreen_window_lower (GdkWindow *window)
385 /* gdk_window_lower already changed the stacking order */
386 _gdk_synthesize_crossing_events_for_geometry_change (window);
390 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
395 gboolean send_expose_events)
397 GdkWindowObject *private = (GdkWindowObject *)window;
398 GdkOffscreenWindow *offscreen;
401 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
408 if (private->destroyed)
413 dw = width - private->width;
414 dh = height - private->height;
419 if (private->width != width ||
420 private->height != height)
422 private->width = width;
423 private->height = height;
425 if (offscreen->surface)
427 cairo_surface_t *old_surface;
430 old_surface = offscreen->surface;
431 offscreen->surface = NULL;
433 offscreen->surface = get_surface (offscreen);
435 cr = cairo_create (offscreen->surface);
436 cairo_set_source_surface (cr, old_surface, 0, 0);
440 cairo_surface_destroy (old_surface);
444 if (GDK_WINDOW_IS_MAPPED (private))
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);
453 gdk_offscreen_window_move_resize (GdkWindow *window,
460 GdkWindowObject *private = (GdkWindowObject *)window;
461 GdkOffscreenWindow *offscreen;
463 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
472 width = private->width;
475 height = private->height;
477 gdk_offscreen_window_move_resize_internal (window, x, y,
483 gdk_offscreen_window_show (GdkWindow *window,
484 gboolean already_mapped)
486 GdkWindowObject *private = (GdkWindowObject *)window;
487 GdkRectangle area = { 0, 0, private->width, private->height };
489 gdk_window_invalidate_rect (window, &area, FALSE);
494 gdk_offscreen_window_hide (GdkWindow *window)
496 GdkWindowObject *private;
497 GdkOffscreenWindow *offscreen;
500 g_return_if_fail (window != NULL);
502 private = (GdkWindowObject*) window;
503 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
505 /* May need to break grabs on children */
506 display = gdk_window_get_display (window);
508 /* TODO: This needs updating to the new grab world */
510 if (display->pointer_grab.window != NULL)
512 if (is_parent_of (window, display->pointer_grab.window))
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,
521 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
528 gdk_offscreen_window_withdraw (GdkWindow *window)
533 gdk_offscreen_window_get_events (GdkWindow *window)
539 gdk_offscreen_window_set_events (GdkWindow *window,
540 GdkEventMask event_mask)
545 gdk_offscreen_window_set_background (GdkWindow *window,
546 cairo_pattern_t *pattern)
551 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
552 const cairo_region_t *shape_region,
559 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
560 const cairo_region_t *shape_region,
567 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
574 gdk_offscreen_window_get_geometry (GdkWindow *window,
581 GdkWindowObject *private = (GdkWindowObject *)window;
583 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
585 if (!GDK_WINDOW_DESTROYED (window))
592 *width = private->width;
594 *height = private->height;
596 *depth = private->depth;
601 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
602 cairo_region_t *area)
608 gdk_offscreen_window_translate (GdkWindow *window,
609 cairo_region_t *area,
613 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (((GdkWindowObject *) window)->impl);
615 if (offscreen->surface)
619 cr = cairo_create (offscreen->surface);
621 area = cairo_region_copy (area);
623 gdk_cairo_region (cr, area);
626 /* NB: This is a self-copy and Cairo doesn't support that yet.
627 * So we do a litle trick.
629 cairo_push_group (cr);
631 cairo_set_source_surface (cr, offscreen->surface, dx, dy);
634 cairo_pop_group_to_source (cr);
640 _gdk_window_add_damage (window, area);
643 static cairo_surface_t *
644 gdk_offscreen_window_resize_cairo_surface (GdkWindow *window,
645 cairo_surface_t *surface,
649 /* No-op. The surface gets resized in
650 * gdk_offscreen_window_move_resize_internal().
656 * gdk_offscreen_window_set_embedder:
657 * @window: a #GdkWindow
658 * @embedder: the #GdkWindow that @window gets embedded in
660 * Sets @window to be embedded in @embedder.
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.
670 gdk_offscreen_window_set_embedder (GdkWindow *window,
673 GdkWindowObject *private = (GdkWindowObject *)window;
674 GdkOffscreenWindow *offscreen;
676 g_return_if_fail (GDK_IS_WINDOW (window));
678 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
681 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
685 g_object_ref (embedder);
686 GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
689 if (offscreen->embedder)
691 g_object_unref (offscreen->embedder);
692 GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
695 offscreen->embedder = embedder;
699 * gdk_offscreen_window_get_embedder:
700 * @window: a #GdkWindow
702 * Gets the window that @window is embedded in.
704 * Returns: the embedding #GdkWindow, or %NULL if @window is not an
705 * embedded offscreen window
710 gdk_offscreen_window_get_embedder (GdkWindow *window)
712 GdkWindowObject *private = (GdkWindowObject *)window;
713 GdkOffscreenWindow *offscreen;
715 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
717 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
720 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
722 return offscreen->embedder;
726 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
728 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
729 GObjectClass *object_class = G_OBJECT_CLASS (klass);
731 object_class->finalize = gdk_offscreen_window_finalize;
733 drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
737 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
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;