[gnome-shell/T29763: 132/249] appActivation: Add launcher for 'endlessm-app://' schemes
- From: Matthew Leeds <mwleeds src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/T29763: 132/249] appActivation: Add launcher for 'endlessm-app://' schemes
- Date: Thu, 21 May 2020 18:20:16 +0000 (UTC)
commit bc499a233e10915b9a0377f4cf8870f51d2e9a5d
Author: Mario Sanchez Prada <mario endlessm com>
Date: Mon Jan 29 14:58:09 2018 +0000
appActivation: Add launcher for 'endlessm-app://' schemes
* 2020-03-24:
+ Squash with 9ec74bde7
+ Squash with 4a2375c4c
Signed-off-by: Andre Moreira Magalhaes <andre endlessm com>
https://phabricator.endlessm.com/T1388
data/dbus-interfaces/meson.build | 1 +
.../org.gnome.Shell.AppLauncher.xml | 16 ++++++
data/eos-launch.desktop.in.in | 8 +++
data/gnome-shell-dbus-interfaces.gresource.xml | 1 +
data/meson.build | 2 +
js/misc/eos-launch.js | 56 ++++++++++++++++++
js/misc/meson.build | 2 +
js/ui/appActivation.js | 35 +++++++++++
js/ui/shellDBus.js | 67 +++++++++++++++++++++-
9 files changed, 187 insertions(+), 1 deletion(-)
---
diff --git a/data/dbus-interfaces/meson.build b/data/dbus-interfaces/meson.build
index 107888bec8..e77b73a269 100644
--- a/data/dbus-interfaces/meson.build
+++ b/data/dbus-interfaces/meson.build
@@ -1,4 +1,5 @@
dbus_interfaces = [
+ 'org.gnome.Shell.AppLauncher.xml',
'org.gnome.Shell.AppStore.xml',
'org.gnome.Shell.Extensions.xml',
'org.gnome.Shell.Introspect.xml',
diff --git a/data/dbus-interfaces/org.gnome.Shell.AppLauncher.xml
b/data/dbus-interfaces/org.gnome.Shell.AppLauncher.xml
new file mode 100644
index 0000000000..f02d8bc5b4
--- /dev/null
+++ b/data/dbus-interfaces/org.gnome.Shell.AppLauncher.xml
@@ -0,0 +1,16 @@
+<node>
+ <interface name="org.gnome.Shell.AppLauncher">
+ <method name="Launch">
+ <arg type="s" direction="in" name="name" />
+ <arg type="u" direction="in" name="timestamp" />
+ </method>
+ <method name="LaunchViaDBusCall">
+ <arg type="s" direction="in" name="name" />
+ <arg type="s" direction="in" name="busName" />
+ <arg type="s" direction="in" name="objectPath" />
+ <arg type="s" direction="in" name="interfaceName" />
+ <arg type="s" direction="in" name="methodName" />
+ <arg type="v" direction="in" name="args" />
+ </method>
+ </interface>
+</node>
diff --git a/data/eos-launch.desktop.in.in b/data/eos-launch.desktop.in.in
new file mode 100644
index 0000000000..820557a345
--- /dev/null
+++ b/data/eos-launch.desktop.in.in
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=EOS Launch
+Comment=Utility to launch EndlessOS applications
+Exec=gjs @pkgdatadir@/eos-launch.js %U
+Categories=EndlessOS;Utility;Core;
+MimeType=x-scheme-handler/endlessm-app;
+Type=Application
+NoDisplay=true
diff --git a/data/gnome-shell-dbus-interfaces.gresource.xml b/data/gnome-shell-dbus-interfaces.gresource.xml
index 536c1daa6a..df3b64b074 100644
--- a/data/gnome-shell-dbus-interfaces.gresource.xml
+++ b/data/gnome-shell-dbus-interfaces.gresource.xml
@@ -42,6 +42,7 @@
<file preprocess="xml-stripblanks">org.gnome.SettingsDaemon.Power.Screen.xml</file>
<file preprocess="xml-stripblanks">org.gnome.SettingsDaemon.Rfkill.xml</file>
<file preprocess="xml-stripblanks">org.gnome.SettingsDaemon.Wacom.xml</file>
+ <file preprocess="xml-stripblanks">org.gnome.Shell.AppLauncher.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.AppStore.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.AudioDeviceSelection.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.CalendarServer.xml</file>
diff --git a/data/meson.build b/data/meson.build
index 2146ce5bf1..29257bbcd5 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -1,5 +1,6 @@
desktop_files = [
'org.gnome.Shell.desktop',
+ 'eos-launch.desktop',
]
service_files = []
@@ -12,6 +13,7 @@ desktopconf = configuration_data()
# We substitute in bindir so it works as an autostart
# file when built in a non-system prefix
desktopconf.set('bindir', bindir)
+desktopconf.set('pkgdatadir', pkgdatadir)
desktopconf.set('systemd_hidden', have_systemd ? 'true' : 'false')
foreach desktop_file : desktop_files
diff --git a/js/misc/eos-launch.js b/js/misc/eos-launch.js
new file mode 100644
index 0000000000..e4cda69d9a
--- /dev/null
+++ b/js/misc/eos-launch.js
@@ -0,0 +1,56 @@
+const { Gio, GLib } = imports.gi;
+
+const AppLauncherIface = '<node> \
+<interface name="org.gnome.Shell.AppLauncher"> \
+<method name="Launch"> \
+ <arg type="s" direction="in" name="name" /> \
+ <arg type="u" direction="in" name="timestamp" /> \
+</method> \
+</interface> \
+</node>';
+
+const AppLauncherProxy = Gio.DBusProxy.makeProxyWrapper(AppLauncherIface);
+
+function getLocalizedAppNames(appName) {
+ // trim .desktop part, if present
+ let idx = appName.indexOf('.desktop');
+ if (idx !== -1)
+ appName = appName.substring(0, idx);
+
+ let appNames = [appName];
+
+ let languageNames = GLib.get_language_names();
+ let variants = GLib.get_locale_variants(languageNames[0]);
+ variants.filter(variant => {
+ // discard variants with an encoding
+ return variant.indexOf('.') === -1;
+ }).forEach(variant => {
+ appNames.push(`${appName}.${variant}`);
+ });
+
+ appNames.push(`${appName}.en`);
+ return appNames;
+}
+
+function createProxyAndLaunch(appName) {
+ try {
+ let proxy = new AppLauncherProxy(
+ Gio.DBus.session,
+ 'org.gnome.Shell',
+ '/org/gnome/Shell');
+ proxy.LaunchSync(appName, 0);
+ } catch (error) {
+ logError(error, `Failed to launch application '${appName}'`);
+ }
+}
+
+var uri = ARGV[0];
+if (!uri) {
+ print('Usage: eos-launch endlessm-app://<application-name>\n');
+} else {
+ let tokens = uri.match(/(endlessm-app:\/\/|)([0-9,a-z,A-Z,-_.]+)/);
+ if (tokens) {
+ let appNames = getLocalizedAppNames(tokens[2]);
+ appNames.some(createProxyAndLaunch);
+ }
+}
diff --git a/js/misc/meson.build b/js/misc/meson.build
index 6b56c9ef69..3947ae66ee 100644
--- a/js/misc/meson.build
+++ b/js/misc/meson.build
@@ -14,3 +14,5 @@ config_js = configure_file(
output: 'config.js',
configuration: jsconf
)
+
+install_data('eos-launch.js', install_dir: pkgdatadir)
diff --git a/js/ui/appActivation.js b/js/ui/appActivation.js
index 53a479704f..88cfe13ac9 100644
--- a/js/ui/appActivation.js
+++ b/js/ui/appActivation.js
@@ -82,6 +82,41 @@ var AppActivationContext = class {
this.showSplash();
}
+ // Activate an app via a D-Bus call and keep track of its splash screen
+ // if we had to open a new window for it. Otherwise, if there were
+ // windows already open, just do the D-Bus call
+ activateViaDBusCall(busName, path, interfaceName, method, args, done) {
+ Gio.bus_get(Gio.BusType.SESSION, null, (source, result) => {
+ let bus = null;
+ try {
+ bus = Gio.bus_get_finish(result);
+ } catch (error) {
+ done(error, null);
+ return;
+ }
+
+ let proxy = new Gio.DBusProxy({
+ g_bus_type: Gio.BusType.SESSION,
+ g_connection: bus,
+ g_default_timeout: GLib.MAXINT32,
+ g_flags: Gio.DBusProxyFlags.NONE,
+ g_interface_name: interfaceName,
+ g_name: busName,
+ g_object_path: path,
+ });
+
+ this.showSplash();
+
+ proxy.call(method, args, Gio.DBusCallFlags.NONE, -1, null, (source2, result2) => {
+ try {
+ done(null, proxy.call_finish(result2));
+ } catch (error) {
+ done(error, null);
+ }
+ });
+ });
+ }
+
activate(event, timestamp) {
let button = event ? event.get_button() : 0;
let modifiers = event ? event.get_state() : 0;
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index d734b46499..69a84410e9 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -1,8 +1,9 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported GnomeShell, ScreenSaverDBus */
-const { EosMetrics, Gio, GLib, Meta } = imports.gi;
+const { EosMetrics, Gio, GLib, Meta, Shell } = imports.gi;
+const AppActivation = imports.ui.appActivation;
const Config = imports.misc.config;
const ExtensionDownloader = imports.ui.extensionDownloader;
const ExtensionUtils = imports.misc.extensionUtils;
@@ -27,6 +28,7 @@ var GnomeShell = class {
this._screenshotService = new Screenshot.ScreenshotService();
this._appstoreService = null;
+ this._appLauncherService = new AppLauncher();
Main.sessionMode.connect('updated', this._sessionModeChanged.bind(this));
this._sessionModeChanged();
@@ -516,3 +518,66 @@ var AppStoreService = class {
this._dbusImpl.emit_signal('ApplicationsChanged', GLib.Variant.new('(as)', [allApps]));
}
};
+
+const AppLauncherIface = loadInterfaceXML('org.gnome.Shell.AppLauncher');
+
+var AppLauncher = class {
+ constructor() {
+ this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(AppLauncherIface, this);
+ this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
+
+ this._appSys = Shell.AppSystem.get_default();
+ }
+
+ LaunchAsync(params, invocation) {
+ let [appName, timestamp] = params;
+
+ let activationContext = this._activationContextForAppName(appName);
+ if (!activationContext) {
+ invocation.return_error_literal(
+ Gio.IOErrorEnum,
+ Gio.IOErrorEnum.NOT_FOUND,
+ `Unable to launch app ${appName}: Not installed`);
+ return;
+ }
+
+ activationContext.activate(null, timestamp);
+ invocation.return_value(null);
+ }
+
+ LaunchViaDBusCallAsync(params, invocation) {
+ let [appName, busName, path, interfaceName, method, args] = params;
+
+ let activationContext = this._activationContextForAppName(appName);
+ if (!activationContext) {
+ invocation.return_error_literal(
+ Gio.IOErrorEnum,
+ Gio.IOErrorEnum.NOT_FOUND,
+ `Unable to launch app ${appName}: Not installed`);
+ return;
+ }
+
+ activationContext.activateViaDBusCall(busName, path, interfaceName, method, args, (error, result) =>
{
+ if (error) {
+ logError(error);
+ invocation.return_error_literal(
+ Gio.IOErrorEnum,
+ Gio.IOErrorEnum.FAILED,
+ `Unable to launch app ${appName} through DBus call on ${busName} ${path}
${interfaceName} ${method}: ${String(error)}`);
+ } else {
+ invocation.return_value(result);
+ }
+ });
+ }
+
+ _activationContextForAppName(appName) {
+ if (!appName.endsWith('.desktop'))
+ appName += '.desktop';
+
+ let app = this._appSys.lookup_app(appName);
+ if (!app)
+ return null;
+
+ return new AppActivation.AppActivationContext(app);
+ }
+};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]