|
|
c7fac9 |
From e9130f3502e36262743a8c1a423a6740b64bcf7f Mon Sep 17 00:00:00 2001
|
|
|
c7fac9 |
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
|
|
c7fac9 |
Date: Wed, 5 Sep 2018 11:15:30 +0200
|
|
|
c7fac9 |
Subject: [PATCH 1/2] Add app introspection API
|
|
|
c7fac9 |
|
|
|
c7fac9 |
Add a D-Bus API that allows the API user to introspect the application
|
|
|
c7fac9 |
state of the shell. Currently the only exposed information is list of
|
|
|
c7fac9 |
running applications and which one is active (i.e. has focus).
|
|
|
c7fac9 |
|
|
|
c7fac9 |
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/326
|
|
|
c7fac9 |
(cherry picked from commit 10c68c6b952959d105c3126fc61f22a199e8e848)
|
|
|
c7fac9 |
---
|
|
|
c7fac9 |
data/meson.build | 3 +-
|
|
|
c7fac9 |
data/org.gnome.Shell.Introspect.xml | 37 +++++++++
|
|
|
c7fac9 |
data/org.gnome.shell.gschema.xml.in | 8 ++
|
|
|
c7fac9 |
js/js-resources.gresource.xml | 1 +
|
|
|
c7fac9 |
js/misc/introspect.js | 116 ++++++++++++++++++++++++++++
|
|
|
c7fac9 |
js/ui/main.js | 4 +
|
|
|
c7fac9 |
6 files changed, 168 insertions(+), 1 deletion(-)
|
|
|
c7fac9 |
create mode 100644 data/org.gnome.Shell.Introspect.xml
|
|
|
c7fac9 |
create mode 100644 js/misc/introspect.js
|
|
|
c7fac9 |
|
|
|
c7fac9 |
diff --git a/data/meson.build b/data/meson.build
|
|
|
c7fac9 |
index 7c9807721..fee44f02e 100644
|
|
|
c7fac9 |
--- a/data/meson.build
|
|
|
c7fac9 |
+++ b/data/meson.build
|
|
|
c7fac9 |
@@ -46,7 +46,8 @@ dbus_interfaces = [
|
|
|
c7fac9 |
'org.gnome.Shell.Screencast.xml',
|
|
|
c7fac9 |
'org.gnome.Shell.Screenshot.xml',
|
|
|
c7fac9 |
'org.gnome.ShellSearchProvider.xml',
|
|
|
c7fac9 |
- 'org.gnome.ShellSearchProvider2.xml'
|
|
|
c7fac9 |
+ 'org.gnome.ShellSearchProvider2.xml',
|
|
|
c7fac9 |
+ 'org.gnome.Shell.Introspect.xml'
|
|
|
c7fac9 |
]
|
|
|
c7fac9 |
install_data(dbus_interfaces, install_dir: ifacedir)
|
|
|
c7fac9 |
|
|
|
c7fac9 |
diff --git a/data/org.gnome.Shell.Introspect.xml b/data/org.gnome.Shell.Introspect.xml
|
|
|
c7fac9 |
new file mode 100644
|
|
|
c7fac9 |
index 000000000..10c48d635
|
|
|
c7fac9 |
--- /dev/null
|
|
|
c7fac9 |
+++ b/data/org.gnome.Shell.Introspect.xml
|
|
|
c7fac9 |
@@ -0,0 +1,37 @@
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
|
|
c7fac9 |
+'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
|
|
c7fac9 |
+<node>
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ org.gnome.Shell.Introspect:
|
|
|
c7fac9 |
+ @short_description: Introspection interface
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ The interface used to introspect the state of Shell, such as running
|
|
|
c7fac9 |
+ applications, currently active application, etc.
|
|
|
c7fac9 |
+ -->
|
|
|
c7fac9 |
+ <interface name="org.gnome.Shell.Introspect">
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ RunningApplicationsChanged:
|
|
|
c7fac9 |
+ @short_description: Notifies when the running applications changes
|
|
|
c7fac9 |
+ -->
|
|
|
c7fac9 |
+ <signal name="RunningApplicationsChanged" />
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ GetRunningApplications:
|
|
|
c7fac9 |
+ @short_description: Retrieves the description of all running applications
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ Each application is associated by an application ID. The details of
|
|
|
c7fac9 |
+ each application consists of a varlist of keys and values. Available
|
|
|
c7fac9 |
+ keys are listed below.
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ 'active-on-seats' - (as) list of seats the application is active on
|
|
|
c7fac9 |
+ (a seat only has at most one active
|
|
|
c7fac9 |
+ application)
|
|
|
c7fac9 |
+ -->
|
|
|
c7fac9 |
+ <method name="GetRunningApplications">
|
|
|
c7fac9 |
+ <arg name="apps" direction="out" type="a{sa{sv}}" />
|
|
|
c7fac9 |
+ </method>
|
|
|
c7fac9 |
+ </interface>
|
|
|
c7fac9 |
+</node>
|
|
|
c7fac9 |
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
|
|
|
c7fac9 |
index 63a19032d..6917d753d 100644
|
|
|
c7fac9 |
--- a/data/org.gnome.shell.gschema.xml.in
|
|
|
c7fac9 |
+++ b/data/org.gnome.shell.gschema.xml.in
|
|
|
c7fac9 |
@@ -90,6 +90,14 @@
|
|
|
c7fac9 |
adapter is ever seen not to have devices associated to it.
|
|
|
c7fac9 |
</description>
|
|
|
c7fac9 |
</key>
|
|
|
c7fac9 |
+ <key name="introspect" type="b">
|
|
|
c7fac9 |
+ <default>false</default>
|
|
|
c7fac9 |
+ <summary>Enable introspection API</summary>
|
|
|
c7fac9 |
+ <description>
|
|
|
c7fac9 |
+ Enables a D-Bus API that allows to introspect the application state of
|
|
|
c7fac9 |
+ the shell.
|
|
|
c7fac9 |
+ </description>
|
|
|
c7fac9 |
+ </key>
|
|
|
c7fac9 |
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
|
|
c7fac9 |
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
|
|
c7fac9 |
</schema>
|
|
|
c7fac9 |
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
|
|
|
c7fac9 |
index 883b62d66..77c2c2abb 100644
|
|
|
c7fac9 |
--- a/js/js-resources.gresource.xml
|
|
|
c7fac9 |
+++ b/js/js-resources.gresource.xml
|
|
|
c7fac9 |
@@ -18,6 +18,7 @@
|
|
|
c7fac9 |
<file>misc/history.js</file>
|
|
|
c7fac9 |
<file>misc/ibusManager.js</file>
|
|
|
c7fac9 |
<file>misc/inputMethod.js</file>
|
|
|
c7fac9 |
+ <file>misc/introspect.js</file>
|
|
|
c7fac9 |
<file>misc/jsParse.js</file>
|
|
|
c7fac9 |
<file>misc/keyboardManager.js</file>
|
|
|
c7fac9 |
<file>misc/loginManager.js</file>
|
|
|
c7fac9 |
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
|
|
|
c7fac9 |
new file mode 100644
|
|
|
c7fac9 |
index 000000000..05ef9e637
|
|
|
c7fac9 |
--- /dev/null
|
|
|
c7fac9 |
+++ b/js/misc/introspect.js
|
|
|
c7fac9 |
@@ -0,0 +1,116 @@
|
|
|
c7fac9 |
+const Gio = imports.gi.Gio;
|
|
|
c7fac9 |
+const GLib = imports.gi.GLib;
|
|
|
c7fac9 |
+const Lang = imports.lang;
|
|
|
c7fac9 |
+const Meta = imports.gi.Meta;
|
|
|
c7fac9 |
+const Shell = imports.gi.Shell;
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+const INTROSPECT_SCHEMA = 'org.gnome.shell';
|
|
|
c7fac9 |
+const INTROSPECT_KEY = 'introspect';
|
|
|
c7fac9 |
+const APP_WHITELIST = ['org.freedesktop.impl.portal.desktop.gtk'];
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+const IntrospectDBusIface = '<node> \
|
|
|
c7fac9 |
+ <interface name="org.gnome.Shell.Introspect"> \
|
|
|
c7fac9 |
+ <signal name="RunningApplicationsChanged" /> \
|
|
|
c7fac9 |
+ <method name="GetRunningApplications"> \
|
|
|
c7fac9 |
+ <arg name="apps" direction="out" type="a{sa{sv}}" /> \
|
|
|
c7fac9 |
+ </method> \
|
|
|
c7fac9 |
+ </interface> \
|
|
|
c7fac9 |
+</node>';
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+var IntrospectService = new Lang.Class({
|
|
|
c7fac9 |
+ Name: 'IntrospectService',
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ _init() {
|
|
|
c7fac9 |
+ this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(IntrospectDBusIface,
|
|
|
c7fac9 |
+ this);
|
|
|
c7fac9 |
+ this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Introspect');
|
|
|
c7fac9 |
+ Gio.DBus.session.own_name('org.gnome.Shell.Introspect',
|
|
|
c7fac9 |
+ Gio.BusNameOwnerFlags.REPLACE,
|
|
|
c7fac9 |
+ null, null);
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ this._runningApplications = {};
|
|
|
c7fac9 |
+ this._runningApplicationsDirty = true;
|
|
|
c7fac9 |
+ this._activeApplication = null;
|
|
|
c7fac9 |
+ this._activeApplicationDirty = true;
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ this._appSystem = Shell.AppSystem.get_default();
|
|
|
c7fac9 |
+ this._appSystem.connect('app-state-changed',
|
|
|
c7fac9 |
+ () => {
|
|
|
c7fac9 |
+ this._runningApplicationsDirty = true;
|
|
|
c7fac9 |
+ this._syncRunningApplications();
|
|
|
c7fac9 |
+ });
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ this._settings = new Gio.Settings({ schema_id: INTROSPECT_SCHEMA });
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ let tracker = Shell.WindowTracker.get_default();
|
|
|
c7fac9 |
+ tracker.connect('notify::focus-app',
|
|
|
c7fac9 |
+ () => {
|
|
|
c7fac9 |
+ this._activeApplicationDirty = true;
|
|
|
c7fac9 |
+ this._syncRunningApplications();
|
|
|
c7fac9 |
+ });
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ this._syncRunningApplications();
|
|
|
c7fac9 |
+ },
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ _isStandaloneApp(app) {
|
|
|
c7fac9 |
+ let windows = app.get_windows();
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ return app.get_windows().some(w => w.transient_for == null);
|
|
|
c7fac9 |
+ },
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ _isIntrospectEnabled() {
|
|
|
c7fac9 |
+ return this._settings.get_boolean(INTROSPECT_KEY);
|
|
|
c7fac9 |
+ },
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ _isSenderWhitelisted(sender) {
|
|
|
c7fac9 |
+ return APP_WHITELIST.includes(sender);
|
|
|
c7fac9 |
+ },
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ _syncRunningApplications() {
|
|
|
c7fac9 |
+ let tracker = Shell.WindowTracker.get_default();
|
|
|
c7fac9 |
+ let apps = this._appSystem.get_running();
|
|
|
c7fac9 |
+ let seatName = "seat0";
|
|
|
c7fac9 |
+ let newRunningApplications = {};
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ let newActiveApplication = null;
|
|
|
c7fac9 |
+ let focusedApp = tracker.focus_app;
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ for (let app of apps) {
|
|
|
c7fac9 |
+ let appInfo = {};
|
|
|
c7fac9 |
+ let isAppActive = (focusedApp == app);
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ if (!this._isStandaloneApp(app))
|
|
|
c7fac9 |
+ continue;
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ if (isAppActive) {
|
|
|
c7fac9 |
+ appInfo['active-on-seats'] = new GLib.Variant('as', [seatName]);
|
|
|
c7fac9 |
+ newActiveApplication = app.get_id();
|
|
|
c7fac9 |
+ }
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ newRunningApplications[app.get_id()] = appInfo;
|
|
|
c7fac9 |
+ }
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ if (this._runningApplicationsDirty ||
|
|
|
c7fac9 |
+ (this._activeApplicationDirty &&
|
|
|
c7fac9 |
+ this._activeApplication != newActiveApplication)) {
|
|
|
c7fac9 |
+ this._runningApplications = newRunningApplications;
|
|
|
c7fac9 |
+ this._activeApplication = newActiveApplication;
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ this._dbusImpl.emit_signal('RunningApplicationsChanged', null);
|
|
|
c7fac9 |
+ }
|
|
|
c7fac9 |
+ this._runningApplicationsDirty = false;
|
|
|
c7fac9 |
+ this._activeApplicationDirty = false;
|
|
|
c7fac9 |
+ },
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ GetRunningApplicationsAsync(params, invocation) {
|
|
|
c7fac9 |
+ if (!this._isIntrospectEnabled() &&
|
|
|
c7fac9 |
+ !this._isSenderWhitelisted(invocation.get_sender())) {
|
|
|
c7fac9 |
+ invocation.return_error_literal(Gio.DBusError,
|
|
|
c7fac9 |
+ Gio.DBusError.ACCESS_DENIED,
|
|
|
c7fac9 |
+ 'App introspection not allowed');
|
|
|
c7fac9 |
+ return;
|
|
|
c7fac9 |
+ }
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
+ invocation.return_value(new GLib.Variant('(a{sa{sv}})', [this._runningApplications]));
|
|
|
c7fac9 |
+ }
|
|
|
c7fac9 |
+});
|
|
|
c7fac9 |
diff --git a/js/ui/main.js b/js/ui/main.js
|
|
|
c7fac9 |
index 2c54bb680..0639b5e7d 100644
|
|
|
c7fac9 |
--- a/js/ui/main.js
|
|
|
c7fac9 |
+++ b/js/ui/main.js
|
|
|
c7fac9 |
@@ -20,6 +20,7 @@ const Environment = imports.ui.environment;
|
|
|
c7fac9 |
const ExtensionSystem = imports.ui.extensionSystem;
|
|
|
c7fac9 |
const ExtensionDownloader = imports.ui.extensionDownloader;
|
|
|
c7fac9 |
const InputMethod = imports.misc.inputMethod;
|
|
|
c7fac9 |
+const Introspect = imports.misc.introspect;
|
|
|
c7fac9 |
const Keyboard = imports.ui.keyboard;
|
|
|
c7fac9 |
const MessageTray = imports.ui.messageTray;
|
|
|
c7fac9 |
const ModalDialog = imports.ui.modalDialog;
|
|
|
c7fac9 |
@@ -82,6 +83,7 @@ var keyboard = null;
|
|
|
c7fac9 |
var layoutManager = null;
|
|
|
c7fac9 |
var kbdA11yDialog = null;
|
|
|
c7fac9 |
var inputMethod = null;
|
|
|
c7fac9 |
+var introspectService = null;
|
|
|
c7fac9 |
let _startDate;
|
|
|
c7fac9 |
let _defaultCssStylesheet = null;
|
|
|
c7fac9 |
let _cssStylesheet = null;
|
|
|
c7fac9 |
@@ -187,6 +189,8 @@ function _initializeUI() {
|
|
|
c7fac9 |
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
|
|
c7fac9 |
componentManager = new Components.ComponentManager();
|
|
|
c7fac9 |
|
|
|
c7fac9 |
+ introspectService = new Introspect.IntrospectService();
|
|
|
c7fac9 |
+
|
|
|
c7fac9 |
layoutManager.init();
|
|
|
c7fac9 |
overview.init();
|
|
|
c7fac9 |
|
|
|
c7fac9 |
--
|
|
|
c7fac9 |
2.20.1
|
|
|
c7fac9 |
|