[gtk+] Clean up the opacity handling
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Clean up the opacity handling
- Date: Mon, 11 Feb 2013 19:43:02 +0000 (UTC)
commit 7319f2934ff0364dad54f71bac9a3e9a7cc8f92f
Author: Alexander Larsson <alexl redhat com>
Date: Mon Feb 11 14:20:40 2013 +0100
Clean up the opacity handling
This cleans up the internals but doesn't really change the behaviour.
https://bugzilla.gnome.org/show_bug.cgi?id=687842
gtk/gtkwidget.c | 153 ++++++++++++++++++++++++-------------------------------
1 files changed, 67 insertions(+), 86 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 8278f98..7bbd4fa 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -712,7 +712,7 @@ static void gtk_widget_set_device_enabled_internal (GtkWidget *widget,
static gboolean event_window_is_still_viewable (GdkEvent *event);
static void gtk_cairo_set_event (cairo_t *cr,
GdkEventExpose *event);
-static void gtk_widget_update_norender (GtkWidget *widget);
+static void gtk_widget_propagate_alpha (GtkWidget *widget);
/* --- variables --- */
static gpointer gtk_widget_parent_class = NULL;
@@ -4038,7 +4038,7 @@ gtk_widget_unparent (GtkWidget *widget)
g_object_notify_queue_clear (G_OBJECT (widget), nqueue);
g_object_notify_queue_thaw (G_OBJECT (widget), nqueue);
- gtk_widget_update_norender (widget);
+ gtk_widget_propagate_alpha (widget);
gtk_widget_pop_verify_invariants (widget);
g_object_unref (widget);
@@ -8168,7 +8168,7 @@ gtk_widget_set_parent (GtkWidget *widget,
gtk_widget_queue_compute_expand (parent);
}
- gtk_widget_update_norender (widget);
+ gtk_widget_propagate_alpha (widget);
gtk_widget_pop_verify_invariants (widget);
}
@@ -13770,7 +13770,7 @@ gtk_widget_register_window (GtkWidget *widget,
if (!gtk_widget_get_has_window (widget) && !gdk_window_has_native (window))
gdk_window_set_opacity (window,
- (priv->norender || priv->norender_children) ? 0.0 : 1.0);
+ priv->norender_children ? 0.0 : 1.0);
}
/**
@@ -13864,72 +13864,82 @@ gtk_widget_set_support_multidevice (GtkWidget *widget,
gdk_window_set_support_multidevice (priv->window, support_multidevice);
}
-static void apply_norender (GtkWidget *widget, gboolean norender);
+/* There are multiple alpha related sources, the user can specify alpha
+ * in gtk_widget_set_opacity, secondly we can get it from the css opacity. These two
+ * are multiplied together to form the total alpha.
+ *
+ * We handle opacity in two ways. For a windowed widget, with opacity set but no opacity
+ * group we directly set the opacity of widget->window. This will cause gdk to properly
+ * redirect drawing inside the window to a buffer and do OVER paint_with_alpha.
+ *
+ * However, if the widget is not windowed,
+ * we do the opacity handling in the ::draw marshaller for the widget. A naive
+ * implementation of this would break for windowed widgets or descendant widgets with
+ * windows, as these would not be handled by the ::draw signal. To handle this we set
+ * all such gdkwindows as fully transparent and then override gtk_cairo_should_draw_window()
+ * to make the draw signal propagate to *all* child widgets/windows.
+ *
+ * Note: We don't make all child windows fully transparent, we stop at the first one
+ * in each branch when propagating down the hierarchy.
+ */
-static void
-apply_norender_cb (GtkWidget *widget, gpointer norender)
-{
- apply_norender (widget, GPOINTER_TO_INT (norender));
-}
+/* This is called when priv->alpha changes, and should
+ * update priv->norender and GdkWindow opacity for this widget and any children that
+ * needs changing. It is also called whenver the parent changes, the parents
+ * norender_children state changes, or the has_window state of the widget changes.
+ */
static void
-propagate_norender_non_window (GtkWidget *widget, gboolean norender)
+gtk_widget_propagate_alpha (GtkWidget *widget)
{
+ GtkWidgetPrivate *priv = widget->priv;
+ GtkWidget *parent;
+ gboolean norender, norender_children;
GList *l;
- g_assert (!gtk_widget_get_has_window (widget));
-
- for (l = widget->priv->registered_windows; l != NULL; l = l->next)
- gdk_window_set_opacity (l->data,
- norender ? 0 : widget->priv->alpha / 255.0);
-
- if (GTK_IS_CONTAINER (widget))
- gtk_container_forall (GTK_CONTAINER (widget), apply_norender_cb,
- GINT_TO_POINTER (norender));
-}
-
-static void
-apply_norender (GtkWidget *widget, gboolean norender)
-{
- if (widget->priv->norender == norender)
- return;
+ parent = priv->parent;
- widget->priv->norender = norender;
+ norender =
+ /* If the parent has norender_children, propagate that here */
+ (parent != NULL && parent->priv->norender_children);
+
+ /* Windowed widget children should norender if: */
+ norender_children =
+ /* The widget is no_window (otherwise its enought to mark it norender/alpha), and */
+ !gtk_widget_get_has_window (widget) &&
+ ( /* norender is set, or */
+ norender ||
+ /* widget has an alpha */
+ priv->alpha != 255
+ );
if (gtk_widget_get_has_window (widget))
{
- if (widget->priv->window != NULL)
- gdk_window_set_opacity (widget->priv->window,
- norender ? 0 : widget->priv->alpha / 255.0);
+ if (priv->window != NULL && !gdk_window_has_native (priv->window))
+ gdk_window_set_opacity (priv->window,
+ norender ? 0 : priv->alpha / 255.0);
+ }
+ else /* !has_window */
+ {
+ for (l = priv->registered_windows; l != NULL; l = l->next)
+ {
+ GdkWindow *w = l->data;
+ if (!gdk_window_has_native (w))
+ gdk_window_set_opacity (w, norender_children ? 0.0 : 1.0);
+ }
}
- else
- propagate_norender_non_window (widget, norender | widget->priv->norender_children);
-}
-
-/* This is called when the norender_children state of a non-window widget changes,
- * its parent changes, or its has_window state changes. It means we need
- * to update the norender of all the windows owned by the widget and those
- * of child widgets, up to and including the first windowed widgets in the hierarchy.
- */
-static void
-gtk_widget_update_norender (GtkWidget *widget)
-{
- gboolean norender;
- GtkWidget *parent;
-
- parent = widget->priv->parent;
- norender =
- parent != NULL &&
- (parent->priv->norender_children ||
- (parent->priv->norender && !gtk_widget_get_has_window (parent)));
+ priv->norender = norender;
+ if (priv->norender_children != norender_children)
+ {
+ priv->norender_children = norender_children;
- apply_norender (widget, norender);
+ if (GTK_IS_CONTAINER (widget))
+ gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback)gtk_widget_propagate_alpha, NULL);
+ }
- /* The above may not have propagated to children if norender_children changed but
- not norender, so we need to enforce propagation. */
- if (!gtk_widget_get_has_window (widget))
- propagate_norender_non_window (widget, norender | widget->priv->norender_children);
+ if (gtk_widget_get_realized (widget))
+ gtk_widget_queue_draw (widget);
}
static void
@@ -13958,37 +13968,8 @@ gtk_widget_update_alpha (GtkWidget *widget)
priv->alpha = alpha;
- if (gtk_widget_get_has_window (widget))
- {
- if (priv->window != NULL)
- gdk_window_set_opacity (priv->window,
- priv->norender ? 0 : priv->alpha / 255.0);
- }
- else
- {
- /* For non windowed widgets we can't use gdk_window_set_opacity() directly, as there is
- no GdkWindow at the right place in the hierarchy. For no-window widget this is not a problem,
- as we just push an opacity group in the draw marshaller.
-
- However, that only works for non-window descendant widgets. If any descendant has a
- window that window will not normally be rendered in the draw signal, so the opacity
- group will not work for it.
+ gtk_widget_propagate_alpha (widget);
- To fix this we set all such windows to a zero opacity, meaning they don't get drawn
- by gdk, and instead we set a NULL _gtk_cairo_get_event during expose so that the draw
- handler recurses into windowed widgets.
-
- We do this by setting "norender_children", which means that any windows in this widget
- or its ancestors (stopping at the first such windows at each branch in the hierarchy)
- are set to zero opacity. This is then propagated into all necessary children as norender,
- which controls whether a window should be exposed or not.
- */
- priv->norender_children = priv->alpha != 255;
- gtk_widget_update_norender (widget);
- }
-
- if (gtk_widget_get_realized (widget))
- gtk_widget_queue_draw (widget);
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]