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, see <http://www.gnu.org/licenses/>.
19 * Modified by the GTK+ Team and others 1997-2005. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include "gdkwindow.h"
28 #include "gdkinternals.h"
29 #include "gdkwindowimpl.h"
35 * Offscreen windows can't be the child of a foreign window,
36 * nor contain foreign windows
37 * GDK_POINTER_MOTION_HINT_MASK isn't effective
40 typedef struct _GdkOffscreenWindow GdkOffscreenWindow;
41 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
43 struct _GdkOffscreenWindow
45 GdkWindowImpl parent_instance;
49 cairo_surface_t *surface;
53 struct _GdkOffscreenWindowClass
55 GdkWindowImplClass parent_class;
58 #define GDK_TYPE_OFFSCREEN_WINDOW (gdk_offscreen_window_get_type())
59 #define GDK_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow))
60 #define GDK_IS_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW))
61 #define GDK_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
62 #define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW))
63 #define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
65 static void gdk_offscreen_window_hide (GdkWindow *window);
67 G_DEFINE_TYPE (GdkOffscreenWindow, gdk_offscreen_window, GDK_TYPE_WINDOW_IMPL)
71 gdk_offscreen_window_finalize (GObject *object)
73 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
75 if (offscreen->surface)
76 cairo_surface_destroy (offscreen->surface);
78 G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
82 gdk_offscreen_window_init (GdkOffscreenWindow *window)
87 gdk_offscreen_window_destroy (GdkWindow *window,
89 gboolean foreign_destroy)
91 gdk_offscreen_window_set_embedder (window, NULL);
94 gdk_offscreen_window_hide (window);
97 static cairo_surface_t *
98 get_surface (GdkOffscreenWindow *offscreen)
100 if (! offscreen->surface)
102 GdkWindow *window = offscreen->wrapper;
104 g_signal_emit_by_name (window, "create-surface",
107 &offscreen->surface);
110 return offscreen->surface;
114 is_parent_of (GdkWindow *parent,
125 w = gdk_window_get_parent (w);
131 static cairo_surface_t *
132 gdk_offscreen_window_ref_cairo_surface (GdkWindow *window)
134 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
136 return cairo_surface_reference (get_surface (offscreen));
140 _gdk_offscreen_window_create_surface (GdkWindow *offscreen,
144 cairo_surface_t *similar;
145 cairo_surface_t *surface;
147 g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (offscreen->impl), NULL);
149 similar = _gdk_window_ref_cairo_surface (offscreen->parent);
151 surface = cairo_surface_create_similar (similar, CAIRO_CONTENT_COLOR_ALPHA, width, height);
153 cairo_surface_destroy (similar);
159 _gdk_offscreen_window_new (GdkWindow *window,
160 GdkWindowAttr *attributes,
161 gint attributes_mask)
163 GdkOffscreenWindow *offscreen;
165 g_return_if_fail (attributes != NULL);
167 if (attributes->wclass != GDK_INPUT_OUTPUT)
168 return; /* Can't support input only offscreens */
170 if (window->parent != NULL && GDK_WINDOW_DESTROYED (window->parent))
173 window->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
174 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
175 offscreen->wrapper = window;
179 gdk_offscreen_window_reparent (GdkWindow *window,
180 GdkWindow *new_parent,
184 GdkWindow *old_parent;
189 /* No input-output children of input-only windows */
190 if (new_parent->input_only && !window->input_only)
193 /* Don't create loops in hierarchy */
194 if (is_parent_of (window, new_parent))
198 was_mapped = GDK_WINDOW_IS_MAPPED (window);
200 gdk_window_hide (window);
203 window->parent->children = g_list_remove (window->parent->children, window);
205 old_parent = window->parent;
206 window->parent = new_parent;
211 window->parent->children = g_list_prepend (window->parent->children, window);
213 _gdk_synthesize_crossing_events_for_geometry_change (window);
215 _gdk_synthesize_crossing_events_for_geometry_change (old_parent);
221 gdk_offscreen_window_set_device_cursor (GdkWindow *window,
228 from_embedder (GdkWindow *window,
229 double embedder_x, double embedder_y,
230 double *offscreen_x, double *offscreen_y)
232 g_signal_emit_by_name (window->impl_window,
234 embedder_x, embedder_y,
235 offscreen_x, offscreen_y,
240 to_embedder (GdkWindow *window,
241 double offscreen_x, double offscreen_y,
242 double *embedder_x, double *embedder_y)
244 g_signal_emit_by_name (window->impl_window,
246 offscreen_x, offscreen_y,
247 embedder_x, embedder_y,
252 gdk_offscreen_window_get_root_coords (GdkWindow *window,
258 GdkOffscreenWindow *offscreen;
264 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
265 if (offscreen->embedder)
271 tmpx = floor (dx + 0.5);
272 tmpy = floor (dy + 0.5);
273 gdk_window_get_root_coords (offscreen->embedder,
288 gdk_offscreen_window_get_device_state (GdkWindow *window,
292 GdkModifierType *mask)
294 GdkOffscreenWindow *offscreen;
297 GdkModifierType tmpmask;
303 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
304 if (offscreen->embedder != NULL)
306 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
307 from_embedder (window,
310 tmpx = floor (dtmpx + 0.5);
311 tmpy = floor (dtmpy + 0.5);
324 * gdk_offscreen_window_get_surface:
325 * @window: a #GdkWindow
327 * Gets the offscreen surface that an offscreen window renders into.
328 * If you need to keep this around over window resizes, you need to
329 * add a reference to it.
331 * Returns: (transfer none): The offscreen surface, or %NULL if not offscreen
334 gdk_offscreen_window_get_surface (GdkWindow *window)
336 GdkOffscreenWindow *offscreen;
338 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
340 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
343 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
345 return get_surface (offscreen);
349 gdk_offscreen_window_raise (GdkWindow *window)
351 /* gdk_window_raise already changed the stacking order */
352 _gdk_synthesize_crossing_events_for_geometry_change (window);
356 gdk_offscreen_window_lower (GdkWindow *window)
358 /* gdk_window_lower already changed the stacking order */
359 _gdk_synthesize_crossing_events_for_geometry_change (window);
363 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
368 gboolean send_expose_events)
370 GdkOffscreenWindow *offscreen;
372 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
379 if (window->destroyed)
385 if (window->width != width ||
386 window->height != height)
388 window->width = width;
389 window->height = height;
391 if (offscreen->surface)
393 cairo_surface_t *old_surface;
396 old_surface = offscreen->surface;
397 offscreen->surface = NULL;
399 offscreen->surface = get_surface (offscreen);
401 cr = cairo_create (offscreen->surface);
402 cairo_set_source_surface (cr, old_surface, 0, 0);
406 cairo_surface_destroy (old_surface);
410 if (GDK_WINDOW_IS_MAPPED (window))
412 /* TODO: Only invalidate new area, i.e. for larger windows */
413 gdk_window_invalidate_rect (window, NULL, TRUE);
414 _gdk_synthesize_crossing_events_for_geometry_change (window);
419 gdk_offscreen_window_move_resize (GdkWindow *window,
433 width = window->width;
436 height = window->height;
438 gdk_offscreen_window_move_resize_internal (window,
444 gdk_offscreen_window_show (GdkWindow *window,
445 gboolean already_mapped)
447 GdkRectangle area = { 0, 0, window->width, window->height };
449 gdk_window_invalidate_rect (window, &area, FALSE);
454 gdk_offscreen_window_hide (GdkWindow *window)
456 /* TODO: This needs updating to the new grab world */
458 GdkOffscreenWindow *offscreen;
461 g_return_if_fail (window != NULL);
463 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
465 /* May need to break grabs on children */
466 display = gdk_window_get_display (window);
468 if (display->pointer_grab.window != NULL)
470 if (is_parent_of (window, display->pointer_grab.window))
472 /* Call this ourselves, even though gdk_display_pointer_ungrab
473 does so too, since we want to pass implicit == TRUE so the
474 broken grab event is generated */
475 _gdk_display_unset_has_pointer_grab (display,
479 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
486 gdk_offscreen_window_withdraw (GdkWindow *window)
491 gdk_offscreen_window_get_events (GdkWindow *window)
497 gdk_offscreen_window_set_events (GdkWindow *window,
498 GdkEventMask event_mask)
503 gdk_offscreen_window_set_background (GdkWindow *window,
504 cairo_pattern_t *pattern)
509 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
510 const cairo_region_t *shape_region,
517 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
518 const cairo_region_t *shape_region,
525 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
532 gdk_offscreen_window_get_geometry (GdkWindow *window,
538 if (!GDK_WINDOW_DESTROYED (window))
545 *width = window->width;
547 *height = window->height;
552 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
553 cairo_region_t *area)
559 gdk_offscreen_window_translate (GdkWindow *window,
560 cairo_region_t *area,
564 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
566 if (offscreen->surface)
570 cr = cairo_create (offscreen->surface);
572 area = cairo_region_copy (area);
574 gdk_cairo_region (cr, area);
577 /* NB: This is a self-copy and Cairo doesn't support that yet.
578 * So we do a litle trick.
580 cairo_push_group (cr);
582 cairo_set_source_surface (cr, offscreen->surface, dx, dy);
585 cairo_pop_group_to_source (cr);
591 _gdk_window_add_damage (window, area);
594 static cairo_surface_t *
595 gdk_offscreen_window_resize_cairo_surface (GdkWindow *window,
596 cairo_surface_t *surface,
600 /* No-op. The surface gets resized in
601 * gdk_offscreen_window_move_resize_internal().
607 * gdk_offscreen_window_set_embedder:
608 * @window: a #GdkWindow
609 * @embedder: the #GdkWindow that @window gets embedded in
611 * Sets @window to be embedded in @embedder.
613 * To fully embed an offscreen window, in addition to calling this
614 * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
615 * signal on the @embedder and the #GdkWindow::to-embedder and
616 * #GdkWindow::from-embedder signals on @window.
621 gdk_offscreen_window_set_embedder (GdkWindow *window,
624 GdkOffscreenWindow *offscreen;
626 g_return_if_fail (GDK_IS_WINDOW (window));
628 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
631 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
635 g_object_ref (embedder);
636 embedder->num_offscreen_children++;
639 if (offscreen->embedder)
641 g_object_unref (offscreen->embedder);
642 offscreen->embedder->num_offscreen_children--;
645 offscreen->embedder = embedder;
649 * gdk_offscreen_window_get_embedder:
650 * @window: a #GdkWindow
652 * Gets the window that @window is embedded in.
654 * Returns: (transfer none): the embedding #GdkWindow, or %NULL
655 * if @window is not an mbedded offscreen window
660 gdk_offscreen_window_get_embedder (GdkWindow *window)
662 GdkOffscreenWindow *offscreen;
664 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
666 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
669 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
671 return offscreen->embedder;
675 gdk_offscreen_window_do_nothing (GdkWindow *window)
680 gdk_offscreen_window_set_boolean (GdkWindow *window,
686 gdk_offscreen_window_set_string (GdkWindow *window,
687 const gchar *setting)
692 gdk_offscreen_window_set_list (GdkWindow *window,
698 gdk_offscreen_window_set_wmfunctions (GdkWindow *window,
699 GdkWMFunction functions)
704 gdk_offscreen_window_set_transient_for (GdkWindow *window,
710 gdk_offscreen_window_process_updates_recurse (GdkWindow *window,
711 cairo_region_t *region)
713 _gdk_window_process_updates_recurse (window, region);
717 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
719 GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
720 GObjectClass *object_class = G_OBJECT_CLASS (klass);
722 object_class->finalize = gdk_offscreen_window_finalize;
724 impl_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
725 impl_class->show = gdk_offscreen_window_show;
726 impl_class->hide = gdk_offscreen_window_hide;
727 impl_class->withdraw = gdk_offscreen_window_withdraw;
728 impl_class->set_events = gdk_offscreen_window_set_events;
729 impl_class->get_events = gdk_offscreen_window_get_events;
730 impl_class->raise = gdk_offscreen_window_raise;
731 impl_class->lower = gdk_offscreen_window_lower;
732 impl_class->restack_under = NULL;
733 impl_class->restack_toplevel = NULL;
734 impl_class->move_resize = gdk_offscreen_window_move_resize;
735 impl_class->set_background = gdk_offscreen_window_set_background;
736 impl_class->reparent = gdk_offscreen_window_reparent;
737 impl_class->set_device_cursor = gdk_offscreen_window_set_device_cursor;
738 impl_class->get_geometry = gdk_offscreen_window_get_geometry;
739 impl_class->get_root_coords = gdk_offscreen_window_get_root_coords;
740 impl_class->get_device_state = gdk_offscreen_window_get_device_state;
741 impl_class->shape_combine_region = gdk_offscreen_window_shape_combine_region;
742 impl_class->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
743 impl_class->set_static_gravities = gdk_offscreen_window_set_static_gravities;
744 impl_class->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
745 impl_class->translate = gdk_offscreen_window_translate;
746 impl_class->destroy = gdk_offscreen_window_destroy;
747 impl_class->destroy_foreign = NULL;
748 impl_class->resize_cairo_surface = gdk_offscreen_window_resize_cairo_surface;
749 impl_class->get_shape = NULL;
750 impl_class->get_input_shape = NULL;
751 impl_class->beep = NULL;
753 impl_class->focus = NULL;
754 impl_class->set_type_hint = NULL;
755 impl_class->get_type_hint = NULL;
756 impl_class->set_modal_hint = NULL;
757 impl_class->set_skip_taskbar_hint = gdk_offscreen_window_set_boolean;
758 impl_class->set_skip_pager_hint = gdk_offscreen_window_set_boolean;
759 impl_class->set_urgency_hint = gdk_offscreen_window_set_boolean;
760 impl_class->set_geometry_hints = NULL;
761 impl_class->set_title = gdk_offscreen_window_set_string;
762 impl_class->set_role = gdk_offscreen_window_set_string;
763 impl_class->set_startup_id = gdk_offscreen_window_set_string;
764 impl_class->set_transient_for = gdk_offscreen_window_set_transient_for;
765 impl_class->get_root_origin = NULL;
766 impl_class->get_frame_extents = NULL;
767 impl_class->set_override_redirect = NULL;
768 impl_class->set_accept_focus = NULL;
769 impl_class->set_focus_on_map = gdk_offscreen_window_set_boolean;
770 impl_class->set_icon_list = gdk_offscreen_window_set_list;
771 impl_class->set_icon_name = gdk_offscreen_window_set_string;
772 impl_class->iconify = gdk_offscreen_window_do_nothing;
773 impl_class->deiconify = gdk_offscreen_window_do_nothing;
774 impl_class->stick = gdk_offscreen_window_do_nothing;
775 impl_class->unstick = gdk_offscreen_window_do_nothing;
776 impl_class->maximize = gdk_offscreen_window_do_nothing;
777 impl_class->unmaximize = gdk_offscreen_window_do_nothing;
778 impl_class->fullscreen = gdk_offscreen_window_do_nothing;
779 impl_class->unfullscreen = gdk_offscreen_window_do_nothing;
780 impl_class->set_keep_above = gdk_offscreen_window_set_boolean;
781 impl_class->set_keep_below = gdk_offscreen_window_set_boolean;
782 impl_class->get_group = NULL;
783 impl_class->set_group = NULL;
784 impl_class->set_decorations = NULL;
785 impl_class->get_decorations = NULL;
786 impl_class->set_functions = gdk_offscreen_window_set_wmfunctions;
787 impl_class->begin_resize_drag = NULL;
788 impl_class->begin_move_drag = NULL;
789 impl_class->enable_synchronized_configure = gdk_offscreen_window_do_nothing;
790 impl_class->configure_finished = NULL;
791 impl_class->set_opacity = NULL;
792 impl_class->set_composited = NULL;
793 impl_class->destroy_notify = NULL;
794 impl_class->register_dnd = gdk_offscreen_window_do_nothing;
795 impl_class->drag_begin = NULL;
796 impl_class->process_updates_recurse = gdk_offscreen_window_process_updates_recurse;
797 impl_class->sync_rendering = NULL;
798 impl_class->simulate_key = NULL;
799 impl_class->simulate_button = NULL;
800 impl_class->get_property = NULL;
801 impl_class->change_property = NULL;
802 impl_class->delete_property = NULL;