diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 15:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 15:07:22 +0000 |
commit | f9d480cfe50ca1d7a0f0b5a2b8bb9932962bfbe7 (patch) | |
tree | ce9e8db2d4e8799780fa72ae8f1953039373e2ee /js/misc/objectManager.js | |
parent | Initial commit. (diff) | |
download | gnome-shell-f9d480cfe50ca1d7a0f0b5a2b8bb9932962bfbe7.tar.xz gnome-shell-f9d480cfe50ca1d7a0f0b5a2b8bb9932962bfbe7.zip |
Adding upstream version 3.38.6.upstream/3.38.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | js/misc/objectManager.js | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/js/misc/objectManager.js b/js/misc/objectManager.js new file mode 100644 index 0000000..4c4e0b6 --- /dev/null +++ b/js/misc/objectManager.js @@ -0,0 +1,285 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const { Gio, GLib } = imports.gi; +const Params = imports.misc.params; +const Signals = imports.signals; + +// Specified in the D-Bus specification here: +// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager +const ObjectManagerIface = ` +<node> +<interface name="org.freedesktop.DBus.ObjectManager"> + <method name="GetManagedObjects"> + <arg name="objects" type="a{oa{sa{sv}}}" direction="out"/> + </method> + <signal name="InterfacesAdded"> + <arg name="objectPath" type="o"/> + <arg name="interfaces" type="a{sa{sv}}" /> + </signal> + <signal name="InterfacesRemoved"> + <arg name="objectPath" type="o"/> + <arg name="interfaces" type="as" /> + </signal> +</interface> +</node>`; + +const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface); + +var ObjectManager = class { + constructor(params) { + params = Params.parse(params, { connection: null, + name: null, + objectPath: null, + knownInterfaces: null, + cancellable: null, + onLoaded: null }); + + this._connection = params.connection; + this._serviceName = params.name; + this._managerPath = params.objectPath; + this._cancellable = params.cancellable; + + this._managerProxy = new Gio.DBusProxy({ g_connection: this._connection, + g_interface_name: ObjectManagerInfo.name, + g_interface_info: ObjectManagerInfo, + g_name: this._serviceName, + g_object_path: this._managerPath, + g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START }); + + this._interfaceInfos = {}; + this._objects = {}; + this._interfaces = {}; + this._onLoaded = params.onLoaded; + + if (params.knownInterfaces) + this._registerInterfaces(params.knownInterfaces); + + // Start out inhibiting load until at least the proxy + // manager is loaded and the remote objects are fetched + this._numLoadInhibitors = 1; + this._initManagerProxy(); + } + + _tryToCompleteLoad() { + if (this._numLoadInhibitors == 0) + return; + + this._numLoadInhibitors--; + if (this._numLoadInhibitors == 0) { + if (this._onLoaded) + this._onLoaded(); + } + } + + async _addInterface(objectPath, interfaceName, onFinished) { + let info = this._interfaceInfos[interfaceName]; + + if (!info) { + if (onFinished) + onFinished(); + return; + } + + let proxy = new Gio.DBusProxy({ g_connection: this._connection, + g_name: this._serviceName, + g_object_path: objectPath, + g_interface_name: interfaceName, + g_interface_info: info, + g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START }); + + try { + await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable); + } catch (e) { + logError(e, `could not initialize proxy for interface ${interfaceName}`); + + if (onFinished) + onFinished(); + return; + } + + let isNewObject; + if (!this._objects[objectPath]) { + this._objects[objectPath] = {}; + isNewObject = true; + } else { + isNewObject = false; + } + + this._objects[objectPath][interfaceName] = proxy; + + if (!this._interfaces[interfaceName]) + this._interfaces[interfaceName] = []; + + this._interfaces[interfaceName].push(proxy); + + if (isNewObject) + this.emit('object-added', objectPath); + + this.emit('interface-added', interfaceName, proxy); + + if (onFinished) + onFinished(); + } + + _removeInterface(objectPath, interfaceName) { + if (!this._objects[objectPath]) + return; + + let proxy = this._objects[objectPath][interfaceName]; + + if (this._interfaces[interfaceName]) { + let index = this._interfaces[interfaceName].indexOf(proxy); + + if (index >= 0) + this._interfaces[interfaceName].splice(index, 1); + + if (this._interfaces[interfaceName].length == 0) + delete this._interfaces[interfaceName]; + } + + this.emit('interface-removed', interfaceName, proxy); + + this._objects[objectPath][interfaceName] = null; + + if (Object.keys(this._objects[objectPath]).length == 0) { + delete this._objects[objectPath]; + this.emit('object-removed', objectPath); + } + } + + async _initManagerProxy() { + try { + await this._managerProxy.init_async( + GLib.PRIORITY_DEFAULT, this._cancellable); + } catch (e) { + logError(e, `could not initialize object manager for object ${this._serviceName}`); + + this._tryToCompleteLoad(); + return; + } + + this._managerProxy.connectSignal('InterfacesAdded', + (objectManager, sender, [objectPath, interfaces]) => { + let interfaceNames = Object.keys(interfaces); + for (let i = 0; i < interfaceNames.length; i++) + this._addInterface(objectPath, interfaceNames[i]); + }); + this._managerProxy.connectSignal('InterfacesRemoved', + (objectManager, sender, [objectPath, interfaceNames]) => { + for (let i = 0; i < interfaceNames.length; i++) + this._removeInterface(objectPath, interfaceNames[i]); + }); + + if (Object.keys(this._interfaceInfos).length == 0) { + this._tryToCompleteLoad(); + return; + } + + this._managerProxy.connect('notify::g-name-owner', () => { + if (this._managerProxy.g_name_owner) + this._onNameAppeared(); + else + this._onNameVanished(); + }); + + if (this._managerProxy.g_name_owner) + this._onNameAppeared(); + } + + _onNameAppeared() { + this._managerProxy.GetManagedObjectsRemote((result, error) => { + if (!result) { + if (error) + logError(error, `could not get remote objects for service ${this._serviceName} path ${this._managerPath}`); + + this._tryToCompleteLoad(); + return; + } + + let [objects] = result; + + if (!objects) { + this._tryToCompleteLoad(); + return; + } + + let objectPaths = Object.keys(objects); + for (let i = 0; i < objectPaths.length; i++) { + let objectPath = objectPaths[i]; + let object = objects[objectPath]; + + let interfaceNames = Object.getOwnPropertyNames(object); + for (let j = 0; j < interfaceNames.length; j++) { + let interfaceName = interfaceNames[j]; + + // Prevent load from completing until the interface is loaded + this._numLoadInhibitors++; + this._addInterface(objectPath, + interfaceName, + this._tryToCompleteLoad.bind(this)); + } + } + this._tryToCompleteLoad(); + }); + } + + _onNameVanished() { + let objectPaths = Object.keys(this._objects); + for (let i = 0; i < objectPaths.length; i++) { + let objectPath = objectPaths[i]; + let object = this._objects[objectPath]; + + let interfaceNames = Object.keys(object); + for (let j = 0; j < interfaceNames.length; j++) { + let interfaceName = interfaceNames[j]; + + if (object[interfaceName]) + this._removeInterface(objectPath, interfaceName); + } + } + } + + _registerInterfaces(interfaces) { + for (let i = 0; i < interfaces.length; i++) { + let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]); + this._interfaceInfos[info.name] = info; + } + } + + getProxy(objectPath, interfaceName) { + let object = this._objects[objectPath]; + + if (!object) + return null; + + return object[interfaceName]; + } + + getProxiesForInterface(interfaceName) { + let proxyList = this._interfaces[interfaceName]; + + if (!proxyList) + return []; + + return proxyList; + } + + getAllProxies() { + let proxies = []; + + let objectPaths = Object.keys(this._objects); + for (let i = 0; i < objectPaths.length; i++) { + let object = this._objects[objectPaths]; + + let interfaceNames = Object.keys(object); + for (let j = 0; j < interfaceNames.length; j++) { + let interfaceName = interfaceNames[j]; + if (object[interfaceName]) + proxies.push(object(interfaceName)); + } + } + + return proxies; + } +}; +Signals.addSignalMethods(ObjectManager.prototype); |