BossBey File Manager
PHP:
8.2.28
OS:
Linux
User:
www-data
Root
/
usr
/
share
/
cinnamon
/
js
/
misc
📤 Upload
📝 New File
📁 New Folder
Close
Editing: signalManager.js
const GObject = imports.gi.GObject; const Lang = imports.lang; const _signalIsConnected = function(signal) { let [sigName, obj, callback, id] = signal; if (!obj) { return false; } if (obj instanceof GObject.Object) { // GObject // MetaWindowActor is always destroyed in muffin, so accessing the // object here will trigger finalized object warnings from CJS. if (obj.is_finalized()) { return false; } return GObject.signal_handler_is_connected(obj, id); } if ('signalHandlerIsConnected' in obj) { // JS Object return obj.signalHandlerIsConnected(id); } return false; }; const _disconnect = function(results) { for (let i = 0; i < results.length; i++) { let [sigName, obj, callback, id] = results[i]; obj.disconnect(id); } }; /** * #SignalManager: * @short_description: A convenience object for managing signals * @_object (Object): The object owning the SignalManager. All callbacks are * binded to %_object unless otherwise specified. * @_storage (Array): An array that stores all the connected signals. Each * signal is stored as an array in the form `[signalName, object, callback, * signalId]`. * * The #SignalManager is a convenience object for managing signals. If you use * this to connect signals, you can later disconnect them by signal name or * just disconnect everything! No need to keep track of those annoying * @signalIds by yourself anymore! * * A common use case is to use the #SignalManager to connect to signals and then * use the @disconnectAllSignals function when the object is destroyed, to * avoid keeping track of all the signals manually. * * However, this is not always needed. If you are connecting to a signal of * your actor, the signals are automatically disconnected when you destroy the * actor. Using the #SignalManager to disconnect all signals is only needed when * connecting to objects that persists after the object disappears. * * Every Javascript object should have its own @SignalManager, and use it to * connect signals of all objects it takes care of. For example, the panel will * have one #SignalManger object, which manages all signals from #GSettings, * `global.display` etc. * * An example usage is as follows: * ``` * class MyApplet extends Applet.Applet { * constructor(orientation, panelHeight, instanceId) { * super(orientation, panelHeight, instanceId); * * this._signalManager = new SignalManager.SignalManager(null); * this._signalManager.connect(global.settings, "changed::foo", (...args) => this._onChanged(...args)); * } * * _onChanged() { * // Do something * } * * on_applet_removed_from_panel() { * this._signalManager.disconnectAllSignals(); * } * } * ``` */ var debug = false; var SignalManager = class SignalManager { /** * _init: * @object (Object): the object owning the #SignalManager (usually @this) (Deprecated) */ constructor(object) { if (object) { global.dump_gjs_stack( 'Initializing SignalManager with an object is deprecated.' + ' Please bind the callback before passing it to SignalManager.' ); } this._storage = []; } /** * connect: * @obj (Object): the object whose signal we are listening to * @sigName (string): the name of the signal we are listening to * @callback (function): the callback function * @bind (Object): (optional) the object to bind the function to. Leave * empty for the owner of the #SignalManager (which has no side effects if * you don't need to bind at all). * @force (boolean): whether to connect again even if it is connected * * This listens to the signal @sigName from @obj and calls @callback when * the signal is emitted. @callback is bound to the @bind argument if passed. * * This checks whether the signal is already connected and will not connect * again if it is already connected. This behaviour can be overridden by * settings @force to be @true. * * For example, what you would normally write as * ``` * global.settings.connect("changed::foo", Lang.bind(this, this._bar)) * ``` * would become * ``` * this._signalManager.connect(global.settings, "changed::foo", this._bar) * ``` * * Note that in this function, the first argument is the object, while the * second is the signal name. In all other methods, you first pass the * signal name, then the object (since the object is rarely passed in other * functions). */ _connect(method, obj, sigName, callback, bind, force) { if (debug) { log(`SignalManager connecting to '${sigName} of ${obj}`); } if (!obj || (!force && this.isConnected(sigName, obj, callback))) return; let id = bind ? obj[method](sigName, Lang.bind(bind, callback)) : obj[method](sigName, callback); this._storage.push([sigName, obj, callback, id]); } connect() { this._connect('connect', ...arguments); } connect_after() { this._connect('connect_after', ...arguments); } /** * isConnected: * @sigName (string): the signal we care about * @obj (Object): (optional) the object we care about, or leave empty if we * don't care about which object it is * @callback (function): (optional) the callback function we care about, or * leave empty if we don't care about what callback is connected * * This checks whether the signal @sigName is connected. The optional * arguments @obj and @callback can be used to specify what signals in * particular we want to know. Note that when you supply @callBack, you * usually want to supply @obj as well, since two different objects can * connect to the same signal with the same callback. * * This is functionally equivalent to (and implemented as) * ``` * this.getSignals(arguments).length > 0); * ``` * * Returns: Whether the signal is connected */ isConnected() { return this.getSignals.apply(this, arguments).length > 0; } /** * getSignals: * @sigName (string): the signal we care about * @obj (Object): (optional) the object we care about, or leave empty if we * don't care about which object it is * @callback (function): (optional) the callback function we care about, or * leave empty if we don't care about what callback is connected * * This returns the list of all signals that matches the description * provided. Each signal is represented by an array in the form * `[signalName, object, callback, signalId]`. * * Returns (Array): The list of signals */ getSignals(sigName, obj, callback) { let results = this._storage; if (sigName) results = results.filter(x => x[0] == sigName); if (obj) results = results.filter(x => x[1] == obj); if (callback) results = results.filter(x => x[2] == callback); return results; } /** * disconnect: * @sigName (string): the signal we care about * @obj (Object): (optional) the object we care about, or leave empty if we * don't care about which object it is * @callback (function): (optional) the callback function we care about, or * leave empty if we don't care about what callback is connected * * This disconnects all *signals* named @sigName. By default, it * disconnects the signal on all objects, but can be fine-tuned with the * optional @obj and @callback arguments. * * This function will do nothing if no such signal is connected, the object * no longer exists, or the signal is somehow already disconnected. So * checks need not be performed before calling this function. */ disconnect() { let results = this.getSignals.apply(this, arguments).filter(_signalIsConnected); _disconnect(results); this._storage = this._storage.filter((x) => { return results.findIndex(function(signalObj) { return signalObj[0] === x[0] && signalObj[1] === x[1]; }) === -1; }); } /** * disconnectAllSignals: * * Disconnects *all signals* managed by the #SignalManager. This is useful * in the @destroy function of objects. */ disconnectAllSignals() { _disconnect( this._storage.filter(_signalIsConnected) ); this._storage = []; } }
Save
Cancel