summaryrefslogtreecommitdiff
path: root/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service')
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/action.js217
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/control.js235
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/shutdown-timer-dbus.js72
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/timer.js286
4 files changed, 0 insertions, 810 deletions
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/action.js b/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/action.js
deleted file mode 100644
index 4b5bf9f..0000000
--- a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/action.js
+++ /dev/null
@@ -1,217 +0,0 @@
-// SPDX-FileCopyrightText: 2023 Deminder <tremminder@gmail.com>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-import Gio from 'gi://Gio';
-import * as Control from './control.js';
-import { proxyPromise } from '../modules/util.js';
-import { pgettext as C_, gettext as _ } from '../modules/translation.js';
-import { logDebug } from '../modules/util.js';
-
-export const ACTIONS = {
- PowerOff: 0,
- Reboot: 1,
- Suspend: 2,
- SuspendThenHibernate: 3,
- Hibernate: 4,
- HybridSleep: 5,
- Halt: 6,
-};
-
-export const WAKE_ACTIONS = { wake: 100, 'no-wake': 101 };
-
-/**
- * Get supported actions.
- * In order to show an error when shutdown or reboot are not supported
- * they are always included here. */
-export async function* supportedActions() {
- const actionDbus = new Action();
- for await (const action of Object.keys(ACTIONS).map(async a =>
- ['PowerOff', 'Reboot'].includes(a) ||
- (await actionDbus.canShutdownAction(a))
- ? a
- : null
- )) {
- if (action) {
- yield action;
- }
- }
-}
-
-export class UnsupportedActionError extends Error {}
-
-export class Action {
- #cancellable = new Gio.Cancellable();
- #cookie = null;
-
- #loginProxy = proxyPromise(
- 'org.freedesktop.login1.Manager',
- Gio.DBus.system,
- 'org.freedesktop.login1',
- '/org/freedesktop/login1',
- this.#cancellable
- );
-
- #screenSaverProxy = proxyPromise(
- 'org.gnome.ScreenSaver',
- Gio.DBus.session,
- 'org.gnome.ScreenSaver',
- '/org/gnome/ScreenSaver',
- this.#cancellable
- );
-
- #sessionProxy = proxyPromise(
- 'org.gnome.SessionManager',
- Gio.DBus.session,
- 'org.gnome.SessionManager',
- '/org/gnome/SessionManager',
- this.#cancellable
- );
-
- destroy() {
- if (this.#cancellable !== null) {
- this.#cancellable.cancel();
- this.#cancellable = null;
- }
- }
-
- #poweroffOrReboot(action) {
- return [ACTIONS.PowerOff, ACTIONS.Reboot].includes(ACTIONS[action]);
- }
-
- /**
- * Perform the shutdown action.
- *
- * @param {string} action the shutdown action
- * @param {boolean} showEndSessionDialog show the end session dialog or directly shutdown
- *
- * @returns {Promise} resolves on action completion
- */
- async shutdownAction(action, showEndSessionDialog) {
- if (!(action in ACTIONS))
- throw new Error(`Unknown shutdown action: ${action}`);
- logDebug('[shutdownAction]', action);
-
- await this.uninhibitSuspend();
-
- const screenSaverProxy = await this.#screenSaverProxy;
- const [screenSaverActive] = await screenSaverProxy.GetActiveAsync();
- if (
- showEndSessionDialog &&
- !screenSaverActive &&
- this.#poweroffOrReboot(action)
- ) {
- const sessionProxy = await this.#sessionProxy;
- if (action === 'PowerOff') {
- await sessionProxy.ShutdownAsync();
- } else {
- await sessionProxy.RebootAsync();
- }
- } else {
- const loginProxy = await this.#loginProxy;
- if (await this.canShutdownAction(action)) {
- await loginProxy[`${action}Async`](true);
- } else if (this.#poweroffOrReboot(action)) {
- await Control.shutdown('now', ACTIONS[action] === ACTIONS.Reboot);
- } else {
- throw new UnsupportedActionError();
- }
- }
- }
-
- /**
- * Check if a shutdown action can be performed (without authentication).
- *
- * @returns {Promise} resolves to `true` if action can be performed, otherwise `false`.
- */
- async canShutdownAction(action) {
- const loginProxy = await this.#loginProxy;
- if (!(action in ACTIONS))
- throw new Error(`Unknown shutdown action: ${action}`);
- const [result] = await loginProxy[`Can${action}Async`]();
- return result === 'yes';
- }
-
- /**
- * Schedule a wake after some minutes or cancel
- *
- * @param {boolean} wake
- * @param {number} minutes
- */
- async wakeAction(wake, minutes) {
- if (wake) {
- await Control.wake(minutes);
- } else {
- await Control.wakeCancel();
- }
- }
-
- async inhibitSuspend() {
- if (this.#cookie === null) {
- const sessionProxy = await this.#sessionProxy;
- const [cookie] = await sessionProxy.InhibitAsync(
- 'user',
- 0,
- 'Inhibit by Shutdown Timer (GNOME-Shell extension)',
- /* Suspend flag */ 4
- );
- this.#cookie = cookie;
- }
- }
-
- async uninhibitSuspend() {
- if (this.#cookie !== null) {
- const sessionProxy = await this.#sessionProxy;
- await sessionProxy.UninhibitAsync(this.#cookie);
- this.#cookie = null;
- }
- }
-}
-
-/**
- * Get the translated action label
- *
- * @param action
- */
-export function actionLabel(action) {
- return {
- SuspendThenHibernate: _('Suspend then Hibernate'),
- HybridSleep: _('Hybrid Sleep'),
- Hibernate: _('Hibernate'),
- Halt: _('Halt'),
- Suspend: _('Suspend'),
- PowerOff: _('Power Off'),
- Reboot: _('Restart'),
- wake: _('Wake'),
- 'no-wake': _('No Wake'),
- }[action];
-}
-
-export function untilText(action) {
- return {
- SuspendThenHibernate: C_('untiltext', 'suspend and hibernate'),
- HybridSleep: C_('untiltext', 'hybrid sleep'),
- Hibernate: C_('untiltext', 'hibernate'),
- Halt: C_('untiltext', 'halt'),
- Suspend: C_('untiltext', 'suspend'),
- PowerOff: C_('untiltext', 'shutdown'),
- Reboot: C_('untiltext', 'reboot'),
- wake: C_('untiltext', 'wakeup'),
- }[action];
-}
-
-export function mapLegacyAction(action) {
- return action in ACTIONS || ['wake', ''].includes(action)
- ? action
- : {
- poweroff: 'PowerOff',
- shutdown: 'PowerOff',
- reboot: 'Reboot',
- suspend: 'Suspend',
- }[action] ??
- {
- p: 'PowerOff',
- r: 'Reboot',
- s: 'Suspend',
- h: 'SuspendThenHibernate',
- }[action[0].toLowerCase()];
-}
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/control.js b/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/control.js
deleted file mode 100644
index 28d184a..0000000
--- a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/control.js
+++ /dev/null
@@ -1,235 +0,0 @@
-// SPDX-FileCopyrightText: 2023 Deminder <tremminder@gmail.com>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-import GLib from 'gi://GLib';
-import Gio from 'gi://Gio';
-import { gettext as _ } from '../modules/translation.js';
-
-import { logDebug } from '../modules/util.js';
-
-function readLine(stream, cancellable) {
- return new Promise((resolve, reject) => {
- stream.read_line_async(0, cancellable, (s, res) => {
- try {
- const line = s.read_line_finish_utf8(res)[0];
-
- if (line !== null) {
- resolve(line);
- } else {
- reject(new Error('No line was read!'));
- }
- } catch (e) {
- reject(e);
- }
- });
- });
-}
-
-function quoteEscape(str) {
- return str.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
-}
-
-/**
- * Execute a command asynchronously and check the exit status.
- *
- * If given, @cancellable can be used to stop the process before it finishes.
- *
- * @param {string[] | string} argv - a list of string arguments or command line that will be parsed
- * @param {Gio.Cancellable} [cancellable] - optional cancellable object
- * @param {boolean} shell - run command as shell command
- * @param logFunc
- * @returns {Promise<void>} - The process success
- */
-export function execCheck(
- argv,
- cancellable = null,
- shell = true,
- logFunc = undefined
-) {
- if (!shell && typeof argv === 'string') {
- argv = GLib.shell_parse_argv(argv)[1];
- }
-
- const isRootProc = argv[0] && argv[0].endsWith('pkexec');
-
- if (shell && Array.isArray(argv)) {
- argv = argv.map(c => `"${quoteEscape(c)}"`).join(' ');
- }
- let cancelId = 0;
- let proc = new Gio.Subprocess({
- argv: (shell ? ['/bin/sh', '-c'] : []).concat(argv),
- flags:
- logFunc !== undefined
- ? Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE
- : Gio.SubprocessFlags.NONE,
- });
- proc.init(cancellable);
-
- if (cancellable instanceof Gio.Cancellable) {
- cancelId = cancellable.connect(() => {
- if (logFunc !== undefined) {
- if (isRootProc) {
- logFunc(`# ${_('Can not cancel root process!')}`);
- } else {
- logFunc(`[${_('CANCEL')}]`);
- }
- }
- proc.force_exit();
- });
- }
- let stdoutStream = null;
- let stderrStream = null;
- let readLineCancellable = null;
-
- if (logFunc !== undefined) {
- readLineCancellable = new Gio.Cancellable();
- stdoutStream = new Gio.DataInputStream({
- base_stream: proc.get_stdout_pipe(),
- close_base_stream: true,
- });
-
- stderrStream = new Gio.DataInputStream({
- base_stream: proc.get_stderr_pipe(),
- close_base_stream: true,
- });
- const readNextLine = async (stream, prefix) => {
- try {
- const line = await readLine(stream, readLineCancellable);
- logFunc(prefix + line);
- logDebug(line);
- await readNextLine(stream, prefix);
- } catch {
- if (!stream.is_closed()) {
- stream.close_async(0, null, (s, sRes) => {
- try {
- s.close_finish(sRes);
- } catch (e) {
- logDebug(`[StreamCloseError] ${e}`);
- }
- });
- }
- }
- };
- // read stdout and stderr asynchronously
- readNextLine(stdoutStream, '');
- readNextLine(stderrStream, '# ');
- }
-
- return new Promise((resolve, reject) => {
- proc.wait_check_async(null, (p, res) => {
- try {
- const success = p.wait_check_finish(res);
- if (!success) {
- let status = p.get_exit_status();
-
- throw new Gio.IOErrorEnum({
- code: Gio.io_error_from_errno(status),
- message: GLib.strerror(status),
- });
- }
-
- resolve();
- } catch (e) {
- reject(e);
- } finally {
- if (readLineCancellable) readLineCancellable.cancel();
- readLineCancellable = null;
- if (cancelId > 0) cancellable.disconnect(cancelId);
- }
- });
- });
-}
-
-export function sleepUntilDeadline(deadlineSeconds, cancellable) {
- return new Promise((resolve, reject) => {
- const secondsLeft = () =>
- deadlineSeconds - GLib.DateTime.new_now_utc().to_unix();
-
- let timeoutId = 0;
- let handlerId = cancellable.connect(() => {
- handlerId = 0;
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
- reject(new Error('Sleep until deadline cancelled!'));
- });
-
- const continueSleep = () => {
- timeoutId = setTimeout(() => {
- timeoutId = 0;
- if (secondsLeft() > 0) {
- continueSleep();
- } else {
- if (handlerId) {
- cancellable.disconnect(handlerId);
- }
- resolve();
- }
- }, 1000);
- };
- continueSleep();
- });
-}
-
-export function installedScriptPath() {
- for (const name of [
- 'shutdowntimerctl',
- `shutdowntimerctl-${GLib.get_user_name()}`,
- ]) {
- const standard = GLib.find_program_in_path(name);
- if (standard !== null) {
- return standard;
- }
- for (const bindir of ['/usr/local/bin/', '/usr/bin/']) {
- const path = bindir + name;
- logDebug(`Looking for: ${path}`);
- if (Gio.File.new_for_path(path).query_exists(null)) {
- return path;
- }
- }
- }
- return null;
-}
-
-function execControlScript(args, noScriptArgs) {
- const installedScript = installedScriptPath();
- if (installedScript !== null) {
- return execCheck(['pkexec', installedScript].concat(args), null, false);
- }
- if (noScriptArgs === undefined) {
- throw new Error(_('Privileged script installation required!'));
- }
- return execCheck(noScriptArgs, null, false);
-}
-
-export function shutdown(minutes, reboot = false) {
- logDebug(`[root-shutdown] ${minutes} minutes, reboot: ${reboot}`);
- return execControlScript(
- [reboot ? 'reboot' : 'shutdown', `${minutes}`],
- ['shutdown', reboot ? '-r' : '-P', `${minutes}`]
- );
-}
-
-function shutdownCancel() {
- logDebug('[root-shutdown] cancel');
- return execControlScript(['shutdown-cancel'], ['shutdown', '-c']);
-}
-
-export function wake(minutes) {
- return execControlScript(['wake', `${minutes}`]);
-}
-
-export function wakeCancel() {
- return execControlScript(['wake-cancel']);
-}
-
-export async function stopRootModeProtection(info) {
- if (['PowerOff', 'Reboot'].includes(info.mode)) {
- await shutdownCancel();
- }
-}
-export async function startRootModeProtection(info) {
- if (['PowerOff', 'Reboot'].includes(info.mode)) {
- await shutdown(Math.max(0, info.minutes) + 1, info.mode === 'Reboot');
- }
-}
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/shutdown-timer-dbus.js b/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/shutdown-timer-dbus.js
deleted file mode 100644
index 8db37a4..0000000
--- a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/shutdown-timer-dbus.js
+++ /dev/null
@@ -1,72 +0,0 @@
-// SPDX-FileCopyrightText: 2023 Deminder <tremminder@gmail.com>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-import Gio from 'gi://Gio';
-import GLib from 'gi://GLib';
-
-import { loadInterfaceXML, logDebug } from '../modules/util.js';
-import { Timer } from './timer.js';
-
-export const ShutdownTimerName = 'org.gnome.Shell.Extensions.ShutdownTimer';
-export const ShutdownTimerObjectPath =
- '/org/gnome/Shell/Extensions/ShutdownTimer';
-export const ShutdownTimerIface = await loadInterfaceXML(ShutdownTimerName);
-
-export class ShutdownTimerDBus {
- constructor({ settings }) {
- this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(
- ShutdownTimerIface,
- this
- );
- this._dbusImpl.export(Gio.DBus.session, ShutdownTimerObjectPath);
-
- this._timer = new Timer({ settings });
- this._timer.connect('message', (_, msg) => {
- logDebug('[shutdown-timer-dbus] msg', msg);
- this._dbusImpl.emit_signal('OnMessage', new GLib.Variant('(s)', [msg]));
- });
- this._timer.connect('change', () => {
- logDebug('[shutdown-timer-dbus] state', this._timer.state);
- this._dbusImpl.emit_signal(
- 'OnStateChange',
- new GLib.Variant('(s)', [this._timer.state])
- );
- });
- this._timer.connect('change-external', () => {
- this._dbusImpl.emit_signal('OnExternalChange', null);
- });
- }
-
- async ScheduleShutdownAsync(parameters, invocation) {
- const [shutdown, action] = parameters;
- logDebug(
- '[sdt-dbus] [ScheduleShutdownAsync] shutdown',
- shutdown,
- 'action',
- action
- );
- await this._timer.toggleShutdown(shutdown, action);
- invocation.return_value(null);
- }
-
- async ScheduleWakeAsync(parameters, invocation) {
- const [wake] = parameters;
- logDebug('[sdt-dbus] [ScheduleWakeAsync] wake', wake);
- await this._timer.toggleWake(wake);
- invocation.return_value(null);
- }
-
- GetStateAsync(_, invocation) {
- logDebug('[sdt-dbus] [GetStateAsync]');
- invocation.return_value(new GLib.Variant('(s)', [this._timer.state]));
- return Promise.resolve();
- }
-
- destroy() {
- logDebug('[sdt-dbus] destroy');
- this._dbusImpl.unexport();
- this._dbusImpl = null;
- this._timer.destroy();
- this._timer = null;
- }
-}
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/timer.js b/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/timer.js
deleted file mode 100644
index 6c439ab..0000000
--- a/raveos-theme/gnome/theme-data/extensions/installed/ShutdownTimer@deminder/dbus-service/timer.js
+++ /dev/null
@@ -1,286 +0,0 @@
-// SPDX-FileCopyrightText: 2023 Deminder <tremminder@gmail.com>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-import GLib from 'gi://GLib';
-import Gio from 'gi://Gio';
-import {
- gettext as _,
- ngettext as _n,
- pgettext as C_,
-} from '../modules/translation.js';
-
-import { logDebug, throttleTimeout } from '../modules/util.js';
-import * as Control from './control.js';
-import {
- longDurationString,
- ScheduleInfo,
- getShutdownScheduleFromSettings,
- getSliderMinutesFromSettings,
-} from '../modules/schedule-info.js';
-import {
- actionLabel,
- Action,
- mapLegacyAction,
- UnsupportedActionError,
-} from './action.js';
-
-const Signals = imports.signals;
-
-export class Timer {
- _timerCancellable = null;
- _updateScheduleCancel = null;
- _action = new Action();
- info = {
- externalShutdown: new ScheduleInfo({
- external: true,
- }),
- externalWake: new ScheduleInfo({
- external: false,
- mode: 'wake',
- }),
- internalShutdown: new ScheduleInfo({ mode: 'PowerOff' }),
- };
-
- constructor({ settings }) {
- this._settings = settings;
-
- const [updateScheduleThrottled, updateScheduleCancel] = throttleTimeout(
- () => this.updateSchedule(),
- 20
- );
- this._updateScheduleCancel = updateScheduleCancel;
- this._settingsIds = [
- 'root-mode-value',
- 'shutdown-timestamp-value',
- 'shutdown-mode-value',
- ].map(settingName =>
- settings.connect(`changed::${settingName}`, updateScheduleThrottled)
- );
-
- this.updateSchedule();
- }
-
- destroy() {
- if (this._settings === null) {
- throw new Error('should not destroy twice');
- }
- // Disconnect settings
- this._settingsIds.forEach(id => this._settings.disconnect(id));
- this._settingsIds = [];
- this._settings = null;
-
- // Cancel schedule updates
- if (this._updateScheduleCancel !== null) {
- this._updateScheduleCancel();
- this._updateScheduleCancel = null;
- }
-
- // Cancel internal timer
- if (this._timerCancellable !== null) {
- this._timerCancellable.cancel();
- this._timerCancellable = null;
- }
-
- // External schedules (for 'shutdown' and 'wake') are not stopped
- }
-
- updateSchedule() {
- const oldInternal = this.info.internalShutdown;
- const internal = getShutdownScheduleFromSettings(this._settings);
- this.info.internalShutdown = internal;
- logDebug(
- `[updateSchedule] internal schedule: ${internal.label} (old internal schedule: ${oldInternal.label})`
- );
- this._updateRootModeProtection(oldInternal);
- if (
- internal.mode !== oldInternal.mode ||
- internal.deadline !== oldInternal.deadline
- ) {
- this.emit('change');
- if (internal.scheduled) {
- if (internal.minutes > 0) {
- // Show schedule info
- this.emit(
- 'message',
- C_('StartSchedulePopup', '%s in %s').format(
- actionLabel(internal.mode),
- longDurationString(
- internal.minutes,
- h => _n('%s hour', '%s hours', h),
- m => _n('%s minute', '%s minutes', m)
- )
- )
- );
- } else {
- logDebug(`[updateSchedule] hidden message for '< 1 minute' schedule`);
- }
- if (this._timerCancellable !== null) {
- this._timerCancellable.cancel();
- this._timerCancellable = null;
- }
- this.executeActionDelayed()
- .then(() => {
- logDebug('[executeActionDelayed] done');
- })
- .catch(err => {
- console.error('executeActionDelayed', err);
- });
- } else {
- if (this._timerCancellable !== null) {
- this._timerCancellable.cancel();
- this._timerCancellable = null;
- }
- if (oldInternal.scheduled) {
- this.emit('message', _('Shutdown Timer stopped'));
- }
- }
- }
- }
-
- async executeAction() {
- const internal = this.info.internalShutdown;
- if (!internal.scheduled) {
- logDebug(`Refusing to exectute non scheduled action! '${internal.mode}'`);
- return;
- }
- logDebug(`Running '${internal.mode}' timer action...`);
- try {
- this.emit('change');
- // Refresh root mode protection
- await Promise.all([
- this._updateRootModeProtection(),
- // Do shutdown
- this._action.shutdownAction(
- internal.mode,
- this._settings.get_boolean('show-end-session-dialog-value')
- ),
- ]);
- } catch (err) {
- if (/* destroyed */ this._settings === null) {
- throw err;
- }
- const newInternal = this.info.internalShutdown;
- if (newInternal.scheduled && newInternal.secondsLeft > 0) {
- logDebug('[timer] Replaced by new schedule.');
- return;
- }
- if (err instanceof UnsupportedActionError) {
- this.emit(
- 'message',
- _('%s is not supported!').format(actionLabel(internal.mode))
- );
- }
- }
- await this.toggleShutdown(false, '');
- }
-
- async executeActionDelayed() {
- const internal = this.info.internalShutdown;
- const secs = internal.secondsLeft;
- if (secs > 0) {
- logDebug(`Started delayed action: ${internal.minutes}min remaining`);
- try {
- this._timerCancellable = new Gio.Cancellable();
- await Control.sleepUntilDeadline(
- internal.deadline,
- this._timerCancellable
- );
- this._timerCancellable = null;
- } catch {
- logDebug(`Canceled delayed action: ${internal.minutes}min remaining`);
- return;
- }
- }
- await this.executeAction();
- }
-
- async toggleWake(wake) {
- try {
- logDebug('[toggleWake] wake', wake);
- await this._action.wakeAction(
- wake,
- getSliderMinutesFromSettings(this._settings, 'wake')
- );
- this.emit('change-external');
- } catch (err) {
- this.emit(
- 'message',
- C_('Error', '%s\n%s').format(_('Wake action failed!'), err)
- );
- this._settings.set_int('shutdown-timestamp-value', -1);
- }
- }
-
- async toggleShutdown(shutdown, legacyAction) {
- // Update shutdown action
- const action = mapLegacyAction(legacyAction);
- if (action === undefined) {
- this.emit(
- 'message',
- _('Unknown shutdown action: "%s"!').format(legacyAction)
- );
- return;
- }
- logDebug('[toggleShutdown] shutdown', shutdown, 'action', action);
- if (action !== '') {
- this._settings.set_string('shutdown-mode-value', action);
- }
-
- // Update shutdown timestamp
- this._settings.set_int(
- 'shutdown-timestamp-value',
- shutdown
- ? GLib.DateTime.new_now_utc().to_unix() +
- Math.max(
- 1,
- getSliderMinutesFromSettings(this._settings, 'shutdown') * 60
- )
- : -1
- );
- if (shutdown) {
- await this._action.inhibitSuspend();
- } else {
- await this._action.uninhibitSuspend();
- }
- if (this._settings.get_boolean('auto-wake-value')) {
- await this.toggleWake(shutdown);
- }
- }
-
- get state() {
- return this.info.internalShutdown.scheduled
- ? this.info.internalShutdown.secondsLeft > 0
- ? 'active'
- : 'action'
- : 'inactive';
- }
-
- /**
- * Ensure that shutdown/reboot is executed even if the Timer fails by running
- * the `shutdown` command delayed by 1 minute.
- */
- async _updateRootModeProtection(oldInternal) {
- if (this._settings.get_boolean('root-mode-value')) {
- const internal = this.info.internalShutdown;
- logDebug('[updateRootModeProtection] mode ', internal.mode);
- try {
- if (oldInternal?.scheduled && oldInternal.mode !== internal.mode) {
- await Control.stopRootModeProtection(oldInternal);
- }
- if (internal.scheduled) {
- await Control.startRootModeProtection(internal);
- } else {
- await Control.stopRootModeProtection(internal);
- }
- } catch (err) {
- this.emit(
- 'message',
- C_('Error', '%s\n%s').format(_('Root mode protection failed!'), err)
- );
- console.error('[updateRootModeProtection]', err);
- }
- this.emit('change-external');
- }
- }
-}
-Signals.addSignalMethods(Timer.prototype);