Merging upstream version 20240916 (Closes: #1079257).
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
37100210a9
commit
af3a3f3a8f
122 changed files with 8062 additions and 6057 deletions
590
extensions/47/hibernate-status/extension.js
Normal file
590
extensions/47/hibernate-status/extension.js
Normal file
|
@ -0,0 +1,590 @@
|
|||
import Gio from 'gi://Gio';
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
import St from 'gi://St';
|
||||
import Clutter from 'gi://Clutter';
|
||||
|
||||
import * as LoginManager from 'resource:///org/gnome/shell/misc/loginManager.js';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as StatusSystem from 'resource:///org/gnome/shell/ui/status/system.js';
|
||||
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||
import * as ExtensionSystem from 'resource:///org/gnome/shell/ui/extensionSystem.js';
|
||||
import * as ModalDialog from 'resource:///org/gnome/shell/ui/modalDialog.js';
|
||||
import * as Dialog from 'resource:///org/gnome/shell/ui/dialog.js';
|
||||
import * as CheckBoxImport from 'resource:///org/gnome/shell/ui/checkBox.js';
|
||||
import {loadInterfaceXML} from 'resource:///org/gnome/shell/misc/fileUtils.js';
|
||||
|
||||
const CheckBox = CheckBoxImport.CheckBox;
|
||||
// Use __ () and N__() for the extension gettext domain, and reuse
|
||||
// the shell domain with the default _() and N_()
|
||||
import {Extension, gettext as __} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
export {__};
|
||||
const N__ = function (e) {
|
||||
return e;
|
||||
};
|
||||
|
||||
const HIBERNATE_CHECK_TIMEOUT = 20000;
|
||||
|
||||
export default class HibernateButtonExtension extends 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(!['no', 'na'].includes(result[0]));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.can_hibernate_sourceID = GLib.idle_add(() => {
|
||||
asyncCallback(false);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_loginManagerHibernate() {
|
||||
if (this._setting.get_boolean('hibernate-works-check')) {
|
||||
this._hibernateStarted = new Date();
|
||||
this.hibernate_sourceID = 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(!['no', 'na'].includes(result[0]));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.can_hybrid_sleep_sourceID = GLib.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);
|
||||
}
|
||||
}
|
||||
|
||||
_loginManagerCanSuspendThenHibernate(asyncCallback) {
|
||||
if (this._loginManager._proxy) {
|
||||
// systemd path
|
||||
this._loginManager._proxy.call(
|
||||
'CanSuspendThenHibernate',
|
||||
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(!['no', 'na'].includes(result[0]));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.can_suspend_then_hibernate_sourceID = GLib.idle_add(() => {
|
||||
asyncCallback(false);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_loginManagerSuspendThenHibernate() {
|
||||
if (this._loginManager._proxy) {
|
||||
// systemd path
|
||||
this._loginManager._proxy.call(
|
||||
'SuspendThenHibernate',
|
||||
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(`Able to hibernate: ${result}`);
|
||||
this._haveHibernate = result;
|
||||
this._updateHibernate();
|
||||
});
|
||||
}
|
||||
|
||||
_updateHibernate() {
|
||||
this._hibernateMenuItem.visible =
|
||||
this._haveHibernate && !Main.sessionMode.isLocked && this._setting.get_boolean('show-hibernate');
|
||||
}
|
||||
|
||||
_updateHaveHybridSleep() {
|
||||
this._loginManagerCanHybridSleep(result => {
|
||||
log(`Able to hybrid-sleep: ${result}`);
|
||||
this._haveHybridSleep = result;
|
||||
this._updateHybridSleep();
|
||||
});
|
||||
}
|
||||
|
||||
_updateHybridSleep() {
|
||||
this._hybridSleepMenuItem.visible =
|
||||
this._haveHybridSleep && !Main.sessionMode.isLocked && this._setting.get_boolean('show-hybrid-sleep');
|
||||
}
|
||||
|
||||
_updateHaveSuspendThenHibernate() {
|
||||
this._loginManagerCanSuspendThenHibernate(result => {
|
||||
log(`Able to suspend then hibernate: ${result}`);
|
||||
this._haveSuspendThenHibernate = result;
|
||||
this._updateSuspendThenHibernate();
|
||||
});
|
||||
}
|
||||
|
||||
_updateSuspendThenHibernate() {
|
||||
this._suspendThenHibernateMenuItem.visible =
|
||||
this._haveSuspendThenHibernate && !Main.sessionMode.isLocked && this._setting.get_boolean('show-suspend-then-hibernate');
|
||||
}
|
||||
|
||||
_updateDefaults() {
|
||||
console.log("Update defaults");
|
||||
let menuItems = this.systemMenu._systemItem.menu._getMenuItems()
|
||||
for (let menuItem of menuItems) {
|
||||
console.log(menuItem.label.get_text())
|
||||
if ( menuItem.label.get_text() === _('Suspend') ) {
|
||||
console.log(`Show suspend button: ${this._setting.get_boolean('show-suspend')}`)
|
||||
menuItem.visible = this._setting.get_boolean('show-suspend');
|
||||
}
|
||||
if ( menuItem.label.get_text() === _('Restart…') ) {
|
||||
console.log(`Show restart button: ${this._setting.get_boolean('show-restart')}`)
|
||||
menuItem.visible = this._setting.get_boolean('show-restart');
|
||||
}
|
||||
if ( menuItem.label.get_text() === _('Power Off…') ) {
|
||||
console.log(`Show shutdown button: ${this._setting.get_boolean('show-shutdown')}`)
|
||||
menuItem.visible = this._setting.get_boolean('show-shutdown');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onHibernateClicked() {
|
||||
this.systemMenu._systemItem.menu.itemActivated();
|
||||
|
||||
if (this._setting.get_boolean('show-hibernate-dialog')) {
|
||||
let HibernateDialogContent = {
|
||||
subject: C_('title', __('Hibernate')),
|
||||
description: __('Do you really want to hibernate the system?'),
|
||||
confirmButtons: [
|
||||
{
|
||||
signal: 'Cancel',
|
||||
label: C_('button', __('Cancel')),
|
||||
key: Clutter.Escape,
|
||||
},
|
||||
{
|
||||
signal: 'ConfirmedHibernate',
|
||||
label: C_('button', __('Hibernate')),
|
||||
default: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
this._dialog = new ConfirmDialog(
|
||||
HibernateDialogContent
|
||||
);
|
||||
this._dialog.connect('ConfirmedHibernate', () =>
|
||||
this._loginManagerHibernate()
|
||||
);
|
||||
this._dialog.open();
|
||||
} else {
|
||||
this._loginManagerHibernate()
|
||||
}
|
||||
}
|
||||
|
||||
_onHybridSleepClicked() {
|
||||
this.systemMenu._systemItem.menu.itemActivated();
|
||||
this._loginManagerHybridSleep();
|
||||
}
|
||||
|
||||
_onSuspendThenHibernateClicked() {
|
||||
this.systemMenu._systemItem.menu.itemActivated();
|
||||
this._loginManagerSuspendThenHibernate();
|
||||
}
|
||||
|
||||
_disableExtension() {
|
||||
Main.extensionManager.disableExtension('hibernate-status@dromi')
|
||||
console.log('Disabled')
|
||||
}
|
||||
|
||||
_cancelDisableExtension(notAgain) {
|
||||
if (notAgain) this.setHibernateWorksCheckEnabled(false);
|
||||
}
|
||||
|
||||
_checkRequirements() {
|
||||
if (GLib.access('/run/systemd/seats', 0) < 0) {
|
||||
let SystemdMissingDialogContent = {
|
||||
subject: C_('title', __('Hibernate button: Systemd Missing')),
|
||||
description: __('Systemd seems to be missing and is required.'),
|
||||
confirmButtons: [
|
||||
{
|
||||
signal: 'Cancel',
|
||||
label: C_('button', __('Cancel')),
|
||||
key: Clutter.Escape,
|
||||
},
|
||||
{
|
||||
signal: 'DisableExtension',
|
||||
label: C_('button', __('Disable Extension')),
|
||||
default: true,
|
||||
},
|
||||
],
|
||||
iconName: 'document-save-symbolic',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon',
|
||||
};
|
||||
|
||||
this._dialog = new 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
|
||||
|
||||
let HibernateFailedDialogContent = {
|
||||
subject: C_('title', __('Hibernate button: Hibernate failed')),
|
||||
description: __(
|
||||
'Looks like hibernation failed. On some linux distributions hibernation is disabled ' +
|
||||
'because not all hardware supports it well; ' +
|
||||
'please check your distribution documentation ' +
|
||||
'on how to enable it.'
|
||||
),
|
||||
checkBox: __("You are wrong, don't check this anymore!"),
|
||||
confirmButtons: [
|
||||
{
|
||||
signal: 'Cancel',
|
||||
label: C_('button', __('Cancel')),
|
||||
key: Clutter.Escape,
|
||||
},
|
||||
{
|
||||
signal: 'DisableExtension',
|
||||
label: C_('button', __('Disable Extension')),
|
||||
default: true,
|
||||
},
|
||||
],
|
||||
iconName: 'document-save-symbolic',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon',
|
||||
}
|
||||
this._dialog = new ConfirmDialog(
|
||||
HibernateFailedDialogContent
|
||||
);
|
||||
this._dialog.connect('DisableExtension', this._disableExtension);
|
||||
this._dialog.connect('Cancel', this._cancelDisableExtension);
|
||||
this._dialog.open();
|
||||
}
|
||||
|
||||
setHibernateWorksCheckEnabled(enabled) {
|
||||
let key = 'hibernate-works-check';
|
||||
if (this._setting.is_writable(key)) {
|
||||
if (this._setting.set_boolean(key, enabled)) {
|
||||
Gio.Settings.sync();
|
||||
} else {
|
||||
throw this._errorSet(key);
|
||||
}
|
||||
} else {
|
||||
throw this._errorWritable(key);
|
||||
}
|
||||
}
|
||||
|
||||
_modifySystemItem() {
|
||||
this._setting = this.getSettings()
|
||||
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()
|
||||
);
|
||||
|
||||
this._suspendThenHibernateMenuItem = new PopupMenu.PopupMenuItem(
|
||||
__('Suspend then Hibernate')
|
||||
);
|
||||
this._suspendThenHibernateMenuItemId = this._suspendThenHibernateMenuItem.connect(
|
||||
'activate',
|
||||
() => this._onSuspendThenHibernateClicked()
|
||||
);
|
||||
|
||||
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.systemMenu._systemItem.menu.addMenuItem(
|
||||
this._suspendThenHibernateMenuItem,
|
||||
afterSuspendPosition
|
||||
);
|
||||
|
||||
this._menuOpenStateChangedId = this.systemMenu._systemItem.menu.connect(
|
||||
'open-state-changed',
|
||||
(menu, open) => {
|
||||
if (!open) return;
|
||||
this._updateDefaults();
|
||||
this._updateHaveHibernate();
|
||||
this._updateHaveHybridSleep();
|
||||
this._updateHaveSuspendThenHibernate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_queueModifySystemItem() {
|
||||
this.sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
if (!Main.panel.statusArea.quickSettings._system)
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
|
||||
this._modifySystemItem();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
enable() {
|
||||
if (!Main.panel.statusArea.quickSettings._system) {
|
||||
this._queueModifySystemItem();
|
||||
} else {
|
||||
this._modifySystemItem();
|
||||
}
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._setting = null;
|
||||
if (this._menuOpenStateChangedId) {
|
||||
this.systemMenu._systemItem.menu.disconnect(
|
||||
this._menuOpenStateChangedId
|
||||
);
|
||||
this._menuOpenStateChangedId = 0;
|
||||
}
|
||||
|
||||
if (this._suspendThenHibernateMenuItemId) {
|
||||
this._suspendThenHibernateMenuItem.disconnect(this._suspendThenHibernateMenuItemId);
|
||||
this._suspendThenHibernateMenuItemId = 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._suspendThenHibernateMenuItem) {
|
||||
this._suspendThenHibernateMenuItem.destroy();
|
||||
this._suspendThenHibernateMenuItem = 0;
|
||||
}
|
||||
|
||||
if (this._hybridSleepMenuItem) {
|
||||
this._hybridSleepMenuItem.destroy();
|
||||
this._hybridSleepMenuItem = 0;
|
||||
}
|
||||
|
||||
if (this._hibernateMenuItem) {
|
||||
this._hibernateMenuItem.destroy();
|
||||
this._hibernateMenuItem = 0;
|
||||
}
|
||||
|
||||
if (this.sourceId) {
|
||||
GLib.Source.remove(this.sourceId);
|
||||
this.sourceId = null;
|
||||
}
|
||||
|
||||
if (this.can_suspend_then_hibernate_sourceID) {
|
||||
GLib.Source.remove(this.can_suspend_then_hibernate_sourceID);
|
||||
this.can_suspend_then_hibernate_sourceID = null;
|
||||
}
|
||||
|
||||
if (this.can_hybrid_sleep_sourceID) {
|
||||
GLib.Source.remove(this.can_hybrid_sleep_sourceID);
|
||||
this.can_hybrid_sleep_sourceID = null;
|
||||
}
|
||||
|
||||
if (this.can_hibernate_sourceID) {
|
||||
GLib.Source.remove(this.can_hibernate_sourceID);
|
||||
this.can_hibernate_sourceID = null;
|
||||
}
|
||||
|
||||
if (this.hibernate_sourceID) {
|
||||
GLib.Source.remove(this.hibernate_sourceID);
|
||||
this.hibernate_sourceID = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var ConfirmDialog = GObject.registerClass(
|
||||
{
|
||||
Signals: {
|
||||
ConfirmedHibernate: {param_types: [GObject.TYPE_BOOLEAN]},
|
||||
DisableExtension: {param_types: [GObject.TYPE_BOOLEAN]},
|
||||
Cancel: {param_types: [GObject.TYPE_BOOLEAN]},
|
||||
},
|
||||
},
|
||||
class ConfirmDialog extends ModalDialog.ModalDialog {
|
||||
_init(dialog) {
|
||||
super._init({
|
||||
styleClass: 'end-session-dialog',
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
|
||||
this._messageDialogContent = new Dialog.MessageDialogContent();
|
||||
|
||||
|
||||
this._messageDialogContent.description = dialog.description;
|
||||
this._messageDialogContent.title = dialog.subject;
|
||||
|
||||
if (dialog.iconName) {
|
||||
this._icon = new St.Icon({
|
||||
icon_name: dialog.iconName,
|
||||
icon_size: _DIALOG_ICON_SIZE,
|
||||
style_class: dialog.iconStyleClass,
|
||||
});
|
||||
}
|
||||
|
||||
if (dialog.checkBox) {
|
||||
this._checkBox = new CheckBox(dialog.checkBox);
|
||||
this._messageDialogContent.add(this._checkBox.actor);
|
||||
}
|
||||
|
||||
this.contentLayout.add_child(this._messageDialogContent);
|
||||
|
||||
let buttons = [];
|
||||
for (let i = 0; i < dialog.confirmButtons.length; i++) {
|
||||
let signal = dialog.confirmButtons[i].signal;
|
||||
let label = dialog.confirmButtons[i].label;
|
||||
let keys = dialog.confirmButtons[i].key;
|
||||
buttons.push({
|
||||
action: () => {
|
||||
let signalId = this.connect('closed', () => {
|
||||
this.disconnect(signalId);
|
||||
this._confirm(signal);
|
||||
});
|
||||
this.close();
|
||||
},
|
||||
label: label,
|
||||
key: keys,
|
||||
});
|
||||
}
|
||||
|
||||
this.setButtons(buttons);
|
||||
}
|
||||
|
||||
_confirm(signal) {
|
||||
var checked;
|
||||
if (this._checkBox) checked = this._checkBox.actor.get_checked();
|
||||
this.emit(signal, checked);
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const _DIALOG_ICON_SIZE = 32;
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue