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/.
30 #include "gdkwindow.h"
31 #include "gdkinternals.h"
32 #include "gdkwindowimpl.h"
33 #include "gdkdrawable.h"
35 #include "gdkscreen.h"
41 * Offscreen windows can't be the child of a foreign window,
42 * nor contain foreign windows
43 * GDK_POINTER_MOTION_HINT_MASK isn't effective
46 typedef struct _GdkOffscreenWindow GdkOffscreenWindow;
47 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
49 struct _GdkOffscreenWindow
51 GdkDrawable parent_instance;
54 GdkColormap *colormap;
57 cairo_surface_t *surface;
61 struct _GdkOffscreenWindowClass
63 GdkDrawableClass parent_class;
66 #define GDK_TYPE_OFFSCREEN_WINDOW (gdk_offscreen_window_get_type())
67 #define GDK_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow))
68 #define GDK_IS_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW))
69 #define GDK_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
70 #define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW))
71 #define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
73 static void gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface);
74 static void gdk_offscreen_window_hide (GdkWindow *window);
76 G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow,
79 G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
80 gdk_offscreen_window_impl_iface_init));
84 gdk_offscreen_window_finalize (GObject *object)
86 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
88 cairo_surface_destroy (offscreen->surface);
90 G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
94 gdk_offscreen_window_init (GdkOffscreenWindow *window)
99 gdk_offscreen_window_destroy (GdkWindow *window,
101 gboolean foreign_destroy)
103 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
104 GdkOffscreenWindow *offscreen;
106 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
108 gdk_offscreen_window_set_embedder (window, NULL);
111 gdk_offscreen_window_hide (window);
113 g_object_unref (offscreen->colormap);
114 offscreen->colormap = NULL;
118 is_parent_of (GdkWindow *parent,
129 w = gdk_window_get_parent (w);
135 static cairo_surface_t *
136 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
138 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
140 return cairo_surface_reference (offscreen->surface);
144 gdk_offscreen_window_get_colormap (GdkDrawable *drawable)
146 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
148 return offscreen->colormap;
152 gdk_offscreen_window_set_colormap (GdkDrawable *drawable,
153 GdkColormap*colormap)
155 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
157 if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper))
160 if (offscreen->colormap == colormap)
163 if (offscreen->colormap)
164 g_object_unref (offscreen->colormap);
166 offscreen->colormap = colormap;
167 if (offscreen->colormap)
168 g_object_ref (offscreen->colormap);
173 gdk_offscreen_window_get_depth (GdkDrawable *drawable)
175 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
177 return gdk_drawable_get_depth (offscreen->wrapper);
181 gdk_offscreen_window_get_source_drawable (GdkDrawable *drawable)
183 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
185 return gdk_screen_get_root_window (offscreen->screen);
189 gdk_offscreen_window_get_screen (GdkDrawable *drawable)
191 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
193 return offscreen->screen;
197 gdk_offscreen_window_get_visual (GdkDrawable *drawable)
199 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
201 return gdk_drawable_get_visual (offscreen->wrapper);
205 _gdk_offscreen_window_new (GdkWindow *window,
208 GdkWindowAttr *attributes,
209 gint attributes_mask)
211 GdkWindowObject *private;
212 GdkOffscreenWindow *offscreen;
214 g_return_if_fail (attributes != NULL);
216 if (attributes->wclass != GDK_INPUT_OUTPUT)
217 return; /* Can't support input only offscreens */
219 private = (GdkWindowObject *)window;
221 if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
224 private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
225 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
226 offscreen->wrapper = window;
228 offscreen->screen = screen;
230 if (attributes_mask & GDK_WA_COLORMAP)
231 offscreen->colormap = g_object_ref (attributes->colormap);
234 if (gdk_screen_get_system_visual (screen) == visual)
236 offscreen->colormap = gdk_screen_get_system_colormap (screen);
237 g_object_ref (offscreen->colormap);
240 offscreen->colormap = gdk_colormap_new (visual, FALSE);
243 offscreen->surface = gdk_window_create_similar_surface ((GdkWindow *)private->parent,
250 gdk_offscreen_window_reparent (GdkWindow *window,
251 GdkWindow *new_parent,
255 GdkWindowObject *private = (GdkWindowObject *)window;
256 GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
257 GdkWindowObject *old_parent;
262 /* No input-output children of input-only windows */
263 if (new_parent_private->input_only && !private->input_only)
266 /* Don't create loops in hierarchy */
267 if (is_parent_of (window, new_parent))
271 was_mapped = GDK_WINDOW_IS_MAPPED (window);
273 gdk_window_hide (window);
276 private->parent->children = g_list_remove (private->parent->children, window);
278 old_parent = private->parent;
279 private->parent = new_parent_private;
283 if (new_parent_private)
284 private->parent->children = g_list_prepend (private->parent->children, window);
286 _gdk_synthesize_crossing_events_for_geometry_change (window);
288 _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
294 from_embedder (GdkWindow *window,
295 double embedder_x, double embedder_y,
296 double *offscreen_x, double *offscreen_y)
298 GdkWindowObject *private;
300 private = (GdkWindowObject *)window;
302 g_signal_emit_by_name (private->impl_window,
304 embedder_x, embedder_y,
305 offscreen_x, offscreen_y,
310 to_embedder (GdkWindow *window,
311 double offscreen_x, double offscreen_y,
312 double *embedder_x, double *embedder_y)
314 GdkWindowObject *private;
316 private = (GdkWindowObject *)window;
318 g_signal_emit_by_name (private->impl_window,
320 offscreen_x, offscreen_y,
321 embedder_x, embedder_y,
326 gdk_offscreen_window_get_root_coords (GdkWindow *window,
332 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
333 GdkOffscreenWindow *offscreen;
339 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
340 if (offscreen->embedder)
346 tmpx = floor (dx + 0.5);
347 tmpy = floor (dy + 0.5);
348 gdk_window_get_root_coords (offscreen->embedder,
363 gdk_offscreen_window_get_device_state (GdkWindow *window,
367 GdkModifierType *mask)
369 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
370 GdkOffscreenWindow *offscreen;
373 GdkModifierType tmpmask;
379 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
380 if (offscreen->embedder != NULL)
382 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
383 from_embedder (window,
386 tmpx = floor (dtmpx + 0.5);
387 tmpy = floor (dtmpy + 0.5);
400 * gdk_offscreen_window_get_surface:
401 * @window: a #GdkWindow
403 * Gets the offscreen surface that an offscreen window renders into.
404 * If you need to keep this around over window resizes, you need to
405 * add a reference to it.
407 * Returns: The offscreen surface, or %NULL if not offscreen
410 gdk_offscreen_window_get_surface (GdkWindow *window)
412 GdkWindowObject *private = (GdkWindowObject *)window;
413 GdkOffscreenWindow *offscreen;
415 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
417 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
420 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
421 return offscreen->surface;
425 gdk_offscreen_window_raise (GdkWindow *window)
427 /* gdk_window_raise already changed the stacking order */
428 _gdk_synthesize_crossing_events_for_geometry_change (window);
432 gdk_offscreen_window_lower (GdkWindow *window)
434 /* gdk_window_lower already changed the stacking order */
435 _gdk_synthesize_crossing_events_for_geometry_change (window);
439 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
444 gboolean send_expose_events)
446 GdkWindowObject *private = (GdkWindowObject *)window;
447 GdkOffscreenWindow *offscreen;
449 cairo_surface_t *old_surface;
451 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
458 if (private->destroyed)
463 dw = width - private->width;
464 dh = height - private->height;
469 if (private->width != width ||
470 private->height != height)
474 private->width = width;
475 private->height = height;
477 old_surface = offscreen->surface;
478 offscreen->surface = cairo_surface_create_similar (old_surface,
479 cairo_surface_get_content (old_surface),
483 cr = cairo_create (offscreen->surface);
484 cairo_set_source_surface (cr, old_surface, 0, 0);
488 cairo_surface_destroy (old_surface);
491 if (GDK_WINDOW_IS_MAPPED (private))
493 // TODO: Only invalidate new area, i.e. for larger windows
494 gdk_window_invalidate_rect (window, NULL, TRUE);
495 _gdk_synthesize_crossing_events_for_geometry_change (window);
500 gdk_offscreen_window_move_resize (GdkWindow *window,
507 GdkWindowObject *private = (GdkWindowObject *)window;
508 GdkOffscreenWindow *offscreen;
510 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
519 width = private->width;
522 height = private->height;
524 gdk_offscreen_window_move_resize_internal (window, x, y,
530 gdk_offscreen_window_show (GdkWindow *window,
531 gboolean already_mapped)
533 GdkWindowObject *private = (GdkWindowObject *)window;
534 GdkRectangle area = { 0, 0, private->width, private->height };
536 gdk_window_clear_area (window, 0, 0,
537 private->width, private->height);
538 gdk_window_invalidate_rect (window, &area, FALSE);
543 gdk_offscreen_window_hide (GdkWindow *window)
545 GdkWindowObject *private;
546 GdkOffscreenWindow *offscreen;
549 g_return_if_fail (window != NULL);
551 private = (GdkWindowObject*) window;
552 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
554 /* May need to break grabs on children */
555 display = gdk_drawable_get_display (window);
557 /* TODO: This needs updating to the new grab world */
559 if (display->pointer_grab.window != NULL)
561 if (is_parent_of (window, display->pointer_grab.window))
563 /* Call this ourselves, even though gdk_display_pointer_ungrab
564 does so too, since we want to pass implicit == TRUE so the
565 broken grab event is generated */
566 _gdk_display_unset_has_pointer_grab (display,
570 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
577 gdk_offscreen_window_withdraw (GdkWindow *window)
582 gdk_offscreen_window_get_events (GdkWindow *window)
588 gdk_offscreen_window_set_events (GdkWindow *window,
589 GdkEventMask event_mask)
594 gdk_offscreen_window_set_background (GdkWindow *window,
595 cairo_pattern_t *pattern)
600 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
601 const cairo_region_t *shape_region,
608 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
609 const cairo_region_t *shape_region,
616 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
623 gdk_offscreen_window_get_geometry (GdkWindow *window,
630 GdkWindowObject *private = (GdkWindowObject *)window;
632 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
634 if (!GDK_WINDOW_DESTROYED (window))
641 *width = private->width;
643 *height = private->height;
645 *depth = private->depth;
650 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
651 cairo_region_t *area)
657 gdk_offscreen_window_translate (GdkWindow *window,
658 cairo_region_t *area,
662 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (((GdkWindowObject *) window)->impl);
665 cr = cairo_create (offscreen->surface);
667 area = cairo_region_copy (area);
669 gdk_cairo_region (cr, area);
672 /* NB: This is a self-copy and Cairo doesn't support that yet.
673 * So we do a litle trick.
675 cairo_push_group (cr);
677 cairo_set_source_surface (cr, offscreen->surface, dx, dy);
680 cairo_pop_group_to_source (cr);
685 _gdk_window_add_damage (window, area);
689 * gdk_offscreen_window_set_embedder:
690 * @window: a #GdkWindow
691 * @embedder: the #GdkWindow that @window gets embedded in
693 * Sets @window to be embedded in @embedder.
695 * To fully embed an offscreen window, in addition to calling this
696 * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
697 * signal on the @embedder and the #GdkWindow::to-embedder and
698 * #GdkWindow::from-embedder signals on @window.
703 gdk_offscreen_window_set_embedder (GdkWindow *window,
706 GdkWindowObject *private = (GdkWindowObject *)window;
707 GdkOffscreenWindow *offscreen;
709 g_return_if_fail (GDK_IS_WINDOW (window));
711 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
714 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
718 g_object_ref (embedder);
719 GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
722 if (offscreen->embedder)
724 g_object_unref (offscreen->embedder);
725 GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
728 offscreen->embedder = embedder;
732 * gdk_offscreen_window_get_embedder:
733 * @window: a #GdkWindow
735 * Gets the window that @window is embedded in.
737 * Returns: the embedding #GdkWindow, or %NULL if @window is not an
738 * embedded offscreen window
743 gdk_offscreen_window_get_embedder (GdkWindow *window)
745 GdkWindowObject *private = (GdkWindowObject *)window;
746 GdkOffscreenWindow *offscreen;
748 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
750 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
753 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
755 return offscreen->embedder;
759 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
761 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
762 GObjectClass *object_class = G_OBJECT_CLASS (klass);
764 object_class->finalize = gdk_offscreen_window_finalize;
766 drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
767 drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
768 drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
769 drawable_class->get_depth = gdk_offscreen_window_get_depth;
770 drawable_class->get_screen = gdk_offscreen_window_get_screen;
771 drawable_class->get_visual = gdk_offscreen_window_get_visual;
772 drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
776 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
778 iface->show = gdk_offscreen_window_show;
779 iface->hide = gdk_offscreen_window_hide;
780 iface->withdraw = gdk_offscreen_window_withdraw;
781 iface->raise = gdk_offscreen_window_raise;
782 iface->lower = gdk_offscreen_window_lower;
783 iface->move_resize = gdk_offscreen_window_move_resize;
784 iface->set_background = gdk_offscreen_window_set_background;
785 iface->get_events = gdk_offscreen_window_get_events;
786 iface->set_events = gdk_offscreen_window_set_events;
787 iface->reparent = gdk_offscreen_window_reparent;
788 iface->get_geometry = gdk_offscreen_window_get_geometry;
789 iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
790 iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
791 iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
792 iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
793 iface->translate = gdk_offscreen_window_translate;
794 iface->get_root_coords = gdk_offscreen_window_get_root_coords;
795 iface->get_device_state = gdk_offscreen_window_get_device_state;
796 iface->destroy = gdk_offscreen_window_destroy;