From 1944003b49e7da2cae5d3684973c0f1e942345fe Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 8 Jan 2025 12:43:18 +0000 Subject: [PATCH 1/7] Add "Favorite" Category to sidebar --- src/Views/CategoryView.vala | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Views/CategoryView.vala b/src/Views/CategoryView.vala index 04c97828c..efc2c8609 100644 --- a/src/Views/CategoryView.vala +++ b/src/Views/CategoryView.vala @@ -208,15 +208,28 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { // Fill the sidebar unowned Gtk.ListBoxRow? new_selected = null; + // Add Favorite category + var row = new CategoryRow (_("Favorites")); + category_switcher.add (row); + int n_rows = 1; foreach (string cat_name in view.app_system.apps.keys) { if (cat_name == "switchboard") { continue; } - var row = new CategoryRow (cat_name); + row = new CategoryRow (cat_name); category_switcher.add (row); - if (old_selected != null && old_selected.cat_name == cat_name) { - new_selected = row; + n_rows++; + } + + + if (old_selected != null) { + for (int i = 0; i < n_rows; i++) { + row = (CategoryRow) category_switcher.get_row_at_index (i); + if (old_selected.cat_name == row.cat_name) { + new_selected = row; + break; + } } } From 2f0deca40618912eb15dc47dfb9e0af63e733e22 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 8 Jan 2025 14:52:36 +0000 Subject: [PATCH 2/7] Populate favorites from dock settings --- src/Indicator.vala | 21 ++++++++++++++++++++ src/SlingshotView.vala | 4 ++++ src/Views/CategoryView.vala | 38 ++++++++++++++++++++++++++++++++----- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 4aa2843f3..fd4bd2521 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -19,6 +19,7 @@ public class Slingshot.Indicator : Wingpanel.Indicator { private const string KEYBINDING_SCHEMA = "io.elementary.desktop.wm.keybindings"; private const string GALA_BEHAVIOR_SCHEMA = "io.elementary.desktop.wm.behavior"; + private const string DOCK_SCHEMA = "io.elementary.dock"; private DBusService? dbus_service = null; private Gtk.Grid? indicator_grid = null; @@ -26,6 +27,7 @@ public class Slingshot.Indicator : Wingpanel.Indicator { private static GLib.Settings? keybinding_settings; private static GLib.Settings? gala_behavior_settings; + private static GLib.Settings? dock_settings; public Indicator () { Object (code_name: Wingpanel.Indicator.APP_LAUNCHER); @@ -39,6 +41,10 @@ public class Slingshot.Indicator : Wingpanel.Indicator { if (SettingsSchemaSource.get_default ().lookup (GALA_BEHAVIOR_SCHEMA, true) != null) { gala_behavior_settings = new GLib.Settings (GALA_BEHAVIOR_SCHEMA); } + + if (SettingsSchemaSource.get_default ().lookup (DOCK_SCHEMA, true) != null) { + dock_settings = new GLib.Settings (DOCK_SCHEMA); + } } construct { @@ -97,6 +103,15 @@ public class Slingshot.Indicator : Wingpanel.Indicator { } }); } + + if (dock_settings != null) { + dock_settings.changed.connect ((key) => { + if (key == "launchers") { + update_favorites (dock_settings.get_strv ("launchers")); + } + }); + update_favorites (dock_settings.get_strv ("launchers")); + } } visible = true; @@ -131,6 +146,12 @@ public class Slingshot.Indicator : Wingpanel.Indicator { indicator_grid.tooltip_markup = Granite.markup_accel_tooltip (accels, _("Open and search apps")); } + + private void update_favorites (string[] dock_launchers) { + if (view != null) { + view.update_favorites (dock_launchers); + } + } } public Wingpanel.Indicator? get_indicator (Module module, Wingpanel.IndicatorManager.ServerType server_type) { diff --git a/src/SlingshotView.vala b/src/SlingshotView.vala index d490acc93..b11c41a7b 100644 --- a/src/SlingshotView.vala +++ b/src/SlingshotView.vala @@ -164,6 +164,10 @@ public class Slingshot.SlingshotView : Gtk.Grid, UnityClient { }); } + public void update_favorites (string[] favs) { + category_view.update_favorites (favs); + } + public void update_launcher_entry (string sender_name, GLib.Variant parameters, bool is_retry = false) { if (!is_retry) { // Wait to let further update requests come in to catch the case where one application diff --git a/src/Views/CategoryView.vala b/src/Views/CategoryView.vala index efc2c8609..974c92719 100644 --- a/src/Views/CategoryView.vala +++ b/src/Views/CategoryView.vala @@ -25,6 +25,7 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { private string? drag_uri = null; private NavListBox category_switcher; private NavListBox listbox; + private Gee.ArrayList favorites; private const Gtk.TargetEntry DND = { "text/uri-list", 0, 0 }; @@ -36,6 +37,8 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { set_visible_window (false); hexpand = true; + favorites = new Gee.ArrayList (); + category_switcher = new NavListBox (); category_switcher.selection_mode = Gtk.SelectionMode.BROWSE; category_switcher.set_sort_func ((Gtk.ListBoxSortFunc) category_sort_func); @@ -204,14 +207,25 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { foreach (unowned Backend.App app in view.app_system.get_apps_by_name ()) { listbox.add (new AppListRow (app.desktop_id, app.desktop_path)); } - listbox.show_all (); + // Fill the sidebar unowned Gtk.ListBoxRow? new_selected = null; - // Add Favorite category - var row = new CategoryRow (_("Favorites")); - category_switcher.add (row); - int n_rows = 1; + CategoryRow row; + int n_rows = 0; + if (favorites.size > 0) { + // Add Favorite category + row = new CategoryRow (_("Favorites")); + category_switcher.add (row); + n_rows++; + + foreach (string app_id in favorites) { + listbox.add (new AppListRow (app_id, "")); + } + } + + listbox.show_all (); + foreach (string cat_name in view.app_system.apps.keys) { if (cat_name == "switchboard") { continue; @@ -237,10 +251,24 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { category_switcher.select_row (new_selected ?? category_switcher.get_row_at_index (0)); } + public void update_favorites (string[] favs) { + favorites.clear (); + foreach (string s in favs) { + favorites.add (s); + } + + listbox.invalidate_filter (); + setup_sidebar (); + } + [CCode (instance_pos = -1)] private bool filter_function (AppListRow row) { unowned CategoryRow category_row = (CategoryRow) category_switcher.get_selected_row (); if (category_row != null) { + if (category_row.cat_name == _("Favorites")) { + return favorites.contains (row.app_id); + } + foreach (Backend.App app in view.app_system.apps[category_row.cat_name]) { if (row.app_id == app.desktop_id) { return true; From ea146278ca4383c3994fb03caa850cef0d3bc1ab Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 8 Jan 2025 16:12:02 +0000 Subject: [PATCH 3/7] Update favorites from dock; modify to filter --- src/Indicator.vala | 24 +++++++++--------------- src/Views/CategoryView.vala | 21 ++++++++------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index fd4bd2521..5eabc3bac 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -71,6 +71,15 @@ public class Slingshot.Indicator : Wingpanel.Indicator { if (dbus_service == null) { dbus_service = new DBusService (view); } + + if (dock_settings != null) { + dock_settings.changed.connect ((key) => { + if (key == "launchers") { + view.update_favorites (dock_settings.get_strv ("launchers")); + } + }); + view.update_favorites (dock_settings.get_strv ("launchers")); + } } return view; @@ -103,15 +112,6 @@ public class Slingshot.Indicator : Wingpanel.Indicator { } }); } - - if (dock_settings != null) { - dock_settings.changed.connect ((key) => { - if (key == "launchers") { - update_favorites (dock_settings.get_strv ("launchers")); - } - }); - update_favorites (dock_settings.get_strv ("launchers")); - } } visible = true; @@ -146,12 +146,6 @@ public class Slingshot.Indicator : Wingpanel.Indicator { indicator_grid.tooltip_markup = Granite.markup_accel_tooltip (accels, _("Open and search apps")); } - - private void update_favorites (string[] dock_launchers) { - if (view != null) { - view.update_favorites (dock_launchers); - } - } } public Wingpanel.Indicator? get_indicator (Module module, Wingpanel.IndicatorManager.ServerType server_type) { diff --git a/src/Views/CategoryView.vala b/src/Views/CategoryView.vala index 974c92719..df23045b4 100644 --- a/src/Views/CategoryView.vala +++ b/src/Views/CategoryView.vala @@ -19,6 +19,7 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { public signal void search_focus_request (); + public const string FAVORITE_CATEGORY = N_("Favorites"); public SlingshotView view { get; construct; } private bool dragging = false; @@ -208,24 +209,19 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { listbox.add (new AppListRow (app.desktop_id, app.desktop_path)); } + listbox.show_all (); // Fill the sidebar unowned Gtk.ListBoxRow? new_selected = null; CategoryRow row; + // Add Favorites category if there are any pinned apps int n_rows = 0; if (favorites.size > 0) { - // Add Favorite category - row = new CategoryRow (_("Favorites")); + row = new CategoryRow (_(FAVORITE_CATEGORY)); category_switcher.add (row); n_rows++; - - foreach (string app_id in favorites) { - listbox.add (new AppListRow (app_id, "")); - } } - listbox.show_all (); - foreach (string cat_name in view.app_system.apps.keys) { if (cat_name == "switchboard") { continue; @@ -236,7 +232,6 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { n_rows++; } - if (old_selected != null) { for (int i = 0; i < n_rows; i++) { row = (CategoryRow) category_switcher.get_row_at_index (i); @@ -253,19 +248,19 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { public void update_favorites (string[] favs) { favorites.clear (); - foreach (string s in favs) { - favorites.add (s); + foreach (string app_id in favs) { + favorites.add (app_id); } - listbox.invalidate_filter (); setup_sidebar (); + listbox.invalidate_filter (); } [CCode (instance_pos = -1)] private bool filter_function (AppListRow row) { unowned CategoryRow category_row = (CategoryRow) category_switcher.get_selected_row (); if (category_row != null) { - if (category_row.cat_name == _("Favorites")) { + if (category_row.cat_name == _(FAVORITE_CATEGORY)) { return favorites.contains (row.app_id); } From 650edd7c2bbf0b8727fbc47ab0403dc04149f95b Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Thu, 9 Jan 2025 13:35:26 +0000 Subject: [PATCH 4/7] Simply popularity measure, get apps by popularity --- src/Backend/App.vala | 2 +- src/Backend/AppSystem.vala | 26 ++++++++++++++++++++++++++ src/Backend/RelevancyService.vala | 21 ++++++++++----------- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/Backend/App.vala b/src/Backend/App.vala index e312d4afd..7b10ab8b3 100644 --- a/src/Backend/App.vala +++ b/src/Backend/App.vala @@ -34,7 +34,7 @@ public class Slingshot.Backend.App : Object { public string exec { get; private set; } public string[] keywords { get; private set;} public Icon icon { get; private set; default = new ThemedIcon ("application-default-icon"); } - public double popularity { get; set; } + public int popularity { get; set; } public string desktop_path { get; private set; } public string categories { get; private set; } public string generic_name { get; private set; default = ""; } diff --git a/src/Backend/AppSystem.vala b/src/Backend/AppSystem.vala index 49950c1bc..58938abf8 100644 --- a/src/Backend/AppSystem.vala +++ b/src/Backend/AppSystem.vala @@ -220,4 +220,30 @@ public class Slingshot.Backend.AppSystem : Object { private static int sort_apps_by_name (Backend.App a, Backend.App b) { return a.name.collate (b.name); } + +#if HAVE_ZEITGEIST + public SList get_apps_by_popularity () { + var sorted_apps = new SList (); + string[] sorted_apps_execs = {}; + + foreach (Gee.ArrayList category in apps.values) { + foreach (App app in category) { + if (!(app.exec in sorted_apps_execs)) { + sorted_apps.insert_sorted_with_data (app, sort_apps_by_popularity); + sorted_apps_execs += app.exec; + } + } + } + + return sorted_apps; + } + + private static int sort_apps_by_popularity (Backend.App a, Backend.App b) { + if (a.popularity == b.popularity) { + return a.name.collate (b.name); + } + + return a.popularity > b.popularity ? 1 : -1; + } +#endif } diff --git a/src/Backend/RelevancyService.vala b/src/Backend/RelevancyService.vala index 364962f63..d127f3d15 100644 --- a/src/Backend/RelevancyService.vala +++ b/src/Backend/RelevancyService.vala @@ -26,8 +26,6 @@ public class Slingshot.Backend.RelevancyService : Object { private bool has_datahub_gio_module = false; private bool refreshing = false; - private const float MULTIPLIER = 65535.0f; - public signal void update_complete (); public RelevancyService () { @@ -104,7 +102,6 @@ public class Slingshot.Backend.RelevancyService : Object { var ptr_arr = new GLib.GenericArray (); ptr_arr.add (event); - try { Zeitgeist.ResultSet rs = yield zg_log.find_events (tr, ptr_arr, Zeitgeist.StorageState.ANY, @@ -119,13 +116,15 @@ public class Slingshot.Backend.RelevancyService : Object { // Zeitgeist (0.6) doesn't have any stats API, so let's approximate foreach (Zeitgeist.Event e in rs) { + if (e.num_subjects () <= 0) { + continue; + } - if (e.num_subjects () <= 0) continue; Zeitgeist.Subject s = e.get_subject (0); - float power = index / (size * 2) + 0.5f; // linearly <0.5, 1.0> - float relevancy = 1.0f / Math.powf (index + 1, power); - app_popularity[s.uri] = (int)(relevancy * MULTIPLIER); + // Simply use the (inverted) order of the app in the result set as + // measure of popularity for now. Suffices for the applications menu. + app_popularity[s.uri] = (int) (size - index); index++; } update_complete (); @@ -137,15 +136,15 @@ public class Slingshot.Backend.RelevancyService : Object { } } - public float get_app_popularity (string desktop_id) { - + public int get_app_popularity (string desktop_id) { var id = "application://" + desktop_id; if (app_popularity.has_key (id)) { - return app_popularity[id] / MULTIPLIER; + // return app_popularity[id] / MULTIPLIER; + return app_popularity[id]; } - return 0.0f; + return 0; } public void app_launched (App app) { From 50f9b11ddf3666e087cb8786a0409771e390375d Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Thu, 9 Jan 2025 13:36:11 +0000 Subject: [PATCH 5/7] Add a Recent category and populate it --- src/Indicator.vala | 4 +- src/SlingshotView.vala | 4 +- src/Views/CategoryView.vala | 78 ++++++++++++++++++++++++++++++------- src/Widgets/AppListRow.vala | 10 +++-- 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 5eabc3bac..419e9a1c0 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -75,10 +75,10 @@ public class Slingshot.Indicator : Wingpanel.Indicator { if (dock_settings != null) { dock_settings.changed.connect ((key) => { if (key == "launchers") { - view.update_favorites (dock_settings.get_strv ("launchers")); + view.update_pinned (dock_settings.get_strv ("launchers")); } }); - view.update_favorites (dock_settings.get_strv ("launchers")); + view.update_pinned (dock_settings.get_strv ("launchers")); } } diff --git a/src/SlingshotView.vala b/src/SlingshotView.vala index b11c41a7b..598dad349 100644 --- a/src/SlingshotView.vala +++ b/src/SlingshotView.vala @@ -164,8 +164,8 @@ public class Slingshot.SlingshotView : Gtk.Grid, UnityClient { }); } - public void update_favorites (string[] favs) { - category_view.update_favorites (favs); + public void update_pinned (string[] pinned) { + category_view.update_pinned (pinned); } public void update_launcher_entry (string sender_name, GLib.Variant parameters, bool is_retry = false) { diff --git a/src/Views/CategoryView.vala b/src/Views/CategoryView.vala index df23045b4..b113e43ad 100644 --- a/src/Views/CategoryView.vala +++ b/src/Views/CategoryView.vala @@ -19,15 +19,23 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { public signal void search_focus_request (); - public const string FAVORITE_CATEGORY = N_("Favorites"); + public const string PINNED_CATEGORY = N_("Pinned"); + public const string RECENT_CATEGORY = N_("Recent"); + public const int N_POPULAR = 12; + public const double MIN_POPULARITY = 1; + public SlingshotView view { get; construct; } private bool dragging = false; private string? drag_uri = null; private NavListBox category_switcher; private NavListBox listbox; - private Gee.ArrayList favorites; + private Gee.ArrayList pinned; + private bool show_pinned = false; +#if HAVE_ZEITGEIST + private Gee.ArrayList popular_apps; +#endif private const Gtk.TargetEntry DND = { "text/uri-list", 0, 0 }; public CategoryView (SlingshotView view) { @@ -38,8 +46,10 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { set_visible_window (false); hexpand = true; - favorites = new Gee.ArrayList (); - + pinned = new Gee.ArrayList (); +#if HAVE_ZEITGEIST + popular_apps = new Gee.ArrayList (); +#endif category_switcher = new NavListBox (); category_switcher.selection_mode = Gtk.SelectionMode.BROWSE; category_switcher.set_sort_func ((Gtk.ListBoxSortFunc) category_sort_func); @@ -69,7 +79,12 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { add (container); - category_switcher.row_selected.connect (() => { + category_switcher.row_selected.connect ((row) => { + if (((CategoryRow) row).cat_name == _(RECENT_CATEGORY)) { + listbox.set_sort_func ((Gtk.ListBoxSortFunc) recent_sort_func); + } else { + listbox.set_sort_func (null); + } listbox.invalidate_filter (); }); @@ -158,6 +173,14 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { return row1.cat_name.collate (row2.cat_name); } + private static int recent_sort_func (AppListRow row1, AppListRow row2) { + if (row1.popularity == row2.popularity) { + return row1.display_name.collate (row2.display_name); + } + + return row1.popularity > row2.popularity ? -1 : 1; + } + private bool create_context_menu (Gdk.Event event) { var selected_row = (AppListRow) listbox.get_selected_row (); @@ -206,18 +229,39 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { listbox.foreach ((app_list_row) => listbox.remove (app_list_row)); foreach (unowned Backend.App app in view.app_system.get_apps_by_name ()) { - listbox.add (new AppListRow (app.desktop_id, app.desktop_path)); + listbox.add (new AppListRow (app.desktop_id, app.desktop_path, app.popularity)); } +#if HAVE_ZEITGEIST + popular_apps.clear (); + var popularity = view.app_system.get_apps_by_popularity (); + int found = 0; + uint index = 0; + uint limit = popularity.length (); + while (found < N_POPULAR && index < limit) { + var app = popularity.nth_data (index); + if (app.popularity > MIN_POPULARITY) { + popular_apps.add (app.desktop_id); + found++; + } + + index++; + } +#endif listbox.show_all (); // Fill the sidebar unowned Gtk.ListBoxRow? new_selected = null; CategoryRow row; - // Add Favorites category if there are any pinned apps + // Add pinned category if there are any pinned apps int n_rows = 0; - if (favorites.size > 0) { - row = new CategoryRow (_(FAVORITE_CATEGORY)); + if (pinned.size > 0) { + row = new CategoryRow (_(PINNED_CATEGORY)); + category_switcher.add (row); + n_rows++; + } + if (popular_apps.size > 0) { + row = new CategoryRow (_(RECENT_CATEGORY)); category_switcher.add (row); n_rows++; } @@ -246,10 +290,10 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { category_switcher.select_row (new_selected ?? category_switcher.get_row_at_index (0)); } - public void update_favorites (string[] favs) { - favorites.clear (); - foreach (string app_id in favs) { - favorites.add (app_id); + public void update_pinned (string[] pinned_apps) { + pinned.clear (); + foreach (string app_id in pinned_apps) { + pinned.add (app_id); } setup_sidebar (); @@ -260,8 +304,12 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { private bool filter_function (AppListRow row) { unowned CategoryRow category_row = (CategoryRow) category_switcher.get_selected_row (); if (category_row != null) { - if (category_row.cat_name == _(FAVORITE_CATEGORY)) { - return favorites.contains (row.app_id); + if (category_row.cat_name == _(PINNED_CATEGORY)) { + return pinned.contains (row.app_id); + } + + if (category_row.cat_name == _(RECENT_CATEGORY)) { + return popular_apps.contains (row.app_id); } foreach (Backend.App app in view.app_system.apps[category_row.cat_name]) { diff --git a/src/Widgets/AppListRow.vala b/src/Widgets/AppListRow.vala index 9cf303586..f891d4845 100644 --- a/src/Widgets/AppListRow.vala +++ b/src/Widgets/AppListRow.vala @@ -19,13 +19,16 @@ public class AppListRow : Gtk.ListBoxRow { public string app_id { get; construct; } + public string display_name { get; construct; } + public int popularity { get; construct; } public string desktop_path { get; construct; } public GLib.DesktopAppInfo app_info { get; private set; } - public AppListRow (string app_id, string desktop_path) { + public AppListRow (string app_id, string desktop_path, int popularity) { Object ( app_id: app_id, - desktop_path: desktop_path + desktop_path: desktop_path, + popularity: popularity ); } @@ -42,7 +45,8 @@ public class AppListRow : Gtk.ListBoxRow { image.gicon = icon; image.pixel_size = 32; - var name_label = new Gtk.Label (app_info.get_display_name ()); + display_name = app_info.get_display_name () + " " + popularity.to_string (); + var name_label = new Gtk.Label (display_name); name_label.set_ellipsize (Pango.EllipsizeMode.END); name_label.xalign = 0; From 82634e3b30b0ec1663c4a1dee94703ff7fdd2b64 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Fri, 10 Jan 2025 18:06:39 +0000 Subject: [PATCH 6/7] Sort Recent/Pinned category first, prefer Recent over Pinned, init properly --- src/Indicator.vala | 12 +++-- src/SlingshotView.vala | 8 ++-- src/Views/CategoryView.vala | 93 +++++++++++++++++++++---------------- src/Widgets/AppListRow.vala | 2 +- 4 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index 419e9a1c0..92b7dacda 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -75,13 +75,18 @@ public class Slingshot.Indicator : Wingpanel.Indicator { if (dock_settings != null) { dock_settings.changed.connect ((key) => { if (key == "launchers") { - view.update_pinned (dock_settings.get_strv ("launchers")); + view.update (dock_settings.get_strv ("launchers")); } }); - view.update_pinned (dock_settings.get_strv ("launchers")); } } + // Wait for AppSystem to initialize + Idle.add (() => { + view.update (dock_settings != null ? dock_settings.get_strv ("launchers") : null); + return Source.REMOVE; + }); + return view; } @@ -120,8 +125,9 @@ public class Slingshot.Indicator : Wingpanel.Indicator { } public override void opened () { - if (view != null) + if (view != null) { view.show_slingshot (); + } } public override void closed () { diff --git a/src/SlingshotView.vala b/src/SlingshotView.vala index 598dad349..436c00423 100644 --- a/src/SlingshotView.vala +++ b/src/SlingshotView.vala @@ -159,13 +159,12 @@ public class Slingshot.SlingshotView : Gtk.Grid, UnityClient { // Auto-update applications grid app_system.changed.connect (() => { grid_view.populate (app_system); - - category_view.setup_sidebar (); + category_view.update (null); }); } - public void update_pinned (string[] pinned) { - category_view.update_pinned (pinned); + public void update (string[] pinned) { + category_view.update (pinned); } public void update_launcher_entry (string sender_name, GLib.Variant parameters, bool is_retry = false) { @@ -327,6 +326,7 @@ public class Slingshot.SlingshotView : Gtk.Grid, UnityClient { public void show_slingshot () { search_entry.text = ""; + category_view.update (null); /* TODO set_focus (null); diff --git a/src/Views/CategoryView.vala b/src/Views/CategoryView.vala index b113e43ad..59b9fd983 100644 --- a/src/Views/CategoryView.vala +++ b/src/Views/CategoryView.vala @@ -31,11 +31,8 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { private NavListBox category_switcher; private NavListBox listbox; private Gee.ArrayList pinned; - private bool show_pinned = false; - -#if HAVE_ZEITGEIST + private bool show_pinned = true; private Gee.ArrayList popular_apps; -#endif private const Gtk.TargetEntry DND = { "text/uri-list", 0, 0 }; public CategoryView (SlingshotView view) { @@ -46,9 +43,10 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { set_visible_window (false); hexpand = true; + popular_apps = new Gee.ArrayList (); pinned = new Gee.ArrayList (); #if HAVE_ZEITGEIST - popular_apps = new Gee.ArrayList (); + show_pinned = false; #endif category_switcher = new NavListBox (); category_switcher.selection_mode = Gtk.SelectionMode.BROWSE; @@ -80,7 +78,7 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { add (container); category_switcher.row_selected.connect ((row) => { - if (((CategoryRow) row).cat_name == _(RECENT_CATEGORY)) { + if (row != null && ((CategoryRow) row).cat_name == _(RECENT_CATEGORY)) { listbox.set_sort_func ((Gtk.ListBoxSortFunc) recent_sort_func); } else { listbox.set_sort_func (null); @@ -170,6 +168,14 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { } private static int category_sort_func (CategoryRow row1, CategoryRow row2) { + if (row1.cat_name == _(RECENT_CATEGORY)) { + return -1; + } + + if (row1.cat_name == _(PINNED_CATEGORY)) { + return row2.cat_name != _(RECENT_CATEGORY) ? -1 : 1; + } + return row1.cat_name.collate (row2.cat_name); } @@ -220,7 +226,7 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { } } - public void setup_sidebar () { + private CategoryRow? setup_sidebar () { CategoryRow? old_selected = (CategoryRow) category_switcher.get_selected_row (); foreach (unowned Gtk.Widget child in category_switcher.get_children ()) { child.destroy (); @@ -232,37 +238,24 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { listbox.add (new AppListRow (app.desktop_id, app.desktop_path, app.popularity)); } -#if HAVE_ZEITGEIST - popular_apps.clear (); - var popularity = view.app_system.get_apps_by_popularity (); - int found = 0; - uint index = 0; - uint limit = popularity.length (); - while (found < N_POPULAR && index < limit) { - var app = popularity.nth_data (index); - if (app.popularity > MIN_POPULARITY) { - popular_apps.add (app.desktop_id); - found++; - } - - index++; - } -#endif listbox.show_all (); // Fill the sidebar - unowned Gtk.ListBoxRow? new_selected = null; - CategoryRow row; - // Add pinned category if there are any pinned apps + CategoryRow? new_selected = null; + CategoryRow? recent_row = null; + CategoryRow? pinned_row = null; int n_rows = 0; - if (pinned.size > 0) { - row = new CategoryRow (_(PINNED_CATEGORY)); - category_switcher.add (row); + + // Add pinned/recent category if there are any pinned/recent apps + if (popular_apps.size > 0) { + recent_row = new CategoryRow (_(RECENT_CATEGORY)); + category_switcher.add (recent_row); n_rows++; } - if (popular_apps.size > 0) { - row = new CategoryRow (_(RECENT_CATEGORY)); - category_switcher.add (row); + + if (pinned.size > 0) { + pinned_row = new CategoryRow (_(PINNED_CATEGORY)); + category_switcher.add (pinned_row); n_rows++; } @@ -271,14 +264,14 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { continue; } - row = new CategoryRow (cat_name); + var row = new CategoryRow (cat_name); category_switcher.add (row); n_rows++; } if (old_selected != null) { for (int i = 0; i < n_rows; i++) { - row = (CategoryRow) category_switcher.get_row_at_index (i); + var row = (CategoryRow) category_switcher.get_row_at_index (i); if (old_selected.cat_name == row.cat_name) { new_selected = row; break; @@ -287,17 +280,37 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { } category_switcher.show_all (); - category_switcher.select_row (new_selected ?? category_switcher.get_row_at_index (0)); + return new_selected ?? (recent_row ?? pinned_row); } - public void update_pinned (string[] pinned_apps) { - pinned.clear (); - foreach (string app_id in pinned_apps) { - pinned.add (app_id); + public void update (string[]? pinned_apps) { + if (pinned_apps != null && show_pinned) { + pinned.clear (); + foreach (string app_id in pinned_apps) { + pinned.add (app_id); + } } - setup_sidebar (); +#if HAVE_ZEITGEIST + popular_apps.clear (); + var popularity = view.app_system.get_apps_by_popularity (); + int found = 0; + uint index = 0; + uint limit = popularity.length (); + while (found < N_POPULAR && index < limit) { + var app = popularity.nth_data (index); + if (app.popularity >= MIN_POPULARITY) { + popular_apps.add (app.desktop_id); + found++; + } + + index++; + } +#endif + var selected = setup_sidebar (); listbox.invalidate_filter (); + listbox.invalidate_sort (); + category_switcher.select_row (selected); } [CCode (instance_pos = -1)] diff --git a/src/Widgets/AppListRow.vala b/src/Widgets/AppListRow.vala index f891d4845..777e196c8 100644 --- a/src/Widgets/AppListRow.vala +++ b/src/Widgets/AppListRow.vala @@ -45,7 +45,7 @@ public class AppListRow : Gtk.ListBoxRow { image.gicon = icon; image.pixel_size = 32; - display_name = app_info.get_display_name () + " " + popularity.to_string (); + display_name = app_info.get_display_name (); var name_label = new Gtk.Label (display_name); name_label.set_ellipsize (Pango.EllipsizeMode.END); name_label.xalign = 0; From 6a5800b48a31f423a75d0343a1d6b7e9872f9371 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Fri, 10 Jan 2025 19:35:13 +0000 Subject: [PATCH 7/7] Fix keeping recent up to date --- src/Backend/AppSystem.vala | 8 ++++- src/Backend/RelevancyService.vala | 15 +++++---- src/Indicator.vala | 56 ++++++++++++++++--------------- src/Views/CategoryView.vala | 33 ++++++++---------- src/Widgets/AppListRow.vala | 21 ++++++------ 5 files changed, 69 insertions(+), 64 deletions(-) diff --git a/src/Backend/AppSystem.vala b/src/Backend/AppSystem.vala index 58938abf8..de9dc79e8 100644 --- a/src/Backend/AppSystem.vala +++ b/src/Backend/AppSystem.vala @@ -63,13 +63,19 @@ public class Slingshot.Backend.AppSystem : Object { private void update_app_system () { debug ("Updating Applications menu tree…"); #if HAVE_ZEITGEIST - rl_service.refresh_popularity (); + rl_service.refresh_popularity.begin (); #endif update_categories_index (); changed (); } + public async void update_popularities () { +#if HAVE_ZEITGEIST + yield rl_service.refresh_popularity (); +#endif + } + private void update_categories_index () { categories_cache.clear (); diff --git a/src/Backend/RelevancyService.vala b/src/Backend/RelevancyService.vala index d127f3d15..36882d0fc 100644 --- a/src/Backend/RelevancyService.vala +++ b/src/Backend/RelevancyService.vala @@ -33,10 +33,13 @@ public class Slingshot.Backend.RelevancyService : Object { zg_log = new Zeitgeist.Log (); app_popularity = new Gee.HashMap (); - refresh_popularity (); + refresh_popularity.begin (); check_data_sources.begin (); - Timeout.add_seconds (60*30, refresh_popularity); + Timeout.add_seconds (60*30, () => { + refresh_popularity.begin (); + return Source.CONTINUE; + }); } @@ -62,12 +65,12 @@ public class Slingshot.Backend.RelevancyService : Object { } } - public bool refresh_popularity () { - - load_application_relevancies.begin (); + public async bool refresh_popularity () { + yield load_application_relevancies (); return true; } + private void reload_relevancies () { Idle.add_full (Priority.LOW, () => { @@ -122,7 +125,7 @@ public class Slingshot.Backend.RelevancyService : Object { Zeitgeist.Subject s = e.get_subject (0); - // Simply use the (inverted) order of the app in the result set as + // Simply use the (inverted) order of the app in the result set as // measure of popularity for now. Suffices for the applications menu. app_popularity[s.uri] = (int) (size - index); index++; diff --git a/src/Indicator.vala b/src/Indicator.vala index 92b7dacda..218c1a06c 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -60,33 +60,6 @@ public class Slingshot.Indicator : Wingpanel.Indicator { } public override Gtk.Widget? get_widget () { - if (view == null) { - view = new SlingshotView (); - - unowned var unity_client = Unity.get_default (); - unity_client.add_client (view); - - view.close_indicator.connect (on_close_indicator); - - if (dbus_service == null) { - dbus_service = new DBusService (view); - } - - if (dock_settings != null) { - dock_settings.changed.connect ((key) => { - if (key == "launchers") { - view.update (dock_settings.get_strv ("launchers")); - } - }); - } - } - - // Wait for AppSystem to initialize - Idle.add (() => { - view.update (dock_settings != null ? dock_settings.get_strv ("launchers") : null); - return Source.REMOVE; - }); - return view; } @@ -121,6 +94,35 @@ public class Slingshot.Indicator : Wingpanel.Indicator { visible = true; + // Create the view now so that there is time for app popularities to initialise + // before the view is shown for the first time. + if (view == null) { + view = new SlingshotView (); + + unowned var unity_client = Unity.get_default (); + unity_client.add_client (view); + + view.close_indicator.connect (on_close_indicator); + + if (dbus_service == null) { + dbus_service = new DBusService (view); + } + + if (dock_settings != null) { + dock_settings.changed.connect ((key) => { + if (key == "launchers") { + view.update (dock_settings.get_strv ("launchers")); + } + }); + } + } + + // Wait for AppSystem to initialize + Idle.add (() => { + view.update (dock_settings != null ? dock_settings.get_strv ("launchers") : null); + return Source.REMOVE; + }); + return indicator_grid; } diff --git a/src/Views/CategoryView.vala b/src/Views/CategoryView.vala index 59b9fd983..bd93ab477 100644 --- a/src/Views/CategoryView.vala +++ b/src/Views/CategoryView.vala @@ -21,7 +21,6 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { public const string PINNED_CATEGORY = N_("Pinned"); public const string RECENT_CATEGORY = N_("Recent"); - public const int N_POPULAR = 12; public const double MIN_POPULARITY = 1; public SlingshotView view { get; construct; } @@ -138,7 +137,7 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { var drag_item = (AppListRow) selected_row; drag_uri = "file://" + drag_item.desktop_path; if (drag_uri != null) { - Gtk.drag_set_icon_gicon (ctx, drag_item.app_info.get_icon (), 32, 32); + Gtk.drag_set_icon_gicon (ctx, drag_item.icon, 32, 32); } view.close_indicator (); @@ -235,7 +234,7 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { listbox.foreach ((app_list_row) => listbox.remove (app_list_row)); foreach (unowned Backend.App app in view.app_system.get_apps_by_name ()) { - listbox.add (new AppListRow (app.desktop_id, app.desktop_path, app.popularity)); + listbox.add (new AppListRow (app)); } listbox.show_all (); @@ -245,7 +244,6 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { CategoryRow? recent_row = null; CategoryRow? pinned_row = null; int n_rows = 0; - // Add pinned/recent category if there are any pinned/recent apps if (popular_apps.size > 0) { recent_row = new CategoryRow (_(RECENT_CATEGORY)); @@ -292,25 +290,22 @@ public class Slingshot.Widgets.CategoryView : Gtk.EventBox { } #if HAVE_ZEITGEIST - popular_apps.clear (); - var popularity = view.app_system.get_apps_by_popularity (); - int found = 0; - uint index = 0; - uint limit = popularity.length (); - while (found < N_POPULAR && index < limit) { - var app = popularity.nth_data (index); - if (app.popularity >= MIN_POPULARITY) { + view.app_system.update_popularities.begin ((obj, res) => { + view.app_system.update_popularities.end (res); + popular_apps.clear (); + var popularity = view.app_system.get_apps_by_popularity (); + popularity.@foreach ((app) => { popular_apps.add (app.desktop_id); - found++; - } - - index++; - } + }); + // Any new entries will not appear until next showing, but + // at lease resort the existing entries. + listbox.invalidate_filter (); + listbox.invalidate_sort (); + }); #endif var selected = setup_sidebar (); - listbox.invalidate_filter (); - listbox.invalidate_sort (); category_switcher.select_row (selected); + } [CCode (instance_pos = -1)] diff --git a/src/Widgets/AppListRow.vala b/src/Widgets/AppListRow.vala index 777e196c8..94a373e19 100644 --- a/src/Widgets/AppListRow.vala +++ b/src/Widgets/AppListRow.vala @@ -17,24 +17,23 @@ * Boston, MA 02110-1301 USA. */ -public class AppListRow : Gtk.ListBoxRow { - public string app_id { get; construct; } - public string display_name { get; construct; } - public int popularity { get; construct; } - public string desktop_path { get; construct; } - public GLib.DesktopAppInfo app_info { get; private set; } +public class Slingshot.AppListRow : Gtk.ListBoxRow { + public Backend.App app {get; construct; } + public string app_id { get { return app.desktop_id; }} + public int popularity { get { return app.popularity; }} + public string desktop_path { get { return app.desktop_path; }} + public string display_name { get; private set; } + public Icon icon { get { return app_info.get_icon (); }} + private GLib.DesktopAppInfo app_info; - public AppListRow (string app_id, string desktop_path, int popularity) { + public AppListRow (Backend.App app) { Object ( - app_id: app_id, - desktop_path: desktop_path, - popularity: popularity + app: app ); } construct { app_info = new GLib.DesktopAppInfo (app_id); - var icon = app_info.get_icon (); weak Gtk.IconTheme theme = Gtk.IconTheme.get_default (); if (icon == null || theme.lookup_by_gicon (icon, 32, Gtk.IconLookupFlags.USE_BUILTIN) == null) {