2011-09-28 13:16:26 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2023-07-10 09:53:00 +00:00
|
|
|
|
|
|
|
import Atk from 'gi://Atk';
|
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import Gio from 'gi://Gio';
|
|
|
|
import GLib from 'gi://GLib';
|
|
|
|
import GObject from 'gi://GObject';
|
|
|
|
import Meta from 'gi://Meta';
|
|
|
|
import Shell from 'gi://Shell';
|
|
|
|
import St from 'gi://St';
|
|
|
|
import UPower from 'gi://UPowerGlib';
|
|
|
|
|
|
|
|
import * as SystemActions from '../../misc/systemActions.js';
|
|
|
|
import * as Main from '../main.js';
|
|
|
|
import * as PopupMenu from '../popupMenu.js';
|
|
|
|
import {PopupAnimation} from '../boxpointer.js';
|
|
|
|
|
|
|
|
import {QuickSettingsItem, QuickToggle, SystemIndicator} from '../quickSettings.js';
|
|
|
|
import {loadInterfaceXML} from '../../misc/fileUtils.js';
|
2022-07-30 01:32:05 +00:00
|
|
|
|
|
|
|
const BUS_NAME = 'org.freedesktop.UPower';
|
|
|
|
const OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice';
|
|
|
|
|
|
|
|
const DisplayDeviceInterface = loadInterfaceXML('org.freedesktop.UPower.Device');
|
|
|
|
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);
|
|
|
|
|
|
|
|
const SHOW_BATTERY_PERCENTAGE = 'show-battery-percentage';
|
|
|
|
|
|
|
|
const PowerToggle = GObject.registerClass({
|
|
|
|
Properties: {
|
|
|
|
'fallback-icon-name': GObject.ParamSpec.string('fallback-icon-name', '', '',
|
|
|
|
GObject.ParamFlags.READWRITE,
|
|
|
|
''),
|
|
|
|
},
|
|
|
|
}, class PowerToggle extends QuickToggle {
|
|
|
|
_init() {
|
|
|
|
super._init({
|
|
|
|
accessible_role: Atk.Role.PUSH_BUTTON,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.add_style_class_name('power-item');
|
|
|
|
|
|
|
|
this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,
|
|
|
|
(proxy, error) => {
|
|
|
|
if (error)
|
|
|
|
console.error(error.message);
|
|
|
|
else
|
|
|
|
this._proxy.connect('g-properties-changed', () => this._sync());
|
|
|
|
this._sync();
|
|
|
|
});
|
|
|
|
|
|
|
|
this.bind_property('fallback-icon-name',
|
|
|
|
this._icon, 'fallback-icon-name',
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
|
|
|
|
this.connect('clicked', () => {
|
|
|
|
const app = Shell.AppSystem.get_default().lookup_app('gnome-power-panel.desktop');
|
|
|
|
Main.overview.hide();
|
|
|
|
Main.panel.closeQuickSettings();
|
|
|
|
app.activate();
|
|
|
|
});
|
|
|
|
|
|
|
|
Main.sessionMode.connect('updated', () => this._sessionUpdated());
|
|
|
|
this._sessionUpdated();
|
|
|
|
this._sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
_sessionUpdated() {
|
|
|
|
this.reactive = Main.sessionMode.allowSettings;
|
|
|
|
}
|
|
|
|
|
|
|
|
_sync() {
|
|
|
|
// Do we have batteries or a UPS?
|
|
|
|
this.visible = this._proxy.IsPresent;
|
|
|
|
if (!this.visible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// The icons
|
|
|
|
let chargingState = this._proxy.State === UPower.DeviceState.CHARGING
|
|
|
|
? '-charging' : '';
|
|
|
|
let fillLevel = 10 * Math.floor(this._proxy.Percentage / 10);
|
|
|
|
const charged =
|
|
|
|
this._proxy.State === UPower.DeviceState.FULLY_CHARGED ||
|
|
|
|
(this._proxy.State === UPower.DeviceState.CHARGING && fillLevel === 100);
|
|
|
|
const icon = charged
|
|
|
|
? 'battery-level-100-charged-symbolic'
|
|
|
|
: `battery-level-${fillLevel}${chargingState}-symbolic`;
|
|
|
|
|
|
|
|
// Make sure we fall back to fallback-icon-name and not GThemedIcon's
|
|
|
|
// default fallbacks
|
|
|
|
const gicon = new Gio.ThemedIcon({
|
|
|
|
name: icon,
|
|
|
|
use_default_fallbacks: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.set({
|
2023-01-30 20:32:39 +00:00
|
|
|
title: _('%d\u2009%%').format(this._proxy.Percentage),
|
2022-07-30 01:32:05 +00:00
|
|
|
fallback_icon_name: this._proxy.IconName,
|
|
|
|
gicon,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2015-03-05 14:46:57 +00:00
|
|
|
|
2022-08-21 16:23:06 +00:00
|
|
|
const ScreenshotItem = GObject.registerClass(
|
|
|
|
class ScreenshotItem extends QuickSettingsItem {
|
|
|
|
_init() {
|
|
|
|
super._init({
|
|
|
|
style_class: 'icon-button',
|
|
|
|
can_focus: true,
|
2022-11-22 20:50:49 +00:00
|
|
|
icon_name: 'screenshooter-symbolic',
|
2022-08-21 16:23:06 +00:00
|
|
|
visible: !Main.sessionMode.isGreeter,
|
2022-08-30 16:10:46 +00:00
|
|
|
accessible_name: _('Take Screenshot'),
|
2022-08-21 16:23:06 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
this.connect('clicked', () => {
|
|
|
|
const topMenu = Main.panel.statusArea.quickSettings.menu;
|
2022-09-07 18:23:38 +00:00
|
|
|
const laters = global.compositor.get_laters();
|
|
|
|
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
|
2022-08-21 16:23:06 +00:00
|
|
|
Main.screenshotUI.open().catch(logError);
|
|
|
|
return GLib.SOURCE_REMOVE;
|
|
|
|
});
|
|
|
|
topMenu.close(PopupAnimation.NONE);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
const SettingsItem = GObject.registerClass(
|
|
|
|
class SettingsItem extends QuickSettingsItem {
|
2019-07-16 09:24:13 +00:00
|
|
|
_init() {
|
2022-07-30 00:17:15 +00:00
|
|
|
super._init({
|
|
|
|
style_class: 'icon-button',
|
|
|
|
can_focus: true,
|
|
|
|
child: new St.Icon(),
|
|
|
|
});
|
|
|
|
|
|
|
|
this._settingsApp = Shell.AppSystem.get_default().lookup_app(
|
|
|
|
'org.gnome.Settings.desktop');
|
|
|
|
|
|
|
|
if (!this._settingsApp)
|
|
|
|
console.warn('Missing required core component Settings, expect trouble…');
|
|
|
|
|
|
|
|
this.child.gicon = this._settingsApp?.get_icon() ?? null;
|
|
|
|
this.accessible_name = this._settingsApp?.get_name() ?? null;
|
|
|
|
|
|
|
|
this.connect('clicked', () => {
|
|
|
|
Main.overview.hide();
|
|
|
|
Main.panel.closeQuickSettings();
|
|
|
|
this._settingsApp.activate();
|
|
|
|
});
|
|
|
|
|
|
|
|
Main.sessionMode.connectObject('updated', () => this._sync(), this);
|
|
|
|
this._sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
_sync() {
|
|
|
|
this.visible =
|
|
|
|
this._settingsApp != null && Main.sessionMode.allowSettings;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const ShutdownItem = GObject.registerClass(
|
|
|
|
class ShutdownItem extends QuickSettingsItem {
|
|
|
|
_init() {
|
|
|
|
super._init({
|
|
|
|
style_class: 'icon-button',
|
|
|
|
hasMenu: true,
|
|
|
|
canFocus: true,
|
2022-08-21 16:24:06 +00:00
|
|
|
icon_name: 'system-shutdown-symbolic',
|
2022-07-30 00:17:15 +00:00
|
|
|
accessible_name: _('Power Off Menu'),
|
|
|
|
});
|
2013-06-06 21:27:25 +00:00
|
|
|
|
2017-08-02 20:57:54 +00:00
|
|
|
this._systemActions = new SystemActions.getDefault();
|
2022-07-30 00:17:15 +00:00
|
|
|
this._items = [];
|
|
|
|
|
2022-09-13 15:18:26 +00:00
|
|
|
this.menu.setHeader('system-shutdown-symbolic', C_('title', 'Power Off'));
|
2022-07-30 00:17:15 +00:00
|
|
|
|
|
|
|
this._addSystemAction(_('Suspend'), 'can-suspend', () => {
|
|
|
|
this._systemActions.activateSuspend();
|
|
|
|
Main.panel.closeQuickSettings();
|
|
|
|
});
|
|
|
|
|
|
|
|
this._addSystemAction(_('Restart…'), 'can-restart', () => {
|
|
|
|
this._systemActions.activateRestart();
|
|
|
|
Main.panel.closeQuickSettings();
|
|
|
|
});
|
|
|
|
|
|
|
|
this._addSystemAction(_('Power Off…'), 'can-power-off', () => {
|
|
|
|
this._systemActions.activatePowerOff();
|
|
|
|
Main.panel.closeQuickSettings();
|
|
|
|
});
|
|
|
|
|
|
|
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
|
|
|
2022-09-03 16:41:55 +00:00
|
|
|
this._addSystemAction(_('Log Out…'), 'can-logout', () => {
|
2022-07-30 00:17:15 +00:00
|
|
|
this._systemActions.activateLogout();
|
|
|
|
Main.panel.closeQuickSettings();
|
|
|
|
});
|
|
|
|
|
|
|
|
this._addSystemAction(_('Switch User…'), 'can-switch-user', () => {
|
|
|
|
this._systemActions.activateSwitchUser();
|
|
|
|
Main.panel.closeQuickSettings();
|
|
|
|
});
|
2013-06-11 19:25:32 +00:00
|
|
|
|
2011-06-03 22:10:55 +00:00
|
|
|
// Whether shutdown is available or not depends on both lockdown
|
|
|
|
// settings (disable-log-out) and Polkit policy - the latter doesn't
|
2022-07-30 00:17:15 +00:00
|
|
|
// notify, so we update the item each time we become visible or
|
2011-06-03 22:10:55 +00:00
|
|
|
// the lockdown setting changes, which should be close enough.
|
2022-07-30 00:17:15 +00:00
|
|
|
this.connect('notify::mapped', () => {
|
|
|
|
if (!this.mapped)
|
2017-10-31 00:38:18 +00:00
|
|
|
return;
|
2012-10-19 15:41:10 +00:00
|
|
|
|
2017-10-31 00:38:18 +00:00
|
|
|
this._systemActions.forceUpdate();
|
|
|
|
});
|
2013-07-17 06:33:09 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
this.connect('clicked', () => this.menu.open());
|
|
|
|
this.connect('popup-menu', () => this.menu.open());
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2009-11-10 17:13:58 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
_addSystemAction(label, propName, callback) {
|
|
|
|
const item = this.menu.addAction(label, callback);
|
|
|
|
this._items.push(item);
|
|
|
|
|
|
|
|
this._systemActions.bind_property(propName,
|
|
|
|
item, 'visible',
|
|
|
|
GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
item.connect('notify::visible', () => this._sync());
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2009-11-10 17:13:58 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
_sync() {
|
|
|
|
this.visible = this._items.some(i => i.visible);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2022-07-30 00:17:15 +00:00
|
|
|
});
|
2011-02-04 23:37:54 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
const LockItem = GObject.registerClass(
|
|
|
|
class LockItem extends QuickSettingsItem {
|
|
|
|
_init() {
|
|
|
|
this._systemActions = new SystemActions.getDefault();
|
2009-11-10 17:13:58 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
super._init({
|
|
|
|
style_class: 'icon-button',
|
|
|
|
can_focus: true,
|
2022-08-21 16:24:06 +00:00
|
|
|
icon_name: 'system-lock-screen-symbolic',
|
2022-09-13 16:59:35 +00:00
|
|
|
accessible_name: C_('action', 'Lock Screen'),
|
2017-08-02 20:57:54 +00:00
|
|
|
});
|
2022-07-30 00:17:15 +00:00
|
|
|
|
2019-10-15 18:51:33 +00:00
|
|
|
this._systemActions.bind_property('can-lock-screen',
|
2022-07-30 00:17:15 +00:00
|
|
|
this, 'visible',
|
|
|
|
GObject.BindingFlags.DEFAULT |
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
2019-10-15 18:51:33 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
this.connect('clicked',
|
|
|
|
() => this._systemActions.activateLockScreen());
|
|
|
|
}
|
|
|
|
});
|
2019-10-15 18:51:33 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
|
|
|
|
const SystemItem = GObject.registerClass(
|
|
|
|
class SystemItem extends QuickSettingsItem {
|
|
|
|
_init() {
|
|
|
|
super._init({
|
|
|
|
style_class: 'quick-settings-system-item',
|
|
|
|
reactive: false,
|
2017-08-02 20:57:54 +00:00
|
|
|
});
|
2013-06-11 21:17:09 +00:00
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
this.child = new St.BoxLayout();
|
2019-10-15 18:51:33 +00:00
|
|
|
|
2022-07-30 01:32:05 +00:00
|
|
|
this._powerToggle = new PowerToggle();
|
|
|
|
this.child.add_child(this._powerToggle);
|
|
|
|
|
2022-08-21 16:29:07 +00:00
|
|
|
this._laptopSpacer = new Clutter.Actor({x_expand: true});
|
|
|
|
this._powerToggle.bind_property('visible',
|
|
|
|
this._laptopSpacer, 'visible',
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.child.add_child(this._laptopSpacer);
|
2022-07-30 00:17:15 +00:00
|
|
|
|
2022-08-21 16:23:06 +00:00
|
|
|
const screenshotItem = new ScreenshotItem();
|
|
|
|
this.child.add_child(screenshotItem);
|
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
const settingsItem = new SettingsItem();
|
|
|
|
this.child.add_child(settingsItem);
|
|
|
|
|
2022-08-21 16:29:07 +00:00
|
|
|
this._desktopSpacer = new Clutter.Actor({x_expand: true});
|
|
|
|
this._powerToggle.bind_property('visible',
|
|
|
|
this._desktopSpacer, 'visible',
|
|
|
|
GObject.BindingFlags.INVERT_BOOLEAN |
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.child.add_child(this._desktopSpacer);
|
|
|
|
|
2022-07-30 00:17:15 +00:00
|
|
|
const lockItem = new LockItem();
|
|
|
|
this.child.add_child(lockItem);
|
|
|
|
|
|
|
|
const shutdownItem = new ShutdownItem();
|
|
|
|
this.child.add_child(shutdownItem);
|
|
|
|
|
|
|
|
this.menu = shutdownItem.menu;
|
|
|
|
}
|
2022-07-30 01:32:05 +00:00
|
|
|
|
|
|
|
get powerToggle() {
|
|
|
|
return this._powerToggle;
|
|
|
|
}
|
2022-07-30 00:17:15 +00:00
|
|
|
});
|
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export const Indicator = GObject.registerClass(
|
2022-07-30 00:17:15 +00:00
|
|
|
class Indicator extends SystemIndicator {
|
|
|
|
_init() {
|
|
|
|
super._init();
|
|
|
|
|
2022-07-30 01:32:05 +00:00
|
|
|
this._desktopSettings = new Gio.Settings({
|
|
|
|
schema_id: 'org.gnome.desktop.interface',
|
|
|
|
});
|
|
|
|
this._desktopSettings.connectObject(
|
|
|
|
`changed::${SHOW_BATTERY_PERCENTAGE}`, () => this._sync(), this);
|
|
|
|
|
|
|
|
this._indicator = this._addIndicator();
|
|
|
|
this._percentageLabel = new St.Label({
|
|
|
|
y_expand: true,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
|
|
|
this.add_child(this._percentageLabel);
|
|
|
|
this.add_style_class_name('power-status');
|
|
|
|
|
|
|
|
this._systemItem = new SystemItem();
|
|
|
|
|
|
|
|
const {powerToggle} = this._systemItem;
|
|
|
|
|
2023-02-22 17:57:18 +00:00
|
|
|
powerToggle.bind_property('title',
|
2022-07-30 01:32:05 +00:00
|
|
|
this._percentageLabel, 'text',
|
|
|
|
GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
|
|
|
|
powerToggle.connectObject(
|
|
|
|
'notify::visible', () => this._sync(),
|
|
|
|
'notify::gicon', () => this._sync(),
|
|
|
|
'notify::fallback-icon-name', () => this._sync(),
|
|
|
|
this);
|
2013-08-23 15:09:51 +00:00
|
|
|
|
2022-07-30 01:32:05 +00:00
|
|
|
this.quickSettingsItems.push(this._systemItem);
|
|
|
|
|
|
|
|
this._sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
_sync() {
|
|
|
|
const {powerToggle} = this._systemItem;
|
|
|
|
if (powerToggle.visible) {
|
|
|
|
this._indicator.set({
|
|
|
|
gicon: powerToggle.gicon,
|
|
|
|
fallback_icon_name: powerToggle.fallback_icon_name,
|
|
|
|
});
|
|
|
|
this._percentageLabel.visible =
|
|
|
|
this._desktopSettings.get_boolean(SHOW_BATTERY_PERCENTAGE);
|
|
|
|
} else {
|
|
|
|
// If there's no battery, then we use the power icon.
|
|
|
|
this._indicator.icon_name = 'system-shutdown-symbolic';
|
|
|
|
this._percentageLabel.hide();
|
|
|
|
}
|
2017-08-02 20:57:54 +00:00
|
|
|
}
|
2019-07-16 09:24:13 +00:00
|
|
|
});
|