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 gdk_offscreen_window_set_embedder (window, NULL);
96 gdk_offscreen_window_hide (window);
99 static cairo_surface_t *
100 get_surface (GdkOffscreenWindow *offscreen)
102 if (! offscreen->surface)
104 GdkWindow *window = offscreen->wrapper;
106 g_signal_emit_by_name (window, "create-surface",
109 &offscreen->surface);
112 return offscreen->surface;
116 is_parent_of (GdkWindow *parent,
127 w = gdk_window_get_parent (w);
133 static cairo_surface_t *
134 gdk_offscreen_window_ref_cairo_surface (GdkWindow *window)
136 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
138 return cairo_surface_reference (get_surface (offscreen));
142 _gdk_offscreen_window_create_surface (GdkWindow *offscreen,
146 cairo_surface_t *similar;
147 cairo_surface_t *surface;
148 cairo_content_t content = CAIRO_CONTENT_COLOR;
150 g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (offscreen->impl), NULL);
152 similar = _gdk_window_ref_cairo_surface (offscreen->parent);
154 if (gdk_window_get_visual (offscreen) ==
155 gdk_screen_get_rgba_visual (gdk_window_get_screen (offscreen)))
157 content = CAIRO_CONTENT_COLOR_ALPHA;
160 surface = cairo_surface_create_similar (similar, content, width, height);
162 cairo_surface_destroy (similar);
168 _gdk_offscreen_window_new (GdkWindow *window,
169 GdkWindowAttr *attributes,
170 gint attributes_mask)
172 GdkOffscreenWindow *offscreen;
174 g_return_if_fail (attributes != NULL);
176 if (attributes->wclass != GDK_INPUT_OUTPUT)
177 return; /* Can't support input only offscreens */
179 if (window->parent != NULL && GDK_WINDOW_DESTROYED (window->parent))
182 window->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
183 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
184 offscreen->wrapper = window;
188 gdk_offscreen_window_reparent (GdkWindow *window,
189 GdkWindow *new_parent,
193 GdkWindow *old_parent;
198 /* No input-output children of input-only windows */
199 if (new_parent->input_only && !window->input_only)
202 /* Don't create loops in hierarchy */
203 if (is_parent_of (window, new_parent))
207 was_mapped = GDK_WINDOW_IS_MAPPED (window);
209 gdk_window_hide (window);
212 window->parent->children = g_list_remove (window->parent->children, window);
214 old_parent = window->parent;
215 window->parent = new_parent;
220 window->parent->children = g_list_prepend (window->parent->children, window);
222 _gdk_synthesize_crossing_events_for_geometry_change (window);
224 _gdk_synthesize_crossing_events_for_geometry_change (old_parent);
230 from_embedder (GdkWindow *window,
231 double embedder_x, double embedder_y,
232 double *offscreen_x, double *offscreen_y)
234 g_signal_emit_by_name (window->impl_window,
236 embedder_x, embedder_y,
237 offscreen_x, offscreen_y,
242 to_embedder (GdkWindow *window,
243 double offscreen_x, double offscreen_y,
244 double *embedder_x, double *embedder_y)
246 g_signal_emit_by_name (window->impl_window,
248 offscreen_x, offscreen_y,
249 embedder_x, embedder_y,
254 gdk_offscreen_window_get_root_coords (GdkWindow *window,
260 GdkOffscreenWindow *offscreen;
266 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
267 if (offscreen->embedder)
273 tmpx = floor (dx + 0.5);
274 tmpy = floor (dy + 0.5);
275 gdk_window_get_root_coords (offscreen->embedder,
290 gdk_offscreen_window_get_device_state (GdkWindow *window,
294 GdkModifierType *mask)
296 GdkOffscreenWindow *offscreen;
299 GdkModifierType tmpmask;
305 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
306 if (offscreen->embedder != NULL)
308 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
309 from_embedder (window,
312 tmpx = floor (dtmpx + 0.5);
313 tmpy = floor (dtmpy + 0.5);
326 * gdk_offscreen_window_get_surface:
327 * @window: a #GdkWindow
329 * Gets the offscreen surface that an offscreen window renders into.
330 * If you need to keep this around over window resizes, you need to
331 * add a reference to it.
333 * Returns: (transfer none): The offscreen surface, or %NULL if not offscreen
336 gdk_offscreen_window_get_surface (GdkWindow *window)
338 GdkOffscreenWindow *offscreen;
340 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
342 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
345 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
347 return get_surface (offscreen);
351 gdk_offscreen_window_raise (GdkWindow *window)
353 /* gdk_window_raise already changed the stacking order */
354 _gdk_synthesize_crossing_events_for_geometry_change (window);
358 gdk_offscreen_window_lower (GdkWindow *window)
360 /* gdk_window_lower already changed the stacking order */
361 _gdk_synthesize_crossing_events_for_geometry_change (window);
365 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
370 gboolean send_expose_events)
372 GdkOffscreenWindow *offscreen;
374 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
381 if (window->destroyed)
387 if (window->width != width ||
388 window->height != height)
390 window->width = width;
391 window->height = height;
393 if (offscreen->surface)
395 cairo_surface_t *old_surface;
398 old_surface = offscreen->surface;
399 offscreen->surface = NULL;
401 offscreen->surface = get_surface (offscreen);
403 cr = cairo_create (offscreen->surface);
404 cairo_set_source_surface (cr, old_surface, 0, 0);
408 cairo_surface_destroy (old_surface);
412 if (GDK_WINDOW_IS_MAPPED (window))
414 /* TODO: Only invalidate new area, i.e. for larger windows */
415 gdk_window_invalidate_rect (window, NULL, TRUE);
416 _gdk_synthesize_crossing_events_for_geometry_change (window);
421 gdk_offscreen_window_move_resize (GdkWindow *window,
435 width = window->width;
438 height = window->height;
440 gdk_offscreen_window_move_resize_internal (window,
446 gdk_offscreen_window_show (GdkWindow *window,
447 gboolean already_mapped)
449 GdkRectangle area = { 0, 0, window->width, window->height };
451 gdk_window_invalidate_rect (window, &area, FALSE);
456 gdk_offscreen_window_hide (GdkWindow *window)
458 /* TODO: This needs updating to the new grab world */
460 GdkOffscreenWindow *offscreen;
463 g_return_if_fail (window != NULL);
465 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
467 /* May need to break grabs on children */
468 display = gdk_window_get_display (window);
470 if (display->pointer_grab.window != NULL)
472 if (is_parent_of (window, display->pointer_grab.window))
474 /* Call this ourselves, even though gdk_display_pointer_ungrab
475 does so too, since we want to pass implicit == TRUE so the
476 broken grab event is generated */
477 _gdk_display_unset_has_pointer_grab (display,
481 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
488 gdk_offscreen_window_withdraw (GdkWindow *window)
493 gdk_offscreen_window_get_events (GdkWindow *window)
499 gdk_offscreen_window_set_events (GdkWindow *window,
500 GdkEventMask event_mask)
505 gdk_offscreen_window_set_background (GdkWindow *window,
506 cairo_pattern_t *pattern)
511 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
512 const cairo_region_t *shape_region,
519 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
520 const cairo_region_t *shape_region,
527 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
534 gdk_offscreen_window_get_geometry (GdkWindow *window,
540 if (!GDK_WINDOW_DESTROYED (window))
547 *width = window->width;
549 *height = window->height;
554 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
555 cairo_region_t *area)
561 gdk_offscreen_window_translate (GdkWindow *window,
562 cairo_region_t *area,
566 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
568 if (offscreen->surface)
572 cr = cairo_create (offscreen->surface);
574 area = cairo_region_copy (area);
576 gdk_cairo_region (cr, area);
579 /* NB: This is a self-copy and Cairo doesn't support that yet.
580 * So we do a litle trick.
582 cairo_push_group (cr);
584 cairo_set_source_surface (cr, offscreen->surface, dx, dy);
587 cairo_pop_group_to_source (cr);
593 _gdk_window_add_damage (window, area);
596 static cairo_surface_t *
597 gdk_offscreen_window_resize_cairo_surface (GdkWindow *window,
598 cairo_surface_t *surface,
602 /* No-op. The surface gets resized in
603 * gdk_offscreen_window_move_resize_internal().
609 * gdk_offscreen_window_set_embedder:
610 * @window: a #GdkWindow
611 * @embedder: the #GdkWindow that @window gets embedded in
613 * Sets @window to be embedded in @embedder.
615 * To fully embed an offscreen window, in addition to calling this
616 * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
617 * signal on the @embedder and the #GdkWindow::to-embedder and
618 * #GdkWindow::from-embedder signals on @window.
623 gdk_offscreen_window_set_embedder (GdkWindow *window,
626 GdkOffscreenWindow *offscreen;
628 g_return_if_fail (GDK_IS_WINDOW (window));
630 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
633 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
637 g_object_ref (embedder);
638 embedder->num_offscreen_children++;
641 if (offscreen->embedder)
643 g_object_unref (offscreen->embedder);
644 offscreen->embedder->num_offscreen_children--;
647 offscreen->embedder = embedder;
651 * gdk_offscreen_window_get_embedder:
652 * @window: a #GdkWindow
654 * Gets the window that @window is embedded in.
656 * Returns: (transfer none): the embedding #GdkWindow, or %NULL
657 * if @window is not an mbedded offscreen window
662 gdk_offscreen_window_get_embedder (GdkWindow *window)
664 GdkOffscreenWindow *offscreen;
666 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
668 if (!GDK_IS_OFFSCREEN_WINDOW (window->impl))
671 offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
673 return offscreen->embedder;
677 gdk_offscreen_window_do_nothing (GdkWindow *window)
682 gdk_offscreen_window_set_boolean (GdkWindow *window,
688 gdk_offscreen_window_set_string (GdkWindow *window,
689 const gchar *setting)
694 gdk_offscreen_window_set_list (GdkWindow *window,
700 gdk_offscreen_window_set_wmfunctions (GdkWindow *window,
701 GdkWMFunction functions)
706 gdk_offscreen_window_set_transient_for (GdkWindow *window,
712 gdk_offscreen_window_process_updates_recurse (GdkWindow *window,
713 cairo_region_t *region)
715 _gdk_window_process_updates_recurse (window, region);
719 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
721 GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
722 GObjectClass *object_class = G_OBJECT_CLASS (klass);
724 object_class->finalize = gdk_offscreen_window_finalize;
726 impl_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
727 impl_class->show = gdk_offscreen_window_show;
728 impl_class->hide = gdk_offscreen_window_hide;
729 impl_class->withdraw = gdk_offscreen_window_withdraw;
730 impl_class->set_events = gdk_offscreen_window_set_events;
731 impl_class->get_events = gdk_offscreen_window_get_events;
732 impl_class->raise = gdk_offscreen_window_raise;
733 impl_class->lower = gdk_offscreen_window_lower;
734 impl_class->restack_under = NULL;
735 impl_class->restack_toplevel = NULL;
736 impl_class->move_resize = gdk_offscreen_window_move_resize;
737 impl_class->set_background = gdk_offscreen_window_set_background;
738 impl_class->reparent = gdk_offscreen_window_reparent;
739 impl_class->set_device_cursor = NULL;
740 impl_class->get_geometry = gdk_offscreen_window_get_geometry;
741 impl_class->get_root_coords = gdk_offscreen_window_get_root_coords;
742 impl_class->get_device_state = gdk_offscreen_window_get_device_state;
743 impl_class->shape_combine_region = gdk_offscreen_window_shape_combine_region;
744 impl_class->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
745 impl_class->set_static_gravities = gdk_offscreen_window_set_static_gravities;
746 impl_class->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
747 impl_class->translate = gdk_offscreen_window_translate;
748 impl_class->destroy = gdk_offscreen_window_destroy;
749 impl_class->destroy_foreign = NULL;
750 impl_class->resize_cairo_surface = gdk_offscreen_window_resize_cairo_surface;
751 impl_class->get_shape = NULL;
752 impl_class->get_input_shape = NULL;
753 impl_class->beep = NULL;
755 impl_class->focus = NULL;
756 impl_class->set_type_hint = NULL;
757 impl_class->get_type_hint = NULL;
758 impl_class->set_modal_hint = NULL;
759 impl_class->set_skip_taskbar_hint = gdk_offscreen_window_set_boolean;
760 impl_class->set_skip_pager_hint = gdk_offscreen_window_set_boolean;
761 impl_class->set_urgency_hint = gdk_offscreen_window_set_boolean;
762 impl_class->set_geometry_hints = NULL;
763 impl_class->set_title = gdk_offscreen_window_set_string;
764 impl_class->set_role = gdk_offscreen_window_set_string;
765 impl_class->set_startup_id = gdk_offscreen_window_set_string;
766 impl_class->set_transient_for = gdk_offscreen_window_set_transient_for;
767 impl_class->get_root_origin = NULL;
768 impl_class->get_frame_extents = NULL;
769 impl_class->set_override_redirect = NULL;
770 impl_class->set_accept_focus = NULL;
771 impl_class->set_focus_on_map = gdk_offscreen_window_set_boolean;
772 impl_class->set_icon_list = gdk_offscreen_window_set_list;
773 impl_class->set_icon_name = gdk_offscreen_window_set_string;
774 impl_class->iconify = gdk_offscreen_window_do_nothing;
775 impl_class->deiconify = gdk_offscreen_window_do_nothing;
776 impl_class->stick = gdk_offscreen_window_do_nothing;
777 impl_class->unstick = gdk_offscreen_window_do_nothing;
778 impl_class->maximize = gdk_offscreen_window_do_nothing;
779 impl_class->unmaximize = gdk_offscreen_window_do_nothing;
780 impl_class->fullscreen = gdk_offscreen_window_do_nothing;
781 impl_class->unfullscreen = gdk_offscreen_window_do_nothing;
782 impl_class->set_keep_above = gdk_offscreen_window_set_boolean;
783 impl_class->set_keep_below = gdk_offscreen_window_set_boolean;
784 impl_class->get_group = NULL;
785 impl_class->set_group = NULL;
786 impl_class->set_decorations = NULL;
787 impl_class->get_decorations = NULL;
788 impl_class->set_functions = gdk_offscreen_window_set_wmfunctions;
789 impl_class->begin_resize_drag = NULL;
790 impl_class->begin_move_drag = NULL;
791 impl_class->enable_synchronized_configure = gdk_offscreen_window_do_nothing;
792 impl_class->configure_finished = NULL;
793 impl_class->set_opacity = NULL;
794 impl_class->set_composited = NULL;
795 impl_class->destroy_notify = NULL;
796 impl_class->register_dnd = gdk_offscreen_window_do_nothing;
797 impl_class->drag_begin = NULL;
798 impl_class->process_updates_recurse = gdk_offscreen_window_process_updates_recurse;
799 impl_class->sync_rendering = NULL;
800 impl_class->simulate_key = NULL;
801 impl_class->simulate_button = NULL;
802 impl_class->get_property = NULL;
803 impl_class->change_property = NULL;
804 impl_class->delete_property = NULL;