From 7f61c15040187bb391e4559569440b9f2c6e9c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 6 Mar 2026 11:30:59 -0800 Subject: [PATCH 01/11] GridView: use carousel as source of truth for page pos --- src/SlingshotView.vala | 10 ++-- src/Views/GridView.vala | 108 +++++++++++++++++----------------------- 2 files changed, 50 insertions(+), 68 deletions(-) diff --git a/src/SlingshotView.vala b/src/SlingshotView.vala index 0c3d4ce5..094351cd 100644 --- a/src/SlingshotView.vala +++ b/src/SlingshotView.vala @@ -264,9 +264,9 @@ public class Slingshot.SlingshotView : Gtk.Bin, UnityClient { var key = Gdk.keyval_name (keyval).replace ("KP_", ""); int page = int.parse (key); if (page < 0 || page == 9) { - grid_view.go_to_last (); + grid_view.last_page (); } else { - grid_view.go_to_number (page); + grid_view.set_page (page - 1); } } @@ -277,7 +277,7 @@ public class Slingshot.SlingshotView : Gtk.Bin, UnityClient { switch (keyval) { case Gdk.Key.Page_Up: if (modality == Modality.NORMAL_VIEW) { - grid_view.go_to_previous (); + grid_view.previous_page (); } else if (modality == Modality.CATEGORY_VIEW) { category_view.page_up (); } @@ -285,7 +285,7 @@ public class Slingshot.SlingshotView : Gtk.Bin, UnityClient { case Gdk.Key.Page_Down: if (modality == Modality.NORMAL_VIEW) { - grid_view.go_to_next (); + grid_view.next_page (); } else if (modality == Modality.CATEGORY_VIEW) { category_view.page_down (); } @@ -293,7 +293,7 @@ public class Slingshot.SlingshotView : Gtk.Bin, UnityClient { case Gdk.Key.End: if (modality == Modality.NORMAL_VIEW) { - grid_view.go_to_last (); + grid_view.last_page (); } break; diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index 5391f36d..7776f85a 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -24,8 +24,6 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { public uint columns; } - private Gtk.Grid current_grid; - private Gee.HashMap grids; private Hdy.Carousel paginator; private Page page; @@ -63,26 +61,6 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { } } - private uint _current_grid_key = 0; - public uint current_grid_key { - get { - return _current_grid_key; - } - - set { - // Clamp to valid values for keyboard navigation - _current_grid_key = value.clamp (1, paginator.n_pages); - var grid = grids.@get (_current_grid_key); - if (grid == null) { - return; - } - - paginator.scroll_to (grid); - current_grid = grid; - refocus (); - } - } - construct { page.rows = 3; page.columns = 5; @@ -101,8 +79,6 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { add (paginator); add (page_switcher); - grids = new Gee.HashMap (null, null); - can_focus = true; focus_in_event.connect_after (() => { refocus (); @@ -111,17 +87,18 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { key_controller = new Gtk.EventControllerKey (this); key_controller.key_pressed.connect (on_key_press); + + paginator.page_changed.connect ((index) => { + refocus (); + }); } public void populate (Backend.AppSystem app_system) { - foreach (Gtk.Grid grid in grids.values) { - grid.destroy (); + foreach (Gtk.Widget child in paginator.get_children ()) { + child.destroy (); } - grids.clear (); - _current_grid_key = 0; // Avoids clamp - add_new_grid (); // Increments current_grid_key to 1 - + var grid = add_new_grid (); // Where to insert new app button var next_row_index = 0; var next_col_index = 0; @@ -136,22 +113,22 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { } if (next_row_index == page.rows) { - add_new_grid (); + grid = add_new_grid (); next_row_index = 0; next_col_index = 0; } - current_grid.attach (app_button, (int)next_col_index, (int)next_row_index); + grid.attach (app_button, (int)next_col_index, (int)next_row_index); next_col_index++; } show_all (); // Show first page after populating the carousel - current_grid_key = 1; + set_page (0); } - private void add_new_grid () { - current_grid = new Gtk.Grid () { + private Gtk.Grid add_new_grid () { + var grid = new Gtk.Grid () { expand = true, row_homogeneous = true, column_homogeneous = true, @@ -164,13 +141,12 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { // Fake grids in case there are not enough apps to fill the grid for (var row = 0; row < page.rows; row++) { for (var column = 0; column < page.columns; column++) { - current_grid.attach (new Gtk.Grid (), column, row, 1, 1); + grid.attach (new Gtk.Grid (), column, row, 1, 1); } } - paginator.add (current_grid); - current_grid_key = current_grid_key + 1; - grids.set (current_grid_key, current_grid); + paginator.add (grid); + return grid; } @@ -178,7 +154,8 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { if (col < 1 || col > page.columns || row < 1 || row > page.rows) { return null; } else { - return current_grid.get_child_at ((int)col - 1, (int)row - 1); + var grid = (Gtk.Grid) paginator.get_children ().nth_data ((int) paginator.get_position ()); + return grid.get_child_at ((int) col - 1, (int) row - 1); } } @@ -188,27 +165,11 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { focused_column = focused_column; } - public void go_to_next () { - current_grid_key++; - } - - public void go_to_previous () { - current_grid_key--; - } - - public void go_to_last () { - current_grid_key = paginator.n_pages; - } - - public void go_to_number (int number) { - current_grid_key = number; - } - private bool on_key_press (uint keyval, uint keycode, Gdk.ModifierType state) { switch (keyval) { case Gdk.Key.Home: case Gdk.Key.KP_Home: - current_grid_key = 1; + set_page (0); return Gdk.EVENT_STOP; case Gdk.Key.Left: @@ -251,9 +212,9 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { private void move_left (Gdk.ModifierType state) { if ((state & Gdk.ModifierType.SHIFT_MASK) > 0) { - current_grid_key--; - } else if (focused_column == 1 && current_grid_key > 1) { - current_grid_key--; + previous_page (); + } else if (focused_column == 1 && paginator.get_position () > 0) { + previous_page (); focused_column = page.columns; } else { focused_column--; @@ -262,12 +223,33 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { private void move_right (Gdk.ModifierType state) { if ((state & Gdk.ModifierType.SHIFT_MASK) > 0) { - current_grid_key++; - } else if (focused_column == page.columns && current_grid_key < paginator.n_pages) { - current_grid_key++; + next_page (); + } else if (focused_column == page.columns && paginator.get_position () < paginator.n_pages - 1) { + next_page (); focused_column = 1; } else { focused_column++; } } + + public void next_page () { + set_page ((int) paginator.get_position () + 1); + } + + public void previous_page () { + set_page ((int) paginator.get_position () - 1); + } + + public void last_page () { + set_page (paginator.n_pages); + } + + public void set_page (uint pos) { + var grid = paginator.get_children ().nth_data (pos); + if (grid == null) { + return; + } + + paginator.scroll_to (grid); + } } From 6cad4c7820137ffda8b6bb430111659aa83ba553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 6 Mar 2026 13:27:49 -0800 Subject: [PATCH 02/11] GridView: rewrite with flowbox --- src/Views/GridView.vala | 176 ++++++++++++++----------------------- src/Widgets/AppButton.vala | 6 +- 2 files changed, 68 insertions(+), 114 deletions(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index 7776f85a..c9f18153 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -20,46 +20,29 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { public signal void app_launched (); private struct Page { - public uint rows; - public uint columns; + public int rows; + public int columns; } - private Hdy.Carousel paginator; - private Page page; - - private Gtk.EventControllerKey key_controller; + private int focused_column { + get { + var flowbox = (Gtk.FlowBox) paginator.get_children ().nth_data ((int) paginator.get_position ()); + var selected_child = flowbox.get_selected_children ().nth_data (0); - private uint _focused_column = 1; - public uint focused_column { - set { - var target_column = value.clamp (1, page.columns); - var target = get_widget_at (target_column, _focused_row); - if (target != null && target is Widgets.AppButton) { - _focused_column = target_column; - target.grab_focus (); + for (int i = 0; i < page.rows * page.columns; i++) { + if (flowbox.get_child_at_index (i) == selected_child) { + return i % page.columns + 1; + } } - } - get { - return _focused_column; + return -1; } } - private uint _focused_row = 1; - public uint focused_row { - set { - var target_row = value.clamp (1, page.rows); - var target = get_widget_at (_focused_column, target_row); - if (target != null && target is Widgets.AppButton) { - _focused_row = target_row; - target.grab_focus (); - } - } + private Hdy.Carousel paginator; + private Page page; - get { - return _focused_row; - } - } + private Gtk.EventControllerKey key_controller; construct { page.rows = 3; @@ -79,18 +62,15 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { add (paginator); add (page_switcher); - can_focus = true; - focus_in_event.connect_after (() => { - refocus (); - return Gdk.EVENT_STOP; - }); + // focus_in_event.connect_after (() => { + // refocus (); + // return Gdk.EVENT_PROPAGATE; + // }); key_controller = new Gtk.EventControllerKey (this); key_controller.key_pressed.connect (on_key_press); - paginator.page_changed.connect ((index) => { - refocus (); - }); + paginator.page_changed.connect (refocus); } public void populate (Backend.AppSystem app_system) { @@ -100,26 +80,24 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { var grid = add_new_grid (); // Where to insert new app button - var next_row_index = 0; - var next_col_index = 0; - + var next_grid_index = 0; foreach (Backend.App app in app_system.get_apps_by_name ()) { var app_button = new Widgets.AppButton (app); app_button.app_launched.connect (() => app_launched ()); - if (next_col_index == page.columns) { - next_col_index = 0; - next_row_index++; - } - - if (next_row_index == page.rows) { + if (next_grid_index == page.rows * page.columns) { grid = add_new_grid (); - next_row_index = 0; - next_col_index = 0; + next_grid_index = 0; } - grid.attach (app_button, (int)next_col_index, (int)next_row_index); - next_col_index++; + grid.add (app_button); + next_grid_index++; + } + + // Empty children in case there are not enough apps to fill a single page + while (next_grid_index < page.rows * page.columns) { + grid.add (new Gtk.FlowBoxChild () { can_focus = false }); + next_grid_index++; } show_all (); @@ -127,42 +105,30 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { set_page (0); } - private Gtk.Grid add_new_grid () { - var grid = new Gtk.Grid () { - expand = true, - row_homogeneous = true, - column_homogeneous = true, + private Gtk.FlowBox add_new_grid () { + var flowbox = new Gtk.FlowBox () { + hexpand = true, + vexpand = true, + homogeneous = true, margin_start = 12, margin_end = 12, + min_children_per_line = page.columns, + max_children_per_line = page.columns, row_spacing = 24, column_spacing = 0 }; - // Fake grids in case there are not enough apps to fill the grid - for (var row = 0; row < page.rows; row++) { - for (var column = 0; column < page.columns; column++) { - grid.attach (new Gtk.Grid (), column, row, 1, 1); - } - } - - paginator.add (grid); - return grid; - } - + flowbox.child_activated.connect ((child) => { + ((AppButton) child).launch_app (); + }); - private Gtk.Widget? get_widget_at (uint col, uint row) { - if (col < 1 || col > page.columns || row < 1 || row > page.rows) { - return null; - } else { - var grid = (Gtk.Grid) paginator.get_children ().nth_data ((int) paginator.get_position ()); - return grid.get_child_at ((int) col - 1, (int) row - 1); - } + paginator.add (flowbox); + return flowbox; } - // Refocus an AppButton after a focus out or page change + // focus the child with the same coords on the new page private void refocus () { - focused_row = focused_row; - focused_column = focused_column; + } private bool on_key_press (uint keyval, uint keycode, Gdk.ModifierType state) { @@ -175,61 +141,51 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { case Gdk.Key.Left: case Gdk.Key.KP_Left: if (get_default_direction () == LTR) { - move_left (state); + return move_left (state); } else { - move_right (state); + return move_right (state); } - return Gdk.EVENT_STOP; - case Gdk.Key.Right: case Gdk.Key.KP_Right: if (get_default_direction () == LTR) { - move_right (state); + return move_right (state); } else { - move_left (state); + return move_left (state); } - - return Gdk.EVENT_STOP; - - case Gdk.Key.Up: - case Gdk.Key.KP_Up: - if (_focused_row == 1) { - break; - } else { - focused_row--; - return Gdk.EVENT_STOP; - } - - case Gdk.Key.Down: - case Gdk.Key.KP_Down: - focused_row++; - return Gdk.EVENT_STOP; } return Gdk.EVENT_PROPAGATE; } - private void move_left (Gdk.ModifierType state) { + private bool move_left (Gdk.ModifierType state) { if ((state & Gdk.ModifierType.SHIFT_MASK) > 0) { previous_page (); - } else if (focused_column == 1 && paginator.get_position () > 0) { + return Gdk.EVENT_STOP; + } + + if (focused_column == 1 && paginator.get_position () > 0) { previous_page (); - focused_column = page.columns; - } else { - focused_column--; + move_focus (LEFT); + return Gdk.EVENT_STOP; } + + return Gdk.EVENT_PROPAGATE; } - private void move_right (Gdk.ModifierType state) { + private bool move_right (Gdk.ModifierType state) { if ((state & Gdk.ModifierType.SHIFT_MASK) > 0) { next_page (); - } else if (focused_column == page.columns && paginator.get_position () < paginator.n_pages - 1) { + return Gdk.EVENT_STOP; + } + + if (focused_column == page.columns && paginator.get_position () < paginator.n_pages - 1) { next_page (); - focused_column = 1; - } else { - focused_column++; + move_focus (RIGHT); + return Gdk.EVENT_STOP; } + + return Gdk.EVENT_PROPAGATE; } public void next_page () { diff --git a/src/Widgets/AppButton.vala b/src/Widgets/AppButton.vala index 8c1ee6a6..c6e8bdbc 100644 --- a/src/Widgets/AppButton.vala +++ b/src/Widgets/AppButton.vala @@ -4,7 +4,7 @@ * 2011-2012 Giulio Collura */ -public class Slingshot.Widgets.AppButton : Gtk.Button { +public class Slingshot.Widgets.AppButton : Gtk.FlowBoxChild { public signal void app_launched (); public Backend.App app { get; construct; } @@ -28,7 +28,7 @@ public class Slingshot.Widgets.AppButton : Gtk.Button { tooltip_text = app.description; - get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); + // get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); var app_label = new Gtk.Label (app.name) { halign = CENTER, @@ -78,8 +78,6 @@ public class Slingshot.Widgets.AppButton : Gtk.Button { app.launched.connect (() => app_launched ()); - this.clicked.connect (launch_app); - click_controller = new Gtk.GestureMultiPress (this) { button = 0, exclusive = true From 417bac9d7b232a2bf96d33708d2ef7e610560a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 7 Mar 2026 09:50:09 -0800 Subject: [PATCH 03/11] lint --- src/Views/GridView.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index c9f18153..90a08e85 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -31,7 +31,7 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { for (int i = 0; i < page.rows * page.columns; i++) { if (flowbox.get_child_at_index (i) == selected_child) { - return i % page.columns + 1; + return i % page.columns + 1; } } @@ -128,7 +128,7 @@ public class Slingshot.Widgets.Grid : Gtk.Grid { // focus the child with the same coords on the new page private void refocus () { - + } private bool on_key_press (uint keyval, uint keycode, Gdk.ModifierType state) { From 5597b376ba933e19f81670603e5b2994c8dcc170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 7 Mar 2026 09:52:59 -0800 Subject: [PATCH 04/11] less expensive operation first --- src/Views/GridView.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index 7887c54a..ba019b92 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -169,7 +169,7 @@ public class Slingshot.Widgets.Grid : Gtk.Box { return Gdk.EVENT_STOP; } - if (focused_column == page.columns && paginator.get_position () < paginator.n_pages - 1) { + if (paginator.get_position () < paginator.n_pages - 1 && focused_column == page.columns) { next_page (); move_focus (RIGHT); return Gdk.EVENT_STOP; From 3eaa9dfb3eff067e3ea8529c741266aa2c895ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 7 Mar 2026 09:55:21 -0800 Subject: [PATCH 05/11] less expensive operation first --- src/Views/GridView.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index ba019b92..ab3aa302 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -154,7 +154,7 @@ public class Slingshot.Widgets.Grid : Gtk.Box { return Gdk.EVENT_STOP; } - if (focused_column == 1 && paginator.get_position () > 0) { + if (paginator.get_position () > 0 && focused_column == 1) { previous_page (); move_focus (LEFT); return Gdk.EVENT_STOP; From ac82e5c6782531f4cd6e8bbc303e2345190dc84a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 7 Mar 2026 10:12:44 -0800 Subject: [PATCH 06/11] remove comments --- src/Views/GridView.vala | 8 ++++---- src/Widgets/AppButton.vala | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index ab3aa302..e97d8aa6 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -52,10 +52,10 @@ public class Slingshot.Widgets.Grid : Gtk.Box { add (paginator); add (page_switcher); - // focus_in_event.connect_after (() => { - // refocus (); - // return Gdk.EVENT_PROPAGATE; - // }); + focus_in_event.connect_after (() => { + refocus (); + return Gdk.EVENT_PROPAGATE; + }); key_controller = new Gtk.EventControllerKey (this); key_controller.key_pressed.connect (on_key_press); diff --git a/src/Widgets/AppButton.vala b/src/Widgets/AppButton.vala index c6e8bdbc..70834254 100644 --- a/src/Widgets/AppButton.vala +++ b/src/Widgets/AppButton.vala @@ -28,8 +28,6 @@ public class Slingshot.Widgets.AppButton : Gtk.FlowBoxChild { tooltip_text = app.description; - // get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); - var app_label = new Gtk.Label (app.name) { halign = CENTER, ellipsize = END, From 65a2632a8e5dd5f746f737f28fc1eca509418e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 9 Mar 2026 12:26:04 -0700 Subject: [PATCH 07/11] Reduce diff slightly --- src/Views/GridView.vala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index cb83d617..16412840 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -10,6 +10,9 @@ public class Slingshot.Widgets.Grid : Gtk.Box { private const int PAGE_ROWS = 3; private const int PAGE_COLUMNS = 5; + private Hdy.Carousel paginator; + private Gtk.EventControllerKey key_controller; + private int focused_column { get { var flowbox = (Gtk.FlowBox) paginator.get_children ().nth_data ((int) paginator.get_position ()); @@ -25,9 +28,6 @@ public class Slingshot.Widgets.Grid : Gtk.Box { } } - private Hdy.Carousel paginator; - private Gtk.EventControllerKey key_controller; - construct { paginator = new Hdy.Carousel () { hexpand = true, From 2529419ebfa96a92341cdbca5918a01060b56c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 9 Mar 2026 13:20:06 -0700 Subject: [PATCH 08/11] Less diff --- src/Views/GridView.vala | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index 16412840..92e5cb32 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -52,8 +52,6 @@ public class Slingshot.Widgets.Grid : Gtk.Box { key_controller = new Gtk.EventControllerKey (this); key_controller.key_pressed.connect (on_key_press); - - paginator.page_changed.connect (refocus); } public void populate (Backend.AppSystem app_system) { From fb95a6f17f51272b47605a7c00a91382f8bce90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 9 Mar 2026 13:43:05 -0700 Subject: [PATCH 09/11] refocus --- src/Views/GridView.vala | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index 92e5cb32..6c33d0a3 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -28,6 +28,9 @@ public class Slingshot.Widgets.Grid : Gtk.Box { } } + private bool should_refocus; + private int focused_index; + construct { paginator = new Hdy.Carousel () { hexpand = true, @@ -50,6 +53,8 @@ public class Slingshot.Widgets.Grid : Gtk.Box { return Gdk.EVENT_PROPAGATE; }); + paginator.page_changed.connect (refocus); + key_controller = new Gtk.EventControllerKey (this); key_controller.key_pressed.connect (on_key_press); } @@ -99,6 +104,8 @@ public class Slingshot.Widgets.Grid : Gtk.Box { column_spacing = 0 }; + flowbox.selected_children_changed.connect (update_focused_index); + flowbox.child_activated.connect ((child) => { ((AppButton) child).launch_app (); }); @@ -107,9 +114,32 @@ public class Slingshot.Widgets.Grid : Gtk.Box { return flowbox; } + private void update_focused_index (Gtk.FlowBox flowbox) { + var selected_child = flowbox.get_selected_children ().nth_data (0); + if (selected_child == null) { + return; + } + + for (int i = 0; i < PAGE_ROWS * PAGE_COLUMNS; i++) { + if (flowbox.get_child_at_index (i) == selected_child) { + focused_index = i; + } + } + } + // focus the child with the same coords on the new page private void refocus () { + // FIXME: in GTK4 check for contains focus instead + if (should_refocus == false) { + should_refocus = true; + return; + } + + var flowbox = (Gtk.FlowBox) paginator.get_children ().nth_data ((int) paginator.get_position ()); + var focus_child = flowbox.get_child_at_index (focused_index); + flowbox.select_child (focus_child); + focus_child.grab_focus (); } private bool on_key_press (uint keyval, uint keycode, Gdk.ModifierType state) { @@ -146,6 +176,7 @@ public class Slingshot.Widgets.Grid : Gtk.Box { } if (paginator.get_position () > 0 && focused_column == 1) { + should_refocus = false; previous_page (); move_focus (LEFT); return Gdk.EVENT_STOP; @@ -161,6 +192,7 @@ public class Slingshot.Widgets.Grid : Gtk.Box { } if (paginator.get_position () < paginator.n_pages - 1 && focused_column == PAGE_COLUMNS) { + should_refocus = false; next_page (); move_focus (RIGHT); return Gdk.EVENT_STOP; @@ -188,6 +220,5 @@ public class Slingshot.Widgets.Grid : Gtk.Box { } paginator.scroll_to (grid); - refocus (); } } From 3edc6c926324620a83f9b285ef07f5cf1ed511a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 9 Mar 2026 13:47:09 -0700 Subject: [PATCH 10/11] DRY --- src/Views/GridView.vala | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/Views/GridView.vala b/src/Views/GridView.vala index 6c33d0a3..94af1396 100644 --- a/src/Views/GridView.vala +++ b/src/Views/GridView.vala @@ -13,21 +13,6 @@ public class Slingshot.Widgets.Grid : Gtk.Box { private Hdy.Carousel paginator; private Gtk.EventControllerKey key_controller; - private int focused_column { - get { - var flowbox = (Gtk.FlowBox) paginator.get_children ().nth_data ((int) paginator.get_position ()); - var selected_child = flowbox.get_selected_children ().nth_data (0); - - for (int i = 0; i < PAGE_ROWS * PAGE_COLUMNS; i++) { - if (flowbox.get_child_at_index (i) == selected_child) { - return i % PAGE_COLUMNS + 1; - } - } - - return -1; - } - } - private bool should_refocus; private int focused_index; @@ -175,7 +160,7 @@ public class Slingshot.Widgets.Grid : Gtk.Box { return Gdk.EVENT_STOP; } - if (paginator.get_position () > 0 && focused_column == 1) { + if (paginator.get_position () > 0 && focused_index % PAGE_COLUMNS == 0) { should_refocus = false; previous_page (); move_focus (LEFT); @@ -191,7 +176,7 @@ public class Slingshot.Widgets.Grid : Gtk.Box { return Gdk.EVENT_STOP; } - if (paginator.get_position () < paginator.n_pages - 1 && focused_column == PAGE_COLUMNS) { + if (paginator.get_position () < paginator.n_pages - 1 && focused_index % PAGE_COLUMNS + 1 == PAGE_COLUMNS) { should_refocus = false; next_page (); move_focus (RIGHT); From 7d27e7b42ac920c3d5bf9bcf64222f171cde5102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 11 Mar 2026 08:20:17 -0700 Subject: [PATCH 11/11] Fix context menu --- src/Widgets/AppButton.vala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Widgets/AppButton.vala b/src/Widgets/AppButton.vala index 70834254..43685e90 100644 --- a/src/Widgets/AppButton.vala +++ b/src/Widgets/AppButton.vala @@ -72,11 +72,15 @@ public class Slingshot.Widgets.AppButton : Gtk.FlowBoxChild { box.add (overlay); box.add (app_label); - child = box; + var event_box = new Gtk.EventBox () { + child = box + }; + + child = event_box; app.launched.connect (() => app_launched ()); - click_controller = new Gtk.GestureMultiPress (this) { + click_controller = new Gtk.GestureMultiPress (event_box) { button = 0, exclusive = true };