inspector: Make the actions tab work again

Bring back the actions tab; we don't receive
changes anymore, since GtkActionMuxer lost
the GActionGroup signals for this, and the
action observer machinery has no way to listen
for all changes.
This commit is contained in:
Matthias Clasen 2020-07-19 01:56:00 -04:00
parent 9b294eb94e
commit 14059afdf1
5 changed files with 134 additions and 169 deletions

View File

@ -27,12 +27,13 @@
#include "gtkbox.h" #include "gtkbox.h"
#include "gtkboxlayout.h" #include "gtkboxlayout.h"
#include "gtkorientable.h" #include "gtkorientable.h"
#include "gtkactionmuxerprivate.h"
struct _GtkInspectorActionEditor struct _GtkInspectorActionEditor
{ {
GtkWidget parent; GtkWidget parent;
GActionGroup *group; GObject *owner;
gchar *name; gchar *name;
gboolean enabled; gboolean enabled;
const GVariantType *parameter_type; const GVariantType *parameter_type;
@ -51,7 +52,7 @@ typedef struct
enum enum
{ {
PROP_0, PROP_0,
PROP_GROUP, PROP_OWNER,
PROP_NAME, PROP_NAME,
PROP_SIZEGROUP PROP_SIZEGROUP
}; };
@ -208,7 +209,10 @@ activate_action (GtkWidget *button,
if (r->parameter_entry) if (r->parameter_entry)
parameter = variant_editor_get_value (r->parameter_entry); parameter = variant_editor_get_value (r->parameter_entry);
g_action_group_activate_action (r->group, r->name, parameter); if (G_IS_ACTION_GROUP (r->owner))
g_action_group_activate_action (G_ACTION_GROUP (r->owner), r->name, parameter);
else if (GTK_IS_ACTION_MUXER (r->owner))
gtk_action_muxer_activate_action (GTK_ACTION_MUXER (r->owner), r->name, parameter);
} }
static void static void
@ -233,7 +237,12 @@ state_changed (GtkWidget *editor,
value = variant_editor_get_value (editor); value = variant_editor_get_value (editor);
if (value) if (value)
g_action_group_change_action_state (r->group, r->name, value); {
if (G_IS_ACTION_GROUP (r->owner))
g_action_group_change_action_state (G_ACTION_GROUP (r->owner), r->name, value);
else if (GTK_IS_ACTION_MUXER (r->owner))
gtk_action_muxer_change_action_state (GTK_ACTION_MUXER (r->owner), r->name, value);
}
} }
static void static void
@ -287,8 +296,16 @@ constructed (GObject *object)
GtkWidget *activate; GtkWidget *activate;
GtkWidget *label; GtkWidget *label;
r->enabled = g_action_group_get_action_enabled (r->group, r->name); if (G_IS_ACTION_GROUP (r->owner))
state = g_action_group_get_action_state (r->group, r->name); g_action_group_query_action (G_ACTION_GROUP (r->owner), r->name,
&r->enabled, &r->parameter_type, NULL, NULL,
&state);
else if (GTK_IS_ACTION_MUXER (r->owner))
gtk_action_muxer_query_action (GTK_ACTION_MUXER (r->owner), r->name,
&r->enabled, &r->parameter_type, NULL, NULL,
&state);
else
state = NULL;
row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
activate = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); activate = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
@ -302,7 +319,6 @@ constructed (GObject *object)
gtk_widget_set_sensitive (r->activate_button, r->enabled); gtk_widget_set_sensitive (r->activate_button, r->enabled);
gtk_box_append (GTK_BOX (activate), r->activate_button); gtk_box_append (GTK_BOX (activate), r->activate_button);
r->parameter_type = g_action_group_get_action_parameter_type (r->group, r->name);
if (r->parameter_type) if (r->parameter_type)
{ {
r->parameter_entry = variant_editor_new (r->parameter_type, parameter_changed, r); r->parameter_entry = variant_editor_new (r->parameter_type, parameter_changed, r);
@ -326,10 +342,13 @@ constructed (GObject *object)
gtk_widget_set_parent (row, GTK_WIDGET (r)); gtk_widget_set_parent (row, GTK_WIDGET (r));
} }
g_signal_connect (r->group, "action-enabled-changed", if (G_IS_ACTION_GROUP (r->owner))
G_CALLBACK (action_enabled_changed_cb), r); {
g_signal_connect (r->group, "action-state-changed", g_signal_connect (r->owner, "action-enabled-changed",
G_CALLBACK (action_state_changed_cb), r); G_CALLBACK (action_enabled_changed_cb), r);
g_signal_connect (r->owner, "action-state-changed",
G_CALLBACK (action_state_changed_cb), r);
}
} }
static void static void
@ -342,8 +361,8 @@ dispose (GObject *object)
g_clear_object (&r->sg); g_clear_object (&r->sg);
if (r->state_type) if (r->state_type)
g_variant_type_free (r->state_type); g_variant_type_free (r->state_type);
g_signal_handlers_disconnect_by_func (r->group, action_enabled_changed_cb, r); g_signal_handlers_disconnect_by_func (r->owner, action_enabled_changed_cb, r);
g_signal_handlers_disconnect_by_func (r->group, action_state_changed_cb, r); g_signal_handlers_disconnect_by_func (r->owner, action_state_changed_cb, r);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (r)))) while ((child = gtk_widget_get_first_child (GTK_WIDGET (r))))
gtk_widget_unparent (child); gtk_widget_unparent (child);
@ -361,8 +380,8 @@ get_property (GObject *object,
switch (param_id) switch (param_id)
{ {
case PROP_GROUP: case PROP_OWNER:
g_value_set_object (value, r->group); g_value_set_object (value, r->owner);
break; break;
case PROP_NAME: case PROP_NAME:
@ -389,8 +408,8 @@ set_property (GObject *object,
switch (param_id) switch (param_id)
{ {
case PROP_GROUP: case PROP_OWNER:
r->group = g_value_get_object (value); r->owner = g_value_get_object (value);
break; break;
case PROP_NAME: case PROP_NAME:
@ -419,9 +438,9 @@ gtk_inspector_action_editor_class_init (GtkInspectorActionEditorClass *klass)
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->set_property = set_property; object_class->set_property = set_property;
g_object_class_install_property (object_class, PROP_GROUP, g_object_class_install_property (object_class, PROP_OWNER,
g_param_spec_object ("group", "Action Group", "The Action Group containing the action", g_param_spec_object ("owner", "Owner", "The owner of the action",
G_TYPE_ACTION_GROUP, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); G_TYPE_OBJECT, G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_NAME, g_object_class_install_property (object_class, PROP_NAME,
g_param_spec_string ("name", "Name", "The action name", g_param_spec_string ("name", "Name", "The action name",
@ -434,12 +453,12 @@ gtk_inspector_action_editor_class_init (GtkInspectorActionEditorClass *klass)
} }
GtkWidget * GtkWidget *
gtk_inspector_action_editor_new (GActionGroup *group, gtk_inspector_action_editor_new (GObject *owner,
const gchar *name, const gchar *name,
GtkSizeGroup *activate) GtkSizeGroup *activate)
{ {
return g_object_new (GTK_TYPE_INSPECTOR_ACTION_EDITOR, return g_object_new (GTK_TYPE_INSPECTOR_ACTION_EDITOR,
"group", group, "owner", owner,
"name", name, "name", name,
"sizegroup", activate, "sizegroup", activate,
NULL); NULL);

View File

@ -33,7 +33,7 @@ typedef struct _GtkInspectorActionEditor GtkInspectorActionEditor;
G_BEGIN_DECLS G_BEGIN_DECLS
GType gtk_inspector_action_editor_get_type (void); GType gtk_inspector_action_editor_get_type (void);
GtkWidget *gtk_inspector_action_editor_new (GActionGroup *group, GtkWidget *gtk_inspector_action_editor_new (GObject *owner,
const gchar *name, const gchar *name,
GtkSizeGroup *activate); GtkSizeGroup *activate);
void gtk_inspector_action_editor_update (GtkInspectorActionEditor *r, void gtk_inspector_action_editor_update (GtkInspectorActionEditor *r,

View File

@ -4,7 +4,7 @@
struct _ActionHolder { struct _ActionHolder {
GObject instance; GObject instance;
GActionGroup *group; GObject *owner;
char *name; char *name;
}; };
@ -20,7 +20,7 @@ action_holder_finalize (GObject *object)
{ {
ActionHolder *holder = ACTION_HOLDER (object); ActionHolder *holder = ACTION_HOLDER (object);
g_object_unref (holder->group); g_object_unref (holder->owner);
g_free (holder->name); g_free (holder->name);
G_OBJECT_CLASS (action_holder_parent_class)->finalize (object); G_OBJECT_CLASS (action_holder_parent_class)->finalize (object);
@ -35,23 +35,23 @@ action_holder_class_init (ActionHolderClass *class)
} }
ActionHolder * ActionHolder *
action_holder_new (GActionGroup *group, action_holder_new (GObject *owner,
const char *name) const char *name)
{ {
ActionHolder *holder; ActionHolder *holder;
holder = g_object_new (ACTION_TYPE_HOLDER, NULL); holder = g_object_new (ACTION_TYPE_HOLDER, NULL);
holder->group = g_object_ref (group); holder->owner = g_object_ref (owner);
holder->name = g_strdup (name); holder->name = g_strdup (name);
return holder; return holder;
} }
GActionGroup * GObject *
action_holder_get_group (ActionHolder *holder) action_holder_get_owner (ActionHolder *holder)
{ {
return holder->group; return holder->owner;
} }
const char * const char *

View File

@ -8,10 +8,10 @@
G_DECLARE_FINAL_TYPE (ActionHolder, action_holder, ACTION, HOLDER, GObject) G_DECLARE_FINAL_TYPE (ActionHolder, action_holder, ACTION, HOLDER, GObject)
ActionHolder * action_holder_new (GActionGroup *group, ActionHolder * action_holder_new (GObject *owner,
const char *name); const char *name);
GActionGroup *action_holder_get_group (ActionHolder *holder); GObject *action_holder_get_owner (ActionHolder *holder);
const char *action_holder_get_name (ActionHolder *holder); const char *action_holder_get_name (ActionHolder *holder);
#endif /* __ACTION_HOLDER_H__ */ #endif /* __ACTION_HOLDER_H__ */

View File

@ -44,7 +44,8 @@ struct _GtkInspectorActions
GtkWidget *list; GtkWidget *list;
GtkWidget *button; GtkWidget *button;
GActionGroup *group; GObject *object;
GListModel *actions; GListModel *actions;
GtkColumnViewColumn *name; GtkColumnViewColumn *name;
}; };
@ -73,16 +74,15 @@ gtk_inspector_actions_init (GtkInspectorActions *sl)
} }
static void static void
action_added_cb (GActionGroup *group, action_added (GObject *owner,
const gchar *action_name, const gchar *action_name,
GtkInspectorActions *sl) GtkInspectorActions *sl)
{ {
ActionHolder *holder = action_holder_new (group, action_name); ActionHolder *holder = action_holder_new (owner, action_name);
g_list_store_append (G_LIST_STORE (sl->actions), holder); g_list_store_append (G_LIST_STORE (sl->actions), holder);
g_object_unref (holder); g_object_unref (holder);
} }
static void static void
setup_name_cb (GtkSignalListItemFactory *factory, setup_name_cb (GtkSignalListItemFactory *factory,
GtkListItem *list_item) GtkListItem *list_item)
@ -124,16 +124,20 @@ bind_enabled_cb (GtkSignalListItemFactory *factory,
{ {
gpointer item; gpointer item;
GtkWidget *label; GtkWidget *label;
GActionGroup *group; GObject *owner;
const char *name; const char *name;
gboolean enabled; gboolean enabled = FALSE;
item = gtk_list_item_get_item (list_item); item = gtk_list_item_get_item (list_item);
label = gtk_list_item_get_child (list_item); label = gtk_list_item_get_child (list_item);
group = action_holder_get_group (ACTION_HOLDER (item)); owner = action_holder_get_owner (ACTION_HOLDER (item));
name = action_holder_get_name (ACTION_HOLDER (item)); name = action_holder_get_name (ACTION_HOLDER (item));
enabled = g_action_group_get_action_enabled (group, name); if (G_IS_ACTION_GROUP (owner))
enabled = g_action_group_get_action_enabled (G_ACTION_GROUP (owner), name);
else if (GTK_IS_ACTION_MUXER (owner))
gtk_action_muxer_query_action (GTK_ACTION_MUXER (owner), name,
&enabled, NULL, NULL, NULL, NULL);
gtk_label_set_label (GTK_LABEL (label), enabled ? "+" : "-"); gtk_label_set_label (GTK_LABEL (label), enabled ? "+" : "-");
} }
@ -156,16 +160,20 @@ bind_parameter_cb (GtkSignalListItemFactory *factory,
{ {
gpointer item; gpointer item;
GtkWidget *label; GtkWidget *label;
GActionGroup *group; GObject *owner;
const char *name; const char *name;
const char *parameter; const char *parameter;
item = gtk_list_item_get_item (list_item); item = gtk_list_item_get_item (list_item);
label = gtk_list_item_get_child (list_item); label = gtk_list_item_get_child (list_item);
group = action_holder_get_group (ACTION_HOLDER (item)); owner = action_holder_get_owner (ACTION_HOLDER (item));
name = action_holder_get_name (ACTION_HOLDER (item)); name = action_holder_get_name (ACTION_HOLDER (item));
parameter = (const gchar *)g_action_group_get_action_parameter_type (group, name); if (G_IS_ACTION_GROUP (owner))
parameter = (const gchar *)g_action_group_get_action_parameter_type (G_ACTION_GROUP (owner), name);
else if (GTK_IS_ACTION_MUXER (owner))
gtk_action_muxer_query_action (GTK_ACTION_MUXER (owner), name,
NULL, (const GVariantType **)&parameter, NULL, NULL, NULL);
gtk_label_set_label (GTK_LABEL (label), parameter); gtk_label_set_label (GTK_LABEL (label), parameter);
} }
@ -190,7 +198,7 @@ bind_state_cb (GtkSignalListItemFactory *factory,
{ {
gpointer item; gpointer item;
GtkWidget *label; GtkWidget *label;
GActionGroup *group; GObject *owner;
const char *name; const char *name;
GVariant *state; GVariant *state;
char *state_string; char *state_string;
@ -198,9 +206,16 @@ bind_state_cb (GtkSignalListItemFactory *factory,
item = gtk_list_item_get_item (list_item); item = gtk_list_item_get_item (list_item);
label = gtk_list_item_get_child (list_item); label = gtk_list_item_get_child (list_item);
group = action_holder_get_group (ACTION_HOLDER (item)); owner = action_holder_get_owner (ACTION_HOLDER (item));
name = action_holder_get_name (ACTION_HOLDER (item)); name = action_holder_get_name (ACTION_HOLDER (item));
state = g_action_group_get_action_state (group, name); if (G_IS_ACTION_GROUP (owner))
state = g_action_group_get_action_state (G_ACTION_GROUP (owner), name);
else if (GTK_IS_ACTION_MUXER (owner))
gtk_action_muxer_query_action (GTK_ACTION_MUXER (owner), name,
NULL, NULL, NULL, NULL, &state);
else
state = NULL;
if (state) if (state)
state_string = g_variant_print (state, FALSE); state_string = g_variant_print (state, FALSE);
else else
@ -218,16 +233,16 @@ bind_changes_cb (GtkSignalListItemFactory *factory,
GtkListItem *list_item) GtkListItem *list_item)
{ {
gpointer item; gpointer item;
GActionGroup *group; GObject *owner;
const char *name; const char *name;
GtkWidget *editor; GtkWidget *editor;
item = gtk_list_item_get_item (list_item); item = gtk_list_item_get_item (list_item);
group = action_holder_get_group (ACTION_HOLDER (item)); owner = action_holder_get_owner (ACTION_HOLDER (item));
name = action_holder_get_name (ACTION_HOLDER (item)); name = action_holder_get_name (ACTION_HOLDER (item));
editor = gtk_inspector_action_editor_new (group, name, NULL); editor = gtk_inspector_action_editor_new (owner, name, NULL);
gtk_widget_add_css_class (editor, "cell"); gtk_widget_add_css_class (editor, "cell");
gtk_list_item_set_child (list_item, editor); gtk_list_item_set_child (list_item, editor);
} }
@ -239,117 +254,61 @@ unbind_changes_cb (GtkSignalListItemFactory *factory,
gtk_list_item_set_child (list_item, NULL); gtk_list_item_set_child (list_item, NULL);
} }
static void
action_removed_cb (GActionGroup *group,
const gchar *action_name,
GtkInspectorActions *sl)
{
int i;
for (i = 0; i < g_list_model_get_n_items (sl->actions); i++)
{
ActionHolder *holder = g_list_model_get_item (sl->actions, i);
if (group == action_holder_get_group (holder) &&
strcmp (action_name, action_holder_get_name (holder)) == 0)
g_list_store_remove (G_LIST_STORE (sl->actions), i);
g_object_unref (holder);
}
}
static void
notify_action_changed (GtkInspectorActions *sl,
GActionGroup *group,
const char *action_name)
{
int i;
for (i = 0; i < g_list_model_get_n_items (sl->actions); i++)
{
ActionHolder *holder = g_list_model_get_item (sl->actions, i);
if (group == action_holder_get_group (holder) &&
strcmp (action_name, action_holder_get_name (holder)) == 0)
g_list_model_items_changed (sl->actions, i, 1, 1);
g_object_unref (holder);
}
}
static void
action_enabled_changed_cb (GActionGroup *group,
const gchar *action_name,
gboolean enabled,
GtkInspectorActions *sl)
{
notify_action_changed (sl, group, action_name);
}
static void
action_state_changed_cb (GActionGroup *group,
const gchar *action_name,
GVariant *state,
GtkInspectorActions *sl)
{
notify_action_changed (sl, group, action_name);
}
static void
refresh_all (GtkInspectorActions *sl)
{
guint n = g_list_model_get_n_items (sl->actions);
g_list_model_items_changed (sl->actions, 0, n, n);
}
static void
connect_group (GActionGroup *group,
GtkInspectorActions *sl)
{
g_signal_connect (group, "action-added", G_CALLBACK (action_added_cb), sl);
g_signal_connect (group, "action-removed", G_CALLBACK (action_removed_cb), sl);
g_signal_connect (group, "action-enabled-changed", G_CALLBACK (action_enabled_changed_cb), sl);
g_signal_connect (group, "action-state-changed", G_CALLBACK (action_state_changed_cb), sl);
}
static void
disconnect_group (GActionGroup *group,
GtkInspectorActions *sl)
{
g_signal_handlers_disconnect_by_func (group, action_added_cb, sl);
g_signal_handlers_disconnect_by_func (group, action_removed_cb, sl);
g_signal_handlers_disconnect_by_func (group, action_enabled_changed_cb, sl);
g_signal_handlers_disconnect_by_func (group, action_state_changed_cb, sl);
}
static void static void
add_group (GtkInspectorActions *sl, add_group (GtkInspectorActions *sl,
GtkStackPage *page,
GActionGroup *group) GActionGroup *group)
{ {
gint i; gint i;
gchar **names; gchar **names;
g_object_set (page, "visible", TRUE, NULL);
connect_group (group, sl);
names = g_action_group_list_actions (group); names = g_action_group_list_actions (group);
for (i = 0; names[i]; i++) for (i = 0; names[i]; i++)
action_added_cb (group, names[i], sl); action_added (G_OBJECT (group), names[i], sl);
g_strfreev (names); g_strfreev (names);
g_set_object (&sl->group, group);
} }
static void static void
remove_group (GtkInspectorActions *sl, add_muxer (GtkInspectorActions *sl,
GtkStackPage *page, GtkActionMuxer *muxer)
GActionGroup *group)
{ {
disconnect_group (group, sl); gint i;
gchar **names;
g_set_object (&sl->group, NULL); names = gtk_action_muxer_list_actions (muxer);
for (i = 0; names[i]; i++)
action_added (G_OBJECT (muxer), names[i], sl);
g_strfreev (names);
}
static gboolean
reload (GtkInspectorActions *sl)
{
g_list_store_remove_all (G_LIST_STORE (sl->actions));
if (GTK_IS_APPLICATION (sl->object))
{
add_group (sl, G_ACTION_GROUP (sl->object));
return TRUE;
}
else if (GTK_IS_WIDGET (sl->object))
{
GtkActionMuxer *muxer;
muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (sl->object), FALSE);
if (muxer)
{
add_muxer (sl, muxer);
return TRUE;
}
}
return FALSE;
}
static void
refresh_all (GtkInspectorActions *sl)
{
reload (sl);
} }
void void
@ -358,29 +317,15 @@ gtk_inspector_actions_set_object (GtkInspectorActions *sl,
{ {
GtkWidget *stack; GtkWidget *stack;
GtkStackPage *page; GtkStackPage *page;
gboolean loaded;
stack = gtk_widget_get_parent (GTK_WIDGET (sl)); stack = gtk_widget_get_parent (GTK_WIDGET (sl));
page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl)); page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl));
gtk_stack_page_set_visible (page, FALSE);
g_object_set (page, "visible", FALSE, NULL); g_set_object (&sl->object, object);
loaded = reload (sl);
if (sl->group) gtk_stack_page_set_visible (page, loaded);
remove_group (sl, page, sl->group);
g_list_store_remove_all (G_LIST_STORE (sl->actions));
if (GTK_IS_APPLICATION (object))
add_group (sl, page, G_ACTION_GROUP (object));
else if (GTK_IS_WIDGET (object))
{
#if 0
GtkActionMuxer *muxer;
muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (object), FALSE);
if (muxer)
add_group (sl, page, G_ACTION_GROUP (muxer));
#endif
}
gtk_column_view_sort_by_column (GTK_COLUMN_VIEW (sl->list), sl->name, GTK_SORT_ASCENDING); gtk_column_view_sort_by_column (GTK_COLUMN_VIEW (sl->list), sl->name, GTK_SORT_ASCENDING);
} }
@ -449,7 +394,7 @@ constructed (GObject *object)
NULL, NULL)); NULL, NULL));
gtk_column_view_column_set_sorter (sl->name, sorter); gtk_column_view_column_set_sorter (sl->name, sorter);
g_object_unref (sorter); g_object_unref (sorter);
sl->actions = G_LIST_MODEL (g_list_store_new (ACTION_TYPE_HOLDER)); sl->actions = G_LIST_MODEL (g_list_store_new (ACTION_TYPE_HOLDER));
sorted = G_LIST_MODEL (gtk_sort_list_model_new (sl->actions, sorted = G_LIST_MODEL (gtk_sort_list_model_new (sl->actions,
gtk_column_view_get_sorter (GTK_COLUMN_VIEW (sl->list)))); gtk_column_view_get_sorter (GTK_COLUMN_VIEW (sl->list))));
@ -466,6 +411,7 @@ dispose (GObject *object)
GtkWidget *child; GtkWidget *child;
g_clear_object (&sl->actions); g_clear_object (&sl->actions);
g_clear_object (&sl->object);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (sl)))) while ((child = gtk_widget_get_first_child (GTK_WIDGET (sl))))
gtk_widget_unparent (child); gtk_widget_unparent (child);