GActionMuxer: add support for parent muxers
If a muxer does not contain an action group with the given prefix, chain up to the "parent" muxer to look for it. This initial implementation is rather inefficient. It will lead to changes on action groups associated with parent muxers being broadcast to all children (regardless of if anybody there is interested or not). An optimised version will follow soon.
This commit is contained in:
committed by
Ryan Lortie
parent
6b7eaf86ed
commit
d1c458f9e1
@ -63,14 +63,24 @@ struct _GActionMuxer
|
|||||||
{
|
{
|
||||||
GObject parent_instance;
|
GObject parent_instance;
|
||||||
|
|
||||||
GHashTable *actions;
|
GHashTable *observed_actions;
|
||||||
GHashTable *groups;
|
GHashTable *groups;
|
||||||
|
GActionMuxer *parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT,
|
G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT,
|
||||||
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_iface_init)
|
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_iface_init)
|
||||||
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVABLE, g_action_muxer_observable_iface_init))
|
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVABLE, g_action_muxer_observable_iface_init))
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_PARENT,
|
||||||
|
NUM_PROPERTIES
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties[NUM_PROPERTIES];
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
GActionMuxer *muxer;
|
GActionMuxer *muxer;
|
||||||
@ -86,147 +96,243 @@ typedef struct
|
|||||||
gulong handler_ids[4];
|
gulong handler_ids[4];
|
||||||
} Group;
|
} Group;
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_append_group_actions (gpointer key,
|
||||||
|
gpointer value,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
const gchar *prefix = key;
|
||||||
|
Group *group = value;
|
||||||
|
GArray *actions = user_data;
|
||||||
|
gchar **group_actions;
|
||||||
|
gchar **action;
|
||||||
|
|
||||||
|
group_actions = g_action_group_list_actions (group->group);
|
||||||
|
for (action = group_actions; *action; action++)
|
||||||
|
{
|
||||||
|
gchar *fullname;
|
||||||
|
|
||||||
|
fullname = g_strconcat (prefix, ".", *action, NULL);
|
||||||
|
g_array_append_val (actions, fullname);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (group_actions);
|
||||||
|
}
|
||||||
|
|
||||||
static gchar **
|
static gchar **
|
||||||
g_action_muxer_list_actions (GActionGroup *action_group)
|
g_action_muxer_list_actions (GActionGroup *action_group)
|
||||||
{
|
{
|
||||||
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
||||||
GHashTableIter iter;
|
GArray *actions;
|
||||||
gchar *key;
|
|
||||||
gchar **keys;
|
|
||||||
gsize i;
|
|
||||||
|
|
||||||
keys = g_new (gchar *, g_hash_table_size (muxer->actions) + 1);
|
actions = g_array_new (TRUE, FALSE, sizeof (gchar *));
|
||||||
|
|
||||||
i = 0;
|
for ( ; muxer != NULL; muxer = muxer->parent)
|
||||||
g_hash_table_iter_init (&iter, muxer->actions);
|
{
|
||||||
while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL))
|
g_hash_table_foreach (muxer->groups,
|
||||||
keys[i++] = g_strdup (key);
|
g_action_muxer_append_group_actions,
|
||||||
keys[i] = NULL;
|
actions);
|
||||||
|
}
|
||||||
|
|
||||||
return keys;
|
return (gchar **) g_array_free (actions, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Group *
|
static Group *
|
||||||
g_action_muxer_find_group (GActionMuxer *muxer,
|
g_action_muxer_find_group (GActionMuxer *muxer,
|
||||||
const gchar **name)
|
const gchar *full_name,
|
||||||
|
const gchar **action_name)
|
||||||
{
|
{
|
||||||
const gchar *dot;
|
const gchar *dot;
|
||||||
gchar *prefix;
|
gchar *prefix;
|
||||||
Group *group;
|
Group *group;
|
||||||
|
|
||||||
dot = strchr (*name, '.');
|
dot = strchr (full_name, '.');
|
||||||
|
|
||||||
if (!dot)
|
if (!dot)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
prefix = g_strndup (*name, dot - *name);
|
prefix = g_strndup (full_name, dot - full_name);
|
||||||
group = g_hash_table_lookup (muxer->groups, prefix);
|
group = g_hash_table_lookup (muxer->groups, prefix);
|
||||||
g_free (prefix);
|
g_free (prefix);
|
||||||
|
|
||||||
*name = dot + 1;
|
if (action_name)
|
||||||
|
*action_name = dot + 1;
|
||||||
|
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Action *
|
|
||||||
g_action_muxer_lookup_action (GActionMuxer *muxer,
|
|
||||||
const gchar *prefix,
|
|
||||||
const gchar *action_name,
|
|
||||||
gchar **fullname)
|
|
||||||
{
|
|
||||||
Action *action;
|
|
||||||
|
|
||||||
*fullname = g_strconcat (prefix, ".", action_name, NULL);
|
|
||||||
action = g_hash_table_lookup (muxer->actions, *fullname);
|
|
||||||
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_action_muxer_action_enabled_changed (GActionGroup *action_group,
|
g_action_muxer_action_enabled_changed (GActionMuxer *muxer,
|
||||||
const gchar *action_name,
|
const gchar *action_name,
|
||||||
gboolean enabled,
|
gboolean enabled)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
Group *group = user_data;
|
|
||||||
gchar *fullname;
|
|
||||||
Action *action;
|
Action *action;
|
||||||
GSList *node;
|
GSList *node;
|
||||||
|
|
||||||
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
|
action = g_hash_table_lookup (muxer->observed_actions, action_name);
|
||||||
for (node = action ? action->watchers : NULL; node; node = node->next)
|
for (node = action ? action->watchers : NULL; node; node = node->next)
|
||||||
g_action_observer_action_enabled_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, enabled);
|
g_action_observer_action_enabled_changed (node->data, G_ACTION_OBSERVABLE (muxer), action_name, enabled);
|
||||||
g_action_group_action_enabled_changed (G_ACTION_GROUP (group->muxer), fullname, enabled);
|
g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), action_name, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_group_action_enabled_changed (GActionGroup *action_group,
|
||||||
|
const gchar *action_name,
|
||||||
|
gboolean enabled,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Group *group = user_data;
|
||||||
|
gchar *fullname;
|
||||||
|
|
||||||
|
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
|
||||||
|
g_action_muxer_action_enabled_changed (group->muxer, fullname, enabled);
|
||||||
|
|
||||||
g_free (fullname);
|
g_free (fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_action_muxer_action_state_changed (GActionGroup *action_group,
|
g_action_muxer_parent_action_enabled_changed (GActionGroup *action_group,
|
||||||
|
const gchar *action_name,
|
||||||
|
gboolean enabled,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GActionMuxer *muxer = user_data;
|
||||||
|
|
||||||
|
g_action_muxer_action_enabled_changed (muxer, action_name, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_action_state_changed (GActionMuxer *muxer,
|
||||||
const gchar *action_name,
|
const gchar *action_name,
|
||||||
GVariant *state,
|
GVariant *state)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
Group *group = user_data;
|
|
||||||
gchar *fullname;
|
|
||||||
Action *action;
|
Action *action;
|
||||||
GSList *node;
|
GSList *node;
|
||||||
|
|
||||||
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
|
action = g_hash_table_lookup (muxer->observed_actions, action_name);
|
||||||
for (node = action ? action->watchers : NULL; node; node = node->next)
|
for (node = action ? action->watchers : NULL; node; node = node->next)
|
||||||
g_action_observer_action_state_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, state);
|
g_action_observer_action_state_changed (node->data, G_ACTION_OBSERVABLE (muxer), action_name, state);
|
||||||
g_action_group_action_state_changed (G_ACTION_GROUP (group->muxer), fullname, state);
|
g_action_group_action_state_changed (G_ACTION_GROUP (muxer), action_name, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_group_action_state_changed (GActionGroup *action_group,
|
||||||
|
const gchar *action_name,
|
||||||
|
GVariant *state,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Group *group = user_data;
|
||||||
|
gchar *fullname;
|
||||||
|
|
||||||
|
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
|
||||||
|
g_action_muxer_action_state_changed (group->muxer, fullname, state);
|
||||||
|
|
||||||
g_free (fullname);
|
g_free (fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_action_muxer_action_added (GActionGroup *action_group,
|
g_action_muxer_parent_action_state_changed (GActionGroup *action_group,
|
||||||
|
const gchar *action_name,
|
||||||
|
GVariant *state,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GActionMuxer *muxer = user_data;
|
||||||
|
|
||||||
|
g_action_muxer_action_state_changed (muxer, action_name, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_action_added (GActionMuxer *muxer,
|
||||||
const gchar *action_name,
|
const gchar *action_name,
|
||||||
gpointer user_data)
|
GActionGroup *original_group,
|
||||||
|
const gchar *orignal_action_name)
|
||||||
{
|
{
|
||||||
const GVariantType *parameter_type;
|
const GVariantType *parameter_type;
|
||||||
Group *group = user_data;
|
|
||||||
gboolean enabled;
|
gboolean enabled;
|
||||||
GVariant *state;
|
GVariant *state;
|
||||||
|
Action *action;
|
||||||
|
|
||||||
if (g_action_group_query_action (group->group, action_name, &enabled, ¶meter_type, NULL, NULL, &state))
|
action = g_hash_table_lookup (muxer->observed_actions, action_name);
|
||||||
|
|
||||||
|
if (action && action->watchers &&
|
||||||
|
g_action_group_query_action (original_group, orignal_action_name,
|
||||||
|
&enabled, ¶meter_type, NULL, NULL, &state))
|
||||||
{
|
{
|
||||||
gchar *fullname;
|
|
||||||
Action *action;
|
|
||||||
GSList *node;
|
GSList *node;
|
||||||
|
|
||||||
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
|
for (node = action->watchers; node; node = node->next)
|
||||||
|
|
||||||
for (node = action ? action->watchers : NULL; node; node = node->next)
|
|
||||||
g_action_observer_action_added (node->data,
|
g_action_observer_action_added (node->data,
|
||||||
G_ACTION_OBSERVABLE (group->muxer),
|
G_ACTION_OBSERVABLE (muxer),
|
||||||
fullname, parameter_type, enabled, state);
|
action_name, parameter_type, enabled, state);
|
||||||
|
|
||||||
g_action_group_action_added (G_ACTION_GROUP (group->muxer), fullname);
|
|
||||||
|
|
||||||
if (state)
|
if (state)
|
||||||
g_variant_unref (state);
|
g_variant_unref (state);
|
||||||
|
|
||||||
g_free (fullname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_action_group_action_added (G_ACTION_GROUP (muxer), action_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_action_muxer_action_removed (GActionGroup *action_group,
|
g_action_muxer_action_added_to_group (GActionGroup *action_group,
|
||||||
const gchar *action_name,
|
const gchar *action_name,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
Group *group = user_data;
|
Group *group = user_data;
|
||||||
gchar *fullname;
|
gchar *fullname;
|
||||||
|
|
||||||
|
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
|
||||||
|
g_action_muxer_action_added (group->muxer, fullname, action_group, action_name);
|
||||||
|
|
||||||
|
g_free (fullname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_action_added_to_parent (GActionGroup *action_group,
|
||||||
|
const gchar *action_name,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GActionMuxer *muxer = user_data;
|
||||||
|
|
||||||
|
g_action_muxer_action_added (muxer, action_name, action_group, action_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_action_removed (GActionMuxer *muxer,
|
||||||
|
const gchar *action_name)
|
||||||
|
{
|
||||||
Action *action;
|
Action *action;
|
||||||
GSList *node;
|
GSList *node;
|
||||||
|
|
||||||
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
|
action = g_hash_table_lookup (muxer->observed_actions, action_name);
|
||||||
for (node = action ? action->watchers : NULL; node; node = node->next)
|
for (node = action ? action->watchers : NULL; node; node = node->next)
|
||||||
g_action_observer_action_removed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname);
|
g_action_observer_action_removed (node->data, G_ACTION_OBSERVABLE (muxer), action_name);
|
||||||
g_action_group_action_removed (G_ACTION_GROUP (group->muxer), fullname);
|
g_action_group_action_removed (G_ACTION_GROUP (muxer), action_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_action_removed_from_group (GActionGroup *action_group,
|
||||||
|
const gchar *action_name,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Group *group = user_data;
|
||||||
|
gchar *fullname;
|
||||||
|
|
||||||
|
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
|
||||||
|
g_action_muxer_action_removed (group->muxer, fullname);
|
||||||
|
|
||||||
g_free (fullname);
|
g_free (fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_action_removed_from_parent (GActionGroup *action_group,
|
||||||
|
const gchar *action_name,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GActionMuxer *muxer = user_data;
|
||||||
|
|
||||||
|
g_action_muxer_action_removed (muxer, action_name);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
g_action_muxer_query_action (GActionGroup *action_group,
|
g_action_muxer_query_action (GActionGroup *action_group,
|
||||||
const gchar *action_name,
|
const gchar *action_name,
|
||||||
@ -238,14 +344,20 @@ g_action_muxer_query_action (GActionGroup *action_group,
|
|||||||
{
|
{
|
||||||
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
||||||
Group *group;
|
Group *group;
|
||||||
|
const gchar *unprefixed_name;
|
||||||
|
|
||||||
group = g_action_muxer_find_group (muxer, &action_name);
|
group = g_action_muxer_find_group (muxer, action_name, &unprefixed_name);
|
||||||
|
|
||||||
if (!group)
|
if (group)
|
||||||
return FALSE;
|
return g_action_group_query_action (group->group, unprefixed_name, enabled,
|
||||||
|
parameter_type, state_type, state_hint, state);
|
||||||
|
|
||||||
return g_action_group_query_action (group->group, action_name, enabled,
|
if (muxer->parent)
|
||||||
parameter_type, state_type, state_hint, state);
|
return g_action_group_query_action (G_ACTION_GROUP (muxer->parent), action_name,
|
||||||
|
enabled, parameter_type,
|
||||||
|
state_type, state_hint, state);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -255,11 +367,14 @@ g_action_muxer_activate_action (GActionGroup *action_group,
|
|||||||
{
|
{
|
||||||
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
||||||
Group *group;
|
Group *group;
|
||||||
|
const gchar *unprefixed_name;
|
||||||
|
|
||||||
group = g_action_muxer_find_group (muxer, &action_name);
|
group = g_action_muxer_find_group (muxer, action_name, &unprefixed_name);
|
||||||
|
|
||||||
if (group)
|
if (group)
|
||||||
g_action_group_activate_action (group->group, action_name, parameter);
|
g_action_group_activate_action (group->group, unprefixed_name, parameter);
|
||||||
|
else if (muxer->parent)
|
||||||
|
g_action_group_activate_action (G_ACTION_GROUP (muxer->parent), action_name, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -269,11 +384,14 @@ g_action_muxer_change_action_state (GActionGroup *action_group,
|
|||||||
{
|
{
|
||||||
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
|
||||||
Group *group;
|
Group *group;
|
||||||
|
const gchar *unprefixed_name;
|
||||||
|
|
||||||
group = g_action_muxer_find_group (muxer, &action_name);
|
group = g_action_muxer_find_group (muxer, action_name, &unprefixed_name);
|
||||||
|
|
||||||
if (group)
|
if (group)
|
||||||
g_action_group_change_action_state (group->group, action_name, state);
|
g_action_group_change_action_state (group->group, unprefixed_name, state);
|
||||||
|
else if (muxer->parent)
|
||||||
|
g_action_group_change_action_state (G_ACTION_GROUP (muxer->parent), action_name, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -289,14 +407,7 @@ g_action_muxer_unregister_internal (Action *action,
|
|||||||
*ptr = g_slist_remove (*ptr, observer);
|
*ptr = g_slist_remove (*ptr, observer);
|
||||||
|
|
||||||
if (action->watchers == NULL)
|
if (action->watchers == NULL)
|
||||||
{
|
g_hash_table_remove (muxer->observed_actions, action->fullname);
|
||||||
g_hash_table_remove (muxer->actions, action->fullname);
|
|
||||||
g_free (action->fullname);
|
|
||||||
|
|
||||||
g_slice_free (Action, action);
|
|
||||||
|
|
||||||
g_object_unref (muxer);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -319,16 +430,16 @@ g_action_muxer_register_observer (GActionObservable *observable,
|
|||||||
GActionMuxer *muxer = G_ACTION_MUXER (observable);
|
GActionMuxer *muxer = G_ACTION_MUXER (observable);
|
||||||
Action *action;
|
Action *action;
|
||||||
|
|
||||||
action = g_hash_table_lookup (muxer->actions, name);
|
action = g_hash_table_lookup (muxer->observed_actions, name);
|
||||||
|
|
||||||
if (action == NULL)
|
if (action == NULL)
|
||||||
{
|
{
|
||||||
action = g_slice_new (Action);
|
action = g_slice_new (Action);
|
||||||
action->muxer = g_object_ref (muxer);
|
action->muxer = muxer;
|
||||||
action->fullname = g_strdup (name);
|
action->fullname = g_strdup (name);
|
||||||
action->watchers = NULL;
|
action->watchers = NULL;
|
||||||
|
|
||||||
g_hash_table_insert (muxer->actions, action->fullname, action);
|
g_hash_table_insert (muxer->observed_actions, action->fullname, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
action->watchers = g_slist_prepend (action->watchers, observer);
|
action->watchers = g_slist_prepend (action->watchers, observer);
|
||||||
@ -343,7 +454,7 @@ g_action_muxer_unregister_observer (GActionObservable *observable,
|
|||||||
GActionMuxer *muxer = G_ACTION_MUXER (observable);
|
GActionMuxer *muxer = G_ACTION_MUXER (observable);
|
||||||
Action *action;
|
Action *action;
|
||||||
|
|
||||||
action = g_hash_table_lookup (muxer->actions, name);
|
action = g_hash_table_lookup (muxer->observed_actions, name);
|
||||||
g_object_weak_unref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
|
g_object_weak_unref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
|
||||||
g_action_muxer_unregister_internal (action, observer);
|
g_action_muxer_unregister_internal (action, observer);
|
||||||
}
|
}
|
||||||
@ -364,23 +475,97 @@ g_action_muxer_free_group (gpointer data)
|
|||||||
g_slice_free (Group, group);
|
g_slice_free (Group, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_free_action (gpointer data)
|
||||||
|
{
|
||||||
|
Action *action = data;
|
||||||
|
GSList *it;
|
||||||
|
|
||||||
|
for (it = action->watchers; it; it = it->next)
|
||||||
|
g_object_weak_unref (G_OBJECT (it->data), g_action_muxer_weak_notify, action);
|
||||||
|
|
||||||
|
g_slist_free (action->watchers);
|
||||||
|
g_free (action->fullname);
|
||||||
|
|
||||||
|
g_slice_free (Action, action);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_action_muxer_finalize (GObject *object)
|
g_action_muxer_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
GActionMuxer *muxer = G_ACTION_MUXER (object);
|
GActionMuxer *muxer = G_ACTION_MUXER (object);
|
||||||
|
|
||||||
g_assert_cmpint (g_hash_table_size (muxer->actions), ==, 0);
|
g_assert_cmpint (g_hash_table_size (muxer->observed_actions), ==, 0);
|
||||||
g_hash_table_unref (muxer->actions);
|
g_hash_table_unref (muxer->observed_actions);
|
||||||
g_hash_table_unref (muxer->groups);
|
g_hash_table_unref (muxer->groups);
|
||||||
|
|
||||||
G_OBJECT_CLASS (g_action_muxer_parent_class)
|
G_OBJECT_CLASS (g_action_muxer_parent_class)
|
||||||
->finalize (object);
|
->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GActionMuxer *muxer = G_ACTION_MUXER (object);
|
||||||
|
|
||||||
|
if (muxer->parent)
|
||||||
|
{
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_added_to_parent, muxer);
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_removed_from_parent, muxer);
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_enabled_changed, muxer);
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_state_changed, muxer);
|
||||||
|
|
||||||
|
g_clear_object (&muxer->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_remove_all (muxer->observed_actions);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (g_action_muxer_parent_class)
|
||||||
|
->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_get_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GActionMuxer *muxer = G_ACTION_MUXER (object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_PARENT:
|
||||||
|
g_value_set_object (value, g_action_muxer_get_parent (muxer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_action_muxer_set_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GActionMuxer *muxer = G_ACTION_MUXER (object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_PARENT:
|
||||||
|
g_action_muxer_set_parent (muxer, g_value_get_object (value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_action_muxer_init (GActionMuxer *muxer)
|
g_action_muxer_init (GActionMuxer *muxer)
|
||||||
{
|
{
|
||||||
muxer->actions = g_hash_table_new (g_str_hash, g_str_equal);
|
muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_action);
|
||||||
muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_group);
|
muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +588,18 @@ g_action_muxer_group_iface_init (GActionGroupInterface *iface)
|
|||||||
static void
|
static void
|
||||||
g_action_muxer_class_init (GObjectClass *class)
|
g_action_muxer_class_init (GObjectClass *class)
|
||||||
{
|
{
|
||||||
|
class->get_property = g_action_muxer_get_property;
|
||||||
|
class->set_property = g_action_muxer_set_property;
|
||||||
class->finalize = g_action_muxer_finalize;
|
class->finalize = g_action_muxer_finalize;
|
||||||
|
class->dispose = g_action_muxer_dispose;
|
||||||
|
|
||||||
|
properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent",
|
||||||
|
"The parent muxer",
|
||||||
|
G_TYPE_ACTION_MUXER,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
g_object_class_install_properties (class, NUM_PROPERTIES, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -447,17 +643,17 @@ g_action_muxer_insert (GActionMuxer *muxer,
|
|||||||
|
|
||||||
actions = g_action_group_list_actions (group->group);
|
actions = g_action_group_list_actions (group->group);
|
||||||
for (i = 0; actions[i]; i++)
|
for (i = 0; actions[i]; i++)
|
||||||
g_action_muxer_action_added (group->group, actions[i], group);
|
g_action_muxer_action_added_to_group (group->group, actions[i], group);
|
||||||
g_strfreev (actions);
|
g_strfreev (actions);
|
||||||
|
|
||||||
group->handler_ids[0] = g_signal_connect (group->group, "action-added",
|
group->handler_ids[0] = g_signal_connect (group->group, "action-added",
|
||||||
G_CALLBACK (g_action_muxer_action_added), group);
|
G_CALLBACK (g_action_muxer_action_added_to_group), group);
|
||||||
group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
|
group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
|
||||||
G_CALLBACK (g_action_muxer_action_removed), group);
|
G_CALLBACK (g_action_muxer_action_removed_from_group), group);
|
||||||
group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
|
group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
|
||||||
G_CALLBACK (g_action_muxer_action_enabled_changed), group);
|
G_CALLBACK (g_action_muxer_group_action_enabled_changed), group);
|
||||||
group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
|
group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
|
||||||
G_CALLBACK (g_action_muxer_action_state_changed), group);
|
G_CALLBACK (g_action_muxer_group_action_state_changed), group);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -487,7 +683,7 @@ g_action_muxer_remove (GActionMuxer *muxer,
|
|||||||
|
|
||||||
actions = g_action_group_list_actions (group->group);
|
actions = g_action_group_list_actions (group->group);
|
||||||
for (i = 0; actions[i]; i++)
|
for (i = 0; actions[i]; i++)
|
||||||
g_action_muxer_action_removed (group->group, actions[i], group);
|
g_action_muxer_action_removed_from_group (group->group, actions[i], group);
|
||||||
g_strfreev (actions);
|
g_strfreev (actions);
|
||||||
|
|
||||||
g_action_muxer_free_group (group);
|
g_action_muxer_free_group (group);
|
||||||
@ -504,3 +700,77 @@ g_action_muxer_new (void)
|
|||||||
{
|
{
|
||||||
return g_object_new (G_TYPE_ACTION_MUXER, NULL);
|
return g_object_new (G_TYPE_ACTION_MUXER, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* g_action_muxer_get_parent:
|
||||||
|
* @muxer: a #GActionMuxer
|
||||||
|
*
|
||||||
|
* Returns: (transfer-none): the parent of @muxer, or NULL.
|
||||||
|
*/
|
||||||
|
GActionMuxer *
|
||||||
|
g_action_muxer_get_parent (GActionMuxer *muxer)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (G_IS_ACTION_MUXER (muxer), NULL);
|
||||||
|
|
||||||
|
return muxer->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* g_action_muxer_set_parent:
|
||||||
|
* @muxer: a #GActionMuxer
|
||||||
|
* @parent: (allow-none): the new parent #GActionMuxer
|
||||||
|
*
|
||||||
|
* Sets the parent of @muxer to @parent.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_action_muxer_set_parent (GActionMuxer *muxer,
|
||||||
|
GActionMuxer *parent)
|
||||||
|
{
|
||||||
|
g_return_if_fail (G_IS_ACTION_MUXER (muxer));
|
||||||
|
g_return_if_fail (parent == NULL || G_IS_ACTION_MUXER (parent));
|
||||||
|
|
||||||
|
if (muxer->parent == parent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (muxer->parent != NULL)
|
||||||
|
{
|
||||||
|
gchar **actions;
|
||||||
|
gchar **it;
|
||||||
|
|
||||||
|
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
|
||||||
|
for (it = actions; *it; it++)
|
||||||
|
g_action_muxer_action_removed (muxer, *it);
|
||||||
|
g_strfreev (actions);
|
||||||
|
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_added_to_parent, muxer);
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_action_removed_from_parent, muxer);
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_enabled_changed, muxer);
|
||||||
|
g_signal_handlers_disconnect_by_func (muxer->parent, g_action_muxer_parent_action_state_changed, muxer);
|
||||||
|
|
||||||
|
g_object_unref (muxer->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
muxer->parent = parent;
|
||||||
|
|
||||||
|
if (muxer->parent != NULL)
|
||||||
|
{
|
||||||
|
gchar **actions;
|
||||||
|
gchar **it;
|
||||||
|
|
||||||
|
g_object_ref (muxer->parent);
|
||||||
|
|
||||||
|
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
|
||||||
|
for (it = actions; *it; it++)
|
||||||
|
g_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it);
|
||||||
|
g_strfreev (actions);
|
||||||
|
|
||||||
|
g_signal_connect (muxer->parent, "action-added",
|
||||||
|
G_CALLBACK (g_action_muxer_action_added_to_parent), muxer);
|
||||||
|
g_signal_connect (muxer->parent, "action-removed",
|
||||||
|
G_CALLBACK (g_action_muxer_action_removed_from_parent), muxer);
|
||||||
|
g_signal_connect (muxer->parent, "action-enabled-changed",
|
||||||
|
G_CALLBACK (g_action_muxer_parent_action_enabled_changed), muxer);
|
||||||
|
g_signal_connect (muxer->parent, "action-state-changed",
|
||||||
|
G_CALLBACK (g_action_muxer_parent_action_state_changed), muxer);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]);
|
||||||
|
}
|
||||||
|
|||||||
@ -46,6 +46,13 @@ G_GNUC_INTERNAL
|
|||||||
void g_action_muxer_remove (GActionMuxer *muxer,
|
void g_action_muxer_remove (GActionMuxer *muxer,
|
||||||
const gchar *prefix);
|
const gchar *prefix);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
GActionMuxer * g_action_muxer_get_parent (GActionMuxer *muxer);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
void g_action_muxer_set_parent (GActionMuxer *muxer,
|
||||||
|
GActionMuxer *parent);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __G_ACTION_MUXER_H__ */
|
#endif /* __G_ACTION_MUXER_H__ */
|
||||||
|
|||||||
Reference in New Issue
Block a user