Skip to content

Commit bb29b6e

Browse files
committed
installed-page: Save extension's toggle focus on state changes
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
1 parent 8885ff7 commit bb29b6e

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)