[PATCH] Fix Lightbox for compositing window managers (#1008446)
Vratislav Podzimek
vpodzime at redhat.com
Tue Sep 17 15:38:54 UTC 2013
On Tue, 2013-09-17 at 11:02 -0400, David Shea wrote:
> If the lightbox is running in a compositing window manager, use Gtk to
> set the color and opacity of the widget. Fallback to drawing the
> background ourselves if we are not composited.
> ---
> widgets/src/Lightbox.c | 126 +++++++++++++++++++++++++++++++++----------------
> 1 file changed, 86 insertions(+), 40 deletions(-)
>
> diff --git a/widgets/src/Lightbox.c b/widgets/src/Lightbox.c
> index 245deab..c399cca 100644
> --- a/widgets/src/Lightbox.c
> +++ b/widgets/src/Lightbox.c
> @@ -33,6 +33,24 @@
> * The lightbox window will show as soon as it is created.
> */
>
> +/*
> + * We have two methods for drawing the transparent background, depending
> + * on whether we can use a compositing window manager for alpha blending
> + * or not.
> + *
> + * In a compositing window manager (e.g., gnome-shell on the livecd), we
> + * create the transparent background using Gtk by overriding the window's
> + * background color and setting an opacity.
> + *
> + * In a non-compositing window manager (e.g., metacity on the install DVD),
> + * we override Gtk's drawing of the widget entirely. We set paintable to
> + * false to indicate that theme information should not be applied, and then
> + * as the parent-window property is being set, we use cairo to paint a new
> + * surface using the parent's Gdk window as the source pattern, apply a 50%
> + * translucent fill to the surface, and then use this surface as the
> + * background for the lightbox's Gdk window.
> + */
> +
> #include <cairo.h>
> #include <gtk/gtk.h>
>
> @@ -48,10 +66,12 @@ struct _AnacondaLightboxPrivate {
> GtkWindow *transient_parent;
> gboolean parent_configure_event_handler_set;
> guint parent_configure_event_handler;
> +
> + gboolean composited;
> };
>
> static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
> -static void anaconda_lightbox_draw_background(GObject *gobject, GParamSpec *psec, gpointer user_data);
> +static void anaconda_lightbox_set_parent_window(GObject *gobject, GParamSpec *psec, gpointer user_data);
>
> static gboolean anaconda_lb_parent_configure_event(GtkWidget *parent, GdkEvent *event, gpointer lightbox);
> static gboolean anaconda_lb_configure_event(GtkWidget *lightbox, GdkEvent *event, gpointer user_data);
> @@ -96,10 +116,32 @@ static void anaconda_lightbox_init(AnacondaLightbox *lightbox)
> gtk_window_set_decorated(GTK_WINDOW(lightbox), FALSE);
> gtk_window_set_has_resize_grip(GTK_WINDOW(lightbox), FALSE);
>
> - /* Indicate we will handle drawing the widget so no theme is applied */
> - gtk_widget_set_app_paintable(GTK_WIDGET(lightbox), TRUE);
> gtk_window_set_type_hint(GTK_WINDOW(lightbox), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
>
> + /* Decide now which background drawing method to use */
> + lightbox->priv->composited = gtk_widget_is_composited(GTK_WIDGET(lightbox));
> + if (lightbox->priv->composited)
> + {
> + GdkRGBA color = {0.0, 0.0, 0.0, 1.0}; /* opaque black */
> +
> + /* Set the background to black */
> + gtk_widget_override_background_color(GTK_WIDGET(lightbox),
> + GTK_STATE_FLAG_NORMAL,
> + &color
> + );
> +
> + /* Set the opacity to 50% */
> + gtk_widget_set_opacity(GTK_WIDGET(lightbox), 0.5);
> + }
> + else
> + {
> + /*
> + * Indicate we will handle drawing the widget, do the rest in
> + * anaconda_lightbox_set_parent_window
> + */
> + gtk_widget_set_app_paintable(GTK_WIDGET(lightbox), TRUE);
> + }
> +
> /* handle restacking events */
> g_signal_connect(lightbox, "configure-event", G_CALLBACK(anaconda_lb_configure_event), NULL);
>
> @@ -117,7 +159,7 @@ static void anaconda_lightbox_set_property(GObject *object, guint prop_id, const
> case PROP_PARENT_WINDOW:
> priv->transient_parent = GTK_WINDOW(g_object_ref(g_value_get_object(value)));
> /* The property is CONSTRUCT_ONLY, so no point calling notify */
> - anaconda_lightbox_draw_background(object, pspec, NULL);
> + anaconda_lightbox_set_parent_window(object, pspec, NULL);
> break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> @@ -181,7 +223,7 @@ static gboolean anaconda_lb_parent_configure_event(
> * Draw the window background. Uses the gobject notify handler signature
> * in case we want to allow parent-window to change in the future.
> */
> -static void anaconda_lightbox_draw_background(
> +static void anaconda_lightbox_set_parent_window(
> GObject *gobject,
> GParamSpec *psec,
> gpointer user_data
> @@ -232,43 +274,47 @@ static void anaconda_lightbox_draw_background(
> G_CALLBACK(anaconda_lb_parent_configure_event), lightbox);
> lightbox->priv->parent_configure_event_handler_set = TRUE;
>
> - /*
> - * NB: We should probably be handling the draw signal in order to refresh
> - * the transparent pattern from the parent window whenver something
> - * changes, but by the time things get to the signal handler the surface is
> - * already set up and doesn't support alpha channels and replacing it
> - * doesn't seem to work quite right. Besides, none of these windows are
> - * supposed to move anyway.
> - */
> -
> - /* Realize the window to initialize the Gdk objects */
> - if (!gtk_widget_get_realized(GTK_WIDGET(lightbox)))
> + /* Handle the non-compositing background case */
> + if (!lightbox->priv->composited)
> {
> - gtk_widget_realize(GTK_WIDGET(lightbox));
> + /*
> + * NB: We should probably be handling the draw signal in order to refresh
> + * the transparent pattern from the parent window whenver something
> + * changes, but by the time things get to the signal handler the surface is
> + * already set up and doesn't support alpha channels and replacing it
> + * doesn't seem to work quite right. Besides, none of these windows are
> + * supposed to move anyway.
> + */
> +
> + /* Realize the window to initialize the Gdk objects */
> + if (!gtk_widget_get_realized(GTK_WIDGET(lightbox)))
> + {
> + gtk_widget_realize(GTK_WIDGET(lightbox));
> + }
> + g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox));
> +
> + /* Create a new surface that supports alpha content */
> + surface = gdk_window_create_similar_surface(g_lightbox_window,
> + CAIRO_CONTENT_COLOR_ALPHA,
> + gdk_window_get_width(g_parent_window),
> + gdk_window_get_height(g_parent_window));
> + cr = cairo_create(surface);
> +
> + /* Use the parent window as a pattern and paint it on the surface */
> + gdk_cairo_set_source_window(cr, g_parent_window, 0, 0);
> + cairo_paint(cr);
> +
> + /* Paint a black, 50% transparent shade */
> + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5);
> + cairo_paint(cr);
> +
> + cairo_destroy(cr);
> +
> + /* Use the surface we painted as the window background */
> + pattern = cairo_pattern_create_for_surface(surface);
> + gdk_window_set_background_pattern(g_lightbox_window, pattern);
> + cairo_pattern_destroy(pattern);
> }
> - g_lightbox_window = gtk_widget_get_window(GTK_WIDGET(lightbox));
> -
> - /* Create a new surface that supports alpha content */
> - surface = gdk_window_create_similar_surface(g_lightbox_window,
> - CAIRO_CONTENT_COLOR_ALPHA,
> - gdk_window_get_width(g_parent_window),
> - gdk_window_get_height(g_parent_window));
> - cr = cairo_create(surface);
> -
> - /* Use the parent window as a pattern and paint it on the surface */
> - gdk_cairo_set_source_window(cr, g_parent_window, 0, 0);
> - cairo_paint(cr);
> -
> - /* Paint a black, 50% transparent shade */
> - cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5);
> - cairo_paint(cr);
> -
> - cairo_destroy(cr);
> -
> - /* Use the surface we painted as the window background */
> - pattern = cairo_pattern_create_for_surface(surface);
> - gdk_window_set_background_pattern(g_lightbox_window, pattern);
> - cairo_pattern_destroy(pattern);
> }
>
> gtk_widget_show(GTK_WIDGET(lightbox));
This looks good to me.
--
Vratislav Podzimek
Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic
More information about the anaconda-patches
mailing list