Blame SOURCES/0001-Add-app-introspection-API.patch

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