[gtk+/gtk-style-context] Implement widget states as a set of flags
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gtk-style-context] Implement widget states as a set of flags
- Date: Mon, 1 Nov 2010 03:02:11 +0000 (UTC)
commit 340a8455c0f72378893a9efcd7d9cb1ed9c85409
Author: Carlos Garnacho <carlosg gnome org>
Date: Sat Oct 30 21:48:38 2010 +0200
Implement widget states as a set of flags
gtk_widget_(set|unset|get)_state_flags() has been added, using GtkStateFlags
to represent the widget state. GtkStateType API has been implemented on top
of the new one.
docs/reference/gtk/gtk3-sections.txt | 3 +
gtk/gtkmarshalers.list | 1 +
gtk/gtkwidget.c | 342 ++++++++++++++++++++++++++--------
gtk/gtkwidget.h | 9 +
4 files changed, 273 insertions(+), 82 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index f9ddd8e..03e38a1 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -4933,6 +4933,9 @@ gtk_widget_is_sensitive
gtk_widget_get_state
gtk_widget_get_visible
gtk_widget_set_visible
+gtk_widget_set_state_flags
+gtk_widget_unset_state_flags
+gtk_widget_get_state_flags
gtk_widget_has_default
gtk_widget_has_focus
gtk_widget_has_grab
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 22af46d..10f0dfd 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -69,6 +69,7 @@ VOID:ENUM,FLOAT,BOOLEAN
VOID:ENUM,INT
VOID:ENUM,INT,BOOLEAN
VOID:ENUM,BOXED
+VOID:FLAGS
VOID:INT
VOID:INT,BOOLEAN
VOID:INT,INT
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 82afb3d..3bc12c0 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -345,15 +345,7 @@ struct _GtkWidgetPrivate
* 5 widget states (defined in "gtkenums.h")
* so 3 bits.
*/
- guint state : 3;
-
- /* The saved state of the widget. When a widget's state
- * is changed to GTK_STATE_INSENSITIVE via
- * "gtk_widget_set_state" or "gtk_widget_set_sensitive"
- * the old state is kept around in this field. The state
- * will be restored once the widget gets sensitive again.
- */
- guint saved_state : 3;
+ guint state_flags : 6;
guint direction : 2;
@@ -445,6 +437,7 @@ enum {
UNREALIZE,
SIZE_REQUEST,
SIZE_ALLOCATE,
+ STATE_FLAGS_CHANGED,
STATE_CHANGED,
PARENT_SET,
HIERARCHY_CHANGED,
@@ -551,10 +544,16 @@ enum {
typedef struct _GtkStateData GtkStateData;
+enum {
+ STATE_CHANGE_REPLACE,
+ STATE_CHANGE_SET,
+ STATE_CHANGE_UNSET
+};
+
struct _GtkStateData
{
- GtkStateType state;
- guint state_restoration : 1;
+ guint flags : 6;
+ guint operation : 2;
guint parent_sensitive : 1;
guint use_forall : 1;
};
@@ -1509,6 +1508,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
*
* The ::state-changed signal is emitted when the widget state changes.
* See gtk_widget_get_state().
+ *
+ * Deprecated: 3.0. Use #GtkWidget::state-flags-changed instead.
*/
widget_signals[STATE_CHANGED] =
g_signal_new (I_("state-changed"),
@@ -1521,6 +1522,26 @@ gtk_widget_class_init (GtkWidgetClass *klass)
GTK_TYPE_STATE_TYPE);
/**
+ * GtkWidget::state-flags-changed:
+ * @widget: the object which received the signal.
+ * @flags: The previous state flags.
+ *
+ * The ::state-flags-changed signal is emitted when the widget state
+ * changes, see gtk_widget_get_state_flags().
+ *
+ * Since: 3.0
+ */
+ widget_signals[STATE_FLAGS_CHANGED] =
+ g_signal_new (I_("state-flags-changed"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GtkWidgetClass, state_flags_changed),
+ NULL, NULL,
+ _gtk_marshal_VOID__FLAGS,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_STATE_FLAGS);
+
+ /**
* GtkWidget::parent-set:
* @widget: the object on which the signal is emitted
* @old_parent: (allow-none): the previous parent, or %NULL if the widget
@@ -3566,8 +3587,6 @@ gtk_widget_init (GtkWidget *widget)
priv = widget->priv;
priv->child_visible = TRUE;
- priv->state = GTK_STATE_NORMAL;
- priv->saved_state = GTK_STATE_NORMAL;
priv->name = NULL;
priv->allocation.x = -1;
priv->allocation.y = -1;
@@ -6802,50 +6821,182 @@ gtk_widget_get_name (GtkWidget *widget)
return G_OBJECT_TYPE_NAME (widget);
}
-/**
- * gtk_widget_set_state:
- * @widget: a #GtkWidget
- * @state: new state for @widget
- *
- * This function is for use in widget implementations. Sets the state
- * of a widget (insensitive, prelighted, etc.) Usually you should set
- * the state using wrapper functions such as gtk_widget_set_sensitive().
- **/
-void
-gtk_widget_set_state (GtkWidget *widget,
- GtkStateType state)
+static void
+_gtk_widget_update_state_flags (GtkWidget *widget,
+ GtkStateFlags flags,
+ guint operation)
{
GtkWidgetPrivate *priv;
- g_return_if_fail (GTK_IS_WIDGET (widget));
-
priv = widget->priv;
- if (state == gtk_widget_get_state (widget))
- return;
+ /* Handle insensitive first, since it is propagated
+ * differently throughout the widget hierarchy.
+ */
+ if ((flags & GTK_STATE_FLAG_INSENSITIVE) !=
+ (priv->state_flags & GTK_STATE_FLAG_INSENSITIVE))
+ gtk_widget_set_sensitive (widget,
+ operation != STATE_CHANGE_UNSET);
- if (state == GTK_STATE_INSENSITIVE)
- gtk_widget_set_sensitive (widget, FALSE);
- else
+ flags &= ~(GTK_STATE_FLAG_INSENSITIVE);
+
+ if (flags != 0 ||
+ operation == STATE_CHANGE_REPLACE)
{
GtkStateData data;
- data.state = state;
- data.state_restoration = FALSE;
+ data.flags = flags;
+ data.operation = operation;
data.use_forall = FALSE;
+
if (priv->parent)
data.parent_sensitive = (gtk_widget_is_sensitive (priv->parent) != FALSE);
else
data.parent_sensitive = TRUE;
gtk_widget_propagate_state (widget, &data);
-
+
if (gtk_widget_is_drawable (widget))
gtk_widget_queue_draw (widget);
}
}
/**
+ * gtk_widget_set_state_flags:
+ * @widget: a #GtkWidget
+ * @flags: State flags to turn on
+ * @clear: Whether to clear state before turning on @flags
+ *
+ * This function is for use in widget implementations. Turns on flag
+ * values in the current widget state (insensitive, prelighted, etc.).
+ *
+ * It is worth mentioning that any other state than %GTK_STATE_FLAG_INSENSITIVE,
+ * will be propagated down to all non-internal children if @widget is a
+ * #GtkContainer, while %GTK_STATE_FLAG_INSENSITIVE itself will be propagated
+ * down to all #GtkContainer children by different means than turning on the
+ * state flag down the hierarchy, both gtk_widget_get_state_flags() and
+ * gtk_widget_is_sensitive() will make use of these.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_widget_set_state_flags (GtkWidget *widget,
+ GtkStateFlags flags,
+ gboolean clear)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if ((!clear && (widget->priv->state_flags & flags) == flags) ||
+ (clear && widget->priv->state_flags == flags))
+ return;
+
+ if (clear)
+ _gtk_widget_update_state_flags (widget, flags, STATE_CHANGE_REPLACE);
+ else
+ _gtk_widget_update_state_flags (widget, flags, STATE_CHANGE_SET);
+}
+
+/**
+ * gtk_widget_unset_state_flags:
+ * @widget: a #GtkWidget
+ * @flags: State flags to turn off
+ *
+ * This function is for use in widget implementations. Turns off flag
+ * values for the current widget state (insensitive, prelighted, etc.).
+ * See gtk_widget_set_state_flags().
+ *
+ * Since: 3.0
+ **/
+void
+gtk_widget_unset_state_flags (GtkWidget *widget,
+ GtkStateFlags flags)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if ((widget->priv->state_flags & flags) == 0)
+ return;
+
+ _gtk_widget_update_state_flags (widget, flags, STATE_CHANGE_UNSET);
+}
+
+/**
+ * gtk_widget_get_state_flags:
+ * @widget: a #GtkWidget
+ *
+ * Returns the widget state as a flag set. It is worth mentioning
+ * that the effective %GTK_STATE_FLAG_INSENSITIVE state will be
+ * returned, that is, also based on parent insensitivity, even if
+ * @widget itself is sensitive.
+ *
+ * Returns: The state flags for widget
+ *
+ * Since: 3.0
+ **/
+GtkStateFlags
+gtk_widget_get_state_flags (GtkWidget *widget)
+{
+ GtkStateFlags flags;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ flags = widget->priv->state_flags;
+
+ if (!gtk_widget_is_sensitive (widget))
+ flags |= GTK_STATE_FLAG_INSENSITIVE;
+
+ return flags;
+}
+
+/**
+ * gtk_widget_set_state:
+ * @widget: a #GtkWidget
+ * @state: new state for @widget
+ *
+ * This function is for use in widget implementations. Sets the state
+ * of a widget (insensitive, prelighted, etc.) Usually you should set
+ * the state using wrapper functions such as gtk_widget_set_sensitive().
+ *
+ * Deprecated: 3.0. Use gtk_widget_set_state_flags() instead.
+ **/
+void
+gtk_widget_set_state (GtkWidget *widget,
+ GtkStateType state)
+{
+ GtkStateFlags flags;
+
+ if (state == gtk_widget_get_state (widget))
+ return;
+
+ switch (state)
+ {
+ case GTK_STATE_ACTIVE:
+ flags = GTK_STATE_FLAG_ACTIVE;
+ break;
+ case GTK_STATE_PRELIGHT:
+ flags = GTK_STATE_FLAG_PRELIGHT;
+ break;
+ case GTK_STATE_SELECTED:
+ flags = GTK_STATE_FLAG_SELECTED;
+ break;
+ case GTK_STATE_INSENSITIVE:
+ flags = GTK_STATE_FLAG_INSENSITIVE;
+ break;
+ case GTK_STATE_INCONSISTENT:
+ flags = GTK_STATE_FLAG_INCONSISTENT;
+ break;
+ case GTK_STATE_FOCUSED:
+ flags = GTK_STATE_FLAG_FOCUSED;
+ break;
+ case GTK_STATE_NORMAL:
+ default:
+ flags = 0;
+ break;
+ }
+
+ _gtk_widget_update_state_flags (widget, flags, STATE_CHANGE_REPLACE);
+}
+
+/**
* gtk_widget_get_state:
* @widget: a #GtkWidget
*
@@ -6854,13 +7005,32 @@ gtk_widget_set_state (GtkWidget *widget,
* Returns: the state of @widget.
*
* Since: 2.18
+ *
+ * Deprecated: 3.0. Use gtk_widget_get_state_flags() instead.
*/
GtkStateType
gtk_widget_get_state (GtkWidget *widget)
{
+ GtkStateFlags flags;
+
g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_STATE_NORMAL);
- return widget->priv->state;
+ flags = gtk_widget_get_state_flags (widget);
+
+ if (flags & GTK_STATE_FLAG_INSENSITIVE)
+ return GTK_STATE_INSENSITIVE;
+ else if (flags & GTK_STATE_FLAG_INCONSISTENT)
+ return GTK_STATE_INCONSISTENT;
+ else if (flags & GTK_STATE_FLAG_ACTIVE)
+ return GTK_STATE_ACTIVE;
+ else if (flags & GTK_STATE_FLAG_SELECTED)
+ return GTK_STATE_SELECTED;
+ else if (flags & GTK_STATE_FLAG_FOCUSED)
+ return GTK_STATE_FOCUSED;
+ else if (flags & GTK_STATE_FLAG_PRELIGHT)
+ return GTK_STATE_PRELIGHT;
+ else
+ return GTK_STATE_NORMAL;
}
/**
@@ -7267,17 +7437,19 @@ gtk_widget_set_sensitive (GtkWidget *widget,
if (widget->priv->sensitive == sensitive)
return;
+ data.flags = GTK_STATE_FLAG_INSENSITIVE;
+
if (sensitive)
{
widget->priv->sensitive = TRUE;
- data.state = priv->saved_state;
+ data.operation = STATE_CHANGE_UNSET;
}
else
{
widget->priv->sensitive = FALSE;
- data.state = gtk_widget_get_state (widget);
+ data.operation = STATE_CHANGE_SET;
}
- data.state_restoration = TRUE;
+
data.use_forall = TRUE;
if (priv->parent)
@@ -7286,6 +7458,7 @@ gtk_widget_set_sensitive (GtkWidget *widget,
data.parent_sensitive = TRUE;
gtk_widget_propagate_state (widget, &data);
+
if (gtk_widget_is_drawable (widget))
gtk_widget_queue_draw (widget);
@@ -7361,6 +7534,7 @@ void
gtk_widget_set_parent (GtkWidget *widget,
GtkWidget *parent)
{
+ GtkStateFlags parent_flags;
GtkWidgetPrivate *priv;
GtkStateData data;
@@ -7387,16 +7561,19 @@ gtk_widget_set_parent (GtkWidget *widget,
g_object_ref_sink (widget);
priv->parent = parent;
- if (gtk_widget_get_state (parent) != GTK_STATE_NORMAL)
- data.state = gtk_widget_get_state (parent);
- else
- data.state = gtk_widget_get_state (widget);
- data.state_restoration = FALSE;
+ parent_flags = gtk_widget_get_state_flags (parent);
+
+ /* Merge both old state and current parent state,
+ * We don't want the insensitive flag to propagate
+ * to the new child though */
+ data.flags = parent_flags & ~GTK_STATE_FLAG_INSENSITIVE;
+ data.flags |= priv->state_flags;
+
+ data.operation = STATE_CHANGE_REPLACE;
data.parent_sensitive = (gtk_widget_is_sensitive (parent) != FALSE);
data.use_forall = gtk_widget_is_sensitive (parent) != gtk_widget_is_sensitive (widget);
-
gtk_widget_propagate_state (widget, &data);
-
+
gtk_widget_reset_rc_styles (widget);
g_signal_emit (widget, widget_signals[PARENT_SET], 0, NULL);
@@ -7994,7 +8171,8 @@ gtk_widget_real_style_set (GtkWidget *widget,
if (gtk_widget_get_realized (widget) &&
gtk_widget_get_has_window (widget))
- gtk_style_set_background (priv->style, priv->window, priv->state);
+ gtk_style_set_background (priv->style, priv->window,
+ gtk_widget_get_state (widget));
}
static void
@@ -10473,33 +10651,27 @@ gtk_widget_propagate_state (GtkWidget *widget,
GtkStateData *data)
{
GtkWidgetPrivate *priv = widget->priv;
- guint8 old_state = gtk_widget_get_state (widget);
- guint8 old_saved_state = priv->saved_state;
+ GtkStateFlags old_flags = priv->state_flags;
+ GtkStateType old_state;
- /* don't call this function with state==GTK_STATE_INSENSITIVE,
- * parent_sensitive==TRUE on a sensitive widget
- */
+ old_state = gtk_widget_get_state (widget);
+ if (!priv->parent_sensitive)
+ old_flags |= GTK_STATE_FLAG_INSENSITIVE;
priv->parent_sensitive = data->parent_sensitive;
- if (gtk_widget_is_sensitive (widget))
+ switch (data->operation)
{
- if (data->state_restoration)
- priv->state = priv->saved_state;
- else
- priv->state = data->state;
- }
- else
- {
- if (!data->state_restoration)
- {
- if (data->state != GTK_STATE_INSENSITIVE)
- priv->saved_state = data->state;
- }
- else if (gtk_widget_get_state (widget) != GTK_STATE_INSENSITIVE)
- priv->saved_state = gtk_widget_get_state (widget);
- priv->state = GTK_STATE_INSENSITIVE;
+ case STATE_CHANGE_REPLACE:
+ priv->state_flags = data->flags;
+ break;
+ case STATE_CHANGE_SET:
+ priv->state_flags |= data->flags;
+ break;
+ case STATE_CHANGE_UNSET:
+ priv->state_flags &= ~(data->flags);
+ break;
}
if (gtk_widget_is_focus (widget) && !gtk_widget_is_sensitive (widget))
@@ -10507,12 +10679,12 @@ gtk_widget_propagate_state (GtkWidget *widget,
GtkWidget *window;
window = gtk_widget_get_toplevel (widget);
+
if (window && gtk_widget_is_toplevel (window))
gtk_window_set_focus (GTK_WINDOW (window), NULL);
}
- if (old_state != gtk_widget_get_state (widget) ||
- old_saved_state != priv->saved_state)
+ if (old_flags != gtk_widget_get_state_flags (widget))
{
g_object_ref (widget);
@@ -10520,6 +10692,7 @@ gtk_widget_propagate_state (GtkWidget *widget,
gtk_grab_remove (widget);
g_signal_emit (widget, widget_signals[STATE_CHANGED], 0, old_state);
+ g_signal_emit (widget, widget_signals[STATE_FLAGS_CHANGED], 0, old_flags);
if (!priv->shadowed)
{
@@ -10546,7 +10719,7 @@ gtk_widget_propagate_state (GtkWidget *widget,
if (!gtk_widget_is_sensitive (widget))
_gtk_widget_synthesize_crossing (widget, NULL, d->data,
GDK_CROSSING_STATE_CHANGED);
- else if (old_state == GTK_STATE_INSENSITIVE)
+ else if (old_flags & GTK_STATE_FLAG_INSENSITIVE)
_gtk_widget_synthesize_crossing (NULL, widget, d->data,
GDK_CROSSING_STATE_CHANGED);
@@ -10558,17 +10731,22 @@ gtk_widget_propagate_state (GtkWidget *widget,
}
if (GTK_IS_CONTAINER (widget))
- {
- data->parent_sensitive = (gtk_widget_is_sensitive (widget) != FALSE);
- if (data->use_forall)
- gtk_container_forall (GTK_CONTAINER (widget),
- (GtkCallback) gtk_widget_propagate_state,
- data);
- else
- gtk_container_foreach (GTK_CONTAINER (widget),
- (GtkCallback) gtk_widget_propagate_state,
- data);
- }
+ {
+ data->parent_sensitive = gtk_widget_is_sensitive (widget);
+
+ /* Do not propagate insensitive state further */
+ data->flags &= ~(GTK_STATE_FLAG_INSENSITIVE);
+
+ if (data->use_forall)
+ gtk_container_forall (GTK_CONTAINER (widget),
+ (GtkCallback) gtk_widget_propagate_state,
+ data);
+ else
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ (GtkCallback) gtk_widget_propagate_state,
+ data);
+ }
+
g_object_unref (widget);
}
}
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index eacb039..640dfb7 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -192,6 +192,8 @@ struct _GtkWidgetClass
GtkAllocation *allocation);
void (* state_changed) (GtkWidget *widget,
GtkStateType previous_state);
+ void (* state_flags_changed) (GtkWidget *widget,
+ GtkStateFlags previous_state_flags);
void (* parent_set) (GtkWidget *widget,
GtkWidget *previous_parent);
void (* hierarchy_changed) (GtkWidget *widget,
@@ -547,6 +549,13 @@ void gtk_widget_set_state (GtkWidget *widget,
GtkStateType state);
GtkStateType gtk_widget_get_state (GtkWidget *widget);
+void gtk_widget_set_state_flags (GtkWidget *widget,
+ GtkStateFlags flags,
+ gboolean clear);
+void gtk_widget_unset_state_flags (GtkWidget *widget,
+ GtkStateFlags flags);
+GtkStateFlags gtk_widget_get_state_flags (GtkWidget *widget);
+
void gtk_widget_set_sensitive (GtkWidget *widget,
gboolean sensitive);
gboolean gtk_widget_get_sensitive (GtkWidget *widget);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]