From 3713a4d3bf8ae2df7d02e63b5b827353e5121d19 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 5 Feb 2023 09:57:47 +0100 Subject: Merging upstream version 20230205. Signed-off-by: Daniel Baumann --- extensions/hibernate-status/extension.js | 248 +++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 extensions/hibernate-status/extension.js (limited to 'extensions/hibernate-status/extension.js') diff --git a/extensions/hibernate-status/extension.js b/extensions/hibernate-status/extension.js new file mode 100644 index 0000000..6e0b248 --- /dev/null +++ b/extensions/hibernate-status/extension.js @@ -0,0 +1,248 @@ +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Mainloop = imports.mainloop; + +const ExtensionUtils = imports.misc.extensionUtils; +const LoginManager = imports.misc.loginManager; +const Main = imports.ui.main; +const StatusSystem = imports.ui.status.system; +const PopupMenu = imports.ui.popupMenu; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const ExtensionSystem = imports.ui.extensionSystem; +const ConfirmDialog = Me.imports.confirmDialog; +const Prefs = new Me.imports.prefs.Prefs(); + + +// Use __ () and N__() for the extension gettext domain, and reuse +// the shell domain with the default _() and N_() +const Gettext = imports.gettext.domain('hibernate-status-button'); +const __ = Gettext.gettext; +const N__ = function(e) { return e }; +ExtensionUtils.initTranslations('hibernate-status-button'); + +const HIBERNATE_CHECK_TIMEOUT = 20000; + +class Extension { + _loginManagerCanHibernate(asyncCallback) { + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("CanHibernate", + null, + Gio.DBusCallFlags.NONE, + -1, null, function (proxy, asyncResult) { + let result, error; + + try { + result = proxy.call_finish(asyncResult).deep_unpack(); + } catch (e) { + error = e; + } + + if (error) + asyncCallback(false); + else + asyncCallback(result[0] != 'no'); + }); + } else { + Mainloop.idle_add(() => { + asyncCallback(false); + return false; + }); + } + } + + _loginManagerHibernate() { + if (Prefs.getHibernateWorksCheckEnabled()) { + this._hibernateStarted = new Date(); + GLib.timeout_add(GLib.PRIORITY_DEFAULT, HIBERNATE_CHECK_TIMEOUT, + () => this._checkDidHibernate()); + } + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("Hibernate", + GLib.Variant.new('(b)', [true]), + Gio.DBusCallFlags.NONE, + -1, null, null); + } else { + // Can't do in ConsoleKit + this._loginManager.emit('prepare-for-sleep', true); + this._loginManager.emit('prepare-for-sleep', false); + } + } + + _loginManagerCanHybridSleep(asyncCallback) { + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("CanHybridSleep", + null, + Gio.DBusCallFlags.NONE, + -1, null, function (proxy, asyncResult) { + let result, error; + + try { + result = proxy.call_finish(asyncResult).deep_unpack(); + } catch (e) { + error = e; + } + + if (error) + asyncCallback(false); + else + asyncCallback(result[0] != 'no'); + }); + } else { + Mainloop.idle_add(() => { + asyncCallback(false); + return false; + }); + } + } + + _loginManagerHybridSleep() { + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("HybridSleep", + GLib.Variant.new('(b)', [true]), + Gio.DBusCallFlags.NONE, + -1, null, null); + } else { + // Can't do in ConsoleKit + this._loginManager.emit('prepare-for-sleep', true); + this._loginManager.emit('prepare-for-sleep', false); + } + } + _updateHaveHibernate() { + this._loginManagerCanHibernate((result) => { + log(`have hibernate ${result}`); + this._haveHibernate = result; + this._updateHibernate(); + }); + } + + _updateHibernate() { + this._hibernateMenuItem.visible = this._haveHibernate && !Main.sessionMode.isLocked; + } + + _updateHaveHybridSleep() { + this._loginManagerCanHybridSleep((result) => { + this._haveHybridSleep = result; + this._updateHybridSleep(); + }); + } + + _updateHybridSleep() { + this._hybridSleepMenuItem.visible = this._haveHybridSleep && !Main.sessionMode.isLocked; + } + + _onHibernateClicked() { + this.systemMenu._systemItem.menu.itemActivated(); + this._dialog = new ConfirmDialog.ConfirmDialog(ConfirmDialog.HibernateDialogContent); + this._dialog.connect('ConfirmedHibernate', () => this._loginManagerHibernate()); + this._dialog.open(); + } + + _onHybridSleepClicked() { + this.systemMenu._systemItem.menu.itemActivated(); + this._loginManagerHybridSleep(); + } + + _disableExtension() { + let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY); + enabledExtensions.splice(enabledExtensions.indexOf(Me.uuid), 1); + global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions); + } + + _cancelDisableExtension(notAgain) { + if (notAgain) + Prefs.setHibernateWorksCheckEnabled(false); + } + + _checkRequirements() { + if (!LoginManager.haveSystemd()) { + this._dialog = new ConfirmDialog.ConfirmDialog(ConfirmDialog.SystemdMissingDialogContent); + this._dialog.connect('DisableExtension', this._disableExtension); + this._dialog.open(); + } + } + + _checkDidHibernate() { + /* This function is called HIBERNATE_CHECK_TIMEOUT ms after + * hibernate started. If it is successful, at that point the GS + * process is already frozen; so when this function is actually + * called, way more than HIBERNATE_CHECK_TIMEOUT ms are passed*/ + if (new Date() - this._hibernateStarted > HIBERNATE_CHECK_TIMEOUT + 5000) { + // hibernate succeeded + return; + } + // hibernate failed + this._dialog = new ConfirmDialog.ConfirmDialog(ConfirmDialog.HibernateFailedDialogContent); + this._dialog.connect('DisableExtension', this._disableExtension); + this._dialog.connect('Cancel', this._cancelDisableExtension); + this._dialog.open(); + } + + enable() { + this._checkRequirements(); + this._loginManager = LoginManager.getLoginManager(); + this.systemMenu = Main.panel.statusArea.quickSettings._system; + + this._hibernateMenuItem = new PopupMenu.PopupMenuItem(__('Hibernate')); + this._hibernateMenuItemId = this._hibernateMenuItem.connect('activate', () => this._onHibernateClicked()); + + this._hybridSleepMenuItem = new PopupMenu.PopupMenuItem(__('Hybrid Sleep')); + this._hybridSleepMenuItemId = this._hybridSleepMenuItem.connect('activate', () => this._onHybridSleepClicked()); + + let afterSuspendPosition = this.systemMenu._systemItem.menu.numMenuItems - 5; + + this.systemMenu._systemItem.menu.addMenuItem(this._hybridSleepMenuItem, afterSuspendPosition); + this.systemMenu._systemItem.menu.addMenuItem(this._hibernateMenuItem, afterSuspendPosition); + + this._menuOpenStateChangedId = this.systemMenu._systemItem.menu.connect('open-state-changed', + (menu, open) => { + if (!open) + return; + this._updateHaveHibernate(); + this._updateHaveHybridSleep(); + }); + } + + disable() { + if (this._menuOpenStateChangedId) { + this.systemMenu._systemItem.menu.disconnect(this._menuOpenStateChangedId); + this._menuOpenStateChangedId = 0; + } + + if (this._hybridSleepMenuItemId) { + this._hybridSleepMenuItem.disconnect(this._hybridSleepMenuItemId); + this._hybridSleepMenuItemId = 0; + } + + if (this._hibernateMenuItemId) { + this._hibernateMenuItem.disconnect(this._hibernateMenuItemId); + this._hibernateMenuItemId = 0; + } + + if (this._hybridSleepMenuItem) { + this._hybridSleepMenuItem.destroy(); + this._hybridSleepMenuItem = 0; + } + + if (this._hibernateMenuItem) { + this._hibernateMenuItem.destroy(); + this._hibernateMenuItem = 0; + } + } +} + +let extension; +function init() { + extension = new Extension(); +} + +function enable() { + extension.enable(); +} + +function disable() { + extension.disable(); +} -- cgit v1.2.3