From fe1fb09904581138c3394459f51049f8eda8e623 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 12 May 2023 19:37:43 +0200 Subject: [PATCH 01/37] Prototype background portal --- data/pantheon.portal | 2 +- src/Background/Portal.vala | 140 ++++++++++++++++++++++++++++++ src/XdgDesktopPortalPantheon.vala | 3 + src/meson.build | 1 + 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/Background/Portal.vala diff --git a/data/pantheon.portal b/data/pantheon.portal index b22a995f..64dffdf3 100644 --- a/data/pantheon.portal +++ b/data/pantheon.portal @@ -1,4 +1,4 @@ [portal] DBusName=org.freedesktop.impl.portal.desktop.pantheon -Interfaces=org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.AppChooser; +Interfaces=org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.AppChooser;org.freedesktop.impl.portal.Background; UseIn=pantheon diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala new file mode 100644 index 00000000..50d55d10 --- /dev/null +++ b/src/Background/Portal.vala @@ -0,0 +1,140 @@ +/* + * SPDX-FileCopyrigthText: 2021 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +[DBus (name = "org.freedesktop.impl.portal.Background")] +public class Background.Portal : Object { + public signal void running_applications_changed (); + + private const string ACTION_ALLOW_BACKGROUND = "allow"; + private const string ACTION_FORBID_BACKGROUND = "forbid"; + + private DBusConnection connection; + private DesktopIntegration desktop_integration; + + public Portal (DBusConnection connection) { + this.connection = connection; + } + + [DBus(name = "org.pantheon.gala.DesktopIntegration")] + public interface DesktopIntegration : GLib.Object { + [DBus(name = "GetRunningApplications")] + public abstract GLib.ObjectPath get_running_applications (out RunningApplication[] running_apps) throws DBusError, IOError; + [DBus(name = "RunningApplicationsChanged")] + public abstract signal void integration_running_applications_changed (); + } + + construct { + try { + desktop_integration = Bus.get_proxy_sync (BusType.SESSION, "org.pantheon.gala", "/org/pantheon/gala/DesktopInterface"); + desktop_integration.integration_running_applications_changed.connect (() => running_applications_changed ()); + } catch (Error e) { + critical (e.message); + } + } + + public struct RunningApplication { + string app_id; + GLib.HashTable details; + } + + public void get_app_state (out HashTable apps) throws DBusError, IOError { + apps = new HashTable (str_hash, str_equal); + + try { + RunningApplication[] result = {}; + desktop_integration.get_running_applications (out result); + for (int i = 0; i < result.length; i++) { + apps.set (result[i].app_id, 1); + } + } catch (Error e) { + critical (e.message); + } + } + + public async void notify_background ( + ObjectPath handle, + string app_id, + string name, + out uint32 response, + out HashTable results + ) throws DBusError, IOError { + var notification = new Notification (_("Background activity")); + notification.set_body (_(""""%s" is running in the background""").printf (name)); + notification.add_button (_("Allow"), ACTION_ALLOW_BACKGROUND); + notification.add_button (_("Forbid"), ACTION_FORBID_BACKGROUND); + + unowned var application = GLib.Application.get_default (); + application.send_notification ("id", notification); + + results = new HashTable (str_hash, str_equal); + + yield; + } + + private enum AutostartFlags { + AUTOSTART_FLAGS_NONE = 0, + AUTOSTART_FLAGS_ACTIVATABLE = 1 + } + + public void enable_autostart ( + string app_id, + bool enable, + string[] commandline, + uint32 flags, + out bool result + ) throws DBusError, IOError { + print ("enable_autostart\n"); + result = false; + string file_name = app_id + ".desktop"; + string directory = Path.build_filename (Environment.get_user_config_dir (), "autostart"); + string full_path = Path.build_filename (directory, file_name); + + if (!enable) { + FileUtils.unlink (full_path); + return; + } + + var autostart_flags = (AutostartFlags) flags; + + var key_file = new KeyFile (); + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_TYPE, "Application"); + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME, app_id); + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_EXEC, flatpak_quote_argv (commandline)); + if (autostart_flags == AUTOSTART_FLAGS_ACTIVATABLE) { + key_file.set_boolean (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_DBUS_ACTIVATABLE, true); + } + key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id + "hahaha it owkrw !!!!"); + + try { + key_file.save_to_file (full_path); + } catch (Error e) { + critical (e.message); + return; + } + + result = true; + } + + private string flatpak_quote_argv (string[] argv) { + var builder = new StringBuilder (); + + for (int i = 0; i < argv.length; i++) { + var str = argv[i]; + for (int j = 0; i < str.length; j++) { + char c = str[j]; + if (!c.isalnum() && + !(c == '-' || c == '/' || c == '~' || + c == ':' || c == '.' || c == '_' || + c == '=' || c == '@')) { + str = Shell.quote (str); + break; + } + } + builder.append (str); + } + + return builder.str; + } +} diff --git a/src/XdgDesktopPortalPantheon.vala b/src/XdgDesktopPortalPantheon.vala index e0af6142..56faed74 100644 --- a/src/XdgDesktopPortalPantheon.vala +++ b/src/XdgDesktopPortalPantheon.vala @@ -37,6 +37,9 @@ private void on_bus_acquired (DBusConnection connection, string name) { connection.register_object ("/org/freedesktop/portal/desktop", new AppChooser.Portal (connection)); debug ("AppChooser Portal registered!"); + + connection.register_object ("/org/freedesktop/portal/desktop", new Background.Portal (connection)); + debug ("Background Portal registered!"); } catch (Error e) { critical ("Unable to register the object: %s", e.message); } diff --git a/src/meson.build b/src/meson.build index e2b14b34..63269b84 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,6 +6,7 @@ executable( 'AppChooser/AppButton.vala', 'AppChooser/Dialog.vala', 'AppChooser/Portal.vala', + 'Background/Portal.vala', configure_file(input: 'Config.vala.in', output: '@BASENAME@', configuration: conf_data), 'ExternalWindow.vala', 'XdgDesktopPortalPantheon.vala', From 913c89548684d65c5d6022a49fae28cb3b4bb0bd Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 12 May 2023 20:07:50 +0200 Subject: [PATCH 02/37] Minor fixes --- src/Background/Portal.vala | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 50d55d10..bc9c8625 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -105,7 +105,7 @@ public class Background.Portal : Object { if (autostart_flags == AUTOSTART_FLAGS_ACTIVATABLE) { key_file.set_boolean (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_DBUS_ACTIVATABLE, true); } - key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id + "hahaha it owkrw !!!!"); + key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id); try { key_file.save_to_file (full_path); @@ -121,10 +121,16 @@ public class Background.Portal : Object { var builder = new StringBuilder (); for (int i = 0; i < argv.length; i++) { + if (i != 0) { + builder.append (" "); + } + var str = argv[i]; - for (int j = 0; i < str.length; j++) { - char c = str[j]; - if (!c.isalnum() && + + for (int j = 1; i <= str.length; j++) { + int index = str.index_of_nth_char (j); + unichar c = str.get_char (index); + if (!c.isalnum () && !(c == '-' || c == '/' || c == '~' || c == ':' || c == '.' || c == '_' || c == '=' || c == '@')) { @@ -132,6 +138,7 @@ public class Background.Portal : Object { break; } } + builder.append (str); } From dccd199616d529b8440535d1d1fa09b70c7c971f Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 12 May 2023 21:08:09 +0200 Subject: [PATCH 03/37] Cleanup --- src/Background/Portal.vala | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index bc9c8625..2f24a18b 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -17,6 +17,11 @@ public class Background.Portal : Object { this.connection = connection; } + public struct RunningApplication { + string app_id; + GLib.HashTable details; + } + [DBus(name = "org.pantheon.gala.DesktopIntegration")] public interface DesktopIntegration : GLib.Object { [DBus(name = "GetRunningApplications")] @@ -34,11 +39,6 @@ public class Background.Portal : Object { } } - public struct RunningApplication { - string app_id; - GLib.HashTable details; - } - public void get_app_state (out HashTable apps) throws DBusError, IOError { apps = new HashTable (str_hash, str_equal); @@ -70,7 +70,11 @@ public class Background.Portal : Object { results = new HashTable (str_hash, str_equal); + //TODO + yield; + + //TODO } private enum AutostartFlags { @@ -85,7 +89,6 @@ public class Background.Portal : Object { uint32 flags, out bool result ) throws DBusError, IOError { - print ("enable_autostart\n"); result = false; string file_name = app_id + ".desktop"; string directory = Path.build_filename (Environment.get_user_config_dir (), "autostart"); @@ -127,9 +130,8 @@ public class Background.Portal : Object { var str = argv[i]; - for (int j = 1; i <= str.length; j++) { - int index = str.index_of_nth_char (j); - unichar c = str.get_char (index); + for (int j = 0; i < str.char_count (); j++) { + char c = str.get (str.index_of_nth_char (j)); if (!c.isalnum () && !(c == '-' || c == '/' || c == '~' || c == ':' || c == '.' || c == '_' || From dbb9c9383d87177d5e8b9165a62a6c8fafb576cb Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 12 May 2023 22:31:32 +0200 Subject: [PATCH 04/37] Add fixmes --- src/Background/Portal.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 2f24a18b..fc5ee460 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -46,7 +46,7 @@ public class Background.Portal : Object { RunningApplication[] result = {}; desktop_integration.get_running_applications (out result); for (int i = 0; i < result.length; i++) { - apps.set (result[i].app_id, 1); + apps.set (result[i].app_id, 1); //FIXME: Don't hardcode } } catch (Error e) { critical (e.message); @@ -130,7 +130,7 @@ public class Background.Portal : Object { var str = argv[i]; - for (int j = 0; i < str.char_count (); j++) { + for (int j = 0; i < str.char_count (); j++) { //FIXME char c = str.get (str.index_of_nth_char (j)); if (!c.isalnum () && !(c == '-' || c == '/' || c == '~' || From 293c4e45c1cae1b31fb9ae069e917c81e5f9c1c5 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 12 May 2023 22:48:22 +0200 Subject: [PATCH 05/37] Fix lint --- src/Background/Portal.vala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index fc5ee460..2e5a34a3 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -22,11 +22,11 @@ public class Background.Portal : Object { GLib.HashTable details; } - [DBus(name = "org.pantheon.gala.DesktopIntegration")] + [DBus (name = "org.pantheon.gala.DesktopIntegration")] public interface DesktopIntegration : GLib.Object { - [DBus(name = "GetRunningApplications")] + [DBus (name = "GetRunningApplications")] public abstract GLib.ObjectPath get_running_applications (out RunningApplication[] running_apps) throws DBusError, IOError; - [DBus(name = "RunningApplicationsChanged")] + [DBus (name = "RunningApplicationsChanged")] public abstract signal void integration_running_applications_changed (); } From 884429cdca2abac7fecd35f0b96a67511cfc83d8 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sat, 13 May 2023 14:25:07 +0200 Subject: [PATCH 06/37] Fix criticals, implement NotifyBackground --- meson.build | 1 + src/Background/Portal.vala | 45 +++++++++++++++++++++---------- src/XdgDesktopPortalPantheon.vala | 1 + src/meson.build | 1 + 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index 1f548f98..2f571f3c 100644 --- a/meson.build +++ b/meson.build @@ -13,6 +13,7 @@ glib_dep = dependency('glib-2.0') gobject_dep = dependency('gobject-2.0') gio_dep = dependency('gio-2.0') granite_dep = dependency('granite-7') +notify_dep = dependency('libnotify') gtk_deps = [ dependency('gtk4') diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 2e5a34a3..35521fa9 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -7,8 +7,8 @@ public class Background.Portal : Object { public signal void running_applications_changed (); - private const string ACTION_ALLOW_BACKGROUND = "allow"; - private const string ACTION_FORBID_BACKGROUND = "forbid"; + private const string ACTION_ALLOW_BACKGROUND = "background.allow"; + private const string ACTION_FORBID_BACKGROUND = "background.forbid"; private DBusConnection connection; private DesktopIntegration desktop_integration; @@ -24,10 +24,10 @@ public class Background.Portal : Object { [DBus (name = "org.pantheon.gala.DesktopIntegration")] public interface DesktopIntegration : GLib.Object { - [DBus (name = "GetRunningApplications")] - public abstract GLib.ObjectPath get_running_applications (out RunningApplication[] running_apps) throws DBusError, IOError; [DBus (name = "RunningApplicationsChanged")] public abstract signal void integration_running_applications_changed (); + [DBus (name = "GetRunningApplications")] + public abstract void get_running_applications (out RunningApplication[] running_apps) throws DBusError, IOError; } construct { @@ -60,21 +60,38 @@ public class Background.Portal : Object { out uint32 response, out HashTable results ) throws DBusError, IOError { - var notification = new Notification (_("Background activity")); - notification.set_body (_(""""%s" is running in the background""").printf (name)); - notification.add_button (_("Allow"), ACTION_ALLOW_BACKGROUND); - notification.add_button (_("Forbid"), ACTION_FORBID_BACKGROUND); + var _results = new HashTable (str_hash, str_equal); - unowned var application = GLib.Application.get_default (); - application.send_notification ("id", notification); + var notification = new Notify.Notification ( + _("Background activity"), + _(""""%s" is running in the background""").printf (name), + "dialog-information" + ); - results = new HashTable (str_hash, str_equal); + notification.add_action (ACTION_ALLOW_BACKGROUND, _("Allow"), () => { + _results.set ("result", 1); + notify_background.callback (); + }); - //TODO + notification.add_action (ACTION_FORBID_BACKGROUND, _("Forbid"), () => { + _results.set ("result", 0); + notify_background.callback (); + }); - yield; + notification.closed.connect (() => { + _results.set ("result", 2); + notify_background.callback (); + }); + + try { + notification.show (); + } catch (Error e) { + critical ("Failed to send background notification for %s: %s", app_id, e.message); + } - //TODO + yield; + response = 0; + results = _results; } private enum AutostartFlags { diff --git a/src/XdgDesktopPortalPantheon.vala b/src/XdgDesktopPortalPantheon.vala index 56faed74..00bb07b8 100644 --- a/src/XdgDesktopPortalPantheon.vala +++ b/src/XdgDesktopPortalPantheon.vala @@ -79,6 +79,7 @@ int main (string[] args) { GLib.Environment.unset_variable ("GTK_USE_PORTAL"); Gtk.init (); + Notify.init ("xdg-desktop-portal"); try { var opt_context = new OptionContext ("- portal backends"); diff --git a/src/meson.build b/src/meson.build index 63269b84..5d3c400b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,6 +16,7 @@ executable( gio_dep, granite_dep, gtk_deps, + notify_dep, x11_dep ], install: true, From d01480bd6626e97e3b3304478f1833712072e256 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sat, 13 May 2023 14:57:14 +0200 Subject: [PATCH 07/37] Update ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 232b577b..c1d187ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y libgranite-7-dev libgtk-4-dev meson valac + apt install -y libgranite-7-dev libgtk-4-dev libnotify-dev meson valac - name: Build run: | meson build From 70aba7bf8ac0de831654c7b8994e0153d15f7c74 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 14 May 2023 18:03:17 +0200 Subject: [PATCH 08/37] Fix quoting of args that don't need quoting --- src/Background/Portal.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 35521fa9..e1aad06f 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -147,7 +147,7 @@ public class Background.Portal : Object { var str = argv[i]; - for (int j = 0; i < str.char_count (); j++) { //FIXME + for (int j = 0; j < str.char_count (); j++) { //FIXME char c = str.get (str.index_of_nth_char (j)); if (!c.isalnum () && !(c == '-' || c == '/' || c == '~' || From 90d7d8aced2004e6ab86bd2a3e19e8529377700a Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 14 May 2023 18:51:48 +0200 Subject: [PATCH 09/37] Use first commandline arg as app_id if it is empty --- src/Background/Portal.vala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index e1aad06f..07fb4251 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -107,6 +107,22 @@ public class Background.Portal : Object { out bool result ) throws DBusError, IOError { result = false; + + /* If the portal request is made by a non-flatpaked application app_id will most of the time be empty */ + if (app_id.strip () == "") { + /* Usually we can then asume that the first commandline arg is the app_id + but just to be sure we only do this with our own (io.elementary.APP) ones. + The reason we do this at all are primarily mail, calendar and tasks, which need to autostart + but currently can't be shipped as flatpaks, so this is useful to not have to care about that stuff + in the respective apps and even allow user intervention */ + if (commandline[0].contains ("io.elementary.")) { + app_id = commandline[0]; + print (app_id); + } else { + return; + } + } + string file_name = app_id + ".desktop"; string directory = Path.build_filename (Environment.get_user_config_dir (), "autostart"); string full_path = Path.build_filename (directory, file_name); From 030d0769b9a2827d26f01473f5bbf5262bbc3807 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 14 May 2023 19:18:42 +0200 Subject: [PATCH 10/37] Cleanup, use enums --- src/Background/Portal.vala | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 07fb4251..55894d6b 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -39,6 +39,12 @@ public class Background.Portal : Object { } } + private enum WindowState { + BACKGROUND = 0, //No open window + RUNNING = 1, //At least one open window + ACTIVE = 2 //In the foreground + } + public void get_app_state (out HashTable apps) throws DBusError, IOError { apps = new HashTable (str_hash, str_equal); @@ -46,13 +52,19 @@ public class Background.Portal : Object { RunningApplication[] result = {}; desktop_integration.get_running_applications (out result); for (int i = 0; i < result.length; i++) { - apps.set (result[i].app_id, 1); //FIXME: Don't hardcode + apps.set (result[i].app_id, WindowState.RUNNING); //FIXME: Don't hardcode: needs implementation on the gala side } } catch (Error e) { critical (e.message); } } + private enum NotifyBackgroundResult { + FORBID = 0, + ALLOW = 1, + ALLOW_ONCE = 2 + } + public async void notify_background ( ObjectPath handle, string app_id, @@ -69,17 +81,17 @@ public class Background.Portal : Object { ); notification.add_action (ACTION_ALLOW_BACKGROUND, _("Allow"), () => { - _results.set ("result", 1); + _results.set ("result", NotifyBackgroundResult.ALLOW); notify_background.callback (); }); notification.add_action (ACTION_FORBID_BACKGROUND, _("Forbid"), () => { - _results.set ("result", 0); + _results.set ("result", NotifyBackgroundResult.FORBID); notify_background.callback (); }); notification.closed.connect (() => { - _results.set ("result", 2); + _results.set ("result", NotifyBackgroundResult.ALLOW_ONCE); notify_background.callback (); }); @@ -90,13 +102,14 @@ public class Background.Portal : Object { } yield; - response = 0; + + response = 0; //Won't be used results = _results; } private enum AutostartFlags { AUTOSTART_FLAGS_NONE = 0, - AUTOSTART_FLAGS_ACTIVATABLE = 1 + AUTOSTART_FLAGS_DBUS_ACTIVATABLE = 1 } public void enable_autostart ( @@ -138,7 +151,7 @@ public class Background.Portal : Object { key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_TYPE, "Application"); key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME, app_id); key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_EXEC, flatpak_quote_argv (commandline)); - if (autostart_flags == AUTOSTART_FLAGS_ACTIVATABLE) { + if (autostart_flags == AUTOSTART_FLAGS_DBUS_ACTIVATABLE) { key_file.set_boolean (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_DBUS_ACTIVATABLE, true); } key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id); @@ -163,7 +176,7 @@ public class Background.Portal : Object { var str = argv[i]; - for (int j = 0; j < str.char_count (); j++) { //FIXME + for (int j = 0; j < str.char_count (); j++) { char c = str.get (str.index_of_nth_char (j)); if (!c.isalnum () && !(c == '-' || c == '/' || c == '~' || From 87a5bf5d1c66b334d80fbbc6450b8a24360b3c51 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 14 May 2023 19:20:26 +0200 Subject: [PATCH 11/37] Cleanup --- src/Background/Portal.vala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 55894d6b..34c21193 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -130,7 +130,6 @@ public class Background.Portal : Object { in the respective apps and even allow user intervention */ if (commandline[0].contains ("io.elementary.")) { app_id = commandline[0]; - print (app_id); } else { return; } From bf2613cf7538c11826e6f55c300b387bdf18a00f Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 14 May 2023 19:35:10 +0200 Subject: [PATCH 12/37] Remove .desktop --- src/Background/Portal.vala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 34c21193..616d7350 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -52,7 +52,12 @@ public class Background.Portal : Object { RunningApplication[] result = {}; desktop_integration.get_running_applications (out result); for (int i = 0; i < result.length; i++) { - apps.set (result[i].app_id, WindowState.RUNNING); //FIXME: Don't hardcode: needs implementation on the gala side + var app_id = result[i].app_id.strip (); + if (app_id.has_suffix (".desktop")) { + var index = app_id.last_index_of (".desktop"); + app_id = app_id.slice (0, index); + } + apps.set (app_id, WindowState.RUNNING); //FIXME: Don't hardcode: needs implementation on the gala side } } catch (Error e) { critical (e.message); From 891ea0abbac8aa5704a3f8ab28f2ca7a28178057 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 14 May 2023 19:58:28 +0200 Subject: [PATCH 13/37] Init Notify with xdg-desktop-portal-pantheon --- src/XdgDesktopPortalPantheon.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XdgDesktopPortalPantheon.vala b/src/XdgDesktopPortalPantheon.vala index 00bb07b8..3fb201f7 100644 --- a/src/XdgDesktopPortalPantheon.vala +++ b/src/XdgDesktopPortalPantheon.vala @@ -79,7 +79,7 @@ int main (string[] args) { GLib.Environment.unset_variable ("GTK_USE_PORTAL"); Gtk.init (); - Notify.init ("xdg-desktop-portal"); + Notify.init ("xdg-desktop-portal-pantheon"); try { var opt_context = new OptionContext ("- portal backends"); From 4701a54f5a4934f426fe0c474a805c7c769e8d25 Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Wed, 17 May 2023 15:37:09 +0200 Subject: [PATCH 14/37] Apply suggestions from code review Co-authored-by: Gustavo Marques --- src/Background/Portal.vala | 98 +++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 53 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 616d7350..4da705c2 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrigthText: 2021 elementary, Inc. (https://elementary.io) + * SPDX-FileCopyrightText: 2023 elementary, Inc. (https://elementary.io) * SPDX-License-Identifier: LGPL-2.1-or-later */ @@ -15,19 +15,23 @@ public class Background.Portal : Object { public Portal (DBusConnection connection) { this.connection = connection; - } - - public struct RunningApplication { - string app_id; - GLib.HashTable details; + try { + desktop_integration = connection.get_proxy_sync ("org.pantheon.gala", "/org/pantheon/gala/DesktopInterface"); + desktop_integration.running_applications_changed (() => running_applications_changed ()); + } catch { + warning ("cannot connect to compositor, background portal working with reduced functionality"); + } } [DBus (name = "org.pantheon.gala.DesktopIntegration")] - public interface DesktopIntegration : GLib.Object { - [DBus (name = "RunningApplicationsChanged")] - public abstract signal void integration_running_applications_changed (); - [DBus (name = "GetRunningApplications")] - public abstract void get_running_applications (out RunningApplication[] running_apps) throws DBusError, IOError; + public interface DesktopIntegration : Object { + public struct RunningApplications { + string app_id; + HashTable details; + } + + public signal void running_applications_changed (); + public abstract RunningApplications[] get_running_applications () throws DBusError, IOError; } construct { @@ -39,29 +43,29 @@ public class Background.Portal : Object { } } - private enum WindowState { - BACKGROUND = 0, //No open window - RUNNING = 1, //At least one open window - ACTIVE = 2 //In the foreground + private enum ApplicationState { + BACKGROUND, + RUNNING, + ACTIVE } - public void get_app_state (out HashTable apps) throws DBusError, IOError { - apps = new HashTable (str_hash, str_equal); - - try { - RunningApplication[] result = {}; - desktop_integration.get_running_applications (out result); - for (int i = 0; i < result.length; i++) { - var app_id = result[i].app_id.strip (); - if (app_id.has_suffix (".desktop")) { - var index = app_id.last_index_of (".desktop"); - app_id = app_id.slice (0, index); - } - apps.set (app_id, WindowState.RUNNING); //FIXME: Don't hardcode: needs implementation on the gala side + public HashTable get_app_state () throws DBusError, IOError { + if (desktop_integration == null) { + throw new DBusError.FAILED ("no connection to compositor"); + } + + var apps = desktop_integration.get_running_applications (); + var results = new HashTable (null, null); + foreach (var app in apps) { + var app_id = app.app_id; + if (app_id.has_suffix (".desktop")) { + app_id = app_id.slice (0, app_id.last_index_of_char ('.')); } - } catch (Error e) { - critical (e.message); + + results[app_id] = ApplicationState.RUNNING; //FIXME: Don't hardcode: needs implementation on the gala side } + + return results; } private enum NotifyBackgroundResult { @@ -117,12 +121,11 @@ public class Background.Portal : Object { AUTOSTART_FLAGS_DBUS_ACTIVATABLE = 1 } - public void enable_autostart ( + public bool enable_autostart ( string app_id, bool enable, string[] commandline, - uint32 flags, - out bool result + uint32 flags ) throws DBusError, IOError { result = false; @@ -140,9 +143,7 @@ public class Background.Portal : Object { } } - string file_name = app_id + ".desktop"; - string directory = Path.build_filename (Environment.get_user_config_dir (), "autostart"); - string full_path = Path.build_filename (directory, file_name); + var path = Path.build_filename (Environment.get_user_config_dir (), "autostart", app_id + ".desktop"); if (!enable) { FileUtils.unlink (full_path); @@ -163,7 +164,7 @@ public class Background.Portal : Object { try { key_file.save_to_file (full_path); } catch (Error e) { - critical (e.message); + warning ("failed to write autostart file: %s", e.message); return; } @@ -173,27 +174,18 @@ public class Background.Portal : Object { private string flatpak_quote_argv (string[] argv) { var builder = new StringBuilder (); - for (int i = 0; i < argv.length; i++) { - if (i != 0) { - builder.append (" "); - } - - var str = argv[i]; - - for (int j = 0; j < str.char_count (); j++) { - char c = str.get (str.index_of_nth_char (j)); - if (!c.isalnum () && - !(c == '-' || c == '/' || c == '~' || - c == ':' || c == '.' || c == '_' || - c == '=' || c == '@')) { - str = Shell.quote (str); + foreach (var arg in argv) { + foreach (var c in (char[]) arg.data) { + if (!c.isalnum () && !(c.to_string () in "-/~:._=@")) { + arg = Shell.quote (arg); break; } } - builder.append (str); + builder.append (arg); + builder.append (" "); } - return builder.str; + return builder.str.strip (); } } From a3c2033614e65068b5563b125a7223fc80fd4c0b Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Wed, 17 May 2023 15:42:17 +0200 Subject: [PATCH 15/37] Fix stuff from code review --- src/Background/Portal.vala | 41 ++++++++++++++------------------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 4da705c2..d7423c28 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -17,9 +17,9 @@ public class Background.Portal : Object { this.connection = connection; try { desktop_integration = connection.get_proxy_sync ("org.pantheon.gala", "/org/pantheon/gala/DesktopInterface"); - desktop_integration.running_applications_changed (() => running_applications_changed ()); + desktop_integration.running_applications_changed.connect (() => running_applications_changed ()); } catch { - warning ("cannot connect to compositor, background portal working with reduced functionality"); + warning ("Cannot connect to compositor, background portal working with reduced functionality."); } } @@ -29,20 +29,11 @@ public class Background.Portal : Object { string app_id; HashTable details; } - + public signal void running_applications_changed (); public abstract RunningApplications[] get_running_applications () throws DBusError, IOError; } - construct { - try { - desktop_integration = Bus.get_proxy_sync (BusType.SESSION, "org.pantheon.gala", "/org/pantheon/gala/DesktopInterface"); - desktop_integration.integration_running_applications_changed.connect (() => running_applications_changed ()); - } catch (Error e) { - critical (e.message); - } - } - private enum ApplicationState { BACKGROUND, RUNNING, @@ -51,20 +42,20 @@ public class Background.Portal : Object { public HashTable get_app_state () throws DBusError, IOError { if (desktop_integration == null) { - throw new DBusError.FAILED ("no connection to compositor"); + throw new DBusError.FAILED ("No connection to compositor."); } - + var apps = desktop_integration.get_running_applications (); - var results = new HashTable (null, null); + var results = new HashTable (null, null); foreach (var app in apps) { var app_id = app.app_id; if (app_id.has_suffix (".desktop")) { app_id = app_id.slice (0, app_id.last_index_of_char ('.')); } - + results[app_id] = ApplicationState.RUNNING; //FIXME: Don't hardcode: needs implementation on the gala side } - + return results; } @@ -127,8 +118,6 @@ public class Background.Portal : Object { string[] commandline, uint32 flags ) throws DBusError, IOError { - result = false; - /* If the portal request is made by a non-flatpaked application app_id will most of the time be empty */ if (app_id.strip () == "") { /* Usually we can then asume that the first commandline arg is the app_id @@ -139,15 +128,15 @@ public class Background.Portal : Object { if (commandline[0].contains ("io.elementary.")) { app_id = commandline[0]; } else { - return; + return false; } } var path = Path.build_filename (Environment.get_user_config_dir (), "autostart", app_id + ".desktop"); if (!enable) { - FileUtils.unlink (full_path); - return; + FileUtils.unlink (path); + return false; } var autostart_flags = (AutostartFlags) flags; @@ -162,13 +151,13 @@ public class Background.Portal : Object { key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id); try { - key_file.save_to_file (full_path); + key_file.save_to_file (path); } catch (Error e) { - warning ("failed to write autostart file: %s", e.message); - return; + warning ("Failed to write autostart file: %s", e.message); + return false; } - result = true; + return true; } private string flatpak_quote_argv (string[] argv) { From fc627b4905e88584585bb71a8b822008581b94a4 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Wed, 17 May 2023 15:47:18 +0200 Subject: [PATCH 16/37] Always use first command_line arg as app_id if it is empty --- src/Background/Portal.vala | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index d7423c28..d62ca38a 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -120,12 +120,8 @@ public class Background.Portal : Object { ) throws DBusError, IOError { /* If the portal request is made by a non-flatpaked application app_id will most of the time be empty */ if (app_id.strip () == "") { - /* Usually we can then asume that the first commandline arg is the app_id - but just to be sure we only do this with our own (io.elementary.APP) ones. - The reason we do this at all are primarily mail, calendar and tasks, which need to autostart - but currently can't be shipped as flatpaks, so this is useful to not have to care about that stuff - in the respective apps and even allow user intervention */ - if (commandline[0].contains ("io.elementary.")) { + /* Usually we can then asume that the first commandline arg is the app_id */ + if (commandline[0].strip () != "") { app_id = commandline[0]; } else { return false; From f95c7eeee8bf09fb81969219ca9b45a61ae3b600 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Wed, 17 May 2023 19:26:02 +0200 Subject: [PATCH 17/37] Handle notifications without libnotify --- .github/workflows/ci.yml | 2 +- meson.build | 1 - src/Background/NotificationHandler.vala | 105 ++++++++++++++++++++++++ src/Background/NotificationRequest.vala | 19 +++++ src/Background/Portal.vala | 48 ++++------- src/XdgDesktopPortalPantheon.vala | 1 - src/meson.build | 3 +- 7 files changed, 144 insertions(+), 35 deletions(-) create mode 100644 src/Background/NotificationHandler.vala create mode 100644 src/Background/NotificationRequest.vala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1d187ff..232b577b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y libgranite-7-dev libgtk-4-dev libnotify-dev meson valac + apt install -y libgranite-7-dev libgtk-4-dev meson valac - name: Build run: | meson build diff --git a/meson.build b/meson.build index 2f571f3c..1f548f98 100644 --- a/meson.build +++ b/meson.build @@ -13,7 +13,6 @@ glib_dep = dependency('glib-2.0') gobject_dep = dependency('gobject-2.0') gio_dep = dependency('gio-2.0') granite_dep = dependency('granite-7') -notify_dep = dependency('libnotify') gtk_deps = [ dependency('gtk4') diff --git a/src/Background/NotificationHandler.vala b/src/Background/NotificationHandler.vala new file mode 100644 index 00000000..a5891ef5 --- /dev/null +++ b/src/Background/NotificationHandler.vala @@ -0,0 +1,105 @@ +public class NotificationHandler : Object { + public const string ACTION_ALLOW_BACKGROUND = "background.allow"; + public const string ACTION_FORBID_BACKGROUND = "background.forbid"; + + private DBusConnection connection; + private HashTable id_notification; + private Notifications notifications; + + private enum NotifyBackgroundResult { + FORBID, + ALLOW, + ALLOW_ONCE + } + + [DBus (name = "org.freedesktop.Notifications")] + public interface Notifications : Object { + public signal void action_invoked (uint32 id, string action_key); + public signal void notification_closed (uint32 id, uint32 reason); + + public abstract void close_notification (uint32 id) throws DBusError, IOError; + public abstract uint32 notify ( + string app_name, + uint32 replaces_id, + string app_icon, + string summary, + string body, + string[] actions, + HashTable hints, + int32 expire_timeout + ) throws DBusError, IOError; + } + + public NotificationHandler (DBusConnection connection) { + this.connection = connection; + id_notification = new HashTable (null, null); + + try { + notifications = connection.get_proxy_sync ("org.freedesktop.Notifications", "/org/freedesktop/Notifications"); + notifications.action_invoked.connect (on_action_invoked); + notifications.notification_closed.connect (on_notification_closed); + } catch { + warning ("Cannot connect to notifications dbus, background portal working with reduced functionality."); + } + } + + public NotificationRequest? send_notification (string app_id, string app_name) { + string[] actions = { + ACTION_ALLOW_BACKGROUND, + _("Allow"), + ACTION_FORBID_BACKGROUND, + _("Forbid") + }; + + try { + var id = notifications.notify ( + Environment.get_prgname (), + 0, + "dialog-information", + _("Background activity"), + _(""""%s" is running in the background""").printf (app_name), + actions, + new HashTable (str_hash, str_equal), + 0 + ); + + var notification = new NotificationRequest (this, id); + id_notification.set (id, notification); + + return notification; + } catch (Error e) { + warning ("Failed to send notification for app id '%s': %s", app_id, e.message); + return null; + } + } + + private void on_action_invoked (uint32 id, string action_key) { + if (id in id_notification) { + var notification = id_notification.get (id); + if (action_key == NotificationHandler.ACTION_ALLOW_BACKGROUND) { + notification.response (NotifyBackgroundResult.ALLOW); + } else if (action_key == NotificationHandler.ACTION_FORBID_BACKGROUND) { + notification.response (NotifyBackgroundResult.FORBID); + } + } + } + + private void on_notification_closed (uint32 id, uint32 reason) { + if (id in id_notification) { + var notification = id_notification.get (id); + if (reason == 2 || reason == 3) { + notification.response (NotifyBackgroundResult.ALLOW_ONCE); + } + } + } + + public void close_notification (uint32 id) { + try { + notifications.close_notification (id); + } catch (Error e) { + warning ("Failed to close notification with id '%u': %s", id, e.message); + } + + id_notification.remove (id); + } +} diff --git a/src/Background/NotificationRequest.vala b/src/Background/NotificationRequest.vala new file mode 100644 index 00000000..94a7c08e --- /dev/null +++ b/src/Background/NotificationRequest.vala @@ -0,0 +1,19 @@ +[DBus (name = "org.freedesktop.impl.portal.Request")] +public class NotificationRequest : Object { + [DBus (visible = false)] + public signal void response (uint32 result); + + public uint register_id { get; set; default = 0; } + + private NotificationHandler handler; + private uint32 id; + + public NotificationRequest (NotificationHandler handler, uint32 id) { + this.handler = handler; + this.id = id; + } + + public void close () throws DBusError, IOError { + handler.close_notification (id); + } +} diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index d62ca38a..5ce8f8c9 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -7,14 +7,13 @@ public class Background.Portal : Object { public signal void running_applications_changed (); - private const string ACTION_ALLOW_BACKGROUND = "background.allow"; - private const string ACTION_FORBID_BACKGROUND = "background.forbid"; - private DBusConnection connection; private DesktopIntegration desktop_integration; + private NotificationHandler notification_handler; public Portal (DBusConnection connection) { this.connection = connection; + notification_handler = new NotificationHandler (connection); try { desktop_integration = connection.get_proxy_sync ("org.pantheon.gala", "/org/pantheon/gala/DesktopInterface"); desktop_integration.running_applications_changed.connect (() => running_applications_changed ()); @@ -59,12 +58,6 @@ public class Background.Portal : Object { return results; } - private enum NotifyBackgroundResult { - FORBID = 0, - ALLOW = 1, - ALLOW_ONCE = 2 - } - public async void notify_background ( ObjectPath handle, string app_id, @@ -72,44 +65,37 @@ public class Background.Portal : Object { out uint32 response, out HashTable results ) throws DBusError, IOError { + response = 0; //Won't be used var _results = new HashTable (str_hash, str_equal); - var notification = new Notify.Notification ( - _("Background activity"), - _(""""%s" is running in the background""").printf (name), - "dialog-information" - ); + var notification_request = notification_handler.send_notification (app_id, name); - notification.add_action (ACTION_ALLOW_BACKGROUND, _("Allow"), () => { - _results.set ("result", NotifyBackgroundResult.ALLOW); - notify_background.callback (); - }); - - notification.add_action (ACTION_FORBID_BACKGROUND, _("Forbid"), () => { - _results.set ("result", NotifyBackgroundResult.FORBID); - notify_background.callback (); - }); + if (notification_request == null) { + _results.set ("result", 2); + results = _results; + return; + } - notification.closed.connect (() => { - _results.set ("result", NotifyBackgroundResult.ALLOW_ONCE); + notification_request.response.connect ((result) => { + _results.set ("result", result); notify_background.callback (); }); try { - notification.show (); + notification_request.register_id = connection.register_object (handle, notification_request); } catch (Error e) { - critical ("Failed to send background notification for %s: %s", app_id, e.message); + critical ("Failed to export request object: %s", e.message); } yield; - response = 0; //Won't be used + connection.unregister_object (notification_request.register_id); results = _results; } private enum AutostartFlags { - AUTOSTART_FLAGS_NONE = 0, - AUTOSTART_FLAGS_DBUS_ACTIVATABLE = 1 + AUTOSTART_FLAGS_NONE, + AUTOSTART_FLAGS_DBUS_ACTIVATABLE } public bool enable_autostart ( @@ -118,7 +104,7 @@ public class Background.Portal : Object { string[] commandline, uint32 flags ) throws DBusError, IOError { - /* If the portal request is made by a non-flatpaked application app_id will most of the time be empty */ + /* If the portal request is made by a non-flatpak application app_id will most of the time be empty */ if (app_id.strip () == "") { /* Usually we can then asume that the first commandline arg is the app_id */ if (commandline[0].strip () != "") { diff --git a/src/XdgDesktopPortalPantheon.vala b/src/XdgDesktopPortalPantheon.vala index 3fb201f7..56faed74 100644 --- a/src/XdgDesktopPortalPantheon.vala +++ b/src/XdgDesktopPortalPantheon.vala @@ -79,7 +79,6 @@ int main (string[] args) { GLib.Environment.unset_variable ("GTK_USE_PORTAL"); Gtk.init (); - Notify.init ("xdg-desktop-portal-pantheon"); try { var opt_context = new OptionContext ("- portal backends"); diff --git a/src/meson.build b/src/meson.build index 5d3c400b..72eda04c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,6 +6,8 @@ executable( 'AppChooser/AppButton.vala', 'AppChooser/Dialog.vala', 'AppChooser/Portal.vala', + 'Background/NotificationHandler.vala', + 'Background/NotificationRequest.vala', 'Background/Portal.vala', configure_file(input: 'Config.vala.in', output: '@BASENAME@', configuration: conf_data), 'ExternalWindow.vala', @@ -16,7 +18,6 @@ executable( gio_dep, granite_dep, gtk_deps, - notify_dep, x11_dep ], install: true, From 1f5116a0d539756245f64c3f0a42bb3f808d9d99 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Wed, 17 May 2023 20:53:44 +0200 Subject: [PATCH 18/37] Rename variable --- src/Background/NotificationHandler.vala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Background/NotificationHandler.vala b/src/Background/NotificationHandler.vala index a5891ef5..07c18ea5 100644 --- a/src/Background/NotificationHandler.vala +++ b/src/Background/NotificationHandler.vala @@ -3,7 +3,7 @@ public class NotificationHandler : Object { public const string ACTION_FORBID_BACKGROUND = "background.forbid"; private DBusConnection connection; - private HashTable id_notification; + private HashTable notification_by_id; private Notifications notifications; private enum NotifyBackgroundResult { @@ -32,7 +32,7 @@ public class NotificationHandler : Object { public NotificationHandler (DBusConnection connection) { this.connection = connection; - id_notification = new HashTable (null, null); + notification_by_id = new HashTable (null, null); try { notifications = connection.get_proxy_sync ("org.freedesktop.Notifications", "/org/freedesktop/Notifications"); @@ -64,7 +64,7 @@ public class NotificationHandler : Object { ); var notification = new NotificationRequest (this, id); - id_notification.set (id, notification); + notification_by_id.set (id, notification); return notification; } catch (Error e) { @@ -74,8 +74,8 @@ public class NotificationHandler : Object { } private void on_action_invoked (uint32 id, string action_key) { - if (id in id_notification) { - var notification = id_notification.get (id); + if (id in notification_by_id) { + var notification = notification_by_id.get (id); if (action_key == NotificationHandler.ACTION_ALLOW_BACKGROUND) { notification.response (NotifyBackgroundResult.ALLOW); } else if (action_key == NotificationHandler.ACTION_FORBID_BACKGROUND) { @@ -85,8 +85,8 @@ public class NotificationHandler : Object { } private void on_notification_closed (uint32 id, uint32 reason) { - if (id in id_notification) { - var notification = id_notification.get (id); + if (id in notification_by_id) { + var notification = notification_by_id.get (id); if (reason == 2 || reason == 3) { notification.response (NotifyBackgroundResult.ALLOW_ONCE); } @@ -100,6 +100,6 @@ public class NotificationHandler : Object { warning ("Failed to close notification with id '%u': %s", id, e.message); } - id_notification.remove (id); + notification_by_id.remove (id); } } From 88db5f878b6427b2155176a7eeb692d58930f5fd Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Wed, 17 May 2023 21:05:12 +0200 Subject: [PATCH 19/37] Don't keep references on expired notifications --- src/Background/NotificationHandler.vala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Background/NotificationHandler.vala b/src/Background/NotificationHandler.vala index 07c18ea5..a3c12028 100644 --- a/src/Background/NotificationHandler.vala +++ b/src/Background/NotificationHandler.vala @@ -81,6 +81,8 @@ public class NotificationHandler : Object { } else if (action_key == NotificationHandler.ACTION_FORBID_BACKGROUND) { notification.response (NotifyBackgroundResult.FORBID); } + + notification_by_id.remove (id); } } @@ -89,6 +91,8 @@ public class NotificationHandler : Object { var notification = notification_by_id.get (id); if (reason == 2 || reason == 3) { notification.response (NotifyBackgroundResult.ALLOW_ONCE); + + notification_by_id.remove (id); } } } From 17bc48a7dd08a62391a517daf90e89042e529f84 Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Thu, 18 May 2023 13:22:17 +0000 Subject: [PATCH 20/37] Apply suggestions from code review Co-authored-by: Gustavo Marques --- src/Background/NotificationHandler.vala | 46 ++++++++++++++----------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Background/NotificationHandler.vala b/src/Background/NotificationHandler.vala index a3c12028..e7e6f29c 100644 --- a/src/Background/NotificationHandler.vala +++ b/src/Background/NotificationHandler.vala @@ -9,7 +9,8 @@ public class NotificationHandler : Object { private enum NotifyBackgroundResult { FORBID, ALLOW, - ALLOW_ONCE + ALLOW_ONCE, + CANCELLED } [DBus (name = "org.freedesktop.Notifications")] @@ -50,16 +51,17 @@ public class NotificationHandler : Object { ACTION_FORBID_BACKGROUND, _("Forbid") }; + var hints = new HashTable (null, null); + hints["desktop-entry"] = app_id; + hints["urgency"] = (uint8) 1; try { var id = notifications.notify ( - Environment.get_prgname (), - 0, - "dialog-information", + app_name, 0, "", _("Background activity"), _(""""%s" is running in the background""").printf (app_name), actions, - new HashTable (str_hash, str_equal), + hints, 0 ); @@ -74,26 +76,28 @@ public class NotificationHandler : Object { } private void on_action_invoked (uint32 id, string action_key) { - if (id in notification_by_id) { - var notification = notification_by_id.get (id); - if (action_key == NotificationHandler.ACTION_ALLOW_BACKGROUND) { - notification.response (NotifyBackgroundResult.ALLOW); - } else if (action_key == NotificationHandler.ACTION_FORBID_BACKGROUND) { - notification.response (NotifyBackgroundResult.FORBID); - } - - notification_by_id.remove (id); + var notification = notification_by_id.take (id); + if (notification == null) { + return; + } + + if (action_key == ACTION_ALLOW_BACKGROUND) { + notification.response (NotifyBackgroundResult.ALLOW); + } else if (action_key == ACTION_FORBID_BACKGROUND) { + notification.response (NotifyBackgroundResult.FORBID); } } private void on_notification_closed (uint32 id, uint32 reason) { - if (id in notification_by_id) { - var notification = notification_by_id.get (id); - if (reason == 2 || reason == 3) { - notification.response (NotifyBackgroundResult.ALLOW_ONCE); - - notification_by_id.remove (id); - } + var notification = notification_by_id.take (id); + if (notification == null) { + return; + } + + if (reason == 2) { + notification.response (NotifyBackgroundResult.ALLOW_ONCE); + } else if (reason == 3) { + notification.response (NotifyBackgroundResult.CANCELLED); } } From 13cdb0e17dbcb343698df703a975baf22921f8cf Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 18 May 2023 14:19:32 +0000 Subject: [PATCH 21/37] Merge NotificationHandler and NotificationRequest --- src/Background/NotificationHandler.vala | 113 ------------------------ src/Background/NotificationRequest.vala | 111 +++++++++++++++++++++-- src/Background/Portal.vala | 26 +++--- src/meson.build | 1 - 4 files changed, 116 insertions(+), 135 deletions(-) delete mode 100644 src/Background/NotificationHandler.vala diff --git a/src/Background/NotificationHandler.vala b/src/Background/NotificationHandler.vala deleted file mode 100644 index e7e6f29c..00000000 --- a/src/Background/NotificationHandler.vala +++ /dev/null @@ -1,113 +0,0 @@ -public class NotificationHandler : Object { - public const string ACTION_ALLOW_BACKGROUND = "background.allow"; - public const string ACTION_FORBID_BACKGROUND = "background.forbid"; - - private DBusConnection connection; - private HashTable notification_by_id; - private Notifications notifications; - - private enum NotifyBackgroundResult { - FORBID, - ALLOW, - ALLOW_ONCE, - CANCELLED - } - - [DBus (name = "org.freedesktop.Notifications")] - public interface Notifications : Object { - public signal void action_invoked (uint32 id, string action_key); - public signal void notification_closed (uint32 id, uint32 reason); - - public abstract void close_notification (uint32 id) throws DBusError, IOError; - public abstract uint32 notify ( - string app_name, - uint32 replaces_id, - string app_icon, - string summary, - string body, - string[] actions, - HashTable hints, - int32 expire_timeout - ) throws DBusError, IOError; - } - - public NotificationHandler (DBusConnection connection) { - this.connection = connection; - notification_by_id = new HashTable (null, null); - - try { - notifications = connection.get_proxy_sync ("org.freedesktop.Notifications", "/org/freedesktop/Notifications"); - notifications.action_invoked.connect (on_action_invoked); - notifications.notification_closed.connect (on_notification_closed); - } catch { - warning ("Cannot connect to notifications dbus, background portal working with reduced functionality."); - } - } - - public NotificationRequest? send_notification (string app_id, string app_name) { - string[] actions = { - ACTION_ALLOW_BACKGROUND, - _("Allow"), - ACTION_FORBID_BACKGROUND, - _("Forbid") - }; - var hints = new HashTable (null, null); - hints["desktop-entry"] = app_id; - hints["urgency"] = (uint8) 1; - - try { - var id = notifications.notify ( - app_name, 0, "", - _("Background activity"), - _(""""%s" is running in the background""").printf (app_name), - actions, - hints, - 0 - ); - - var notification = new NotificationRequest (this, id); - notification_by_id.set (id, notification); - - return notification; - } catch (Error e) { - warning ("Failed to send notification for app id '%s': %s", app_id, e.message); - return null; - } - } - - private void on_action_invoked (uint32 id, string action_key) { - var notification = notification_by_id.take (id); - if (notification == null) { - return; - } - - if (action_key == ACTION_ALLOW_BACKGROUND) { - notification.response (NotifyBackgroundResult.ALLOW); - } else if (action_key == ACTION_FORBID_BACKGROUND) { - notification.response (NotifyBackgroundResult.FORBID); - } - } - - private void on_notification_closed (uint32 id, uint32 reason) { - var notification = notification_by_id.take (id); - if (notification == null) { - return; - } - - if (reason == 2) { - notification.response (NotifyBackgroundResult.ALLOW_ONCE); - } else if (reason == 3) { - notification.response (NotifyBackgroundResult.CANCELLED); - } - } - - public void close_notification (uint32 id) { - try { - notifications.close_notification (id); - } catch (Error e) { - warning ("Failed to close notification with id '%u': %s", id, e.message); - } - - notification_by_id.remove (id); - } -} diff --git a/src/Background/NotificationRequest.vala b/src/Background/NotificationRequest.vala index 94a7c08e..f44b1d62 100644 --- a/src/Background/NotificationRequest.vala +++ b/src/Background/NotificationRequest.vala @@ -3,17 +3,114 @@ public class NotificationRequest : Object { [DBus (visible = false)] public signal void response (uint32 result); - public uint register_id { get; set; default = 0; } + private const string ACTION_ALLOW_BACKGROUND = "background.allow"; + private const string ACTION_FORBID_BACKGROUND = "background.forbid"; - private NotificationHandler handler; - private uint32 id; + private static HashTable notification_by_id; + private static Notifications notifications; - public NotificationRequest (NotificationHandler handler, uint32 id) { - this.handler = handler; - this.id = id; + private uint32 id = 0; + + public enum NotifyBackgroundResult { + FORBID, + ALLOW, + ALLOW_ONCE, + CANCELLED + } + + [DBus (name = "org.freedesktop.Notifications")] + public interface Notifications : Object { + public signal void action_invoked (uint32 id, string action_key); + public signal void notification_closed (uint32 id, uint32 reason); + + public abstract void close_notification (uint32 id) throws DBusError, IOError; + public abstract uint32 notify ( + string app_name, + uint32 replaces_id, + string app_icon, + string summary, + string body, + string[] actions, + HashTable hints, + int32 expire_timeout + ) throws DBusError, IOError; + } + + [DBus (visible = false)] + public static void init (DBusConnection connection) { + notification_by_id = new HashTable (null, null); + + try { + notifications = connection.get_proxy_sync ("org.freedesktop.Notifications", "/org/freedesktop/Notifications"); + notifications.action_invoked.connect (on_action_invoked); + notifications.notification_closed.connect (on_notification_closed); + } catch { + warning ("Cannot connect to notifications dbus, background portal working with reduced functionality."); + } + } + + private static void on_action_invoked (uint32 id, string action_key) { + var notification = notification_by_id.take (id); + if (notification == null) { + return; + } + + if (action_key == ACTION_ALLOW_BACKGROUND) { + notification.response (NotifyBackgroundResult.ALLOW); + } else if (action_key == ACTION_FORBID_BACKGROUND) { + notification.response (NotifyBackgroundResult.FORBID); + } + } + + private static void on_notification_closed (uint32 id, uint32 reason) { + var notification = notification_by_id.take (id); + if (notification == null) { + return; + } + + if (reason == 2) { //Dismissed by user + notification.response (NotifyBackgroundResult.ALLOW_ONCE); + } else if (reason == 3) { //Closed via DBus call + notification.response (NotifyBackgroundResult.CANCELLED); + } + } + + [DBus (visible = false)] + public void send_notification (string app_id, string app_name) { + string[] actions = { + ACTION_ALLOW_BACKGROUND, + _("Allow"), + ACTION_FORBID_BACKGROUND, + _("Forbid") + }; + var hints = new HashTable (null, null); + hints["desktop-entry"] = app_id; + hints["urgency"] = (uint8) 1; + + try { + id = notifications.notify ( + app_name, 0, "", + _("Background activity"), + _(""""%s" is running in the background""").printf (app_name), + actions, + hints, + 0 + ); + + notification_by_id.set (id, this); + } catch (Error e) { + warning ("Failed to send notification for app id '%s': %s", app_id, e.message); + response (NotifyBackgroundResult.ALLOW_ONCE); + } } public void close () throws DBusError, IOError { - handler.close_notification (id); + try { + notifications.close_notification (id); + } catch (Error e) { + // the notification was already closed, or we lost the connection to the server + response (NotifyBackgroundResult.CANCELLED); + notification_by_id.remove (id); + } } } diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 5ce8f8c9..9e6e5652 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -9,11 +9,10 @@ public class Background.Portal : Object { private DBusConnection connection; private DesktopIntegration desktop_integration; - private NotificationHandler notification_handler; public Portal (DBusConnection connection) { this.connection = connection; - notification_handler = new NotificationHandler (connection); + NotificationRequest.init (connection); try { desktop_integration = connection.get_proxy_sync ("org.pantheon.gala", "/org/pantheon/gala/DesktopInterface"); desktop_integration.running_applications_changed.connect (() => running_applications_changed ()); @@ -68,28 +67,27 @@ public class Background.Portal : Object { response = 0; //Won't be used var _results = new HashTable (str_hash, str_equal); - var notification_request = notification_handler.send_notification (app_id, name); - - if (notification_request == null) { - _results.set ("result", 2); - results = _results; - return; - } - + var notification_request = new NotificationRequest (); notification_request.response.connect ((result) => { - _results.set ("result", result); + if (result != NotificationRequest.NotifyBackgroundResult.CANCELLED) { + _results.set ("result", result); + } notify_background.callback (); }); + uint register_id = 0; try { - notification_request.register_id = connection.register_object (handle, notification_request); + register_id = connection.register_object (handle, notification_request); } catch (Error e) { - critical ("Failed to export request object: %s", e.message); + warning ("Failed to export request object: %s", e.message); + throw new DBusError.OBJECT_PATH_IN_USE (e.message); } + notification_request.send_notification (app_id, name); + yield; - connection.unregister_object (notification_request.register_id); + connection.unregister_object (register_id); results = _results; } diff --git a/src/meson.build b/src/meson.build index 72eda04c..4b88f74f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,7 +6,6 @@ executable( 'AppChooser/AppButton.vala', 'AppChooser/Dialog.vala', 'AppChooser/Portal.vala', - 'Background/NotificationHandler.vala', 'Background/NotificationRequest.vala', 'Background/Portal.vala', configure_file(input: 'Config.vala.in', output: '@BASENAME@', configuration: conf_data), From 732c8c02c6b51b67b81247bd423d74876ca1b06b Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 18 May 2023 14:20:49 +0000 Subject: [PATCH 22/37] Add license header --- src/Background/NotificationRequest.vala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Background/NotificationRequest.vala b/src/Background/NotificationRequest.vala index f44b1d62..49564b04 100644 --- a/src/Background/NotificationRequest.vala +++ b/src/Background/NotificationRequest.vala @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2023 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + [DBus (name = "org.freedesktop.impl.portal.Request")] public class NotificationRequest : Object { [DBus (visible = false)] From 8d0e6e1410249e7613a38a8cf7753c5f46ae2368 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 18 May 2023 14:29:36 +0000 Subject: [PATCH 23/37] Change notification content --- src/Background/NotificationRequest.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Background/NotificationRequest.vala b/src/Background/NotificationRequest.vala index 49564b04..9285b586 100644 --- a/src/Background/NotificationRequest.vala +++ b/src/Background/NotificationRequest.vala @@ -96,7 +96,7 @@ public class NotificationRequest : Object { id = notifications.notify ( app_name, 0, "", _("Background activity"), - _(""""%s" is running in the background""").printf (app_name), + _(""""%s" is running in the background without appropriate permission""").printf (app_name), actions, hints, 0 From 61fce137bf267818a560ec787b842f9aacbb67ae Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 18 May 2023 22:49:19 +0200 Subject: [PATCH 24/37] Add failed result, set response --- src/Background/NotificationRequest.vala | 5 +++-- src/Background/Portal.vala | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Background/NotificationRequest.vala b/src/Background/NotificationRequest.vala index 9285b586..daf99320 100644 --- a/src/Background/NotificationRequest.vala +++ b/src/Background/NotificationRequest.vala @@ -20,7 +20,8 @@ public class NotificationRequest : Object { FORBID, ALLOW, ALLOW_ONCE, - CANCELLED + CANCELLED, + FAILED } [DBus (name = "org.freedesktop.Notifications")] @@ -105,7 +106,7 @@ public class NotificationRequest : Object { notification_by_id.set (id, this); } catch (Error e) { warning ("Failed to send notification for app id '%s': %s", app_id, e.message); - response (NotifyBackgroundResult.ALLOW_ONCE); + response (NotifyBackgroundResult.FAILED); } } diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 9e6e5652..c1c805b0 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -64,13 +64,22 @@ public class Background.Portal : Object { out uint32 response, out HashTable results ) throws DBusError, IOError { - response = 0; //Won't be used + uint32 _response = 2; var _results = new HashTable (str_hash, str_equal); var notification_request = new NotificationRequest (); + notification_request.response.connect ((result) => { - if (result != NotificationRequest.NotifyBackgroundResult.CANCELLED) { - _results.set ("result", result); + switch (result) { + case NotificationRequest.NotifyBackgroundResult.CANCELLED: + _response = 1; + break; + case NotificationRequest.NotifyBackgroundResult.FAILED: + break; + default: + _response = 0; + _results["result"] = result; + break; } notify_background.callback (); }); @@ -88,6 +97,7 @@ public class Background.Portal : Object { yield; connection.unregister_object (register_id); + response = _response; results = _results; } From 5b4cc606cdc1dfee5ac482857f5bbeaf644d0319 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 18 May 2023 22:51:50 +0200 Subject: [PATCH 25/37] Formatting --- src/Background/Portal.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index c1c805b0..d0d2a49e 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -81,6 +81,7 @@ public class Background.Portal : Object { _results["result"] = result; break; } + notify_background.callback (); }); From c566a4bc480a99c6c7b9daafbd8ba766b777c784 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Fri, 19 May 2023 13:01:12 +0200 Subject: [PATCH 26/37] Cleanup --- src/Background/NotificationRequest.vala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Background/NotificationRequest.vala b/src/Background/NotificationRequest.vala index daf99320..a1071bd5 100644 --- a/src/Background/NotificationRequest.vala +++ b/src/Background/NotificationRequest.vala @@ -63,7 +63,7 @@ public class NotificationRequest : Object { if (action_key == ACTION_ALLOW_BACKGROUND) { notification.response (NotifyBackgroundResult.ALLOW); - } else if (action_key == ACTION_FORBID_BACKGROUND) { + } else { notification.response (NotifyBackgroundResult.FORBID); } } @@ -115,8 +115,6 @@ public class NotificationRequest : Object { notifications.close_notification (id); } catch (Error e) { // the notification was already closed, or we lost the connection to the server - response (NotifyBackgroundResult.CANCELLED); - notification_by_id.remove (id); } } } From 1f7dd77eb2ee640c808fc3462c0c0127c3c27a9a Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Mon, 22 May 2023 12:31:08 +0200 Subject: [PATCH 27/37] Apply suggestions from code review Co-authored-by: Gustavo Marques --- src/Background/Portal.vala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index d0d2a49e..cf3b6f77 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -103,15 +103,15 @@ public class Background.Portal : Object { } private enum AutostartFlags { - AUTOSTART_FLAGS_NONE, - AUTOSTART_FLAGS_DBUS_ACTIVATABLE + NONE, + DBUS_ACTIVATABLE } public bool enable_autostart ( string app_id, bool enable, string[] commandline, - uint32 flags + AutostartFlags flags ) throws DBusError, IOError { /* If the portal request is made by a non-flatpak application app_id will most of the time be empty */ if (app_id.strip () == "") { From 6b6ec9eed68578104bc5d6ff049f5d54a0657e90 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 12:34:22 +0200 Subject: [PATCH 28/37] Fix issues from code review --- src/Background/Portal.vala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index cf3b6f77..29f540d2 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -102,7 +102,7 @@ public class Background.Portal : Object { results = _results; } - private enum AutostartFlags { + public enum AutostartFlags { NONE, DBUS_ACTIVATABLE } @@ -130,13 +130,11 @@ public class Background.Portal : Object { return false; } - var autostart_flags = (AutostartFlags) flags; - var key_file = new KeyFile (); key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_TYPE, "Application"); key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME, app_id); key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_EXEC, flatpak_quote_argv (commandline)); - if (autostart_flags == AUTOSTART_FLAGS_DBUS_ACTIVATABLE) { + if (flags == DBUS_ACTIVATABLE) { key_file.set_boolean (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_DBUS_ACTIVATABLE, true); } key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id); From 881051779f464d4feaa3b4742df83e9858eff005 Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Mon, 22 May 2023 12:41:35 +0200 Subject: [PATCH 29/37] Apply suggestions from code review Co-authored-by: Gustavo Marques --- src/Background/NotificationRequest.vala | 2 +- src/Background/Portal.vala | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Background/NotificationRequest.vala b/src/Background/NotificationRequest.vala index a1071bd5..67866b27 100644 --- a/src/Background/NotificationRequest.vala +++ b/src/Background/NotificationRequest.vala @@ -100,7 +100,7 @@ public class NotificationRequest : Object { _(""""%s" is running in the background without appropriate permission""").printf (app_name), actions, hints, - 0 + -1 ); notification_by_id.set (id, this); diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 29f540d2..54dbb63f 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -113,17 +113,16 @@ public class Background.Portal : Object { string[] commandline, AutostartFlags flags ) throws DBusError, IOError { - /* If the portal request is made by a non-flatpak application app_id will most of the time be empty */ - if (app_id.strip () == "") { - /* Usually we can then asume that the first commandline arg is the app_id */ - if (commandline[0].strip () != "") { - app_id = commandline[0]; - } else { - return false; - } + var filename = app_id; + + /* If the portal request is made by a non-flatpak application app_id will most of the time be empty + * Use the commandline as a fallback for the autostart filename. + */ + if (filename == "") { + filename = string.joinv("-", commandline[0]).replace ("--", "-"); } - var path = Path.build_filename (Environment.get_user_config_dir (), "autostart", app_id + ".desktop"); + var path = Path.build_filename (Environment.get_user_config_dir (), "autostart", filename + ".desktop"); if (!enable) { FileUtils.unlink (path); @@ -137,7 +136,9 @@ public class Background.Portal : Object { if (flags == DBUS_ACTIVATABLE) { key_file.set_boolean (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_DBUS_ACTIVATABLE, true); } - key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id); + if (app_id != "") { + key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id); + } try { key_file.save_to_file (path); From ed1d592840e4fa2df13e1e97f7e19a59db665d2c Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 12:52:52 +0200 Subject: [PATCH 30/37] Use AppInfo to get name + icon, use all commandline args as filename --- src/Background/Portal.vala | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 54dbb63f..8e128290 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -116,10 +116,10 @@ public class Background.Portal : Object { var filename = app_id; /* If the portal request is made by a non-flatpak application app_id will most of the time be empty - * Use the commandline as a fallback for the autostart filename. + * We then use the commandline as a fallback for the autostart filename. */ - if (filename == "") { - filename = string.joinv("-", commandline[0]).replace ("--", "-"); + if (filename.strip () == "") { + filename = string.joinv("-", commandline).replace ("--", "-"); } var path = Path.build_filename (Environment.get_user_config_dir (), "autostart", filename + ".desktop"); @@ -129,14 +129,27 @@ public class Background.Portal : Object { return false; } + var app_info = app_id.strip () != "" ? new DesktopAppInfo (app_id + ".desktop") : null; var key_file = new KeyFile (); - key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_TYPE, "Application"); - key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME, app_id); + + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_TYPE, KeyFileDesktop.TYPE_APPLICATION); + + if (app_info != null) { + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME, app_info.get_name ()); + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_ICON, app_info.get_string (KeyFileDesktop.KEY_ICON)); + } else { + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME, _("Custom Command")); + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_ICON, "application-default-icon"); + } + + key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_COMMENT, string.joinv (" ", commandline)); key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_EXEC, flatpak_quote_argv (commandline)); + if (flags == DBUS_ACTIVATABLE) { key_file.set_boolean (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_DBUS_ACTIVATABLE, true); } - if (app_id != "") { + + if (app_id.strip () != "") { key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id); } From d8eb4acc034447ebba4cc84f7d67f69381ad1fbc Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 12:53:51 +0200 Subject: [PATCH 31/37] Fix lint --- src/Background/Portal.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 8e128290..32a0f9c0 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -119,7 +119,7 @@ public class Background.Portal : Object { * We then use the commandline as a fallback for the autostart filename. */ if (filename.strip () == "") { - filename = string.joinv("-", commandline).replace ("--", "-"); + filename = string.joinv ("-", commandline).replace ("--", "-"); } var path = Path.build_filename (Environment.get_user_config_dir (), "autostart", filename + ".desktop"); From f06b99128f0e73d79ddccb503194e530f722e2c9 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 15:09:47 +0200 Subject: [PATCH 32/37] Add some dbug messages and fix issue with the appstate variant not being a uint32 --- src/Background/Portal.vala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 32a0f9c0..0168318f 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -51,7 +51,10 @@ public class Background.Portal : Object { app_id = app_id.slice (0, app_id.last_index_of_char ('.')); } - results[app_id] = ApplicationState.RUNNING; //FIXME: Don't hardcode: needs implementation on the gala side + var app_state = ApplicationState.RUNNING; //FIXME: Don't hardcode: needs implementation on the gala side + + results[app_id] = new Variant.uint32 (app_state); + debug ("App state of '%s' set to %u (= %s).", app_id, app_state, app_state.to_string ()); } return results; @@ -64,6 +67,8 @@ public class Background.Portal : Object { out uint32 response, out HashTable results ) throws DBusError, IOError { + debug ("Notify background for '%s'.", app_id); + uint32 _response = 2; var _results = new HashTable (str_hash, str_equal); @@ -93,6 +98,7 @@ public class Background.Portal : Object { throw new DBusError.OBJECT_PATH_IN_USE (e.message); } + debug ("Sending desktop notification for '%s'.", app_id); notification_request.send_notification (app_id, name); yield; @@ -160,6 +166,8 @@ public class Background.Portal : Object { return false; } + debug ("Autostart file installed for '%s'.", app_id); + return true; } From 67004b1accadb9f498832fe8646ee12d7d9cad9d Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 15:36:22 +0200 Subject: [PATCH 33/37] Add another debug message --- src/Background/Portal.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 0168318f..7861c30c 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -87,6 +87,8 @@ public class Background.Portal : Object { break; } + debug ("Response to background activity of '%s': %s.", app_id, result.to_string ()); + notify_background.callback (); }); From c851f0d1b4c555648f78427279a566f4243a0043 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 16:30:50 +0200 Subject: [PATCH 34/37] Fix autostart --- src/Background/Portal.vala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 7861c30c..332e804c 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -119,8 +119,9 @@ public class Background.Portal : Object { string app_id, bool enable, string[] commandline, - AutostartFlags flags + uint32 flags ) throws DBusError, IOError { + flags = (AutostartFlags)flags; var filename = app_id; /* If the portal request is made by a non-flatpak application app_id will most of the time be empty @@ -153,7 +154,7 @@ public class Background.Portal : Object { key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_COMMENT, string.joinv (" ", commandline)); key_file.set_string (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_EXEC, flatpak_quote_argv (commandline)); - if (flags == DBUS_ACTIVATABLE) { + if (flags == AutostartFlags.DBUS_ACTIVATABLE) { key_file.set_boolean (KeyFileDesktop.GROUP, KeyFileDesktop.KEY_DBUS_ACTIVATABLE, true); } From 72eea6ecf1c5d3664c961ca047819c7be9002cd8 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 16:36:31 +0200 Subject: [PATCH 35/37] Cleanup --- src/Background/Portal.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 332e804c..86f35f90 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -121,7 +121,7 @@ public class Background.Portal : Object { string[] commandline, uint32 flags ) throws DBusError, IOError { - flags = (AutostartFlags)flags; + (AutostartFlags)flags; var filename = app_id; /* If the portal request is made by a non-flatpak application app_id will most of the time be empty From f29b0ae0334bff03f4f764152d2c7da06ef0738c Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 16:51:03 +0200 Subject: [PATCH 36/37] Cleanup --- src/Background/Portal.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 86f35f90..4973bc40 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -53,7 +53,7 @@ public class Background.Portal : Object { var app_state = ApplicationState.RUNNING; //FIXME: Don't hardcode: needs implementation on the gala side - results[app_id] = new Variant.uint32 (app_state); + results[app_id] = (uint32) app_state; debug ("App state of '%s' set to %u (= %s).", app_id, app_state, app_state.to_string ()); } @@ -83,7 +83,7 @@ public class Background.Portal : Object { break; default: _response = 0; - _results["result"] = result; + _results["result"] = (uint32) result; break; } From 14d29bb7a537e91b6789648179d949761f84120c Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 May 2023 17:24:38 +0200 Subject: [PATCH 37/37] Use Flags --- src/Background/Portal.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Background/Portal.vala b/src/Background/Portal.vala index 4973bc40..129b2439 100644 --- a/src/Background/Portal.vala +++ b/src/Background/Portal.vala @@ -110,6 +110,7 @@ public class Background.Portal : Object { results = _results; } + [Flags] public enum AutostartFlags { NONE, DBUS_ACTIVATABLE @@ -119,9 +120,8 @@ public class Background.Portal : Object { string app_id, bool enable, string[] commandline, - uint32 flags + AutostartFlags flags ) throws DBusError, IOError { - (AutostartFlags)flags; var filename = app_id; /* If the portal request is made by a non-flatpak application app_id will most of the time be empty