From 8be0c5a58a923e57be88f073341cf72cffd9c3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 5 Sep 2018 11:15:30 +0200 Subject: [PATCH] Add app introspection API Add a D-Bus API that allows the API user to introspect the application state of the shell. Currently the only exposed information is list of running applications and which one is active (i.e. has focus). https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/326 --- data/dbus-interfaces/meson.build | 1 + .../org.gnome.Shell.Introspect.xml | 37 ++++++ .../gnome-shell-dbus-interfaces.gresource.xml | 1 + data/org.gnome.shell.gschema.xml.in | 8 ++ js/js-resources.gresource.xml | 1 + js/misc/introspect.js | 111 ++++++++++++++++++ js/ui/main.js | 4 + 7 files changed, 163 insertions(+) create mode 100644 data/dbus-interfaces/org.gnome.Shell.Introspect.xml create mode 100644 js/misc/introspect.js diff --git a/data/dbus-interfaces/meson.build b/data/dbus-interfaces/meson.build index 4ba832661..c96bbbb4d 100644 --- a/data/dbus-interfaces/meson.build +++ b/data/dbus-interfaces/meson.build @@ -1,5 +1,6 @@ dbus_interfaces = [ 'org.gnome.Shell.Extensions.xml', + 'org.gnome.Shell.Introspect.xml', 'org.gnome.Shell.PadOsd.xml', 'org.gnome.Shell.Screencast.xml', 'org.gnome.Shell.Screenshot.xml', diff --git a/data/dbus-interfaces/org.gnome.Shell.Introspect.xml b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml new file mode 100644 index 000000000..10c48d635 --- /dev/null +++ b/data/dbus-interfaces/org.gnome.Shell.Introspect.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + diff --git a/data/gnome-shell-dbus-interfaces.gresource.xml b/data/gnome-shell-dbus-interfaces.gresource.xml index 5183672c9..ba148ca1f 100644 --- a/data/gnome-shell-dbus-interfaces.gresource.xml +++ b/data/gnome-shell-dbus-interfaces.gresource.xml @@ -40,6 +40,7 @@ org.gnome.SettingsDaemon.Wacom.xml org.gnome.Shell.AudioDeviceSelection.xml org.gnome.Shell.Extensions.xml + org.gnome.Shell.Introspect.xml org.gnome.Shell.HotplugSniffer.xml org.gnome.Shell.PerfHelper.xml org.gnome.Shell.PortalHelper.xml diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in index a7251cd06..87898a36e 100644 --- a/data/org.gnome.shell.gschema.xml.in +++ b/data/org.gnome.shell.gschema.xml.in @@ -90,6 +90,14 @@ adapter is ever seen not to have devices associated to it. + + false + Enable introspection API + + Enables a D-Bus API that allows to introspect the application state of + the shell. + + diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml index 75a6c3b12..a3dd2be08 100644 --- a/js/js-resources.gresource.xml +++ b/js/js-resources.gresource.xml @@ -16,6 +16,7 @@ misc/history.js misc/ibusManager.js misc/inputMethod.js + misc/introspect.js misc/jsParse.js misc/keyboardManager.js misc/loginManager.js diff --git a/js/misc/introspect.js b/js/misc/introspect.js new file mode 100644 index 000000000..fa0a66e00 --- /dev/null +++ b/js/misc/introspect.js @@ -0,0 +1,111 @@ +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; + +const INTROSPECT_SCHEMA = 'org.gnome.shell'; +const INTROSPECT_KEY = 'introspect'; +const APP_WHITELIST = ['org.freedesktop.impl.portal.desktop.gtk']; + +const { loadInterfaceXML } = imports.misc.fileUtils; + +const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect'); + +var IntrospectService = new Lang.Class({ + Name: 'IntrospectService', + + _init() { + this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(IntrospectDBusIface, + this); + this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Introspect'); + Gio.DBus.session.own_name('org.gnome.Shell.Introspect', + Gio.BusNameOwnerFlags.REPLACE, + null, null); + + this._runningApplications = {}; + this._runningApplicationsDirty = true; + this._activeApplication = null; + this._activeApplicationDirty = true; + + this._appSystem = Shell.AppSystem.get_default(); + this._appSystem.connect('app-state-changed', + () => { + this._runningApplicationsDirty = true; + this._syncRunningApplications(); + }); + + this._settings = new Gio.Settings({ schema_id: INTROSPECT_SCHEMA }); + + let tracker = Shell.WindowTracker.get_default(); + tracker.connect('notify::focus-app', + () => { + this._activeApplicationDirty = true; + this._syncRunningApplications(); + }); + + this._syncRunningApplications(); + }, + + _isStandaloneApp(app) { + let windows = app.get_windows(); + + return app.get_windows().some(w => w.transient_for == null); + }, + + _isIntrospectEnabled() { + return this._settings.get_boolean(INTROSPECT_KEY); + }, + + _isSenderWhitelisted(sender) { + return APP_WHITELIST.includes(sender); + }, + + _syncRunningApplications() { + let tracker = Shell.WindowTracker.get_default(); + let apps = this._appSystem.get_running(); + let seatName = "seat0"; + let newRunningApplications = {}; + + let newActiveApplication = null; + let focusedApp = tracker.focus_app; + + for (let app of apps) { + let appInfo = {}; + let isAppActive = (focusedApp == app); + + if (!this._isStandaloneApp(app)) + continue; + + if (isAppActive) { + appInfo['active-on-seats'] = new GLib.Variant('as', [seatName]); + newActiveApplication = app.get_id(); + } + + newRunningApplications[app.get_id()] = appInfo; + } + + if (this._runningApplicationsDirty || + (this._activeApplicationDirty && + this._activeApplication != newActiveApplication)) { + this._runningApplications = newRunningApplications; + this._activeApplication = newActiveApplication; + + this._dbusImpl.emit_signal('RunningApplicationsChanged', null); + } + this._runningApplicationsDirty = false; + this._activeApplicationDirty = false; + }, + + GetRunningApplicationsAsync(params, invocation) { + if (!this._isIntrospectEnabled() && + !this._isSenderWhitelisted(invocation.get_sender())) { + invocation.return_error_literal(Gio.DBusError, + Gio.DBusError.ACCESS_DENIED, + 'App introspection not allowed'); + return; + } + + invocation.return_value(new GLib.Variant('(a{sa{sv}})', [this._runningApplications])); + } +}); diff --git a/js/ui/main.js b/js/ui/main.js index 9e7ce8706..f87b1ad02 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -20,6 +20,7 @@ const Environment = imports.ui.environment; const ExtensionSystem = imports.ui.extensionSystem; const ExtensionDownloader = imports.ui.extensionDownloader; const InputMethod = imports.misc.inputMethod; +const Introspect = imports.misc.introspect; const Keyboard = imports.ui.keyboard; const MessageTray = imports.ui.messageTray; const ModalDialog = imports.ui.modalDialog; @@ -82,6 +83,7 @@ var keyboard = null; var layoutManager = null; var kbdA11yDialog = null; var inputMethod = null; +var introspectService = null; let _startDate; let _defaultCssStylesheet = null; let _cssStylesheet = null; @@ -187,6 +189,8 @@ function _initializeUI() { windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler(); componentManager = new Components.ComponentManager(); + introspectService = new Introspect.IntrospectService(); + layoutManager.init(); overview.init();