[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