Skip to content

Commit 98cc6bd

Browse files
committed
installed-page: Save extensions' toggles focus on state changes
The items-changed signal is now emitted unchanged in the model from ExmManager and is connected after binding the manager in ExmInstalledPage from where the callback saves, emits items-changed and restores focus. This approach allows to keep binding GtkListBox to the extensions model and not having to manage the changes manually. Fix #220
1 parent 8885ff7 commit 98cc6bd

File tree

7 files changed

+135
-22
lines changed

7 files changed

+135
-22
lines changed

src/exm-extension-row.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ on_state_changed (GtkSwitch *toggle,
269269
return TRUE;
270270
}
271271

272+
void
273+
exm_search_row_focus_toggle (ExmExtensionRow *self)
274+
{
275+
gtk_widget_grab_focus (GTK_WIDGET (self->ext_toggle));
276+
}
277+
272278
static void
273279
exm_extension_row_class_init (ExmExtensionRowClass *klass)
274280
{

src/exm-extension-row.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ G_BEGIN_DECLS
1111

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

14-
ExmExtensionRow *
15-
exm_extension_row_new (ExmExtension *extension,
16-
ExmManager *manager);
14+
ExmExtensionRow *exm_extension_row_new (ExmExtension *extension,
15+
ExmManager *manager);
16+
17+
void exm_search_row_focus_toggle (ExmExtensionRow *self);
1718

1819
G_END_DECLS

src/exm-installed-page.blp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ template $ExmInstalledPage: Gtk.Widget {
1919
action-name: "app.logout";
2020
}
2121

22-
Adw.PreferencesPage {
22+
Adw.PreferencesPage prefs_page {
2323
Adw.PreferencesGroup {
2424
Adw.SwitchRow global_toggle {
2525
[prefix]

src/exm-installed-page.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct _ExmInstalledPage
3939
// Template Widgets
4040
GtkStack *stack;
4141
AdwBanner *updates_banner;
42+
AdwPreferencesPage *prefs_page;
4243
AdwSwitchRow *global_toggle;
4344
GtkListBox *user_list_box;
4445
GtkListBox *system_list_box;
@@ -312,6 +313,89 @@ on_updates_available (ExmManager *manager G_GNUC_UNUSED,
312313
g_timeout_add (500, G_SOURCE_FUNC (show_updates_banner), self);
313314
}
314315

316+
static gboolean
317+
focus_matching_extension (GtkListBox *list_box,
318+
ExmExtension *extension)
319+
{
320+
int index = 0;
321+
ExmExtensionRow *row;
322+
323+
while ((row = EXM_EXTENSION_ROW (gtk_list_box_get_row_at_index (list_box, index))))
324+
{
325+
ExmExtension *row_extension;
326+
327+
g_object_get(row, "extension", &row_extension, NULL);
328+
329+
if (is_extension_equal (extension, row_extension))
330+
{
331+
exm_search_row_focus_toggle (row);
332+
g_object_unref (row_extension);
333+
334+
return TRUE;
335+
}
336+
337+
index++;
338+
}
339+
340+
return FALSE;
341+
}
342+
343+
static void
344+
on_extensions_changed (GListModel *model,
345+
guint position,
346+
guint removed,
347+
guint added,
348+
ExmInstalledPage *self)
349+
{
350+
if (!self->sort_enabled_first || (removed > 0 && added > 0))
351+
return;
352+
353+
GtkRoot *toplevel;
354+
GtkWidget *widget;
355+
ExmExtension *extension;
356+
357+
toplevel = gtk_widget_get_root (GTK_WIDGET (self));
358+
widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
359+
360+
extension = EXM_EXTENSION (g_list_model_get_object (model, position));
361+
362+
if (!extension)
363+
return;
364+
365+
GtkAdjustment *adjustment = NULL;
366+
double scroll_pos = 0.0;
367+
gboolean has_focus = widget && gtk_widget_has_focus (widget);
368+
369+
if (has_focus)
370+
{
371+
GtkWidget *child;
372+
373+
// Save scrolled window position
374+
child = gtk_widget_get_first_child (GTK_WIDGET (self->prefs_page));
375+
if (child && GTK_IS_SCROLLED_WINDOW (child))
376+
{
377+
adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (child));
378+
if (adjustment)
379+
scroll_pos = gtk_adjustment_get_value (adjustment);
380+
}
381+
}
382+
383+
if (g_list_store_find_with_equal_func (G_LIST_STORE (model), extension, (GEqualFunc)is_extension_equal, &position))
384+
g_list_model_items_changed (model, position, 1, 1);
385+
386+
if (has_focus && gtk_widget_get_child_visible (GTK_WIDGET (self)))
387+
{
388+
if (!focus_matching_extension (self->user_list_box, extension))
389+
focus_matching_extension (self->system_list_box, extension);
390+
}
391+
392+
// Restore scrolled window position
393+
if (adjustment)
394+
gtk_adjustment_set_value (adjustment, scroll_pos);
395+
396+
g_object_unref (extension);
397+
}
398+
315399
static void
316400
invalidate_model_bindings (ExmInstalledPage *self)
317401
{
@@ -325,7 +409,14 @@ invalidate_model_bindings (ExmInstalledPage *self)
325409
NULL);
326410

327411
if (ext_model)
412+
{
328413
bind_list_box (ext_model, self);
414+
415+
g_signal_connect (ext_model,
416+
"items-changed",
417+
G_CALLBACK (on_extensions_changed),
418+
self);
419+
}
329420
}
330421

331422
static void
@@ -382,6 +473,7 @@ exm_installed_page_class_init (ExmInstalledPageClass *klass)
382473

383474
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, stack);
384475
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, updates_banner);
476+
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, prefs_page);
385477
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, global_toggle);
386478
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, user_list_box);
387479
gtk_widget_class_bind_template_child (widget_class, ExmInstalledPage, system_list_box);

src/local/exm-extension.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,25 @@ exm_extension_set_property (GObject *object,
176176
}
177177
}
178178

179+
gint
180+
compare_extension (ExmExtension *a,
181+
ExmExtension *b,
182+
gpointer user_data G_GNUC_UNUSED)
183+
{
184+
const gchar *uuid_a, *uuid_b;
185+
g_object_get (a, "uuid", &uuid_a, NULL);
186+
g_object_get (b, "uuid", &uuid_b, NULL);
187+
188+
return g_strcmp0 (uuid_a, uuid_b);
189+
}
190+
191+
gboolean
192+
is_extension_equal (ExmExtension *a,
193+
ExmExtension *b)
194+
{
195+
return compare_extension (a, b, NULL) == 0;
196+
}
197+
179198
static void
180199
exm_extension_class_init (ExmExtensionClass *klass)
181200
{

src/local/exm-extension.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ G_BEGIN_DECLS
88

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

11-
ExmExtension *exm_extension_new (const gchar *uuid);
11+
ExmExtension *exm_extension_new (const gchar *uuid);
12+
13+
gint compare_extension (ExmExtension *a,
14+
ExmExtension *b,
15+
gpointer user_data);
16+
17+
gboolean is_extension_equal (ExmExtension *a,
18+
ExmExtension *b);
1219

1320
G_END_DECLS

src/local/exm-manager.c

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -712,16 +712,6 @@ update_extension_list (ExmManager *self)
712712
queue_notify_extension_updates (self);
713713
}
714714

715-
static gboolean
716-
is_extension_equal (ExmExtension *a, ExmExtension *b)
717-
{
718-
const gchar *uuid_a, *uuid_b;
719-
g_object_get (a, "uuid", &uuid_a, NULL);
720-
g_object_get (b, "uuid", &uuid_b, NULL);
721-
722-
return strcmp (uuid_a, uuid_b) == 0;
723-
}
724-
725715
static void
726716
on_state_changed (ShellExtensions *object G_GNUC_UNUSED,
727717
const gchar *arg_uuid,
@@ -752,25 +742,23 @@ on_state_changed (ShellExtensions *object G_GNUC_UNUSED,
752742

753743
if (is_new)
754744
{
755-
g_list_store_append (list_store, extension);
745+
g_list_store_insert_sorted (list_store, extension, (GCompareDataFunc)compare_extension, NULL);
756746
return;
757747
}
758748

749+
guint position;
750+
759751
if (is_uninstall_operation)
760752
{
761-
guint position;
762753
if (g_list_store_find_with_equal_func (list_store, extension, (GEqualFunc)is_extension_equal, &position))
763754
g_list_store_remove (list_store, position);
764755

765756
return;
766757
}
767758

768759
// Emit items-changed signal to re-sort extension list
769-
{
770-
guint position;
771-
if (g_list_store_find_with_equal_func (list_store, extension, (GEqualFunc)is_extension_equal, &position))
772-
g_list_model_items_changed (G_LIST_MODEL (list_store), position, 1, 1);
773-
}
760+
if (g_list_store_find_with_equal_func (list_store, extension, (GEqualFunc)is_extension_equal, &position))
761+
g_list_model_items_changed (G_LIST_MODEL (list_store), position, 0, 0);
774762

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

0 commit comments

Comments
 (0)