[gnome-builder] egg-state-machine: add support for enabling GSimpleActions
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] egg-state-machine: add support for enabling GSimpleActions
- Date: Tue, 5 May 2015 01:44:21 +0000 (UTC)
commit e76418772bd4259c9afdfb215b3d6ce520db570b
Author: Christian Hergert <christian hergert me>
Date: Mon May 4 18:44:13 2015 -0700
egg-state-machine: add support for enabling GSimpleActions
This allows you to pin actions that should be enabled or disabled in a
given state.
Simply add the action to the state you care about, and set wether or not
you want enabled to be inverted. Normally, the action will be enabled
when you enter that state.
contrib/egg/egg-state-machine.c | 103 ++++++++++++++++++++++++++++++++++++++-
contrib/egg/egg-state-machine.h | 6 ++-
tests/test-egg-state-machine.c | 12 +++++
3 files changed, 118 insertions(+), 3 deletions(-)
---
diff --git a/contrib/egg/egg-state-machine.c b/contrib/egg/egg-state-machine.c
index cba6d72..da38181 100644
--- a/contrib/egg/egg-state-machine.c
+++ b/contrib/egg/egg-state-machine.c
@@ -29,15 +29,28 @@ typedef struct
/*
* Containers for lazily bound signals and bindings.
*
- * Each is a GHashTable indexed by state name, containing another
- * GHashTable indexed by source object.
+ * Each is a GHashTable indexed by state name, containing another GHashTable indexed by
+ * source object.
*/
GHashTable *binding_sets_by_state;
GHashTable *signal_groups_by_state;
+ /*
+ * Container for actions which should have sensitivity mutated during state transitions.
+ *
+ * GHashTable of GPtrArray of ActionState.
+ */
+ GHashTable *actions_by_state;
+
gsize sequence;
} EggStateMachinePrivate;
+typedef struct
+{
+ GSimpleAction *action;
+ guint invert_enabled : 1;
+} ActionState;
+
G_DEFINE_TYPE_WITH_PRIVATE (EggStateMachine, egg_state_machine, G_TYPE_OBJECT)
G_DEFINE_QUARK (EggStateMachineError, egg_state_machine_error)
@@ -55,6 +68,18 @@ enum {
static GParamSpec *gParamSpecs [LAST_PROP];
static guint gSignals [LAST_SIGNAL];
+static void
+action_state_free (gpointer data)
+{
+ ActionState *state = data;
+
+ if (state != NULL)
+ {
+ g_clear_object (&state->action);
+ g_slice_free (ActionState, state);
+ }
+}
+
static gboolean
egg_state_transition_accumulator (GSignalInvocationHint *hint,
GValue *return_value,
@@ -91,7 +116,9 @@ egg_state_machine_do_transition (EggStateMachine *self,
EggStateMachinePrivate *priv = egg_state_machine_get_instance_private (self);
GHashTableIter iter;
const gchar *key;
+ GPtrArray *action_states;
GHashTable *value;
+ gsize i;
g_assert (EGG_IS_STATE_MACHINE (self));
g_assert (new_state != NULL);
@@ -140,6 +167,35 @@ egg_state_machine_do_transition (EggStateMachine *self,
egg_binding_set_set_source (binding_set, enabled ? instance : NULL);
}
}
+
+ /* apply GSimpleAction:enabled to non-matching states */
+ g_hash_table_iter_init (&iter, priv->actions_by_state);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&action_states))
+ {
+ if (g_strcmp0 (key, priv->state) == 0)
+ continue;
+
+ for (i = 0; i < action_states->len; i++)
+ {
+ ActionState *action_state;
+
+ action_state = g_ptr_array_index (action_states, i);
+ g_simple_action_set_enabled (action_state->action, action_state->invert_enabled);
+ }
+ }
+
+ /* apply GSimpleAction:enabled to matching state */
+ action_states = g_hash_table_lookup (priv->actions_by_state, priv->state);
+ if (action_states != NULL)
+ {
+ for (i = 0; i < action_states->len; i++)
+ {
+ ActionState *action_state;
+
+ action_state = g_ptr_array_index (action_states, i);
+ g_simple_action_set_enabled (action_state->action, !action_state->invert_enabled);
+ }
+ }
}
/**
@@ -222,6 +278,7 @@ egg_state_machine_finalize (GObject *object)
g_clear_pointer (&priv->state, g_free);
g_clear_pointer (&priv->binding_sets_by_state, g_hash_table_unref);
g_clear_pointer (&priv->signal_groups_by_state, g_hash_table_unref);
+ g_clear_pointer (&priv->actions_by_state, g_hash_table_unref);
G_OBJECT_CLASS (egg_state_machine_parent_class)->finalize (object);
}
@@ -328,6 +385,12 @@ egg_state_machine_init (EggStateMachine *self)
g_str_equal,
g_free,
(GDestroyNotify)g_hash_table_destroy);
+
+ priv->actions_by_state =
+ g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)g_ptr_array_unref);
}
static void
@@ -491,6 +554,42 @@ egg_state_machine_bind (EggStateMachine *self,
egg_binding_set_set_source (binding_set, source);
}
+void
+egg_state_machine_add_action (EggStateMachine *self,
+ const gchar *state,
+ GSimpleAction *action,
+ gboolean invert_enabled)
+{
+ EggStateMachinePrivate *priv = egg_state_machine_get_instance_private (self);
+ ActionState *action_state;
+ GPtrArray *actions;
+ gboolean enabled;
+
+ g_return_if_fail (EGG_IS_STATE_MACHINE (self));
+ g_return_if_fail (state != NULL);
+ g_return_if_fail (G_IS_SIMPLE_ACTION (action));
+
+ action_state = g_slice_new0 (ActionState);
+ action_state->action = g_object_ref (action);
+ action_state->invert_enabled = invert_enabled;
+
+ actions = g_hash_table_lookup (priv->actions_by_state, state);
+
+ if (actions == NULL)
+ {
+ actions = g_ptr_array_new_with_free_func (action_state_free);
+ g_hash_table_insert (priv->actions_by_state, g_strdup (state), actions);
+ }
+
+ g_ptr_array_add (actions, action_state);
+
+ enabled = (g_strcmp0 (state, priv->state) == 0);
+ if (invert_enabled)
+ enabled = !enabled;
+
+ g_simple_action_set_enabled (action, enabled);
+}
+
EggStateMachine *
egg_state_machine_new (void)
{
diff --git a/contrib/egg/egg-state-machine.h b/contrib/egg/egg-state-machine.h
index 5b38700..6a8e55c 100644
--- a/contrib/egg/egg-state-machine.h
+++ b/contrib/egg/egg-state-machine.h
@@ -19,7 +19,7 @@
#ifndef EGG_STATE_MACHINE_H
#define EGG_STATE_MACHINE_H
-#include <glib-object.h>
+#include <gio/gio.h>
G_BEGIN_DECLS
@@ -74,6 +74,10 @@ void egg_state_machine_connect_object (EggStateMachine *self,
GCallback callback,
gpointer user_data,
GConnectFlags flags);
+void egg_state_machine_add_action (EggStateMachine *self,
+ const gchar *state,
+ GSimpleAction *action,
+ gboolean invert_sensitive);
G_END_DECLS
diff --git a/tests/test-egg-state-machine.c b/tests/test-egg-state-machine.c
index b9e01e4..d221503 100644
--- a/tests/test-egg-state-machine.c
+++ b/tests/test-egg-state-machine.c
@@ -207,6 +207,7 @@ test_state_machine_basic (void)
{
EggStateMachine *machine;
EggStateTransition ret;
+ GSimpleAction *action;
TestObject *dummy;
TestObject *obj1;
TestObject *obj2;
@@ -215,6 +216,7 @@ test_state_machine_basic (void)
machine = egg_state_machine_new ();
g_object_add_weak_pointer (G_OBJECT (machine), (gpointer *)&machine);
+ action = g_simple_action_new ("my-action", NULL);
dummy = g_object_new (TEST_TYPE_OBJECT, NULL);
obj1 = g_object_new (TEST_TYPE_OBJECT, NULL);
obj2 = g_object_new (TEST_TYPE_OBJECT, NULL);
@@ -231,14 +233,20 @@ test_state_machine_basic (void)
egg_state_machine_bind (machine, "state1", obj1, "string", dummy, "string", 0);
egg_state_machine_bind (machine, "state2", obj2, "string", dummy, "string", 0);
+ egg_state_machine_add_action (machine, "state1", action, FALSE);
+
g_signal_connect (machine, "transition", G_CALLBACK (transition_cb), NULL);
+ g_assert_cmpint (g_action_get_enabled (G_ACTION (action)), ==, FALSE);
+
ret = egg_state_machine_transition (machine, "state1", &error);
g_assert_no_error (error);
g_assert_cmpint (ret, ==, EGG_STATE_TRANSITION_SUCCESS);
g_assert_cmpint (dummy->obj1_count, ==, 0);
g_assert_cmpint (dummy->obj2_count, ==, 0);
+ g_assert_cmpint (g_action_get_enabled (G_ACTION (action)), ==, TRUE);
+
g_signal_emit_by_name (obj1, "frobnicate");
g_assert_cmpint (dummy->obj1_count, ==, 1);
g_assert_cmpint (dummy->obj2_count, ==, 0);
@@ -251,6 +259,8 @@ test_state_machine_basic (void)
g_assert_no_error (error);
g_assert_cmpint (ret, ==, EGG_STATE_TRANSITION_SUCCESS);
+ g_assert_cmpint (g_action_get_enabled (G_ACTION (action)), ==, FALSE);
+
g_signal_emit_by_name (obj1, "frobnicate");
g_assert_cmpint (dummy->obj1_count, ==, 1);
g_assert_cmpint (dummy->obj2_count, ==, 0);
@@ -287,6 +297,8 @@ test_state_machine_basic (void)
g_object_unref (machine);
g_assert (machine == NULL);
+
+ g_clear_object (&action);
}
gint
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]