Skip to content

Commit

Permalink
installed-page: Save extension's toggle focus on state changes
Browse files Browse the repository at this point in the history
The items-changed signal is now emitted without adding or removing items
to the model from ExmManager and is connected after binding the manager
in ExmInstalledPage from where the callback saves, emits items-changed
adding and removing as done before in ExmManager, and restores focus.

This approach allows us to keep binding GtkListBox to the extensions
model and not having to manage the changes manually.

Fix #220
  • Loading branch information
oscfdezdz committed Feb 2, 2025
1 parent 8885ff7 commit bb29b6e
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 22 deletions.
6 changes: 6 additions & 0 deletions src/exm-extension-row.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ on_state_changed (GtkSwitch *toggle,
return TRUE;
}

void
exm_search_row_focus_toggle (ExmExtensionRow *self)
{
gtk_widget_grab_focus (GTK_WIDGET (self->ext_toggle));
}

static void
exm_extension_row_class_init (ExmExtensionRowClass *klass)
{
Expand Down
7 changes: 4 additions & 3 deletions src/exm-extension-row.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ G_BEGIN_DECLS

G_DECLARE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, EXM, EXTENSION_ROW, AdwExpanderRow)

ExmExtensionRow *
exm_extension_row_new (ExmExtension *extension,
ExmManager *manager);
ExmExtensionRow *exm_extension_row_new (ExmExtension *extension,
ExmManager *manager);

void exm_search_row_focus_toggle (ExmExtensionRow *self);

G_END_DECLS
2 changes: 1 addition & 1 deletion src/exm-installed-page.blp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ template $ExmInstalledPage: Gtk.Widget {
action-name: "app.logout";
}

Adw.PreferencesPage {
Adw.PreferencesPage prefs_page {
Adw.PreferencesGroup {
Adw.SwitchRow global_toggle {
[prefix]
Expand Down
92 changes: 92 additions & 0 deletions src/exm-installed-page.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct _ExmInstalledPage
// Template Widgets
GtkStack *stack;
AdwBanner *updates_banner;
AdwPreferencesPage *prefs_page;
AdwSwitchRow *global_toggle;
GtkListBox *user_list_box;
GtkListBox *system_list_box;
Expand Down Expand Up @@ -312,6 +313,89 @@ on_updates_available (ExmManager *manager G_GNUC_UNUSED,
g_timeout_add (500, G_SOURCE_FUNC (show_updates_banner), self);
}

static gboolean
focus_matching_extension (GtkListBox *list_box,
ExmExtension *extension)
{
int index = 0;
ExmExtensionRow *row;

while ((row = EXM_EXTENSION_ROW (gtk_list_box_get_row_at_index (list_box, index))))
{
ExmExtension *row_extension;

g_object_get(row, "extension", &row_extension, NULL);

if (is_extension_equal (extension, row_extension))
{
exm_search_row_focus_toggle (row);
g_object_unref (row_extension);

return TRUE;
}

index++;
}

return FALSE;
}

static void
on_extensions_changed (GListModel *model,
guint position,
guint removed,
guint added,
ExmInstalledPage *self)
{
if (!self->sort_enabled_first || (removed > 0 && added > 0))
return;

GtkRoot *toplevel;
GtkWidget *widget;
ExmExtension *extension;

toplevel = gtk_widget_get_root (GTK_WIDGET (self));
widget = gtk_window_get_focus (GTK_WINDOW (toplevel));

extension = EXM_EXTENSION (g_list_model_get_object (model, position));

if (!extension)
return;

GtkAdjustment *adjustment = NULL;
double scroll_pos = 0.0;
gboolean has_focus = widget && gtk_widget_has_focus (widget);

if (has_focus)
{
GtkWidget *child;

// Save scrolled window position
child = gtk_widget_get_first_child (GTK_WIDGET (self->prefs_page));
if (child && GTK_IS_SCROLLED_WINDOW (child))
{
adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (child));
if (adjustment)
scroll_pos = gtk_adjustment_get_value (adjustment);
}
}

if (g_list_store_find_with_equal_func (G_LIST_STORE (model), extension, (GEqualFunc)is_extension_equal, &position))
g_list_model_items_changed (model, position, 1, 1);

if (has_focus && gtk_widget_get_child_visible (GTK_WIDGET (self)))
{
if (!focus_matching_extension (self->user_list_box, extension))
focus_matching_extension (self->system_list_box, extension);
}

// Restore scrolled window position
if (adjustment)
gtk_adjustment_set_value (adjustment, scroll_pos);

g_object_unref (extension);
}

static void
invalidate_model_bindings (ExmInstalledPage *self)
{
Expand All @@ -325,7 +409,14 @@ invalidate_model_bindings (ExmInstalledPage *self)
NULL);

if (ext_model)
{
bind_list_box (ext_model, self);

g_signal_connect (ext_model,
"items-changed",
G_CALLBACK (on_extensions_changed),
self);
}
}

static void
Expand Down Expand Up @@ -382,6 +473,7 @@ exm_installed_page_class_init (ExmInstalledPageClass *klass)

gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, stack);
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, updates_banner);
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, prefs_page);
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, global_toggle);
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, user_list_box);
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, system_list_box);
Expand Down
19 changes: 19 additions & 0 deletions src/local/exm-extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,25 @@ exm_extension_set_property (GObject *object,
}
}

gint
compare_extension (ExmExtension *a,
ExmExtension *b,
gpointer user_data G_GNUC_UNUSED)
{
const gchar *uuid_a, *uuid_b;
g_object_get (a, "uuid", &uuid_a, NULL);
g_object_get (b, "uuid", &uuid_b, NULL);

return g_strcmp0 (uuid_a, uuid_b);
}

gboolean
is_extension_equal (ExmExtension *a,
ExmExtension *b)
{
return compare_extension (a, b, NULL) == 0;
}

static void
exm_extension_class_init (ExmExtensionClass *klass)
{
Expand Down
9 changes: 8 additions & 1 deletion src/local/exm-extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ G_BEGIN_DECLS

G_DECLARE_FINAL_TYPE (ExmExtension, exm_extension, EXM, EXTENSION, GObject)

ExmExtension *exm_extension_new (const gchar *uuid);
ExmExtension *exm_extension_new (const gchar *uuid);

gint compare_extension (ExmExtension *a,
ExmExtension *b,
gpointer user_data);

gboolean is_extension_equal (ExmExtension *a,
ExmExtension *b);

G_END_DECLS
22 changes: 5 additions & 17 deletions src/local/exm-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,16 +712,6 @@ update_extension_list (ExmManager *self)
queue_notify_extension_updates (self);
}

static gboolean
is_extension_equal (ExmExtension *a, ExmExtension *b)
{
const gchar *uuid_a, *uuid_b;
g_object_get (a, "uuid", &uuid_a, NULL);
g_object_get (b, "uuid", &uuid_b, NULL);

return strcmp (uuid_a, uuid_b) == 0;
}

static void
on_state_changed (ShellExtensions *object G_GNUC_UNUSED,
const gchar *arg_uuid,
Expand Down Expand Up @@ -752,25 +742,23 @@ on_state_changed (ShellExtensions *object G_GNUC_UNUSED,

if (is_new)
{
g_list_store_append (list_store, extension);
g_list_store_insert_sorted (list_store, extension, (GCompareDataFunc)compare_extension, NULL);
return;
}

guint position;

if (is_uninstall_operation)
{
guint position;
if (g_list_store_find_with_equal_func (list_store, extension, (GEqualFunc)is_extension_equal, &position))
g_list_store_remove (list_store, position);

return;
}

// Emit items-changed signal to re-sort extension list
{
guint position;
if (g_list_store_find_with_equal_func (list_store, extension, (GEqualFunc)is_extension_equal, &position))
g_list_model_items_changed (G_LIST_MODEL (list_store), position, 1, 1);
}
if (g_list_store_find_with_equal_func (list_store, extension, (GEqualFunc)is_extension_equal, &position))
g_list_model_items_changed (G_LIST_MODEL (list_store), position, 0, 0);

// If the extension that has changed has an update, then
// one or more extensions have updates available. Lazily
Expand Down

0 comments on commit bb29b6e

Please sign in to comment.