From a88e59c1a80163647194476b53f5378c5350ecec Mon Sep 17 00:00:00 2001 From: Evan Welsh Date: Mon, 4 Jul 2022 18:30:44 -0400 Subject: [PATCH] Adopt EventEmitter class instead of injecting Signal methods Introduce a new class, EventEmitter, which implements signal handling for pure JavaScript classes. EventEmitter still utilizes GJS' addSignalMethods internally. EventEmitter allows static typechecking to understand the structure of event-emitting JS classes and makes creating child classes simpler. The name 'EventEmitter' mirrors a common name for this pattern in Node and in JS libraries. Part-of: --- js/gdm/batch.js | 12 +++++------- js/gdm/credentialManager.js | 6 +++++- js/gdm/oVirt.js | 2 -- js/gdm/realmd.js | 8 +++++--- js/gdm/util.js | 9 +++++---- js/gdm/vmware.js | 2 -- js/js-resources.gresource.xml | 1 + js/misc/history.js | 8 +++++--- js/misc/ibusManager.js | 7 ++++--- js/misc/loginManager.js | 10 +++++----- js/misc/objectManager.js | 8 +++++--- js/misc/signalTracker.js | 21 +-------------------- js/misc/signals.js | 22 ++++++++++++++++++++++ js/misc/smartcardManager.js | 7 ++++--- js/misc/weather.js | 8 +++++--- js/ui/appFavorites.js | 7 ++++--- js/ui/background.js | 13 +++++++------ js/ui/components/networkAgent.js | 7 ++++--- js/ui/dnd.js | 7 ++++--- js/ui/environment.js | 7 ------- js/ui/extensionSystem.js | 9 +++++---- js/ui/focusCaretTracker.js | 8 +++++--- js/ui/keyboard.js | 12 +++++++----- js/ui/layout.js | 7 ++++--- js/ui/lookingGlass.js | 7 ++++--- js/ui/magnifier.js | 8 +++++--- js/ui/mpris.js | 15 ++++++++------- js/ui/overview.js | 7 ++++--- js/ui/padOsd.js | 7 ++++--- js/ui/popupMenu.js | 12 +++++++----- js/ui/screenShield.js | 8 +++++--- js/ui/sessionMode.js | 7 ++++--- js/ui/status/keyboard.js | 17 ++++++++++------- js/ui/status/network.js | 18 ++++++++++-------- js/ui/status/rfkill.js | 25 +++++++++++++------------ js/ui/status/thunderbolt.js | 12 +++++++----- js/ui/status/volume.js | 7 ++++--- js/ui/xdndHandler.js | 8 +++++--- tests/unit/signalTracker.js | 7 ++----- 39 files changed, 204 insertions(+), 169 deletions(-) create mode 100644 js/misc/signals.js diff --git a/js/gdm/batch.js b/js/gdm/batch.js index ca29fc792..f841f0f8e 100644 --- a/js/gdm/batch.js +++ b/js/gdm/batch.js @@ -43,12 +43,15 @@ * are not used elsewhere. These APIs may ultimately get dropped entirely and * replaced by something else. */ +/* exported ConcurrentBatch, ConsecutiveBatch */ const { GObject } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; -var Task = class { +var Task = class extends Signals.EventEmitter { constructor(scope, handler) { + super(); + if (scope) this.scope = scope; else @@ -64,7 +67,6 @@ var Task = class { return null; } }; -Signals.addSignalMethods(Task.prototype); var Hold = class extends Task { constructor() { @@ -101,7 +103,6 @@ var Hold = class extends Task { return this._acquisitions > 0; } }; -Signals.addSignalMethods(Hold.prototype); var Batch = class extends Task { constructor(scope, tasks) { @@ -171,7 +172,6 @@ var Batch = class extends Task { this.tasks = this.tasks.splice(0, this._currentTaskIndex + 1); } }; -Signals.addSignalMethods(Batch.prototype); var ConcurrentBatch = class extends Batch { process() { @@ -186,7 +186,6 @@ var ConcurrentBatch = class extends Batch { this.nextTask(); } }; -Signals.addSignalMethods(ConcurrentBatch.prototype); var ConsecutiveBatch = class extends Batch { process() { @@ -205,4 +204,3 @@ var ConsecutiveBatch = class extends Batch { } } }; -Signals.addSignalMethods(ConsecutiveBatch.prototype); diff --git a/js/gdm/credentialManager.js b/js/gdm/credentialManager.js index 5c4bc7e62..c53de11df 100644 --- a/js/gdm/credentialManager.js +++ b/js/gdm/credentialManager.js @@ -1,8 +1,12 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- /* exported CredentialManager */ -var CredentialManager = class CredentialManager { +const Signals = imports.misc.signals; + +var CredentialManager = class CredentialManager extends Signals.EventEmitter { constructor(service) { + super(); + this._token = null; this._service = service; this._authenticatedSignalId = null; diff --git a/js/gdm/oVirt.js b/js/gdm/oVirt.js index 21b43b246..32e0aa528 100644 --- a/js/gdm/oVirt.js +++ b/js/gdm/oVirt.js @@ -2,7 +2,6 @@ /* exported getOVirtCredentialsManager */ const Gio = imports.gi.Gio; -const Signals = imports.signals; const Credential = imports.gdm.credentialManager; var SERVICE_NAME = 'gdm-ovirtcred'; @@ -43,7 +42,6 @@ var OVirtCredentialsManager = class OVirtCredentialsManager extends Credential.C }); } }; -Signals.addSignalMethods(OVirtCredentialsManager.prototype); function getOVirtCredentialsManager() { if (!_oVirtCredentialsManager) diff --git a/js/gdm/realmd.js b/js/gdm/realmd.js index ba38bcd62..3c16098d4 100644 --- a/js/gdm/realmd.js +++ b/js/gdm/realmd.js @@ -1,7 +1,8 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported Manager */ const Gio = imports.gi.Gio; -const Signals = imports.signals; +const Signals = imports.misc.signals; const { loadInterfaceXML } = imports.misc.fileUtils; @@ -14,8 +15,10 @@ const Service = Gio.DBusProxy.makeProxyWrapper(ServiceIface); const RealmIface = loadInterfaceXML("org.freedesktop.realmd.Realm"); const Realm = Gio.DBusProxy.makeProxyWrapper(RealmIface); -var Manager = class { +var Manager = class extends Signals.EventEmitter { constructor() { + super(); + this._aggregateProvider = Provider(Gio.DBus.system, 'org.freedesktop.realmd', '/org/freedesktop/realmd', @@ -105,4 +108,3 @@ var Manager = class { this._updateLoginFormat(); } }; -Signals.addSignalMethods(Manager.prototype); diff --git a/js/gdm/util.js b/js/gdm/util.js index 53cbb72ff..d4923f2a7 100644 --- a/js/gdm/util.js +++ b/js/gdm/util.js @@ -1,9 +1,10 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- /* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY, - DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */ + DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor, + ShellUserVerifier */ const { Clutter, Gdm, Gio, GLib } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Batch = imports.gdm.batch; const OVirt = imports.gdm.oVirt; @@ -135,8 +136,9 @@ function cloneAndFadeOutActor(actor) { return hold; } -var ShellUserVerifier = class { +var ShellUserVerifier = class extends Signals.EventEmitter { constructor(client, params) { + super(); params = Params.parse(params, { reauthenticationOnly: false }); this._reauthOnly = params.reauthenticationOnly; @@ -783,4 +785,3 @@ var ShellUserVerifier = class { this._verificationFailed(serviceName, true); } }; -Signals.addSignalMethods(ShellUserVerifier.prototype); diff --git a/js/gdm/vmware.js b/js/gdm/vmware.js index 20d40743e..260b7c8e9 100644 --- a/js/gdm/vmware.js +++ b/js/gdm/vmware.js @@ -2,7 +2,6 @@ /* exported getVmwareCredentialsManager */ const Gio = imports.gi.Gio; -const Signals = imports.signals; const Credential = imports.gdm.credentialManager; const dbusPath = '/org/vmware/viewagent/Credentials'; @@ -46,7 +45,6 @@ var VmwareCredentialsManager = class VmwareCredentialsManager extends Credential }); } }; -Signals.addSignalMethods(VmwareCredentialsManager.prototype); function getVmwareCredentialsManager() { if (!_vmwareCredentialsManager) diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml index eb4e365ae..fc5af0aee 100644 --- a/js/js-resources.gresource.xml +++ b/js/js-resources.gresource.xml @@ -29,6 +29,7 @@ misc/permissionStore.js misc/signalTracker.js misc/smartcardManager.js + misc/signals.js misc/systemActions.js misc/util.js misc/weather.js diff --git a/js/misc/history.js b/js/misc/history.js index af21574ce..268f13bb8 100644 --- a/js/misc/history.js +++ b/js/misc/history.js @@ -1,13 +1,16 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported HistoryManager */ -const Signals = imports.signals; +const Signals = imports.misc.signals; const Clutter = imports.gi.Clutter; const Params = imports.misc.params; var DEFAULT_LIMIT = 512; -var HistoryManager = class { +var HistoryManager = class extends Signals.EventEmitter { constructor(params) { + super(); + params = Params.parse(params, { gsettingsKey: null, limit: DEFAULT_LIMIT, @@ -109,4 +112,3 @@ var HistoryManager = class { global.settings.set_strv(this._key, this._history); } }; -Signals.addSignalMethods(HistoryManager.prototype); diff --git a/js/misc/ibusManager.js b/js/misc/ibusManager.js index 8bcfb3674..ce43489ae 100644 --- a/js/misc/ibusManager.js +++ b/js/misc/ibusManager.js @@ -2,7 +2,7 @@ /* exported getIBusManager */ const { Gio, GLib, IBus, Meta, Shell } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const IBusCandidatePopup = imports.ui.ibusCandidatePopup; @@ -40,8 +40,10 @@ function getIBusManager() { return _ibusManager; } -var IBusManager = class { +var IBusManager = class extends Signals.EventEmitter { constructor() { + super(); + IBus.init(); // This is the longest we'll keep the keyboard frozen until an input @@ -325,4 +327,3 @@ var IBusManager = class { }); } }; -Signals.addSignalMethods(IBusManager.prototype); diff --git a/js/misc/loginManager.js b/js/misc/loginManager.js index dec0b120b..f5ebaf657 100644 --- a/js/misc/loginManager.js +++ b/js/misc/loginManager.js @@ -2,7 +2,7 @@ /* exported canLock, getLoginManager, registerSessionWithGDM */ const { GLib, Gio } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const { loadInterfaceXML } = imports.misc.fileUtils; @@ -87,8 +87,10 @@ function getLoginManager() { return _loginManager; } -var LoginManagerSystemd = class { +var LoginManagerSystemd = class extends Signals.EventEmitter { constructor() { + super(); + this._proxy = new SystemdLoginManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); @@ -202,9 +204,8 @@ var LoginManagerSystemd = class { this.emit('prepare-for-sleep', aboutToSuspend); } }; -Signals.addSignalMethods(LoginManagerSystemd.prototype); -var LoginManagerDummy = class { +var LoginManagerDummy = class extends Signals.EventEmitter { getCurrentSessionProxy(_callback) { // we could return a DummySession object that fakes whatever callers // expect (at the time of writing: connect() and connectSignal() @@ -236,4 +237,3 @@ var LoginManagerDummy = class { return null; } }; -Signals.addSignalMethods(LoginManagerDummy.prototype); diff --git a/js/misc/objectManager.js b/js/misc/objectManager.js index 42076f21e..724e5d24e 100644 --- a/js/misc/objectManager.js +++ b/js/misc/objectManager.js @@ -1,8 +1,9 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported ObjectManager */ const { Gio, GLib } = imports.gi; const Params = imports.misc.params; -const Signals = imports.signals; +const Signals = imports.misc.signals; // Specified in the D-Bus specification here: // http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager @@ -25,8 +26,10 @@ const ObjectManagerIface = ` const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface); -var ObjectManager = class { +var ObjectManager = class extends Signals.EventEmitter { constructor(params) { + super(); + params = Params.parse(params, { connection: null, name: null, @@ -288,4 +291,3 @@ var ObjectManager = class { return proxies; } }; -Signals.addSignalMethods(ObjectManager.prototype); diff --git a/js/misc/signalTracker.js b/js/misc/signalTracker.js index bcfa72de9..e7a14910d 100644 --- a/js/misc/signalTracker.js +++ b/js/misc/signalTracker.js @@ -1,4 +1,4 @@ -/* exported TransientSignalHolder, addObjectSignalMethods */ +/* exported TransientSignalHolder, connectObject, disconnectObject */ const { GObject } = imports.gi; const destroyableTypes = []; @@ -214,25 +214,6 @@ function disconnectObject(thisObj, obj) { SignalManager.getDefault().getSignalTracker(thisObj).untrack(obj); } -/** - * Add connectObject()/disconnectObject() methods - * to prototype. The prototype must have the connect() - * and disconnect() signal methods. - * - * @param {prototype} proto - a prototype - */ -function addObjectSignalMethods(proto) { - proto['connectObject'] = function (...args) { - connectObject(this, ...args); - }; - proto['connect_object'] = proto['connectObject']; - - proto['disconnectObject'] = function (obj) { - disconnectObject(this, obj); - }; - proto['disconnect_object'] = proto['disconnectObject']; -} - /** * Register a GObject type as having a 'destroy' signal * that should disconnect all handlers diff --git a/js/misc/signals.js b/js/misc/signals.js new file mode 100644 index 000000000..f4acced0c --- /dev/null +++ b/js/misc/signals.js @@ -0,0 +1,22 @@ +const Signals = imports.signals; +const SignalTracker = imports.misc.signalTracker; + +var EventEmitter = class EventEmitter { + connectObject(...args) { + return SignalTracker.connectObject(this, ...args); + } + + disconnectObject(...args) { + return SignalTracker.disconnectObject(this, ...args); + } + + connect_object(...args) { + return this.connectObject(...args); + } + + disconnect_object(...args) { + return this.disconnectObject(...args); + } +}; + +Signals.addSignalMethods(EventEmitter.prototype); diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js index 938327238..851cc445f 100644 --- a/js/misc/smartcardManager.js +++ b/js/misc/smartcardManager.js @@ -2,7 +2,7 @@ /* exported getSmartcardManager */ const Gio = imports.gi.Gio; -const Signals = imports.signals; +const Signals = imports.misc.signals; const ObjectManager = imports.misc.objectManager; @@ -25,8 +25,10 @@ function getSmartcardManager() { return _smartcardManager; } -var SmartcardManager = class { +var SmartcardManager = class extends Signals.EventEmitter { constructor() { + super(); + this._objectManager = new ObjectManager.ObjectManager({ connection: Gio.DBus.session, name: 'org.gnome.SettingsDaemon.Smartcard', @@ -114,4 +116,3 @@ var SmartcardManager = class { return true; } }; -Signals.addSignalMethods(SmartcardManager.prototype); diff --git a/js/misc/weather.js b/js/misc/weather.js index 1cd4e38ee..4f175b956 100644 --- a/js/misc/weather.js +++ b/js/misc/weather.js @@ -1,7 +1,8 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported WeatherClient */ const { Geoclue, Gio, GLib, GWeather, Shell } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const PermissionStore = imports.misc.permissionStore; @@ -20,8 +21,10 @@ const WEATHER_APP_ID = 'org.gnome.Weather.desktop'; // Minimum time between updates to show loading indication var UPDATE_THRESHOLD = 10 * GLib.TIME_SPAN_MINUTE; -var WeatherClient = class { +var WeatherClient = class extends Signals.EventEmitter { constructor() { + super(); + this._loading = false; this._locationValid = false; this._lastUpdate = GLib.DateTime.new_from_unix_local(0); @@ -319,4 +322,3 @@ var WeatherClient = class { this._updateAutoLocation(); } }; -Signals.addSignalMethods(WeatherClient.prototype); diff --git a/js/ui/appFavorites.js b/js/ui/appFavorites.js index 18fc3d020..d8a3018e5 100644 --- a/js/ui/appFavorites.js +++ b/js/ui/appFavorites.js @@ -3,7 +3,7 @@ const Shell = imports.gi.Shell; const ParentalControlsManager = imports.misc.parentalControlsManager; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Main = imports.ui.main; @@ -64,8 +64,10 @@ const RENAMED_DESKTOP_IDS = { 'evince.desktop': 'org.gnome.Evince.desktop', }; -class AppFavorites { +class AppFavorites extends Signals.EventEmitter { constructor() { + super(); + // Filter the apps through the user’s parental controls. this._parentalControlsManager = ParentalControlsManager.getDefault(); this._parentalControlsManager.connect('app-filter-changed', () => { @@ -201,7 +203,6 @@ class AppFavorites { }); } } -Signals.addSignalMethods(AppFavorites.prototype); var appFavoritesInstance = null; function getAppFavorites() { diff --git a/js/ui/background.js b/js/ui/background.js index a68f23301..829ffb42b 100644 --- a/js/ui/background.js +++ b/js/ui/background.js @@ -1,5 +1,5 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported SystemBackground */ +/* exported SystemBackground, BackgroundManager */ // READ THIS FIRST // Background handling is a maze of objects, both objects in this file, and @@ -95,7 +95,7 @@ // MetaBackgroundImage MetaBackgroundImage const { Clutter, GDesktopEnums, Gio, GLib, GObject, GnomeDesktop, Meta } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const LoginManager = imports.misc.loginManager; const Main = imports.ui.main; @@ -137,8 +137,10 @@ function _fileEqual0(file1, file2) { return file1.equal(file2); } -var BackgroundCache = class BackgroundCache { +var BackgroundCache = class BackgroundCache extends Signals.EventEmitter { constructor() { + super(); + this._fileMonitors = {}; this._backgroundSources = {}; this._animations = {}; @@ -221,7 +223,6 @@ var BackgroundCache = class BackgroundCache { } } }; -Signals.addSignalMethods(BackgroundCache.prototype); function getBackgroundCache() { if (!_backgroundCache) @@ -682,8 +683,9 @@ class Animation extends GnomeDesktop.BGSlideShow { } }); -var BackgroundManager = class BackgroundManager { +var BackgroundManager = class BackgroundManager extends Signals.EventEmitter { constructor(params) { + super(); params = Params.parse(params, { container: null, layoutManager: Main.layoutManager, @@ -838,4 +840,3 @@ var BackgroundManager = class BackgroundManager { return backgroundActor; } }; -Signals.addSignalMethods(BackgroundManager.prototype); diff --git a/js/ui/components/networkAgent.js b/js/ui/components/networkAgent.js index 532924ce5..ba02f88be 100644 --- a/js/ui/components/networkAgent.js +++ b/js/ui/components/networkAgent.js @@ -2,7 +2,7 @@ /* exported Component */ const { Clutter, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Dialog = imports.ui.dialog; const Main = imports.ui.main; @@ -411,8 +411,10 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog { } }); -var VPNRequestHandler = class { +var VPNRequestHandler = class extends Signals.EventEmitter { constructor(agent, requestId, authHelper, serviceType, connection, hints, flags) { + super(); + this._agent = agent; this._requestId = requestId; this._connection = connection; @@ -668,7 +670,6 @@ var VPNRequestHandler = class { } } }; -Signals.addSignalMethods(VPNRequestHandler.prototype); var NetworkAgent = class { constructor() { diff --git a/js/ui/dnd.js b/js/ui/dnd.js index f5f3bb40b..125024204 100644 --- a/js/ui/dnd.js +++ b/js/ui/dnd.js @@ -2,7 +2,7 @@ /* exported addDragMonitor, removeDragMonitor, makeDraggable */ const { Clutter, GLib, Meta, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Main = imports.ui.main; const Params = imports.misc.params; @@ -78,8 +78,10 @@ function removeDragMonitor(monitor) { } } -var _Draggable = class _Draggable { +var _Draggable = class _Draggable extends Signals.EventEmitter { constructor(actor, params) { + super(); + params = Params.parse(params, { manualMode: false, timeoutThreshold: 0, @@ -801,7 +803,6 @@ var _Draggable = class _Draggable { currentDraggable = null; } }; -Signals.addSignalMethods(_Draggable.prototype); /** * makeDraggable: diff --git a/js/ui/environment.js b/js/ui/environment.js index affc2b62b..ca27e02fb 100644 --- a/js/ui/environment.js +++ b/js/ui/environment.js @@ -45,7 +45,6 @@ try { const { Clutter, Gio, GLib, GObject, Meta, Polkit, Shell, St } = imports.gi; const Gettext = imports.gettext; -const Signals = imports.signals; const System = imports.system; const SignalTracker = imports.misc.signalTracker; @@ -358,12 +357,6 @@ function init() { SignalTracker.disconnectObject(this, ...args); }; - const _addSignalMethods = Signals.addSignalMethods; - Signals.addSignalMethods = function (prototype) { - _addSignalMethods(prototype); - SignalTracker.addObjectSignalMethods(prototype); - }; - SignalTracker.registerDestroyableType(Clutter.Actor); // Miscellaneous monkeypatching diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js index fbfd6c4b0..20abfcf43 100644 --- a/js/ui/extensionSystem.js +++ b/js/ui/extensionSystem.js @@ -1,8 +1,8 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported init connect disconnect */ +/* exported init connect disconnect ExtensionManager */ const { GLib, Gio, GObject, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const ExtensionDownloader = imports.ui.extensionDownloader; const ExtensionUtils = imports.misc.extensionUtils; @@ -19,8 +19,10 @@ const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validatio const UPDATE_CHECK_TIMEOUT = 24 * 60 * 60; // 1 day in seconds -var ExtensionManager = class { +var ExtensionManager = class extends Signals.EventEmitter { constructor() { + super(); + this._initialized = false; this._updateNotified = false; @@ -655,7 +657,6 @@ var ExtensionManager = class { this._enableAllExtensions(); } }; -Signals.addSignalMethods(ExtensionManager.prototype); const ExtensionUpdateSource = GObject.registerClass( class ExtensionUpdateSource extends MessageTray.Source { diff --git a/js/ui/focusCaretTracker.js b/js/ui/focusCaretTracker.js index cc70ae514..5cfe7a849 100644 --- a/js/ui/focusCaretTracker.js +++ b/js/ui/focusCaretTracker.js @@ -20,15 +20,18 @@ * Contributor: * Magdalen Berns */ +/* exported FocusCaretTracker */ const Atspi = imports.gi.Atspi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const CARETMOVED = 'object:text-caret-moved'; const STATECHANGED = 'object:state-changed'; -var FocusCaretTracker = class FocusCaretTracker { +var FocusCaretTracker = class FocusCaretTracker extends Signals.EventEmitter { constructor() { + super(); + this._atspiListener = Atspi.EventListener.new(this._onChanged.bind(this)); this._atspiInited = false; @@ -86,4 +89,3 @@ var FocusCaretTracker = class FocusCaretTracker { this._caretListenerRegistered = false; } }; -Signals.addSignalMethods(FocusCaretTracker.prototype); diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js index b40886cc1..ac36f3573 100644 --- a/js/ui/keyboard.js +++ b/js/ui/keyboard.js @@ -2,7 +2,7 @@ /* exported KeyboardManager */ const { Clutter, Gio, GLib, GObject, Graphene, Meta, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const EdgeDragAction = imports.ui.edgeDragAction; const InputSourceManager = imports.ui.status.keyboard; @@ -574,8 +574,10 @@ var KeyboardModel = class { } }; -var FocusTracker = class { +var FocusTracker = class extends Signals.EventEmitter { constructor() { + super(); + this._rect = null; global.display.connectObject( @@ -670,7 +672,6 @@ var FocusTracker = class { return rect; } }; -Signals.addSignalMethods(FocusTracker.prototype); var EmojiPager = GObject.registerClass({ Properties: { @@ -2055,8 +2056,10 @@ var Keyboard = GObject.registerClass({ } }); -var KeyboardController = class { +var KeyboardController = class extends Signals.EventEmitter { constructor() { + super(); + let seat = Clutter.get_default_backend().get_default_seat(); this._virtualDevice = seat.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE); @@ -2147,4 +2150,3 @@ var KeyboardController = class { keyval, Clutter.KeyState.RELEASED); } }; -Signals.addSignalMethods(KeyboardController.prototype); diff --git a/js/ui/layout.js b/js/ui/layout.js index 9bce25881..9393d04a9 100644 --- a/js/ui/layout.js +++ b/js/ui/layout.js @@ -2,7 +2,7 @@ /* exported MonitorConstraint, LayoutManager */ const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Background = imports.ui.background; const BackgroundMenu = imports.ui.backgroundMenu; @@ -1268,8 +1268,10 @@ class HotCorner extends Clutter.Actor { } }); -var PressureBarrier = class PressureBarrier { +var PressureBarrier = class PressureBarrier extends Signals.EventEmitter { constructor(threshold, timeout, actionMode) { + super(); + this._threshold = threshold; this._timeout = timeout; this._actionMode = actionMode; @@ -1409,7 +1411,6 @@ var PressureBarrier = class PressureBarrier { this._trigger(); } }; -Signals.addSignalMethods(PressureBarrier.prototype); var ScreenTransition = GObject.registerClass( class ScreenTransition extends Clutter.Actor { diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js index 46004f406..f3af5638e 100644 --- a/js/ui/lookingGlass.js +++ b/js/ui/lookingGlass.js @@ -4,7 +4,7 @@ const { Clutter, Cogl, Gio, GLib, GObject, Graphene, Meta, Pango, Shell, St, } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const System = imports.system; const History = imports.misc.history; @@ -56,8 +56,10 @@ function _getAutoCompleteGlobalKeywords() { return keywords.concat(windowProperties).concat(headerProperties); } -var AutoComplete = class AutoComplete { +var AutoComplete = class AutoComplete extends Signals.EventEmitter { constructor(entry) { + super(); + this._entry = entry; this._entry.connect('key-press-event', this._entryKeyPressEvent.bind(this)); this._lastTabTime = global.get_current_time(); @@ -121,7 +123,6 @@ var AutoComplete = class AutoComplete { this._entry.clutter_text.insert_text(additionalCompletionText, cursorPos); } }; -Signals.addSignalMethods(AutoComplete.prototype); var Notebook = GObject.registerClass({ diff --git a/js/ui/magnifier.js b/js/ui/magnifier.js index 44cdef0af..f4012dedf 100644 --- a/js/ui/magnifier.js +++ b/js/ui/magnifier.js @@ -1,9 +1,10 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported Magnifier */ const { Atspi, Clutter, GDesktopEnums, Gio, GLib, GObject, Meta, Shell, St, } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Background = imports.ui.background; const FocusCaretTracker = imports.ui.focusCaretTracker; @@ -88,8 +89,10 @@ var MouseSpriteContent = GObject.registerClass({ } }); -var Magnifier = class Magnifier { +var Magnifier = class Magnifier extends Signals.EventEmitter { constructor() { + super(); + // Magnifier is a manager of ZoomRegions. this._zoomRegions = []; @@ -724,7 +727,6 @@ var Magnifier = class Magnifier { } } }; -Signals.addSignalMethods(Magnifier.prototype); var ZoomRegion = class ZoomRegion { constructor(magnifier, mouseSourceActor) { diff --git a/js/ui/mpris.js b/js/ui/mpris.js index 171424769..e78f2114f 100644 --- a/js/ui/mpris.js +++ b/js/ui/mpris.js @@ -1,6 +1,6 @@ /* exported MediaSection */ const { Gio, GObject, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Main = imports.ui.main; const MessageList = imports.ui.messageList; @@ -86,14 +86,16 @@ class MediaMessage extends MessageList.Message { } }); -var MprisPlayer = class MprisPlayer { +var MprisPlayer = class MprisPlayer extends Signals.EventEmitter { constructor(busName) { + super(); + this._mprisProxy = new MprisProxy(Gio.DBus.session, busName, - '/org/mpris/MediaPlayer2', - this._onMprisProxyReady.bind(this)); + '/org/mpris/MediaPlayer2', + this._onMprisProxyReady.bind(this)); this._playerProxy = new MprisPlayerProxy(Gio.DBus.session, busName, - '/org/mpris/MediaPlayer2', - this._onPlayerProxyReady.bind(this)); + '/org/mpris/MediaPlayer2', + this._onPlayerProxyReady.bind(this)); this._visible = false; this._trackArtists = []; @@ -233,7 +235,6 @@ var MprisPlayer = class MprisPlayer { } } }; -Signals.addSignalMethods(MprisPlayer.prototype); var MediaSection = GObject.registerClass( class MediaSection extends MessageList.MessageListSection { diff --git a/js/ui/overview.js b/js/ui/overview.js index 615c6b10a..86e02a844 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -2,7 +2,7 @@ /* exported Overview, ANIMATION_TIME */ const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; // Time for initial animation going into Overview mode; // this is defined here to make it available in imports. @@ -103,8 +103,10 @@ class OverviewActor extends St.BoxLayout { } }); -var Overview = class { +var Overview = class extends Signals.EventEmitter { constructor() { + super(); + this._initCalled = false; this._visible = false; @@ -649,4 +651,3 @@ var Overview = class { return this._overview.searchEntry; } }; -Signals.addSignalMethods(Overview.prototype); diff --git a/js/ui/padOsd.js b/js/ui/padOsd.js index b273b0ce8..d0cbbe0e2 100644 --- a/js/ui/padOsd.js +++ b/js/ui/padOsd.js @@ -5,7 +5,7 @@ const { Atk, Clutter, GDesktopEnums, Gio, GLib, GObject, Gtk, Meta, Pango, Rsvg, St, } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; @@ -957,8 +957,10 @@ var PadOsd = GObject.registerClass({ const PadOsdIface = loadInterfaceXML('org.gnome.Shell.Wacom.PadOsd'); -var PadOsdService = class { +var PadOsdService = class extends Signals.EventEmitter { constructor() { + super(); + this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(PadOsdIface, this); this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Wacom'); Gio.DBus.session.own_name('org.gnome.Shell.Wacom.PadOsd', Gio.BusNameOwnerFlags.REPLACE, null, null); @@ -987,4 +989,3 @@ var PadOsdService = class { invocation.return_value(null); } }; -Signals.addSignalMethods(PadOsdService.prototype); diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js index 83471030e..6c5549d35 100644 --- a/js/ui/popupMenu.js +++ b/js/ui/popupMenu.js @@ -4,7 +4,7 @@ PopupMenuSection, PopupSubMenuMenuItem, PopupMenuManager */ const { Atk, Clutter, Gio, GObject, Graphene, Shell, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const BoxPointer = imports.ui.boxpointer; const Main = imports.ui.main; @@ -480,8 +480,10 @@ class PopupImageMenuItem extends PopupBaseMenuItem { } }); -var PopupMenuBase = class { +var PopupMenuBase = class extends Signals.EventEmitter { constructor(sourceActor, styleClass) { + super(); + if (this.constructor === PopupMenuBase) throw new TypeError(`Cannot instantiate abstract class ${this.constructor.name}`); @@ -805,7 +807,6 @@ var PopupMenuBase = class { Main.sessionMode.disconnectObject(this); } }; -Signals.addSignalMethods(PopupMenuBase.prototype); var PopupMenu = class extends PopupMenuBase { constructor(sourceActor, arrowAlignment, arrowSide) { @@ -951,8 +952,10 @@ var PopupMenu = class extends PopupMenuBase { } }; -var PopupDummyMenu = class { +var PopupDummyMenu = class extends Signals.EventEmitter { constructor(sourceActor) { + super(); + this.sourceActor = sourceActor; this.actor = sourceActor; this.actor._delegate = this; @@ -986,7 +989,6 @@ var PopupDummyMenu = class { this.emit('destroy'); } }; -Signals.addSignalMethods(PopupDummyMenu.prototype); var PopupSubMenu = class extends PopupMenuBase { constructor(sourceActor, sourceArrow) { diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js index be6a72190..d19f7503d 100644 --- a/js/ui/screenShield.js +++ b/js/ui/screenShield.js @@ -1,10 +1,11 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported ScreenShield */ const { AccountsService, Clutter, Gio, GLib, Graphene, Meta, Shell, St, } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const GnomeSession = imports.misc.gnomeSession; const OVirt = imports.gdm.oVirt; @@ -44,8 +45,10 @@ var CURTAIN_SLIDE_TIME = 300; * This will ensure that the screen blanks at the right time when it fades out. * https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependency. */ -var ScreenShield = class { +var ScreenShield = class extends Signals.EventEmitter { constructor() { + super(); + this.actor = Main.layoutManager.screenShieldGroup; this._lockScreenState = MessageTray.State.HIDDEN; @@ -676,4 +679,3 @@ var ScreenShield = class { }); } }; -Signals.addSignalMethods(ScreenShield.prototype); diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js index b8b627370..5712b4d24 100644 --- a/js/ui/sessionMode.js +++ b/js/ui/sessionMode.js @@ -2,7 +2,7 @@ /* exported SessionMode, listModes */ const GLib = imports.gi.GLib; -const Signals = imports.signals; +const Signals = imports.misc.signals; const FileUtils = imports.misc.fileUtils; const Params = imports.misc.params; @@ -145,8 +145,10 @@ function listModes() { loop.run(); } -var SessionMode = class { +var SessionMode = class extends Signals.EventEmitter { constructor() { + super(); + _loadModes(); let isPrimary = _modes[global.session_mode] && _modes[global.session_mode].isPrimary; @@ -199,4 +201,3 @@ var SessionMode = class { this.emit('updated'); } }; -Signals.addSignalMethods(SessionMode.prototype); diff --git a/js/ui/status/keyboard.js b/js/ui/status/keyboard.js index 15b4ddb6f..7d6d5fdca 100644 --- a/js/ui/status/keyboard.js +++ b/js/ui/status/keyboard.js @@ -3,7 +3,7 @@ const { Clutter, Gio, GLib, GObject, IBus, Meta, Shell, St } = imports.gi; const Gettext = imports.gettext; -const Signals = imports.signals; +const Signals = imports.misc.signals; const IBusManager = imports.misc.ibusManager; const KeyboardManager = imports.misc.keyboardManager; @@ -32,8 +32,10 @@ class LayoutMenuItem extends PopupMenu.PopupBaseMenuItem { } }); -var InputSource = class { +var InputSource = class extends Signals.EventEmitter { constructor(type, id, displayName, shortName, index) { + super(); + this.type = type; this.id = id; this.displayName = displayName; @@ -69,7 +71,6 @@ var InputSource = class { return engineDesc.layout; } }; -Signals.addSignalMethods(InputSource.prototype); var InputSourcePopup = GObject.registerClass( class InputSourcePopup extends SwitcherPopup.SwitcherPopup { @@ -135,8 +136,10 @@ class InputSourceSwitcher extends SwitcherPopup.SwitcherList { } }); -var InputSourceSettings = class { +var InputSourceSettings = class extends Signals.EventEmitter { constructor() { + super(); + if (this.constructor === InputSourceSettings) throw new TypeError(`Cannot instantiate abstract class ${this.constructor.name}`); } @@ -173,7 +176,6 @@ var InputSourceSettings = class { return false; } }; -Signals.addSignalMethods(InputSourceSettings.prototype); var InputSourceSystemSettings = class extends InputSourceSettings { constructor() { @@ -300,8 +302,10 @@ var InputSourceSessionSettings = class extends InputSourceSettings { } }; -var InputSourceManager = class { +var InputSourceManager = class extends Signals.EventEmitter { constructor() { + super(); + // All valid input sources currently in the gsettings // KEY_INPUT_SOURCES list indexed by their index there this._inputSources = {}; @@ -771,7 +775,6 @@ var InputSourceManager = class { return this._keyboardManager; } }; -Signals.addSignalMethods(InputSourceManager.prototype); let _inputSourceManager = null; diff --git a/js/ui/status/network.js b/js/ui/status/network.js index caa71c363..1598941b6 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js @@ -1,7 +1,7 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- /* exported NMApplet */ const { Clutter, Gio, GLib, GObject, Meta, NM, Polkit, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Animation = imports.ui.animation; const Main = imports.ui.main; @@ -107,8 +107,10 @@ function launchSettingsPanel(panel, ...args) { } } -var NMConnectionItem = class { +var NMConnectionItem = class extends Signals.EventEmitter { constructor(section, connection) { + super(); + this._section = section; this._connection = connection; this._activeConnection = null; @@ -193,10 +195,11 @@ var NMConnectionItem = class { this._sync(); } }; -Signals.addSignalMethods(NMConnectionItem.prototype); -var NMConnectionSection = class NMConnectionSection { +var NMConnectionSection = class NMConnectionSection extends Signals.EventEmitter { constructor(client) { + super(); + if (this.constructor === NMConnectionSection) throw new TypeError(`Cannot instantiate abstract type ${this.constructor.name}`); @@ -320,7 +323,6 @@ var NMConnectionSection = class NMConnectionSection { this._sync(); } }; -Signals.addSignalMethods(NMConnectionSection.prototype); var NMConnectionDevice = class NMConnectionDevice extends NMConnectionSection { constructor(client, device) { @@ -1242,8 +1244,10 @@ class NMWirelessDialog extends ModalDialog.ModalDialog { } }); -var NMDeviceWireless = class { +var NMDeviceWireless = class extends Signals.EventEmitter { constructor(client, device) { + super(); + this._client = client; this._device = device; @@ -1433,7 +1437,6 @@ var NMDeviceWireless = class { return 'network-wireless-no-route-symbolic'; } }; -Signals.addSignalMethods(NMDeviceWireless.prototype); var NMWireguardItem = class extends NMConnectionItem { _buildUI() { @@ -1657,7 +1660,6 @@ var NMVpnSection = class extends NMConnectionSection { return ''; } }; -Signals.addSignalMethods(NMVpnSection.prototype); var DeviceCategory = class extends PopupMenu.PopupMenuSection { constructor(category) { diff --git a/js/ui/status/rfkill.js b/js/ui/status/rfkill.js index 9f8b09dd2..518da2561 100644 --- a/js/ui/status/rfkill.js +++ b/js/ui/status/rfkill.js @@ -2,7 +2,7 @@ /* exported Indicator */ const { Gio, GObject } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Main = imports.ui.main; const PanelMenu = imports.ui.panelMenu; @@ -16,18 +16,20 @@ const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill'; const RfkillManagerInterface = loadInterfaceXML('org.gnome.SettingsDaemon.Rfkill'); const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface); -var RfkillManager = class { +var RfkillManager = class extends Signals.EventEmitter { constructor() { + super(); + this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH, - (proxy, error) => { - if (error) { - log(error.message); - return; - } - this._proxy.connect('g-properties-changed', - this._changed.bind(this)); - this._changed(); - }); + (proxy, error) => { + if (error) { + log(error.message); + return; + } + this._proxy.connect('g-properties-changed', + this._changed.bind(this)); + this._changed(); + }); } get airplaneMode() { @@ -50,7 +52,6 @@ var RfkillManager = class { this.emit('airplane-mode-changed'); } }; -Signals.addSignalMethods(RfkillManager.prototype); var _manager; function getRfkillManager() { diff --git a/js/ui/status/thunderbolt.js b/js/ui/status/thunderbolt.js index 348bf643c..e9fba78ed 100644 --- a/js/ui/status/thunderbolt.js +++ b/js/ui/status/thunderbolt.js @@ -4,7 +4,7 @@ // the following is a modified version of bolt/contrib/js/client.js const { Gio, GLib, GObject, Polkit, Shell } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Main = imports.ui.main; const MessageTray = imports.ui.messageTray; @@ -49,8 +49,10 @@ const BOLT_DBUS_CLIENT_IFACE = 'org.freedesktop.bolt1.Manager'; const BOLT_DBUS_NAME = 'org.freedesktop.bolt'; const BOLT_DBUS_PATH = '/org/freedesktop/bolt'; -var Client = class { +var Client = class extends Signals.EventEmitter { constructor() { + super(); + this._proxy = null; this.probing = false; this._getProxy(); @@ -127,11 +129,12 @@ var Client = class { return this._proxy.AuthMode; } }; -Signals.addSignalMethods(Client.prototype); /* helper class to automatically authorize new devices */ -var AuthRobot = class { +var AuthRobot = class extends Signals.EventEmitter { constructor(client) { + super(); + this._client = client; this._devicesToEnroll = []; @@ -217,7 +220,6 @@ var AuthRobot = class { return GLib.SOURCE_REMOVE; } }; -Signals.addSignalMethods(AuthRobot.prototype); /* eof client.js */ diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js index f623ee680..744d650e9 100644 --- a/js/ui/status/volume.js +++ b/js/ui/status/volume.js @@ -2,7 +2,7 @@ /* exported Indicator */ const { Clutter, Gio, GLib, GObject, Gvc, St } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Main = imports.ui.main; const PanelMenu = imports.ui.panelMenu; @@ -29,8 +29,10 @@ function getMixerControl() { return _mixerControl; } -var StreamSlider = class { +var StreamSlider = class extends Signals.EventEmitter { constructor(control) { + super(); + this._control = control; this.item = new PopupMenu.PopupBaseMenuItem({ activate: false }); @@ -213,7 +215,6 @@ var StreamSlider = class { return maxVolume / this._control.get_vol_max_norm(); } }; -Signals.addSignalMethods(StreamSlider.prototype); var OutputStreamSlider = class extends StreamSlider { constructor(control) { diff --git a/js/ui/xdndHandler.js b/js/ui/xdndHandler.js index 706e0c1a4..3a4880b41 100644 --- a/js/ui/xdndHandler.js +++ b/js/ui/xdndHandler.js @@ -1,13 +1,16 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported XdndHandler */ const { Clutter } = imports.gi; -const Signals = imports.signals; +const Signals = imports.misc.signals; const DND = imports.ui.dnd; const Main = imports.ui.main; -var XdndHandler = class { +var XdndHandler = class extends Signals.EventEmitter { constructor() { + super(); + // Used to display a clone of the cursor window when the // window group is hidden (like it happens in the overview) this._cursorWindowClone = null; @@ -111,4 +114,3 @@ var XdndHandler = class { } } }; -Signals.addSignalMethods(XdndHandler.prototype); diff --git a/tests/unit/signalTracker.js b/tests/unit/signalTracker.js index a6f50e257..7943d0a20 100644 --- a/tests/unit/signalTracker.js +++ b/tests/unit/signalTracker.js @@ -5,7 +5,7 @@ const { GObject } = imports.gi; const JsUnit = imports.jsUnit; -const Signals = imports.signals; +const Signals = imports.misc.signals; const Environment = imports.ui.environment; const { TransientSignalHolder, registerDestroyableType } = imports.misc.signalTracker; @@ -17,14 +17,11 @@ const Destroyable = GObject.registerClass({ }, class Destroyable extends GObject.Object {}); registerDestroyableType(Destroyable); -class PlainEmitter {} -Signals.addSignalMethods(PlainEmitter.prototype); - const GObjectEmitter = GObject.registerClass({ Signals: { 'signal': {} }, }, class GObjectEmitter extends Destroyable {}); -const emitter1 = new PlainEmitter(); +const emitter1 = new Signals.EventEmitter(); const emitter2 = new GObjectEmitter(); const tracked1 = new Destroyable();