util: Add new trySpawnAppCommandline function

Add a new helper function to launch a command line as if it was an
application. This has the advantage of using the appropriate code paths
in GLib (and gnome-shell currently) to place the launched program into a
separate systemd scope.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1384
This commit is contained in:
Benjamin Berg 2020-07-31 15:28:34 +02:00
parent b689b35b7d
commit 4e54cbcc60

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine, /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnAppCommandline,
formatTime, formatTimeSpan, createTimeLabel, insertSorted, trySpawnCommandLine, formatTime, formatTimeSpan, createTimeLabel,
ensureActorVisibleInScrollView, wiggle */ insertSorted, ensureActorVisibleInScrollView, wiggle */
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
@ -86,18 +86,49 @@ function spawnCommandLine(commandLine) {
} }
} }
// trySpawnAppCommandline:
// @command: The command to spawn
//
// Runs @command as if it was an application, handling startup notification
// and placing it into a separate systemd scope.
function trySpawnAppCommandline(command) {
const quoted = command.replace(/%/g, '%%');
// This cannot fail currently
const app = Gio.AppInfo.create_from_commandline(quoted, null,
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
// Launching applications does not check whether the executable exists,
// it'll just log an error later on. So do an explicit check here.
const exec = app.get_executable();
if (!GLib.find_program_in_path(exec)) {
throw new GLib.SpawnError({
code: GLib.SpawnError.NOENT,
message: _('Command not found'),
});
}
try {
let context = global.create_app_launch_context(0, -1);
app.launch([], context);
} catch (err) {
// Replace "Error invoking global.create_app_launch_context: " with
// something nicer
err.message = err.message.replace(/[^:]*: /, '%s\n'.format(_('Could not parse command:')));
throw err;
}
}
// spawnApp: // spawnApp:
// @argv: an argv array // @argv: an argv array
// //
// Runs @argv as if it was an application, handling startup notification // Runs @argv as if it was an application, handling startup notification
// and placing it into a separate systemd scope.
function spawnApp(argv) { function spawnApp(argv) {
try { try {
let app = Gio.AppInfo.create_from_commandline(argv.join(' '), null, trySpawnAppCommandline(argv.join(' '));
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION); } catch (err) {
let context = global.create_app_launch_context(0, -1);
app.launch([], context);
} catch (err) {
_handleSpawnError(argv[0], err); _handleSpawnError(argv[0], err);
} }
} }