Skip to content

Commit

Permalink
Background: make asynchronous, get notifications proxy lazily
Browse files Browse the repository at this point in the history
make all of the dbus calls and methods asynchronous so that we don't end up
blocking others interfaces, methods and initialization.

the notification proxy is now also started when we first call
send_notification() so we don't end starting it early than necessary or
blocking the initialization for too much time.

Signed-off-by: Gustavo Marques <[email protected]>
  • Loading branch information
Marukesu committed Jun 7, 2023
1 parent bf258a7 commit 5347f1a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 44 deletions.
67 changes: 38 additions & 29 deletions src/Background/NotificationRequest.vala
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ private interface Fdo.Notifications : Object {
CANCELLED
}

public abstract void close_notification (uint32 id) throws DBusError, IOError;
public abstract uint32 notify (
public async abstract void close_notification (uint32 id) throws DBusError, IOError;
public async abstract uint32 notify (
string app_name,
uint32 replaces_id,
string app_icon,
Expand All @@ -40,7 +40,7 @@ public class Background.NotificationRequest : Object {
private const string ACTION_FORBID_BACKGROUND = "background.forbid";

private static HashTable<uint32, unowned NotificationRequest> requests;
private static Fdo.Notifications notifications;
private static Fdo.Notifications? notifications;

private uint32 id = 0;

Expand All @@ -52,16 +52,8 @@ public class Background.NotificationRequest : Object {
FAILED
}

public static void init (DBusConnection connection) {
static construct {
requests = new HashTable<uint32, unowned NotificationRequest> (null, null);

try {
notifications = connection.get_proxy_sync (Fdo.Notifications.NAME, Fdo.Notifications.PATH);
notifications.action_invoked.connect (action_invoked);
notifications.notification_closed.connect (notification_closed);
} catch {
warning ("Cannot connect to notifications dbus, portal working with reduced functionality.");
}
}

private static void action_invoked (uint32 id, string action_key) {
Expand Down Expand Up @@ -92,6 +84,22 @@ public class Background.NotificationRequest : Object {

[DBus (visible = false)]
public void send_notification (string app_id, string app_name) {
if (notifications == null) {
Bus.get_proxy.begin<Fdo.Notifications> (SESSION, Fdo.Notifications.NAME, Fdo.Notifications.PATH, NONE, null,
(obj, res) => {
try {
notifications = Bus.get_proxy.end (res);
notifications.action_invoked.connect (action_invoked);
notifications.notification_closed.connect (notification_closed);
send_notification (app_id, app_name);
} catch {
warning ("Cannot connect to notifications server, skipping notify request for '%s'", app_id);
response (FAILED);
}
});
return;
}

string[] actions = {
ACTION_ALLOW_BACKGROUND,
_("Allow"),
Expand All @@ -103,26 +111,27 @@ public class Background.NotificationRequest : Object {
hints["desktop-entry"] = app_id;
hints["urgency"] = (uint8) 1;

try {
id = notifications.notify (
app_name, 0, "",
_("Background activity"),
_("%s” is running in the background without appropriate permission").printf (app_name),
actions,
hints,
-1
);

requests[id] = this;
} catch (Error e) {
warning ("Failed to notify background activity from '%s': %s", app_id, e.message);
response (FAILED);
}
notifications.notify.begin (
app_name, 0, "",
_("Background activity"),
_("%s” is running in the background without appropriate permission").printf (app_name),
actions,
hints,
-1, (obj, res) => {
try {
id = notifications.notify.end (res);
requests[id] = this;
} catch (Error e) {
warning ("Failed to notify background activity from '%s': %s", app_id, e.message);
response (FAILED);
}
}
);
}

public void close () throws DBusError, IOError {
public async void close () throws DBusError, IOError {
try {
notifications.close_notification (id);
yield notifications.close_notification (id);
} catch (Error e) {
// the notification was already closed, or we lost the connection to the server
}
Expand Down
42 changes: 27 additions & 15 deletions src/Background/Portal.vala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ private interface Gala.DesktopIntegration : Object {
HashTable<string,Variant> details;
}

public abstract RunningApplications[] get_running_applications () throws DBusError, IOError;
public abstract async RunningApplications[] get_running_applications () throws DBusError, IOError;
}

[DBus (name = "org.freedesktop.impl.portal.Background")]
Expand All @@ -27,14 +27,19 @@ public class Background.Portal : Object {

public Portal (DBusConnection connection) {
this.connection = connection;
NotificationRequest.init (connection);
try {
desktop_integration = connection.get_proxy_sync (Gala.DesktopIntegration.NAME, Gala.DesktopIntegration.PATH);
desktop_integration.running_applications_changed.connect (() => running_applications_changed ());
} catch {
warning ("Cannot connect to compositor, portal working with reduced functionality.");
}

connection.get_proxy.begin<Gala.DesktopIntegration> (
Gala.DesktopIntegration.NAME,
Gala.DesktopIntegration.PATH,
NONE, null, (obj, res) => {
try {
desktop_integration = connection.get_proxy.end (res);
desktop_integration.running_applications_changed.connect (() => running_applications_changed ());
} catch {
warning ("Cannot connect to compositor, portal working with reduced functionality.");
}
}
);
}

[DBus (signature = "u")]
Expand All @@ -44,15 +49,15 @@ public class Background.Portal : Object {
ACTIVE
}

public HashTable<string, Variant> get_app_state () throws DBusError, IOError {
public async HashTable<string, Variant> get_app_state () throws DBusError, IOError {
if (desktop_integration == null) {
throw new DBusError.FAILED ("No connection to compositor.");
}

var results = new HashTable<string, Variant> (null, null);
debug ("getting application states");

foreach (var app in desktop_integration.get_running_applications ()) {
foreach (var app in yield desktop_integration.get_running_applications ()) {
var app_id = app.app_id;
if (app_id.has_suffix (".desktop")) {
app_id = app_id.slice (0, app_id.last_index_of_char ('.'));
Expand Down Expand Up @@ -114,7 +119,7 @@ public class Background.Portal : Object {
DBUS_ACTIVATABLE
}

public bool enable_autostart (
public async bool enable_autostart (
string app_id,
bool enable,
string[] commandline,
Expand All @@ -136,9 +141,9 @@ public class Background.Portal : Object {
_app_id = string.joinv ("-", commandline).replace ("--", "-").replace ("--", "-");
}

var path = Path.build_filename (Environment.get_user_config_dir (), "autostart", _app_id + ".desktop");
var file = File.new_build_filename (Environment.get_user_config_dir (), "autostart", _app_id + ".desktop");
if (!enable) {
FileUtils.unlink (path);
try { yield file.delete_async (); } catch {}
return false;
}

Expand All @@ -162,14 +167,21 @@ public class Background.Portal : Object {
key_file.set_string (KeyFileDesktop.GROUP, "X-Flatpak", app_id);
}

FileCreateFlags create_flags = PRIVATE | REPLACE_DESTINATION;
var contents = key_file.to_data ();

try {
key_file.save_to_file (path);
try {
yield file.replace_contents_async (contents.data, null, true, create_flags, null, null);
} catch (IOError.CANT_CREATE_BACKUP e) {
yield file.replace_contents_async (contents.data, null, false, create_flags, null, null);
}
} catch (Error e) {
warning ("Failed to write autostart file: %s", e.message);
throw new DBusError.FAILED (e.message);
}

debug ("Autostart file installed at '%s'.", path);
debug ("Autostart file installed at '%s'.", file.get_path ());
return true;
}

Expand Down

0 comments on commit 5347f1a

Please sign in to comment.