Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions src/AppSystem/App.vala
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ public class Dock.App : Object {
switcheroo_control.apply_gpu_environment (context, prefers_nondefault_gpu);
}

context.launched.connect (start_systemd_scope);

try {
if (action != null) {
app_info.launch_action (action, context);
Expand All @@ -152,6 +154,93 @@ public class Dock.App : Object {
}
}

private async void start_systemd_scope (AppLaunchContext context, GLib.AppInfo appinfo, Variant platform_data) {
int pid;
if (!platform_data.lookup ("pid", "i", out pid)) {
return;
}

var app_name = appinfo.get_id () ?? appinfo.get_executable ();
// if we got a path, use the binary name only
if (app_name.has_prefix ("/")) {
app_name = Path.get_basename (app_name);
} else if (app_name.has_suffix (".desktop")) {
app_name = app_name.substring (0, app_name.length - 8);
}

DBusConnection connection;
try {
connection = Bus.get_sync (SESSION, null);
} catch (Error e) {
critical ("Couldn't connect to DBus: %s", e.message);
return;
}

// If an app is dbus activatable, we don't launch it directly
// dbus-daemon launches it for us, so we can't get pid from platform_data
if (appinfo is DesktopAppInfo && ((DesktopAppInfo) appinfo).get_boolean ("DBusActivatable")) {
try {
var reply = connection.call_sync (
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionUnixProcessID",
new Variant ("(s)", app_name),
new VariantType ("(u)"),
NONE,
1000,
null
);

reply.get ("(u)", out pid);
} catch (Error e) {
critical ("Couldn't get pid of dbus activatable app: %s", e.message);
return;
}
}

var string_builder = new StringBuilder.sized (app_name.length);
for (var i = 0; i < app_name.length; i++) {
var c = app_name[i];
if (c.isalnum () || c == ':' || c == '_' || c == '.') {
string_builder.append_c (c);
} else {
string_builder.append_printf ("\\x%02x", c);
}
}

var builder = new VariantBuilder (new VariantType ("(ssa(sv)a(sa(sv)))"));
builder.add ("s", "app-pantheon-%s-%d.scope".printf (string_builder.free_and_steal (), pid));
builder.add ("s", "fail");

builder.open (new VariantType ("a(sv)"));
builder.add ("(sv)", "Description", new Variant.string ("Application launched by %s".printf (GLib.Application.get_default ().application_id)));
builder.add ("(sv)", "PIDs", new Variant.array (VariantType.UINT32, { (uint32) pid }));

// Default to let systemd garbage collect failed applications we launched.
builder.add ("(sv)", "CollectMode", new Variant.string ("inactive-or-failed"));
builder.close ();

builder.open (new VariantType ("a(sa(sv))"));
builder.close ();

try {
connection.call_sync (
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit",
builder.end (),
new VariantType ("(o)"),
NO_AUTO_START,
1000,
null
);
} catch (Error e) {
warning ("Couldn't put an app into Systemd scope: %s", e.message);
}
}

public bool launch_new_instance (AppLaunchContext context) {
// Treat this as a string to distinguish between false and null
var single_main_window = app_info.get_string ("SingleMainWindow");
Expand Down