[PATCH] Fix Lightbox for compositing window managers (#1008446)
David Shea
dshea at redhat.com
Tue Sep 17 15:02:59 UTC 2013
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));
--
1.8.3.1
More information about the anaconda-patches
mailing list