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 "gdkpixmap.h"
34 #include "gdkdrawable.h"
36 #include "gdkscreen.h"
38 #include "gdkcursor.h"
43 * Offscreen windows can't be the child of a foreign window,
44 * nor contain foreign windows
45 * GDK_POINTER_MOTION_HINT_MASK isn't effective
48 typedef struct _GdkOffscreenWindow GdkOffscreenWindow;
49 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
51 struct _GdkOffscreenWindow
53 GdkDrawable parent_instance;
57 GdkColormap *colormap;
64 struct _GdkOffscreenWindowClass
66 GdkDrawableClass parent_class;
69 #define GDK_TYPE_OFFSCREEN_WINDOW (gdk_offscreen_window_get_type())
70 #define GDK_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow))
71 #define GDK_IS_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW))
72 #define GDK_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
73 #define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW))
74 #define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
76 static void gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface);
77 static void gdk_offscreen_window_hide (GdkWindow *window);
79 G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow,
82 G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
83 gdk_offscreen_window_impl_iface_init));
87 gdk_offscreen_window_finalize (GObject *object)
89 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
91 if (offscreen->cursor)
92 gdk_cursor_unref (offscreen->cursor);
94 offscreen->cursor = NULL;
96 g_object_unref (offscreen->pixmap);
98 G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
102 gdk_offscreen_window_init (GdkOffscreenWindow *window)
107 gdk_offscreen_window_destroy (GdkWindow *window,
109 gboolean foreign_destroy)
111 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
112 GdkOffscreenWindow *offscreen;
114 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
116 gdk_offscreen_window_set_embedder (window, NULL);
119 gdk_offscreen_window_hide (window);
121 g_object_unref (offscreen->colormap);
122 offscreen->colormap = NULL;
126 is_parent_of (GdkWindow *parent,
137 w = gdk_window_get_parent (w);
143 static cairo_surface_t *
144 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
146 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
148 return _gdk_drawable_ref_cairo_surface (offscreen->pixmap);
152 gdk_offscreen_window_get_colormap (GdkDrawable *drawable)
154 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
156 return offscreen->colormap;
160 gdk_offscreen_window_set_colormap (GdkDrawable *drawable,
161 GdkColormap*colormap)
163 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
165 if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper))
168 if (offscreen->colormap == colormap)
171 if (offscreen->colormap)
172 g_object_unref (offscreen->colormap);
174 offscreen->colormap = colormap;
175 if (offscreen->colormap)
176 g_object_ref (offscreen->colormap);
181 gdk_offscreen_window_get_depth (GdkDrawable *drawable)
183 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
185 return gdk_drawable_get_depth (offscreen->wrapper);
189 gdk_offscreen_window_get_source_drawable (GdkDrawable *drawable)
191 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
193 return _gdk_drawable_get_source_drawable (offscreen->pixmap);
197 gdk_offscreen_window_get_screen (GdkDrawable *drawable)
199 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
201 return offscreen->screen;
205 gdk_offscreen_window_get_visual (GdkDrawable *drawable)
207 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
209 return gdk_drawable_get_visual (offscreen->wrapper);
213 _gdk_offscreen_window_new (GdkWindow *window,
216 GdkWindowAttr *attributes,
217 gint attributes_mask)
219 GdkWindowObject *private;
220 GdkOffscreenWindow *offscreen;
222 g_return_if_fail (attributes != NULL);
224 if (attributes->wclass != GDK_INPUT_OUTPUT)
225 return; /* Can't support input only offscreens */
227 private = (GdkWindowObject *)window;
229 if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
232 private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
233 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
234 offscreen->wrapper = window;
236 offscreen->screen = screen;
238 if (attributes_mask & GDK_WA_COLORMAP)
239 offscreen->colormap = g_object_ref (attributes->colormap);
242 if (gdk_screen_get_system_visual (screen) == visual)
244 offscreen->colormap = gdk_screen_get_system_colormap (screen);
245 g_object_ref (offscreen->colormap);
248 offscreen->colormap = gdk_colormap_new (visual, FALSE);
251 offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent,
255 gdk_drawable_set_colormap (offscreen->pixmap, offscreen->colormap);
259 gdk_offscreen_window_reparent (GdkWindow *window,
260 GdkWindow *new_parent,
264 GdkWindowObject *private = (GdkWindowObject *)window;
265 GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
266 GdkWindowObject *old_parent;
271 /* No input-output children of input-only windows */
272 if (new_parent_private->input_only && !private->input_only)
275 /* Don't create loops in hierarchy */
276 if (is_parent_of (window, new_parent))
280 was_mapped = GDK_WINDOW_IS_MAPPED (window);
282 gdk_window_hide (window);
285 private->parent->children = g_list_remove (private->parent->children, window);
287 old_parent = private->parent;
288 private->parent = new_parent_private;
292 if (new_parent_private)
293 private->parent->children = g_list_prepend (private->parent->children, window);
295 _gdk_synthesize_crossing_events_for_geometry_change (window);
297 _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
303 from_embedder (GdkWindow *window,
304 double embedder_x, double embedder_y,
305 double *offscreen_x, double *offscreen_y)
307 GdkWindowObject *private;
309 private = (GdkWindowObject *)window;
311 g_signal_emit_by_name (private->impl_window,
313 embedder_x, embedder_y,
314 offscreen_x, offscreen_y,
319 to_embedder (GdkWindow *window,
320 double offscreen_x, double offscreen_y,
321 double *embedder_x, double *embedder_y)
323 GdkWindowObject *private;
325 private = (GdkWindowObject *)window;
327 g_signal_emit_by_name (private->impl_window,
329 offscreen_x, offscreen_y,
330 embedder_x, embedder_y,
335 gdk_offscreen_window_get_root_coords (GdkWindow *window,
341 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
342 GdkOffscreenWindow *offscreen;
348 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
349 if (offscreen->embedder)
355 tmpx = floor (dx + 0.5);
356 tmpy = floor (dy + 0.5);
357 gdk_window_get_root_coords (offscreen->embedder,
372 gdk_offscreen_window_get_deskrelative_origin (GdkWindow *window,
376 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
377 GdkOffscreenWindow *offscreen;
383 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
384 if (offscreen->embedder)
387 gdk_window_get_deskrelative_origin (offscreen->embedder,
393 tmpx = floor (tmpx + dx + 0.5);
394 tmpy = floor (tmpy + dy + 0.5);
407 gdk_offscreen_window_get_device_state (GdkWindow *window,
411 GdkModifierType *mask)
413 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
414 GdkOffscreenWindow *offscreen;
417 GdkModifierType tmpmask;
423 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
424 if (offscreen->embedder != NULL)
426 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
427 from_embedder (window,
430 tmpx = floor (dtmpx + 0.5);
431 tmpy = floor (dtmpy + 0.5);
444 * gdk_offscreen_window_get_pixmap:
445 * @window: a #GdkWindow
447 * Gets the offscreen pixmap that an offscreen window renders into.
448 * If you need to keep this around over window resizes, you need to
449 * add a reference to it.
451 * Returns: The offscreen pixmap, or %NULL if not offscreen
456 gdk_offscreen_window_get_pixmap (GdkWindow *window)
458 GdkWindowObject *private = (GdkWindowObject *)window;
459 GdkOffscreenWindow *offscreen;
461 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
463 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
466 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
467 return offscreen->pixmap;
471 gdk_offscreen_window_raise (GdkWindow *window)
473 /* gdk_window_raise already changed the stacking order */
474 _gdk_synthesize_crossing_events_for_geometry_change (window);
478 gdk_offscreen_window_lower (GdkWindow *window)
480 /* gdk_window_lower already changed the stacking order */
481 _gdk_synthesize_crossing_events_for_geometry_change (window);
485 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
490 gboolean send_expose_events)
492 GdkWindowObject *private = (GdkWindowObject *)window;
493 GdkOffscreenWindow *offscreen;
495 GdkPixmap *old_pixmap;
497 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
504 if (private->destroyed)
509 dw = width - private->width;
510 dh = height - private->height;
515 if (private->width != width ||
516 private->height != height)
520 private->width = width;
521 private->height = height;
523 old_pixmap = offscreen->pixmap;
524 offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
529 cr = gdk_cairo_create (offscreen->pixmap);
530 gdk_cairo_set_source_pixmap (cr, old_pixmap, 0, 0);
535 if (GDK_WINDOW_IS_MAPPED (private))
537 // TODO: Only invalidate new area, i.e. for larger windows
538 gdk_window_invalidate_rect (window, NULL, TRUE);
539 _gdk_synthesize_crossing_events_for_geometry_change (window);
544 gdk_offscreen_window_move_resize (GdkWindow *window,
551 GdkWindowObject *private = (GdkWindowObject *)window;
552 GdkOffscreenWindow *offscreen;
554 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
563 width = private->width;
566 height = private->height;
568 gdk_offscreen_window_move_resize_internal (window, x, y,
574 gdk_offscreen_window_show (GdkWindow *window,
575 gboolean already_mapped)
577 GdkWindowObject *private = (GdkWindowObject *)window;
579 gdk_window_clear_area_e (window, 0, 0,
580 private->width, private->height);
585 gdk_offscreen_window_hide (GdkWindow *window)
587 GdkWindowObject *private;
588 GdkOffscreenWindow *offscreen;
591 g_return_if_fail (window != NULL);
593 private = (GdkWindowObject*) window;
594 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
596 /* May need to break grabs on children */
597 display = gdk_drawable_get_display (window);
599 /* TODO: This needs updating to the new grab world */
601 if (display->pointer_grab.window != NULL)
603 if (is_parent_of (window, display->pointer_grab.window))
605 /* Call this ourselves, even though gdk_display_pointer_ungrab
606 does so too, since we want to pass implicit == TRUE so the
607 broken grab event is generated */
608 _gdk_display_unset_has_pointer_grab (display,
612 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
619 gdk_offscreen_window_withdraw (GdkWindow *window)
624 gdk_offscreen_window_get_events (GdkWindow *window)
630 gdk_offscreen_window_set_events (GdkWindow *window,
631 GdkEventMask event_mask)
636 gdk_offscreen_window_set_background (GdkWindow *window,
637 const GdkColor *color)
639 GdkWindowObject *private = (GdkWindowObject *)window;
641 private->bg_color = *color;
643 if (private->bg_pixmap &&
644 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
645 private->bg_pixmap != GDK_NO_BG)
646 g_object_unref (private->bg_pixmap);
648 private->bg_pixmap = NULL;
652 gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
655 GdkWindowObject *private = (GdkWindowObject *)window;
658 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
659 private->bg_pixmap != GDK_NO_BG &&
660 !gdk_drawable_get_colormap (pixmap))
662 g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
666 if (private->bg_pixmap &&
667 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
668 private->bg_pixmap != GDK_NO_BG)
669 g_object_unref (private->bg_pixmap);
671 private->bg_pixmap = pixmap;
674 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
675 private->bg_pixmap != GDK_NO_BG)
676 g_object_ref (pixmap);
680 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
681 const cairo_region_t *shape_region,
688 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
689 const cairo_region_t *shape_region,
696 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
703 gdk_offscreen_window_get_geometry (GdkWindow *window,
710 GdkWindowObject *private = (GdkWindowObject *)window;
712 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
714 if (!GDK_WINDOW_DESTROYED (window))
721 *width = private->width;
723 *height = private->height;
725 *depth = private->depth;
730 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
731 cairo_region_t *area)
737 gdk_offscreen_window_translate (GdkWindow *window,
738 cairo_region_t *area,
742 cairo_surface_t *surface;
745 /* Can't use gdk_cairo_create here due to clipping */
746 surface = _gdk_drawable_ref_cairo_surface (window);
747 cr = cairo_create (surface);
748 cairo_surface_destroy (surface);
750 area = cairo_region_copy (area);
752 gdk_cairo_region (cr, area);
755 /* NB: This is a self-copy and Cairo doesn't support that yet.
756 * So we do a litle trick.
758 cairo_push_group (cr);
760 gdk_cairo_set_source_pixmap (cr, window, dx, dy);
763 cairo_pop_group_to_source (cr);
768 _gdk_window_add_damage (window, area);
772 * gdk_offscreen_window_set_embedder:
773 * @window: a #GdkWindow
774 * @embedder: the #GdkWindow that @window gets embedded in
776 * Sets @window to be embedded in @embedder.
778 * To fully embed an offscreen window, in addition to calling this
779 * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
780 * signal on the @embedder and the #GdkWindow::to-embedder and
781 * #GdkWindow::from-embedder signals on @window.
786 gdk_offscreen_window_set_embedder (GdkWindow *window,
789 GdkWindowObject *private = (GdkWindowObject *)window;
790 GdkOffscreenWindow *offscreen;
792 g_return_if_fail (GDK_IS_WINDOW (window));
794 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
797 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
801 g_object_ref (embedder);
802 GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
805 if (offscreen->embedder)
807 g_object_unref (offscreen->embedder);
808 GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
811 offscreen->embedder = embedder;
815 * gdk_offscreen_window_get_embedder:
816 * @window: a #GdkWindow
818 * Gets the window that @window is embedded in.
820 * Returns: the embedding #GdkWindow, or %NULL if @window is not an
821 * embedded offscreen window
826 gdk_offscreen_window_get_embedder (GdkWindow *window)
828 GdkWindowObject *private = (GdkWindowObject *)window;
829 GdkOffscreenWindow *offscreen;
831 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
833 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
836 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
838 return offscreen->embedder;
842 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
844 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
845 GObjectClass *object_class = G_OBJECT_CLASS (klass);
847 object_class->finalize = gdk_offscreen_window_finalize;
849 drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
850 drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
851 drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
852 drawable_class->get_depth = gdk_offscreen_window_get_depth;
853 drawable_class->get_screen = gdk_offscreen_window_get_screen;
854 drawable_class->get_visual = gdk_offscreen_window_get_visual;
855 drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
859 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
861 iface->show = gdk_offscreen_window_show;
862 iface->hide = gdk_offscreen_window_hide;
863 iface->withdraw = gdk_offscreen_window_withdraw;
864 iface->raise = gdk_offscreen_window_raise;
865 iface->lower = gdk_offscreen_window_lower;
866 iface->move_resize = gdk_offscreen_window_move_resize;
867 iface->set_background = gdk_offscreen_window_set_background;
868 iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
869 iface->get_events = gdk_offscreen_window_get_events;
870 iface->set_events = gdk_offscreen_window_set_events;
871 iface->reparent = gdk_offscreen_window_reparent;
872 iface->get_geometry = gdk_offscreen_window_get_geometry;
873 iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
874 iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
875 iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
876 iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
877 iface->translate = gdk_offscreen_window_translate;
878 iface->get_root_coords = gdk_offscreen_window_get_root_coords;
879 iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
880 iface->get_device_state = gdk_offscreen_window_get_device_state;
881 iface->destroy = gdk_offscreen_window_destroy;