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"
39 #include "gdkcursor.h"
44 * Offscreen windows can't be the child of a foreign window,
45 * nor contain foreign windows
46 * GDK_POINTER_MOTION_HINT_MASK isn't effective
49 typedef struct _GdkOffscreenWindow GdkOffscreenWindow;
50 typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
52 struct _GdkOffscreenWindow
54 GdkDrawable parent_instance;
58 GdkColormap *colormap;
65 struct _GdkOffscreenWindowClass
67 GdkDrawableClass parent_class;
70 #define GDK_TYPE_OFFSCREEN_WINDOW (gdk_offscreen_window_get_type())
71 #define GDK_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow))
72 #define GDK_IS_OFFSCREEN_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW))
73 #define GDK_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
74 #define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW))
75 #define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
77 static void gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface);
78 static void gdk_offscreen_window_hide (GdkWindow *window);
80 G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow,
83 G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
84 gdk_offscreen_window_impl_iface_init));
88 gdk_offscreen_window_finalize (GObject *object)
90 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
92 if (offscreen->cursor)
93 gdk_cursor_unref (offscreen->cursor);
95 offscreen->cursor = NULL;
97 g_object_unref (offscreen->pixmap);
99 G_OBJECT_CLASS (gdk_offscreen_window_parent_class)->finalize (object);
103 gdk_offscreen_window_init (GdkOffscreenWindow *window)
108 gdk_offscreen_window_destroy (GdkWindow *window,
110 gboolean foreign_destroy)
112 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
113 GdkOffscreenWindow *offscreen;
115 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
117 gdk_offscreen_window_set_embedder (window, NULL);
120 gdk_offscreen_window_hide (window);
122 g_object_unref (offscreen->colormap);
123 offscreen->colormap = NULL;
127 is_parent_of (GdkWindow *parent,
138 w = gdk_window_get_parent (w);
145 gdk_offscreen_window_create_gc (GdkDrawable *drawable,
147 GdkGCValuesMask values_mask)
149 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
151 return gdk_gc_new_with_values (offscreen->pixmap, values, values_mask);
154 static cairo_surface_t *
155 gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
157 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
159 return _gdk_drawable_ref_cairo_surface (offscreen->pixmap);
163 gdk_offscreen_window_get_colormap (GdkDrawable *drawable)
165 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
167 return offscreen->colormap;
171 gdk_offscreen_window_set_colormap (GdkDrawable *drawable,
172 GdkColormap*colormap)
174 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
176 if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper))
179 if (offscreen->colormap == colormap)
182 if (offscreen->colormap)
183 g_object_unref (offscreen->colormap);
185 offscreen->colormap = colormap;
186 if (offscreen->colormap)
187 g_object_ref (offscreen->colormap);
192 gdk_offscreen_window_get_depth (GdkDrawable *drawable)
194 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
196 return gdk_drawable_get_depth (offscreen->wrapper);
200 gdk_offscreen_window_get_source_drawable (GdkDrawable *drawable)
202 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
204 return _gdk_drawable_get_source_drawable (offscreen->pixmap);
208 gdk_offscreen_window_get_composite_drawable (GdkDrawable *drawable,
213 gint *composite_x_offset,
214 gint *composite_y_offset)
216 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
218 return g_object_ref (offscreen->pixmap);
222 gdk_offscreen_window_get_screen (GdkDrawable *drawable)
224 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
226 return offscreen->screen;
230 gdk_offscreen_window_get_visual (GdkDrawable *drawable)
232 GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
234 return gdk_drawable_get_visual (offscreen->wrapper);
238 add_damage (GdkOffscreenWindow *offscreen,
244 cairo_region_t *damage;
253 /* This should really take into account line width, line
254 * joins (and miter) and line caps. But these are hard
255 * to compute, rarely used and generally a pain. And in
256 * the end a snug damage rectangle is not that important
257 * as multiple damages are generally created anyway.
259 * So, we just add some padding around the rect.
260 * We use a padding of 3 pixels, plus an extra row
261 * below and on the right for the normal line size. I.E.
262 * line from (0,0) to (2,0) gets h=0 but is really
263 * at least one pixel tall.
271 damage = cairo_region_create_rectangle (&rect);
272 _gdk_window_add_damage (offscreen->wrapper, damage);
273 cairo_region_destroy (damage);
277 _gdk_offscreen_window_new (GdkWindow *window,
280 GdkWindowAttr *attributes,
281 gint attributes_mask)
283 GdkWindowObject *private;
284 GdkOffscreenWindow *offscreen;
286 g_return_if_fail (attributes != NULL);
288 if (attributes->wclass != GDK_INPUT_OUTPUT)
289 return; /* Can't support input only offscreens */
291 private = (GdkWindowObject *)window;
293 if (private->parent != NULL && GDK_WINDOW_DESTROYED (private->parent))
296 private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
297 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
298 offscreen->wrapper = window;
300 offscreen->screen = screen;
302 if (attributes_mask & GDK_WA_COLORMAP)
303 offscreen->colormap = g_object_ref (attributes->colormap);
306 if (gdk_screen_get_system_visual (screen) == visual)
308 offscreen->colormap = gdk_screen_get_system_colormap (screen);
309 g_object_ref (offscreen->colormap);
312 offscreen->colormap = gdk_colormap_new (visual, FALSE);
315 offscreen->pixmap = gdk_pixmap_new ((GdkDrawable *)private->parent,
319 gdk_drawable_set_colormap (offscreen->pixmap, offscreen->colormap);
323 gdk_offscreen_window_reparent (GdkWindow *window,
324 GdkWindow *new_parent,
328 GdkWindowObject *private = (GdkWindowObject *)window;
329 GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
330 GdkWindowObject *old_parent;
335 /* No input-output children of input-only windows */
336 if (new_parent_private->input_only && !private->input_only)
339 /* Don't create loops in hierarchy */
340 if (is_parent_of (window, new_parent))
344 was_mapped = GDK_WINDOW_IS_MAPPED (window);
346 gdk_window_hide (window);
349 private->parent->children = g_list_remove (private->parent->children, window);
351 old_parent = private->parent;
352 private->parent = new_parent_private;
356 if (new_parent_private)
357 private->parent->children = g_list_prepend (private->parent->children, window);
359 _gdk_synthesize_crossing_events_for_geometry_change (window);
361 _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (old_parent));
367 from_embedder (GdkWindow *window,
368 double embedder_x, double embedder_y,
369 double *offscreen_x, double *offscreen_y)
371 GdkWindowObject *private;
373 private = (GdkWindowObject *)window;
375 g_signal_emit_by_name (private->impl_window,
377 embedder_x, embedder_y,
378 offscreen_x, offscreen_y,
383 to_embedder (GdkWindow *window,
384 double offscreen_x, double offscreen_y,
385 double *embedder_x, double *embedder_y)
387 GdkWindowObject *private;
389 private = (GdkWindowObject *)window;
391 g_signal_emit_by_name (private->impl_window,
393 offscreen_x, offscreen_y,
394 embedder_x, embedder_y,
399 gdk_offscreen_window_get_root_coords (GdkWindow *window,
405 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
406 GdkOffscreenWindow *offscreen;
412 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
413 if (offscreen->embedder)
419 tmpx = floor (dx + 0.5);
420 tmpy = floor (dy + 0.5);
421 gdk_window_get_root_coords (offscreen->embedder,
436 gdk_offscreen_window_get_deskrelative_origin (GdkWindow *window,
440 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
441 GdkOffscreenWindow *offscreen;
447 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
448 if (offscreen->embedder)
451 gdk_window_get_deskrelative_origin (offscreen->embedder,
457 tmpx = floor (tmpx + dx + 0.5);
458 tmpy = floor (tmpy + dy + 0.5);
471 gdk_offscreen_window_get_device_state (GdkWindow *window,
475 GdkModifierType *mask)
477 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
478 GdkOffscreenWindow *offscreen;
481 GdkModifierType tmpmask;
487 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
488 if (offscreen->embedder != NULL)
490 gdk_window_get_device_position (offscreen->embedder, device, &tmpx, &tmpy, &tmpmask);
491 from_embedder (window,
494 tmpx = floor (dtmpx + 0.5);
495 tmpy = floor (dtmpy + 0.5);
508 * gdk_offscreen_window_get_pixmap:
509 * @window: a #GdkWindow
511 * Gets the offscreen pixmap that an offscreen window renders into.
512 * If you need to keep this around over window resizes, you need to
513 * add a reference to it.
515 * Returns: The offscreen pixmap, or %NULL if not offscreen
520 gdk_offscreen_window_get_pixmap (GdkWindow *window)
522 GdkWindowObject *private = (GdkWindowObject *)window;
523 GdkOffscreenWindow *offscreen;
525 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
527 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
530 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
531 return offscreen->pixmap;
535 gdk_offscreen_window_raise (GdkWindow *window)
537 /* gdk_window_raise already changed the stacking order */
538 _gdk_synthesize_crossing_events_for_geometry_change (window);
542 gdk_offscreen_window_lower (GdkWindow *window)
544 /* gdk_window_lower already changed the stacking order */
545 _gdk_synthesize_crossing_events_for_geometry_change (window);
549 gdk_offscreen_window_move_resize_internal (GdkWindow *window,
554 gboolean send_expose_events)
556 GdkWindowObject *private = (GdkWindowObject *)window;
557 GdkOffscreenWindow *offscreen;
560 GdkPixmap *old_pixmap;
562 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
569 if (private->destroyed)
574 dw = width - private->width;
575 dh = height - private->height;
580 if (private->width != width ||
581 private->height != height)
585 private->width = width;
586 private->height = height;
588 old_pixmap = offscreen->pixmap;
589 offscreen->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
594 cr = gdk_cairo_create (offscreen->pixmap);
595 gdk_cairo_set_source_pixmap (cr, old_pixmap, 0, 0);
600 if (GDK_WINDOW_IS_MAPPED (private))
602 // TODO: Only invalidate new area, i.e. for larger windows
603 gdk_window_invalidate_rect (window, NULL, TRUE);
604 _gdk_synthesize_crossing_events_for_geometry_change (window);
609 gdk_offscreen_window_move_resize (GdkWindow *window,
616 GdkWindowObject *private = (GdkWindowObject *)window;
617 GdkOffscreenWindow *offscreen;
619 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
628 width = private->width;
631 height = private->height;
633 gdk_offscreen_window_move_resize_internal (window, x, y,
639 gdk_offscreen_window_show (GdkWindow *window,
640 gboolean already_mapped)
642 GdkWindowObject *private = (GdkWindowObject *)window;
644 gdk_window_clear_area_e (window, 0, 0,
645 private->width, private->height);
650 gdk_offscreen_window_hide (GdkWindow *window)
652 GdkWindowObject *private;
653 GdkOffscreenWindow *offscreen;
656 g_return_if_fail (window != NULL);
658 private = (GdkWindowObject*) window;
659 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
661 /* May need to break grabs on children */
662 display = gdk_drawable_get_display (window);
664 /* TODO: This needs updating to the new grab world */
666 if (display->pointer_grab.window != NULL)
668 if (is_parent_of (window, display->pointer_grab.window))
670 /* Call this ourselves, even though gdk_display_pointer_ungrab
671 does so too, since we want to pass implicit == TRUE so the
672 broken grab event is generated */
673 _gdk_display_unset_has_pointer_grab (display,
677 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
684 gdk_offscreen_window_withdraw (GdkWindow *window)
689 gdk_offscreen_window_get_events (GdkWindow *window)
695 gdk_offscreen_window_set_events (GdkWindow *window,
696 GdkEventMask event_mask)
701 gdk_offscreen_window_set_background (GdkWindow *window,
702 const GdkColor *color)
704 GdkWindowObject *private = (GdkWindowObject *)window;
705 GdkColormap *colormap = gdk_drawable_get_colormap (window);
707 private->bg_color = *color;
708 gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
710 if (private->bg_pixmap &&
711 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
712 private->bg_pixmap != GDK_NO_BG)
713 g_object_unref (private->bg_pixmap);
715 private->bg_pixmap = NULL;
719 gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
722 GdkWindowObject *private = (GdkWindowObject *)window;
725 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
726 private->bg_pixmap != GDK_NO_BG &&
727 !gdk_drawable_get_colormap (pixmap))
729 g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
733 if (private->bg_pixmap &&
734 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
735 private->bg_pixmap != GDK_NO_BG)
736 g_object_unref (private->bg_pixmap);
738 private->bg_pixmap = pixmap;
741 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
742 private->bg_pixmap != GDK_NO_BG)
743 g_object_ref (pixmap);
747 gdk_offscreen_window_shape_combine_region (GdkWindow *window,
748 const cairo_region_t *shape_region,
755 gdk_offscreen_window_input_shape_combine_region (GdkWindow *window,
756 const cairo_region_t *shape_region,
763 gdk_offscreen_window_set_static_gravities (GdkWindow *window,
770 gdk_offscreen_window_get_geometry (GdkWindow *window,
777 GdkWindowObject *private = (GdkWindowObject *)window;
779 g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
781 if (!GDK_WINDOW_DESTROYED (window))
788 *width = private->width;
790 *height = private->height;
792 *depth = private->depth;
797 gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
798 cairo_region_t *area)
804 gdk_offscreen_window_translate (GdkWindow *window,
805 cairo_region_t *area,
809 cairo_surface_t *surface;
812 /* Can't use gdk_cairo_create here due to clipping */
813 surface = _gdk_drawable_ref_cairo_surface (window);
814 cr = cairo_create (surface);
815 cairo_surface_destroy (surface);
817 area = cairo_region_copy (area);
819 gdk_cairo_region (cr, area);
822 /* NB: This is a self-copy and Cairo doesn't support that yet.
823 * So we do a litle trick.
825 cairo_push_group (cr);
827 gdk_cairo_set_source_pixmap (cr, window, dx, dy);
830 cairo_pop_group_to_source (cr);
835 _gdk_window_add_damage (window, area);
839 * gdk_offscreen_window_set_embedder:
840 * @window: a #GdkWindow
841 * @embedder: the #GdkWindow that @window gets embedded in
843 * Sets @window to be embedded in @embedder.
845 * To fully embed an offscreen window, in addition to calling this
846 * function, it is also necessary to handle the #GdkWindow::pick-embedded-child
847 * signal on the @embedder and the #GdkWindow::to-embedder and
848 * #GdkWindow::from-embedder signals on @window.
853 gdk_offscreen_window_set_embedder (GdkWindow *window,
856 GdkWindowObject *private = (GdkWindowObject *)window;
857 GdkOffscreenWindow *offscreen;
859 g_return_if_fail (GDK_IS_WINDOW (window));
861 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
864 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
868 g_object_ref (embedder);
869 GDK_WINDOW_OBJECT (embedder)->num_offscreen_children++;
872 if (offscreen->embedder)
874 g_object_unref (offscreen->embedder);
875 GDK_WINDOW_OBJECT (offscreen->embedder)->num_offscreen_children--;
878 offscreen->embedder = embedder;
882 * gdk_offscreen_window_get_embedder:
883 * @window: a #GdkWindow
885 * Gets the window that @window is embedded in.
887 * Returns: the embedding #GdkWindow, or %NULL if @window is not an
888 * embedded offscreen window
893 gdk_offscreen_window_get_embedder (GdkWindow *window)
895 GdkWindowObject *private = (GdkWindowObject *)window;
896 GdkOffscreenWindow *offscreen;
898 g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
900 if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
903 offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
905 return offscreen->embedder;
909 gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
911 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
912 GObjectClass *object_class = G_OBJECT_CLASS (klass);
914 object_class->finalize = gdk_offscreen_window_finalize;
916 drawable_class->create_gc = gdk_offscreen_window_create_gc;
917 drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
918 drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
919 drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
920 drawable_class->get_depth = gdk_offscreen_window_get_depth;
921 drawable_class->get_screen = gdk_offscreen_window_get_screen;
922 drawable_class->get_visual = gdk_offscreen_window_get_visual;
923 drawable_class->get_source_drawable = gdk_offscreen_window_get_source_drawable;
924 drawable_class->get_composite_drawable = gdk_offscreen_window_get_composite_drawable;
928 gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
930 iface->show = gdk_offscreen_window_show;
931 iface->hide = gdk_offscreen_window_hide;
932 iface->withdraw = gdk_offscreen_window_withdraw;
933 iface->raise = gdk_offscreen_window_raise;
934 iface->lower = gdk_offscreen_window_lower;
935 iface->move_resize = gdk_offscreen_window_move_resize;
936 iface->set_background = gdk_offscreen_window_set_background;
937 iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
938 iface->get_events = gdk_offscreen_window_get_events;
939 iface->set_events = gdk_offscreen_window_set_events;
940 iface->reparent = gdk_offscreen_window_reparent;
941 iface->get_geometry = gdk_offscreen_window_get_geometry;
942 iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
943 iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
944 iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
945 iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
946 iface->translate = gdk_offscreen_window_translate;
947 iface->get_root_coords = gdk_offscreen_window_get_root_coords;
948 iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
949 iface->get_device_state = gdk_offscreen_window_get_device_state;
950 iface->destroy = gdk_offscreen_window_destroy;