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 (cherry picked from commit 10c68c6b952959d105c3126fc61f22a199e8e848)
This commit is contained in:
parent
0e7c424e50
commit
bb2764dc69
@ -46,7 +46,8 @@ dbus_interfaces = [
|
||||
'org.gnome.Shell.Screencast.xml',
|
||||
'org.gnome.Shell.Screenshot.xml',
|
||||
'org.gnome.ShellSearchProvider.xml',
|
||||
'org.gnome.ShellSearchProvider2.xml'
|
||||
'org.gnome.ShellSearchProvider2.xml',
|
||||
'org.gnome.Shell.Introspect.xml'
|
||||
]
|
||||
install_data(dbus_interfaces, install_dir: ifacedir)
|
||||
|
||||
|
37
data/org.gnome.Shell.Introspect.xml
Normal file
37
data/org.gnome.Shell.Introspect.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||
<node>
|
||||
|
||||
<!--
|
||||
org.gnome.Shell.Introspect:
|
||||
@short_description: Introspection interface
|
||||
|
||||
The interface used to introspect the state of Shell, such as running
|
||||
applications, currently active application, etc.
|
||||
-->
|
||||
<interface name="org.gnome.Shell.Introspect">
|
||||
|
||||
<!--
|
||||
RunningApplicationsChanged:
|
||||
@short_description: Notifies when the running applications changes
|
||||
-->
|
||||
<signal name="RunningApplicationsChanged" />
|
||||
|
||||
<!--
|
||||
GetRunningApplications:
|
||||
@short_description: Retrieves the description of all running applications
|
||||
|
||||
Each application is associated by an application ID. The details of
|
||||
each application consists of a varlist of keys and values. Available
|
||||
keys are listed below.
|
||||
|
||||
'active-on-seats' - (as) list of seats the application is active on
|
||||
(a seat only has at most one active
|
||||
application)
|
||||
-->
|
||||
<method name="GetRunningApplications">
|
||||
<arg name="apps" direction="out" type="a{sa{sv}}" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
@ -90,6 +90,14 @@
|
||||
adapter is ever seen not to have devices associated to it.
|
||||
</description>
|
||||
</key>
|
||||
<key name="introspect" type="b">
|
||||
<default>false</default>
|
||||
<summary>Enable introspection API</summary>
|
||||
<description>
|
||||
Enables a D-Bus API that allows to introspect the application state of
|
||||
the shell.
|
||||
</description>
|
||||
</key>
|
||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
||||
</schema>
|
||||
|
@ -19,6 +19,7 @@
|
||||
<file>misc/history.js</file>
|
||||
<file>misc/ibusManager.js</file>
|
||||
<file>misc/inputMethod.js</file>
|
||||
<file>misc/introspect.js</file>
|
||||
<file>misc/jsParse.js</file>
|
||||
<file>misc/keyboardManager.js</file>
|
||||
<file>misc/loginManager.js</file>
|
||||
|
116
js/misc/introspect.js
Normal file
116
js/misc/introspect.js
Normal file
@ -0,0 +1,116 @@
|
||||
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 IntrospectDBusIface = '<node> \
|
||||
<interface name="org.gnome.Shell.Introspect"> \
|
||||
<signal name="RunningApplicationsChanged" /> \
|
||||
<method name="GetRunningApplications"> \
|
||||
<arg name="apps" direction="out" type="a{sa{sv}}" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
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]));
|
||||
}
|
||||
});
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user