diff options
author | Matthias Clasen <mclasen@redhat.com> | 2007-06-01 12:16:12 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2007-06-01 12:16:12 +0000 |
commit | 885ba0464824c56137d7b4f9182930066463291c (patch) | |
tree | 444382dc37906067546e5701eb022a0262b5f792 /gdk | |
parent | 62c13f04630c74cb98053586c6870a87a6a8e1d9 (diff) | |
download | gtk+-885ba0464824c56137d7b4f9182930066463291c.tar.gz |
Add support for composited child windows. (#412882, Ryan Lortie)
2007-06-01 Matthias Clasen <mclasen@redhat.com>
Add support for composited child windows. (#412882, Ryan Lortie)
* gdk/gdk.symbols:
* gdk/gdkdisplay.h:
* gdk/gdkinternals.h:
* gdk/gdkwindow.[hc]: Add gdk_display_supports_composite() and
gdk_window_set_composited().
* gdk/x11/gdkevents-x11.c:
* gdk/x11/gdkdisplay-x11.[hc]:
* gdk/x11/gdkwindow-x11.[hc]: X11 implementation.
* gdk/win32/gdkdisplay-win32.c:
* gdk/win32/gdkwindow-win32.c: Dummy win32 implementration.
* gdk/quartz/gdkdisplay-quartz.c:
* gdk/quartz/gdkwindow-quartz.c: Dummy Quartz implementation.
* gdk/directfb/gdkdisplay-directfb.c:
* gdk/directfb/gdkwindow-directfb.c: Dummy DirectFB implementation.
* tests/testgtk.c: Add a "composited window" test.
svn path=/trunk/; revision=18004
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/directfb/gdkdisplay-directfb.c | 7 | ||||
-rw-r--r-- | gdk/directfb/gdkwindow-directfb.c | 8 | ||||
-rw-r--r-- | gdk/gdk.symbols | 2 | ||||
-rw-r--r-- | gdk/gdkdisplay.h | 1 | ||||
-rw-r--r-- | gdk/gdkinternals.h | 3 | ||||
-rw-r--r-- | gdk/gdkwindow.c | 91 | ||||
-rw-r--r-- | gdk/gdkwindow.h | 4 | ||||
-rw-r--r-- | gdk/quartz/gdkdisplay-quartz.c | 8 | ||||
-rw-r--r-- | gdk/quartz/gdkwindow-quartz.c | 5 | ||||
-rw-r--r-- | gdk/win32/gdkdisplay-win32.c | 6 | ||||
-rw-r--r-- | gdk/win32/gdkwindow-win32.c | 5 | ||||
-rw-r--r-- | gdk/x11/gdkdisplay-x11.c | 56 | ||||
-rw-r--r-- | gdk/x11/gdkdisplay-x11.h | 4 | ||||
-rw-r--r-- | gdk/x11/gdkevents-x11.c | 28 | ||||
-rw-r--r-- | gdk/x11/gdkwindow-x11.c | 62 | ||||
-rw-r--r-- | gdk/x11/gdkwindow-x11.h | 8 |
16 files changed, 295 insertions, 3 deletions
diff --git a/gdk/directfb/gdkdisplay-directfb.c b/gdk/directfb/gdkdisplay-directfb.c index 9cf7a2fdb1..04275fee27 100644 --- a/gdk/directfb/gdkdisplay-directfb.c +++ b/gdk/directfb/gdkdisplay-directfb.c @@ -511,6 +511,13 @@ gdk_notify_startup_complete_with_id (const gchar* startup_id) { } + +gboolean +gdk_display_supports_composite (GdkDisplay *display) +{ + return FALSE; +} + #define __GDK_DISPLAY_X11_C__ #include "gdkaliasdef.c" diff --git a/gdk/directfb/gdkwindow-directfb.c b/gdk/directfb/gdkwindow-directfb.c index 59e28b7393..7fe3911852 100644 --- a/gdk/directfb/gdkwindow-directfb.c +++ b/gdk/directfb/gdkwindow-directfb.c @@ -3038,6 +3038,14 @@ gdk_window_set_opacity (GdkWindow *window, cardinal = opacity * 0xff; gdk_directfb_window_set_opacity(window,cardinal); } + +void +_gdk_windowing_window_set_composited (GdkWindow *window, + gboolean composited) +{ +} + + #define __GDK_WINDOW_X11_C__ #include "gdkaliasdef.c" diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index 56722e7cb6..8757324fcc 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -466,6 +466,7 @@ gdk_display_supports_clipboard_persistence gdk_display_supports_selection_notification gdk_display_supports_shapes gdk_display_supports_input_shapes +gdk_display_supports_composite #endif #endif @@ -673,6 +674,7 @@ gdk_window_remove_filter gdk_window_set_debug_updates gdk_window_set_user_data gdk_window_thaw_updates +gdk_window_set_composited #endif #endif diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h index c627a08581..b55b312257 100644 --- a/gdk/gdkdisplay.h +++ b/gdk/gdkdisplay.h @@ -181,6 +181,7 @@ void gdk_display_store_clipboard (GdkDisplay *display, gboolean gdk_display_supports_shapes (GdkDisplay *display); gboolean gdk_display_supports_input_shapes (GdkDisplay *display); +gboolean gdk_display_supports_composite (GdkDisplay *display); G_END_DECLS diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 1c279f4ec3..f97b97be04 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -337,6 +337,9 @@ void _gdk_windowing_window_destroy_foreign (GdkWindow *window); void _gdk_windowing_display_set_sm_client_id (GdkDisplay *display, const gchar *sm_client_id); +void _gdk_windowing_window_set_composited (GdkWindow *window, + gboolean composited); + #define GDK_TYPE_PAINTABLE (_gdk_paintable_get_type ()) #define GDK_PAINTABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_PAINTABLE, GdkPaintable)) #define GDK_IS_PAINTABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_PAINTABLE)) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index d0d1573a6e..5e1d830698 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -1042,6 +1042,7 @@ gdk_window_end_paint (GdkWindow *window) { #ifdef USE_BACKING_STORE GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowObject *composited; GdkWindowPaint *paint; GdkGC *tmp_gc; GdkRectangle clip_box; @@ -1094,6 +1095,34 @@ gdk_window_end_paint (GdkWindow *window) g_object_unref (paint->pixmap); gdk_region_destroy (paint->region); g_free (paint); + + /* find a composited window in our hierarchy to signal its + * parent to redraw, calculating the clip box as we go... + * + * stop if parent becomes NULL since then we'd have nowhere + * to draw (ie: 'composited' will always be non-NULL here). + */ + for (composited = private; + composited->parent; + composited = composited->parent) + { + int width, height; + + gdk_drawable_get_size (GDK_DRAWABLE (composited->parent), + &width, &height); + + clip_box.x += composited->x; + clip_box.y += composited->y; + clip_box.width = MIN (clip_box.width, width - clip_box.x); + clip_box.height = MIN (clip_box.height, height - clip_box.y); + + if (composited->composited) + { + gdk_window_invalidate_rect (GDK_WINDOW (composited->parent), + &clip_box, FALSE); + break; + } + } #endif /* USE_BACKING_STORE */ } @@ -2601,7 +2630,8 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window, child_region = gdk_region_rectangle (&child_rect); /* remove child area from the invalid area of the parent */ - if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped) + if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped && + !child->composited) gdk_region_subtract (visible_region, child_region); if (child_func && (*child_func) ((GdkWindow *)child, user_data)) @@ -3056,5 +3086,64 @@ gdk_window_foreign_new (GdkNativeWindow anid) return gdk_window_foreign_new_for_display (gdk_display_get_default (), anid); } +/** + * gdk_window_set_composited: + * @window: a #GdkWindow + * + * Sets a #GdkWindow as composited. Composited windows do + * not automatically have their contents drawn to the screen. + * Drawing is redirected to an offscreen buffer and an expose + * event is emitted on the parent of the composited window. + * It is the responsibility of the parent's expose handler to + * manually merge the off-screen content onto the screen in + * whatever way it sees fit. See <xref linkend="composited-window-example"/> + * for an example. + * + * It only makes sense for child windows to be composited; see + * gdk_window_set_opacity() if you need translucent toplevel + * windows. + * + * An additional effect of this call is that the area of this + * window is no longer clipped from regions marked for + * invalidation on its parent. Draws done on the parent + * window are also no longer clipped by the child. + * + * This call is only supported on some systems (currently, + * only X11 with new enough Xcomposite and Xdamage extensions). + * You must call gdk_display_supports_composite() to check if + * setting a window as composited is supported before + * attempting to do so. + * + * Since: 2.12 + */ +void +gdk_window_set_composited (GdkWindow *window, + gboolean composited) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkDisplay *display; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + composited = composited != FALSE; + + if (private->composited == composited) + return; + + display = gdk_drawable_get_display (GDK_DRAWABLE (window)); + + if (!gdk_display_supports_composite (display) && composited) + { + g_warning ("gdk_window_set_composited called but " + "compositing is not supported"); + return; + } + + _gdk_windowing_window_set_composited (window, composited); + + private->composited = composited; +} + #define __GDK_WINDOW_C__ #include "gdkaliasdef.c" diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 9ff3a09fca..d50d3e6c9a 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -289,6 +289,7 @@ struct _GdkWindowObject guint guffaw_gravity : 1; guint input_only : 1; guint modal_hint : 1; + guint composited : 1; guint destroyed : 2; @@ -394,6 +395,9 @@ void gdk_window_shape_combine_region (GdkWindow *window, */ void gdk_window_set_child_shapes (GdkWindow *window); +void gdk_window_set_composited (GdkWindow *window, + gboolean composited); + /* * This routine allows you to merge (ie ADD) child shapes to your * own window's shape keeping its current shape and ADDING the child diff --git a/gdk/quartz/gdkdisplay-quartz.c b/gdk/quartz/gdkdisplay-quartz.c index b34567eaf7..3f9a01f254 100644 --- a/gdk/quartz/gdkdisplay-quartz.c +++ b/gdk/quartz/gdkdisplay-quartz.c @@ -169,3 +169,11 @@ gdk_display_store_clipboard (GdkDisplay *display, { /* FIXME: Implement */ } + + +gboolean +gdk_display_supports_composite (GdkDisplay *display) +{ + /* FIXME: Implement */ + return FALSE; +} diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c index 31f2b01a39..51f253ecf2 100644 --- a/gdk/quartz/gdkwindow-quartz.c +++ b/gdk/quartz/gdkwindow-quartz.c @@ -2155,3 +2155,8 @@ gdk_window_set_opacity (GdkWindow *window, [impl->toplevel setAlphaValue: opacity]; } + +void +_gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited) +{ +} diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c index 5b77fb11bb..78c26bf779 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -389,3 +389,9 @@ gdk_display_supports_input_shapes (GdkDisplay *display) return FALSE; } + +gboolean +gdk_display_supports_composite (GdkDisplay *display) +{ + return FALSE; +} diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 631d4200d1..fad5644a3b 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -3571,3 +3571,8 @@ gdk_window_set_opacity (GdkWindow *window, opacity * 0xff, LWA_ALPHA)); } + +void +_gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited) +{ +} diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index c57ef2e833..de7c1f2f83 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -54,6 +54,14 @@ #include <X11/extensions/shape.h> #endif +#ifdef HAVE_XCOMPOSITE +#include <X11/extensions/Xcomposite.h> +#endif + +#ifdef HAVE_XDAMAGE +#include <X11/extensions/Xdamage.h> +#endif + static void gdk_display_x11_dispose (GObject *object); static void gdk_display_x11_finalize (GObject *object); @@ -206,6 +214,29 @@ gdk_display_open (const gchar *display_name) #endif display_x11->have_xfixes = FALSE; +#ifdef HAVE_XCOMPOSITE + if (XCompositeQueryExtension (display_x11->xdisplay, + &ignore, &ignore)) + display_x11->have_xcomposite = TRUE; + else +#endif + display_x11->have_xcomposite = FALSE; + +#ifdef HAVE_XDAMAGE + if (XDamageQueryExtension (display_x11->xdisplay, + &display_x11->xdamage_event_base, + &ignore)) + { + display_x11->have_xdamage = TRUE; + + gdk_x11_register_standard_event_type (display, + display_x11->xdamage_event_base, + XDamageNumberEvents); + } + else +#endif + display_x11->have_xdamage = FALSE; + display_x11->have_shapes = FALSE; display_x11->have_input_shapes = FALSE; #ifdef HAVE_SHAPE_EXT @@ -1363,5 +1394,30 @@ gdk_x11_display_get_startup_notification_id (GdkDisplay *display) return GDK_DISPLAY_X11 (display)->startup_notification_id; } +/** + * gdk_display_supports_composite: + * @display: a #GdkDisplay + * + * Returns %TRUE if gdk_window_set_composited() can be used + * to redirect drawing on the window using compositing. + * + * Currently this only works on X11 with XComposite and + * XDamage extensions available. + * + * Returns: %TRUE if windows may be composited. + * + * Since: 2.12 + */ +gboolean +gdk_display_supports_composite (GdkDisplay *display) +{ + GdkDisplayX11 *x11_display = GDK_DISPLAY_X11 (display); + + return x11_display->have_xcomposite && + x11_display->have_xdamage && + x11_display->have_xfixes; +} + + #define __GDK_DISPLAY_X11_C__ #include "gdkaliasdef.c" diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index 14b8fd5b29..7b2654cd7c 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -81,6 +81,10 @@ struct _GdkDisplayX11 gboolean have_xfixes; gint xfixes_event_base; + gboolean have_xcomposite; + gboolean have_xdamage; + gint xdamage_event_base; + /* If the SECURITY extension is in place, whether this client holds * a trusted authorization and so is allowed to make various requests * (grabs, properties etc.) Otherwise always TRUE. */ diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 6df08bb3df..b9560d46ed 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -2101,6 +2101,34 @@ gdk_event_translate (GdkDisplay *display, } else #endif +#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES) + if (display_x11->have_xdamage && window_private->composited && + xevent->type == display_x11->xdamage_event_base + XDamageNotify) + { + XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent; + XserverRegion repair; + GdkRectangle rect; + + rect.x = window_private->x + damage_event->area.x; + rect.y = window_private->y + damage_event->area.y; + rect.width = damage_event->area.width; + rect.height = damage_event->area.height; + + repair = XFixesCreateRegion (display_x11->xdisplay, + &damage_event->area, 1); + XDamageSubtract (display_x11->xdisplay, + window_impl->damage, + repair, None); + XFixesDestroyRegion (display_x11->xdisplay, repair); + + if (window_private->parent != NULL) + _gdk_window_process_expose (GDK_WINDOW (window_private->parent), + damage_event->serial, &rect); + + return_val = TRUE; + } + else +#endif { /* something else - (e.g., a Xinput event) */ diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index e3e84270d6..a58de4526d 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -59,6 +59,18 @@ #include <X11/extensions/shape.h> #endif +#ifdef HAVE_XCOMPOSITE +#include <X11/extensions/Xcomposite.h> +#endif + +#ifdef HAVE_XFIXES +#include <X11/extensions/Xfixes.h> +#endif + +#ifdef HAVE_XDAMAGE +#include <X11/extensions/Xdamage.h> +#endif + const int _gdk_event_mask_table[21] = { ExposureMask, @@ -185,6 +197,14 @@ gdk_window_impl_x11_finalize (GObject *object) _gdk_xgrab_check_destroy (GDK_WINDOW (wrapper)); +#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES) + if (window_impl->damage != None) + { + XDamageDestroy (GDK_WINDOW_XDISPLAY (object), window_impl->damage); + window_impl->damage = None; + } +#endif + if (!GDK_WINDOW_DESTROYED (wrapper)) { GdkDisplay *display = GDK_WINDOW_DISPLAY (wrapper); @@ -6413,10 +6433,14 @@ gdk_window_beep (GdkWindow *window) * * Request the windowing system to make @window partially transparent, * with opacity 0 being fully transparent and 1 fully opaque. (Values - * of the opacity parameter are clamped to the [0,1] range.) On X11 - * this works only on X screens with a compositing manager running. + * of the opacity parameter are clamped to the [0,1] range.) + * + * On X11, this works only on X screens with a compositing manager + * running. * * For setting up per-pixel alpha, see gdk_screen_get_rgba_colormap(). + * For making non-toplevel windows translucent, see + * gdk_window_set_composited(). * * Since: 2.12 */ @@ -6455,5 +6479,39 @@ gdk_window_set_opacity (GdkWindow *window, (guchar *) cardinal, 1); } +void +_gdk_windowing_window_set_composited (GdkWindow *window, + gboolean composited) +{ +#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES) + GdkWindowObject *private = (GdkWindowObject *) window; + GdkDisplayX11 *x11_display; + GdkWindowImplX11 *impl; + GdkDisplay *display; + Display *dpy; + Window xid; + + impl = GDK_WINDOW_IMPL_X11 (private->impl); + + display = gdk_screen_get_display (GDK_DRAWABLE_IMPL_X11 (impl)->screen); + x11_display = GDK_DISPLAY_X11 (display); + dpy = GDK_DISPLAY_XDISPLAY (display); + xid = GDK_WINDOW_XWINDOW (private); + + if (composited) + { + XCompositeRedirectWindow (dpy, xid, CompositeRedirectManual); + impl->damage = XDamageCreate (dpy, xid, XDamageReportBoundingBox); + } + else + { + XCompositeUnredirectWindow (dpy, xid, CompositeRedirectManual); + XDamageDestroy (dpy, impl->damage); + impl->damage = None; + } +#endif +} + + #define __GDK_WINDOW_X11_C__ #include "gdkaliasdef.c" diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h index 18fa23a057..3ab23d6003 100644 --- a/gdk/x11/gdkwindow-x11.h +++ b/gdk/x11/gdkwindow-x11.h @@ -29,6 +29,10 @@ #include <gdk/x11/gdkdrawable-x11.h> +#ifdef HAVE_XDAMAGE +#include <X11/extensions/Xdamage.h> +#endif + #ifdef HAVE_XSYNC #include <X11/extensions/sync.h> #endif @@ -79,6 +83,10 @@ struct _GdkWindowImplX11 gint8 toplevel_window_type; guint override_redirect : 1; guint use_synchronized_configure : 1; + +#if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES) + Damage damage; +#endif }; struct _GdkWindowImplX11Class |