diff --git a/src/exm-extension-row.blp b/src/exm-extension-row.blp index 2fe2df83..5be6c888 100644 --- a/src/exm-extension-row.blp +++ b/src/exm-extension-row.blp @@ -8,9 +8,9 @@ template $ExmExtensionRow : Adw.ExpanderRow { [action] Gtk.Switch ext_toggle { valign: center; - halign: center; - - action-name: 'row.state-set'; + active: bind template.extension as <$ExmExtension>.enabled; + sensitive: bind template.extension as <$ExmExtension>.can-change; + state-set => $on_state_changed(); } [action] diff --git a/src/exm-extension-row.c b/src/exm-extension-row.c index b3141696..63c0fa24 100644 --- a/src/exm-extension-row.c +++ b/src/exm-extension-row.c @@ -12,6 +12,8 @@ struct _ExmExtensionRow ExmExtension *extension; gchar *uuid; + ExmManager *manager; + GtkButton *remove_btn; GtkButton *prefs_btn; GtkButton *details_btn; @@ -25,8 +27,6 @@ struct _ExmExtensionRow GtkImage *update_icon; GtkImage *error_icon; GtkImage *out_of_date_icon; - - guint signal_handler; }; G_DEFINE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, ADW_TYPE_EXPANDER_ROW) @@ -34,6 +34,7 @@ G_DEFINE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, ADW_TYPE_EXPANDER_ROW) enum { PROP_0, PROP_EXTENSION, + PROP_MANAGER, N_PROPS }; @@ -47,10 +48,12 @@ static void unbind_extension (ExmExtensionRow *self); ExmExtensionRow * -exm_extension_row_new (ExmExtension *extension) +exm_extension_row_new (ExmExtension *extension, + ExmManager *manager) { return g_object_new (EXM_TYPE_EXTENSION_ROW, "extension", extension, + "manager", manager, NULL); } @@ -85,6 +88,9 @@ exm_extension_row_get_property (GObject *object, case PROP_EXTENSION: g_value_set_object (value, self->extension); break; + case PROP_MANAGER: + g_value_set_object (value, self->manager); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -103,77 +109,12 @@ exm_extension_row_set_property (GObject *object, case PROP_EXTENSION: bind_extension (self, g_value_get_object (value)); break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -void -update_state (ExmExtension *extension, - GParamSpec *pspec, - ExmExtensionRow *row) -{ - // We update the state of the action without activating it. If we activate - // it, then it will go back to gnome-shell and explicitly enable/disable - // the extension. We do not want this behaviour as it messes with the global - // extension toggle. - - g_return_if_fail (EXM_IS_EXTENSION (extension)); - g_return_if_fail (EXM_IS_EXTENSION_ROW (row)); - - g_assert (row->extension == extension); - - const gchar *uuid; - ExmExtensionState new_state; - GAction *action; - - g_object_get (extension, - "state", &new_state, - "uuid", &uuid, - NULL); - - g_info ("%s: %s\n", uuid, g_enum_to_string (EXM_TYPE_EXTENSION_STATE, new_state)); - - action = g_action_map_lookup_action (G_ACTION_MAP (row->action_group), "state-set"); - - // Reset state - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE); - gtk_widget_set_visible (GTK_WIDGET (row->error_icon), FALSE); - gtk_widget_set_visible (GTK_WIDGET (row->out_of_date_icon), FALSE); - - switch (new_state) - { - case EXM_EXTENSION_STATE_ACTIVE: - g_simple_action_set_state (G_SIMPLE_ACTION (action), - g_variant_new_boolean (TRUE)); - break; - - case EXM_EXTENSION_STATE_INACTIVE: - g_simple_action_set_state (G_SIMPLE_ACTION (action), - g_variant_new_boolean (FALSE)); + case PROP_MANAGER: + self->manager = g_value_get_object (value); break; - - case EXM_EXTENSION_STATE_ERROR: - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE); - gtk_widget_set_visible (GTK_WIDGET (row->error_icon), TRUE); - g_simple_action_set_state (G_SIMPLE_ACTION (action), - g_variant_new_boolean (FALSE)); - break; - - case EXM_EXTENSION_STATE_OUT_OF_DATE: - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE); - gtk_widget_set_visible (GTK_WIDGET (row->out_of_date_icon), TRUE); - g_simple_action_set_state (G_SIMPLE_ACTION (action), - g_variant_new_boolean (FALSE)); - break; - default: - break; + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } - gboolean is_enabled = (new_state == EXM_EXTENSION_STATE_ACTIVE); - - // Update state of toggle - g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (is_enabled)); } static void @@ -184,12 +125,22 @@ set_error_label_visible (ExmExtensionRow *self, gtk_widget_set_visible (GTK_WIDGET (self->error_label_tag), visible); } +static gboolean +transform_to_state (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + g_value_set_boolean (to_value, g_value_get_enum (from_value) == EXM_EXTENSION_STATE_ACTIVE); + + return TRUE; +} + static void unbind_extension (ExmExtensionRow *self) { if (self->extension != NULL) { - g_signal_handler_disconnect (self->extension, self->signal_handler); g_clear_object (&self->extension); g_clear_pointer (&self->uuid, g_free); } @@ -216,13 +167,14 @@ bind_extension (ExmExtensionRow *self, return; gchar *name, *uuid, *description, *version, *error_msg; - gboolean has_prefs, has_update, is_user; + gboolean enabled, has_prefs, has_update, is_user; ExmExtensionState state; g_object_get (self->extension, "display-name", &name, "uuid", &uuid, "description", &description, "state", &state, + "enabled", &enabled, "has-prefs", &has_prefs, "has-update", &has_update, "is-user", &is_user, @@ -248,26 +200,62 @@ bind_extension (ExmExtensionRow *self, gboolean has_error = (error_msg != NULL) && (strlen(error_msg) != 0); set_error_label_visible (self, has_error); - gtk_actionable_set_action_target (GTK_ACTIONABLE (self->details_btn), "s", uuid); + gtk_widget_set_visible (GTK_WIDGET (self->error_icon), state == EXM_EXTENSION_STATE_ERROR); + gtk_widget_set_visible (GTK_WIDGET (self->out_of_date_icon), state == EXM_EXTENSION_STATE_OUT_OF_DATE); - // One way binding from extension ("source of truth") to switch - self->signal_handler = g_signal_connect (self->extension, - "notify::state", - G_CALLBACK (update_state), - self); + gtk_actionable_set_action_target (GTK_ACTIONABLE (self->details_btn), "s", uuid); GAction *action; - action = g_action_map_lookup_action (G_ACTION_MAP (self->action_group), "state-set"); - g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (TRUE)); - action = g_action_map_lookup_action (G_ACTION_MAP (self->action_group), "open-prefs"); g_simple_action_set_enabled (G_SIMPLE_ACTION (action), has_prefs); action = g_action_map_lookup_action (G_ACTION_MAP (self->action_group), "remove"); g_simple_action_set_enabled (G_SIMPLE_ACTION (action), is_user); - update_state (self->extension, NULL, self); + g_object_bind_property_full (self->extension, + "state", + self->ext_toggle, + "state", + G_BINDING_SYNC_CREATE, + transform_to_state, + NULL, + NULL, + NULL); + + // Keep compatibility with GNOME Shell versions prior to 46 + if (gtk_switch_get_state (self->ext_toggle) != enabled && + (state == EXM_EXTENSION_STATE_ACTIVE || state == EXM_EXTENSION_STATE_ACTIVATING)) + g_object_set (self->extension, "enabled", !enabled, NULL); +} + +static gboolean +on_state_changed (GtkSwitch *toggle, + gboolean state, + ExmExtensionRow *self) +{ + g_return_if_fail (EXM_IS_EXTENSION_ROW (self)); + + g_assert (self->ext_toggle == toggle); + + gboolean enabled; + + g_object_get (self->extension, "enabled", &enabled, NULL); + + // Prevents changing extensions' state when global switch is toggled + if (state == enabled) + return TRUE; + + // Keep compatibility with GNOME Shell versions prior to 46 + if (gtk_switch_get_state (toggle) != enabled) + g_object_set (self->extension, "enabled", !enabled, NULL); + + if (state) + exm_manager_enable_extension (self->manager, self->extension); + else + exm_manager_disable_extension (self->manager, self->extension); + + return TRUE; } static void @@ -287,6 +275,13 @@ exm_extension_row_class_init (ExmExtensionRowClass *klass) EXM_TYPE_EXTENSION, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); + properties [PROP_MANAGER] + = g_param_spec_object ("manager", + "Manager", + "Manager", + EXM_TYPE_MANAGER, + G_PARAM_READWRITE); + g_object_class_install_properties (object_class, N_PROPS, properties); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); @@ -305,26 +300,8 @@ exm_extension_row_class_init (ExmExtensionRowClass *klass) gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, update_icon); gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, error_icon); gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, out_of_date_icon); -} -static void -state_changed (GSimpleAction *action, - GVariant *new_value, - ExmExtensionRow *self) -{ - GVariant *variant; - gboolean enabled; - - g_return_if_fail (self->extension); - - variant = g_action_get_state (G_ACTION (action)); - enabled = g_variant_get_boolean (variant); - - gtk_widget_activate_action (GTK_WIDGET (self), - "ext.state-set", - "(sb)", self->uuid, !enabled); - - g_simple_action_set_state (action, new_value); + gtk_widget_class_bind_template_callback (widget_class, on_state_changed); } static void @@ -354,26 +331,20 @@ uninstall (GSimpleAction *action, static void exm_extension_row_init (ExmExtensionRow *self) { - GSimpleAction *state_action; GSimpleAction *open_prefs_action; GSimpleAction *remove_action; - GtkWidget *action_row; gtk_widget_init_template (GTK_WIDGET (self)); // Define Actions self->action_group = g_simple_action_group_new (); - state_action = g_simple_action_new_stateful ("state-set", NULL, g_variant_new_boolean (TRUE)); - g_signal_connect (state_action, "change-state", G_CALLBACK (state_changed), self); - open_prefs_action = g_simple_action_new ("open-prefs", NULL); g_signal_connect (open_prefs_action, "activate", G_CALLBACK (open_prefs), self); remove_action = g_simple_action_new ("remove", NULL); g_signal_connect (remove_action, "activate", G_CALLBACK (uninstall), self); - g_action_map_add_action (G_ACTION_MAP (self->action_group), G_ACTION (state_action)); g_action_map_add_action (G_ACTION_MAP (self->action_group), G_ACTION (open_prefs_action)); g_action_map_add_action (G_ACTION_MAP (self->action_group), G_ACTION (remove_action)); diff --git a/src/exm-extension-row.h b/src/exm-extension-row.h index 1020a25f..838cd9fd 100644 --- a/src/exm-extension-row.h +++ b/src/exm-extension-row.h @@ -3,6 +3,7 @@ #include #include "local/exm-extension.h" +#include "local/exm-manager.h" G_BEGIN_DECLS @@ -11,6 +12,7 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, EXM, EXTENSION_ROW, AdwExpanderRow) ExmExtensionRow * -exm_extension_row_new (ExmExtension *extension); +exm_extension_row_new (ExmExtension *extension, + ExmManager *manager); G_END_DECLS diff --git a/src/exm-installed-page.c b/src/exm-installed-page.c index 7fe56dad..b90c355b 100644 --- a/src/exm-installed-page.c +++ b/src/exm-installed-page.c @@ -102,13 +102,15 @@ exm_installed_page_set_property (GObject *object, } static GtkWidget * -widget_factory (ExmExtension* extension) +widget_factory (ExmExtension *extension, + ExmInstalledPage *self) { ExmExtensionRow *row; g_return_if_fail (EXM_IS_EXTENSION (extension)); + g_return_if_fail (EXM_IS_INSTALLED_PAGE (self)); - row = exm_extension_row_new (extension); + row = exm_extension_row_new (extension, self->manager); return GTK_WIDGET (row); } @@ -136,9 +138,10 @@ compare_enabled (ExmExtension *this, ExmExtension *other) } static void -bind_list_box (GtkListBox *list_box, - GListModel *model, - gboolean sort_enabled_first) +bind_list_box (GtkListBox *list_box, + GListModel *model, + gboolean sort_enabled_first, + ExmInstalledPage *self) { GtkExpression *expression; GtkStringSorter *alphabetical_sorter; @@ -172,7 +175,7 @@ bind_list_box (GtkListBox *list_box, gtk_list_box_bind_model (list_box, G_LIST_MODEL (sorted_model), (GtkListBoxCreateWidgetFunc) widget_factory, - NULL, NULL); + self, NULL); } static guint @@ -219,12 +222,14 @@ invalidate_model_bindings (ExmInstalledPage *self) if (user_ext_model) bind_list_box (self->user_list_box, user_ext_model, - self->sort_enabled_first); + self->sort_enabled_first, + self); if (system_ext_model) bind_list_box (self->system_list_box, system_ext_model, - self->sort_enabled_first); + self->sort_enabled_first, + self); } static void diff --git a/src/exm-window.c b/src/exm-window.c index d9f8a626..abc03cf7 100644 --- a/src/exm-window.c +++ b/src/exm-window.c @@ -117,27 +117,6 @@ extension_open_prefs (GtkWidget *widget, exm_manager_open_prefs (self->manager, extension); } -static void -extension_state_set (GtkWidget *widget, - const char *action_name, - GVariant *param) -{ - ExmWindow *self; - ExmExtension *extension; - gchar *uuid; - gboolean state; - - self = EXM_WINDOW (widget); - g_variant_get (param, "(sb)", &uuid, &state); - - extension = exm_manager_get_by_uuid (self->manager, uuid); - - if (state) - exm_manager_enable_extension (self->manager, extension); - else - exm_manager_disable_extension (self->manager, extension); -} - typedef struct { ExmManager *manager; @@ -421,7 +400,6 @@ exm_window_class_init (ExmWindowClass *klass) // then be passed to each page. gtk_widget_class_install_action (widget_class, "ext.install", "(sb)", extension_install); gtk_widget_class_install_action (widget_class, "ext.remove", "s", extension_remove); - gtk_widget_class_install_action (widget_class, "ext.state-set", "(sb)", extension_state_set); gtk_widget_class_install_action (widget_class, "ext.open-prefs", "s", extension_open_prefs); gtk_widget_class_install_action (widget_class, "win.show-detail", "s", show_view); gtk_widget_class_install_action (widget_class, "win.show-main", NULL, show_view);