2019-01-31 09:07:06 -05:00
|
|
|
/* exported IntrospectService */
|
2019-02-08 22:21:36 -05:00
|
|
|
const { Gio, GLib, Meta, Shell } = imports.gi;
|
2018-09-05 05:15:30 -04:00
|
|
|
|
|
|
|
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');
|
|
|
|
|
2017-10-30 21:19:44 -04:00
|
|
|
var IntrospectService = class {
|
|
|
|
constructor() {
|
2018-09-05 05:15:30 -04:00
|
|
|
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();
|
2019-11-25 13:44:10 -05:00
|
|
|
|
|
|
|
this._whitelistMap = new Map();
|
|
|
|
APP_WHITELIST.forEach(appName => {
|
|
|
|
Gio.DBus.watch_name(Gio.BusType.SESSION,
|
|
|
|
appName,
|
|
|
|
Gio.BusNameWatcherFlags.NONE,
|
|
|
|
(conn, name, owner) => this._whitelistMap.set(name, owner),
|
|
|
|
(conn, name) => this._whitelistMap.delete(name));
|
|
|
|
});
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2018-09-05 05:15:30 -04:00
|
|
|
|
|
|
|
_isStandaloneApp(app) {
|
|
|
|
return app.get_windows().some(w => w.transient_for == null);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2018-09-05 05:15:30 -04:00
|
|
|
|
|
|
|
_isIntrospectEnabled() {
|
2019-01-29 14:36:54 -05:00
|
|
|
return this._settings.get_boolean(INTROSPECT_KEY);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2018-09-05 05:15:30 -04:00
|
|
|
|
|
|
|
_isSenderWhitelisted(sender) {
|
2019-11-25 13:44:10 -05:00
|
|
|
return [...this._whitelistMap.values()].includes(sender);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2018-09-05 05:15:30 -04:00
|
|
|
|
2019-05-15 18:57:27 -04:00
|
|
|
_getSandboxedAppId(app) {
|
|
|
|
let ids = app.get_windows().map(w => w.get_sandboxed_app_id());
|
|
|
|
return ids.find(id => id != null);
|
|
|
|
}
|
|
|
|
|
2018-09-05 05:15:30 -04:00
|
|
|
_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 = {};
|
2019-08-19 15:38:51 -04:00
|
|
|
let isAppActive = focusedApp == app;
|
2018-09-05 05:15:30 -04:00
|
|
|
|
|
|
|
if (!this._isStandaloneApp(app))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (isAppActive) {
|
|
|
|
appInfo['active-on-seats'] = new GLib.Variant('as', [seatName]);
|
|
|
|
newActiveApplication = app.get_id();
|
|
|
|
}
|
|
|
|
|
2019-05-15 18:57:27 -04:00
|
|
|
let sandboxedAppId = this._getSandboxedAppId(app);
|
|
|
|
if (sandboxedAppId)
|
|
|
|
appInfo['sandboxed-app-id'] = new GLib.Variant('s', sandboxedAppId);
|
|
|
|
|
2018-09-05 05:15:30 -04:00
|
|
|
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;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2018-09-05 05:15:30 -04:00
|
|
|
|
2018-12-12 10:02:29 -05:00
|
|
|
_isEligibleWindow(window) {
|
|
|
|
if (window.is_override_redirect())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
let type = window.get_window_type();
|
2019-08-19 15:38:51 -04:00
|
|
|
return type == Meta.WindowType.NORMAL ||
|
2018-12-12 10:02:29 -05:00
|
|
|
type == Meta.WindowType.DIALOG ||
|
|
|
|
type == Meta.WindowType.MODAL_DIALOG ||
|
2019-08-19 15:38:51 -04:00
|
|
|
type == Meta.WindowType.UTILITY;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2018-12-12 10:02:29 -05:00
|
|
|
|
2019-09-25 14:36:28 -04:00
|
|
|
_isInvocationAllowed(invocation) {
|
|
|
|
if (this._isIntrospectEnabled())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (this._isSenderWhitelisted(invocation.get_sender()))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-05 05:15:30 -04:00
|
|
|
GetRunningApplicationsAsync(params, invocation) {
|
2019-09-25 14:36:28 -04:00
|
|
|
if (!this._isInvocationAllowed(invocation)) {
|
2018-09-05 05:15:30 -04:00
|
|
|
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]));
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2018-12-12 10:02:29 -05:00
|
|
|
|
|
|
|
GetWindowsAsync(params, invocation) {
|
|
|
|
let focusWindow = global.display.get_focus_window();
|
|
|
|
let apps = this._appSystem.get_running();
|
|
|
|
let windowsList = {};
|
|
|
|
|
2019-09-25 14:36:28 -04:00
|
|
|
if (!this._isInvocationAllowed(invocation)) {
|
2018-12-12 10:02:29 -05:00
|
|
|
invocation.return_error_literal(Gio.DBusError,
|
|
|
|
Gio.DBusError.ACCESS_DENIED,
|
|
|
|
'App introspection not allowed');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let app of apps) {
|
|
|
|
let windows = app.get_windows();
|
|
|
|
for (let window of windows) {
|
|
|
|
|
|
|
|
if (!this._isEligibleWindow(window))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
let windowId = window.get_id();
|
|
|
|
let frameRect = window.get_frame_rect();
|
|
|
|
let title = window.get_title();
|
|
|
|
let wmClass = window.get_wm_class();
|
2019-05-15 18:57:27 -04:00
|
|
|
let sandboxedAppId = window.get_sandboxed_app_id();
|
2018-12-12 10:02:29 -05:00
|
|
|
|
|
|
|
windowsList[windowId] = {
|
|
|
|
'app-id': GLib.Variant.new('s', app.get_id()),
|
|
|
|
'client-type': GLib.Variant.new('u', window.get_client_type()),
|
|
|
|
'is-hidden': GLib.Variant.new('b', window.is_hidden()),
|
2019-08-19 15:38:51 -04:00
|
|
|
'has-focus': GLib.Variant.new('b', window == focusWindow),
|
2018-12-12 10:02:29 -05:00
|
|
|
'width': GLib.Variant.new('u', frameRect.width),
|
2019-08-20 17:43:54 -04:00
|
|
|
'height': GLib.Variant.new('u', frameRect.height),
|
2018-12-12 10:02:29 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// These properties may not be available for all windows:
|
|
|
|
if (title != null)
|
|
|
|
windowsList[windowId]['title'] = GLib.Variant.new('s', title);
|
|
|
|
|
|
|
|
if (wmClass != null)
|
|
|
|
windowsList[windowId]['wm-class'] = GLib.Variant.new('s', wmClass);
|
2019-05-15 18:57:27 -04:00
|
|
|
|
2019-08-19 20:51:42 -04:00
|
|
|
if (sandboxedAppId != null) {
|
2019-05-15 18:57:27 -04:00
|
|
|
windowsList[windowId]['sandboxed-app-id'] =
|
|
|
|
GLib.Variant.new('s', sandboxedAppId);
|
2019-08-19 20:51:42 -04:00
|
|
|
}
|
2018-12-12 10:02:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList]));
|
2018-09-05 05:15:30 -04:00
|
|
|
}
|
2017-10-30 21:19:44 -04:00
|
|
|
};
|