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_screen (GdkDrawable *drawable)
183 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
185 return offscreen->screen;
189 gdk_offscreen_window_get_visual (GdkDrawable *drawable)
191 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
193 return gdk_drawable_get_visual (offscreen->wrapper);
197 _gdk_offscreen_window_new (GdkWindow *window,
200 GdkWindowAttr *attributes,
201 gint attributes_mask)
203 GdkWindowObject *private;
204 GdkOffscreenWindow *offscreen;
206 g_return_if_fail (attributes != NULL);
208 if (attributes->wclass != GDK_INPUT_OUTPUT)
209 return; /* Can't support input only offscreens */
211 private = (GdkWindowObject *)window;
213 if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
216 private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
217 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
218 offscreen->wrapper = window;
220 offscreen->screen = screen;
222 if (attributes_mask & GDK_WA_COLORMAP)
223 offscreen->colormap = g_object_ref (attributes->colormap);
226 if (gdk_screen_get_system_visual (screen) == visual)
228 offscreen->colormap = gdk_screen_get_system_colormap (screen);
229 g_object_ref (offscreen->colormap);
232 offscreen->colormap = gdk_colormap_new (visual, FALSE);
235 offscreen->surface = gdk_window_create_similar_surface ((GdkWindow *)private->parent,
242 gdk_offscreen_window_reparent (GdkWindow *window,
243 GdkWindow *new_parent,
247 GdkWindowObject *private = (GdkWindowObject *)window;
248 GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
249 GdkWindowObject *old_parent;
254 /* No input-output children of input-only windows */
255 if (new_parent_private->input_only && !private->input_only)
258 /* Don't create loops in hierarchy */
259 if (is_parent_of (window, new_parent))
263 was_mapped = GDK_WINDOW_IS_MAPPED (window);
265 gdk_window_hide (window);
268 private->parent->children = g_list_remove (private->parent->children, window);
270 old_parent = private->parent;
271 private->parent = new_parent_private;
275 if (new_parent_private)
276 private->parent->children = g_list_prepend (private->parent->children, window);
278 _gdk_synthesize_crossing_events_for_geometry_change (window);
280 _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
286 from_embedder (GdkWindow *window,
287 double embedder_x, double embedder_y,
288 double *offscreen_x, double *offscreen_y)
290 GdkWindowObject *private;
292 private = (GdkWindowObject *)window;
294 g_signal_emit_by_name (private->impl_window,
296 embedder_x, embedder_y,
297 offscreen_x, offscreen_y,
302 to_embedder (GdkWindow *window,
303 double offscreen_x, double offscreen_y,
304 double *embedder_x, double *embedder_y)
306 GdkWindowObject *private;
308 private = (GdkWindowObject *)window;
310 g_signal_emit_by_name (private->impl_window,
312 offscreen_x, offscreen_y,
313 embedder_x, embedder_y,
318 gdk_offscreen_window_get_root_coords (GdkWindow *window,
324 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
325 GdkOffscreenWindow *offscreen;
331 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
332 if (offscreen->embedder)
338 tmpx = floor (dx + 0.5);
339 tmpy = floor (dy + 0.5);
340 gdk_window_get_root_coords (offscreen->embedder,
355 gdk_offscreen_window_get_device_state (GdkWindow *window,
359 GdkModifierType *mask)
361 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
362 GdkOffscreenWindow *offscreen;
365 GdkModifierType tmpmask;
371 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
372 if (offscreen->embedder != NULL)
374 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
375 from_embedder (window,
378 tmpx = floor (dtmpx + 0.5);
379 tmpy = floor (dtmpy + 0.5);
392 * gdk_offscreen_window_get_surface:
393 * @window: a #GdkWindow
395 * Gets the offscreen surface that an offscreen window renders into.
396 * If you need to keep this around over window resizes, you need to
397 * add a reference to it.
399 * Returns: The offscreen surface, or %NULL if not offscreen
402 gdk_offscreen_window_get_surface (GdkWindow *window)
404 GdkWindowObject *private = (GdkWindowObject *)window;
405 GdkOffscreenWindow *offscreen;
407 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
409 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
412 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
413 return offscreen->surface;
417 gdk_offscreen_window_raise (GdkWindow *window)
419 /* gdk_window_raise already changed the stacking order */
420 _gdk_synthesize_crossing_events_for_geometry_change (window);
424 gdk_offscreen_window_lower (GdkWindow *window)
426 /* gdk_window_lower already changed the stacking order */
427 _gdk_synthesize_crossing_events_for_geometry_change (window);
431 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
436 gboolean send_expose_events)
438 GdkWindowObject *private = (GdkWindowObject *)window;
439 GdkOffscreenWindow *offscreen;
441 cairo_surface_t *old_surface;
443 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
450 if (private->destroyed)
455 dw = width - private->width;
456 dh = height - private->height;
461 if (private->width != width ||
462 private->height != height)
466 private->width = width;
467 private->height = height;
469 old_surface = offscreen->surface;
470 offscreen->surface = cairo_surface_create_similar (old_surface,
471 cairo_surface_get_content (old_surface),
475 cr = cairo_create (offscreen->surface);
476 cairo_set_source_surface (cr, old_surface, 0, 0);
480 cairo_surface_destroy (old_surface);
483 if (GDK_WINDOW_IS_MAPPED (private))
485 // TODO: Only invalidate new area, i.e. for larger windows
486 gdk_window_invalidate_rect (window, NULL, TRUE);
487 _gdk_synthesize_crossing_events_for_geometry_change (window);
492 gdk_offscreen_window_move_resize (GdkWindow *window,
499 GdkWindowObject *private = (GdkWindowObject *)window;
500 GdkOffscreenWindow *offscreen;
502 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
511 width = private->width;
514 height = private->height;
516 gdk_offscreen_window_move_resize_internal (window, x, y,
522 gdk_offscreen_window_show (GdkWindow *window,
523 gboolean already_mapped)
525 GdkWindowObject *private = (GdkWindowObject *)window;
526 GdkRectangle area = { 0, 0, private->width, private->height };
528 gdk_window_clear_area (window, 0, 0,
529 private->width, private->height);
530 gdk_window_invalidate_rect (window, &area, FALSE);
535 gdk_offscreen_window_hide (GdkWindow *window)
537 GdkWindowObject *private;
538 GdkOffscreenWindow *offscreen;
541 g_return_if_fail (window != NULL);
543 private = (GdkWindowObject*) window;
544 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
546 /* May need to break grabs on children */
547 display = gdk_drawable_get_display (window);
549 /* TODO: This needs updating to the new grab world */
551 if (display->pointer_grab.window != NULL)
553 if (is_parent_of (window, display->pointer_grab.window))
555 /* Call this ourselves, even though gdk_display_pointer_ungrab
556 does so too, since we want to pass implicit == TRUE so the
557 broken grab event is generated */
558 _gdk_display_unset_has_pointer_grab (display,
562 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
569 gdk_offscreen_window_withdraw (GdkWindow *window)
574 gdk_offscreen_window_get_events (GdkWindow *window)
580 gdk_offscreen_window_set_events (GdkWindow *window,
581 GdkEventMask event_mask)
586 gdk_offscreen_window_set_background (GdkWindow *window,
587 cairo_pattern_t *pattern)
592 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
593 const cairo_region_t *shape_region,
600 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
601 const cairo_region_t *shape_region,
608 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
615 gdk_offscreen_window_get_geometry (GdkWindow *window,
622 GdkWindowObject *private = (GdkWindowObject *)window;
624 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
626 if (!GDK_WINDOW_DESTROYED (window))
633 *width = private->width;
635 *height = private->height;
637 *depth = private->depth;
642 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
643 cairo_region_t *area)
649 gdk_offscreen_window_translate (GdkWindow *window,
650 cairo_region_t *area,
654 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (((GdkWindowObject *) window)->impl);
657 cr = cairo_create (offscreen->surface);
659 area = cairo_region_copy (area);
661 gdk_cairo_region (cr, area);
664 /* NB: This is a self-copy and Cairo doesn't support that yet.
665 * So we do a litle trick.
667 cairo_push_group (cr);
669 cairo_set_source_surface (cr, offscreen->surface, dx, dy);
672 cairo_pop_group_to_source (cr);
677 _gdk_window_add_damage (window, area);
681 * gdk_offscreen_window_set_embedder:
682 * @window: a #GdkWindow
683 * @embedder: the #GdkWindow that @window gets embedded in
685 * Sets @window to be embedded in @embedder.
687 * To fully embed an offscreen window, in addition to calling this
688 * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
689 * signal on the @embedder and the #GdkWindow::to-embedder and
690 * #GdkWindow::from-embedder signals on @window.
695 gdk_offscreen_window_set_embedder (GdkWindow *window,
698 GdkWindowObject *private = (GdkWindowObject *)window;
699 GdkOffscreenWindow *offscreen;
701 g_return_if_fail (GDK_IS_WINDOW (window));
703 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
706 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
710 g_object_ref (embedder);
711 GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
714 if (offscreen->embedder)
716 g_object_unref (offscreen->embedder);
717 GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
720 offscreen->embedder = embedder;
724 * gdk_offscreen_window_get_embedder:
725 * @window: a #GdkWindow
727 * Gets the window that @window is embedded in.
729 * Returns: the embedding #GdkWindow, or %NULL if @window is not an
730 * embedded offscreen window
735 gdk_offscreen_window_get_embedder (GdkWindow *window)
737 GdkWindowObject *private = (GdkWindowObject *)window;
738 GdkOffscreenWindow *offscreen;
740 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
742 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
745 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
747 return offscreen->embedder;
751 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
753 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
754 GObjectClass *object_class = G_OBJECT_CLASS (klass);
756 object_class->finalize = gdk_offscreen_window_finalize;
758 drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
759 drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
760 drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
761 drawable_class->get_depth = gdk_offscreen_window_get_depth;
762 drawable_class->get_screen = gdk_offscreen_window_get_screen;
763 drawable_class->get_visual = gdk_offscreen_window_get_visual;
767 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
769 iface->show = gdk_offscreen_window_show;
770 iface->hide = gdk_offscreen_window_hide;
771 iface->withdraw = gdk_offscreen_window_withdraw;
772 iface->raise = gdk_offscreen_window_raise;
773 iface->lower = gdk_offscreen_window_lower;
774 iface->move_resize = gdk_offscreen_window_move_resize;
775 iface->set_background = gdk_offscreen_window_set_background;
776 iface->get_events = gdk_offscreen_window_get_events;
777 iface->set_events = gdk_offscreen_window_set_events;
778 iface->reparent = gdk_offscreen_window_reparent;
779 iface->get_geometry = gdk_offscreen_window_get_geometry;
780 iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
781 iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
782 iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
783 iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
784 iface->translate = gdk_offscreen_window_translate;
785 iface->get_root_coords = gdk_offscreen_window_get_root_coords;
786 iface->get_device_state = gdk_offscreen_window_get_device_state;
787 iface->destroy = gdk_offscreen_window_destroy;