c3afe1a83a
Track locked status and use it to provide a reduced version of the panel in the locked screen. Accessibility, input sources and volume menus are preserved, without the link to the control center. Network, battery and user menu are reduced to pure indicators, with no menu. This is similar to the design but not exactly, because designers in IRC said that network needs more analysis before exposing, and because the design didn't account for a11y and IM (so the one menu metaphor is not really appropriate). https://bugzilla.gnome.org/show_bug.cgi?id=619955
225 lines
7.4 KiB
JavaScript
225 lines
7.4 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
const Gio = imports.gi.Gio;
|
|
const Lang = imports.lang;
|
|
const Mainloop = imports.mainloop;
|
|
const Shell = imports.gi.Shell;
|
|
const St = imports.gi.St;
|
|
|
|
const Main = imports.ui.main;
|
|
const PanelMenu = imports.ui.panelMenu;
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
const Util = imports.misc.util;
|
|
|
|
const BUS_NAME = 'org.gnome.SettingsDaemon';
|
|
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
|
|
|
|
const UPDeviceType = {
|
|
UNKNOWN: 0,
|
|
AC_POWER: 1,
|
|
BATTERY: 2,
|
|
UPS: 3,
|
|
MONITOR: 4,
|
|
MOUSE: 5,
|
|
KEYBOARD: 6,
|
|
PDA: 7,
|
|
PHONE: 8,
|
|
MEDIA_PLAYER: 9,
|
|
TABLET: 10,
|
|
COMPUTER: 11
|
|
};
|
|
|
|
const UPDeviceState = {
|
|
UNKNOWN: 0,
|
|
CHARGING: 1,
|
|
DISCHARGING: 2,
|
|
EMPTY: 3,
|
|
FULLY_CHARGED: 4,
|
|
PENDING_CHARGE: 5,
|
|
PENDING_DISCHARGE: 6
|
|
};
|
|
|
|
const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
|
|
<method name="GetDevices">
|
|
<arg type="a(susdut)" direction="out" />
|
|
</method>
|
|
<method name="GetPrimaryDevice">
|
|
<arg type="(susdut)" direction="out" />
|
|
</method>
|
|
<property name="Icon" type="s" access="read" />
|
|
</interface>;
|
|
|
|
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface);
|
|
|
|
const Indicator = new Lang.Class({
|
|
Name: 'PowerIndicator',
|
|
Extends: PanelMenu.SystemStatusButton,
|
|
|
|
_init: function() {
|
|
this.parent('battery-missing', _("Battery"));
|
|
|
|
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
|
|
|
this._deviceItems = [ ];
|
|
this._hasPrimary = false;
|
|
this._primaryDeviceId = null;
|
|
|
|
this._batteryItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
|
this._primaryPercentage = new St.Label();
|
|
this._batteryItem.addActor(this._primaryPercentage, { align: St.Align.END });
|
|
this.menu.addMenuItem(this._batteryItem);
|
|
|
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
this._otherDevicePosition = 2;
|
|
|
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
|
|
|
|
this._proxy.connect('g-properties-changed',
|
|
Lang.bind(this, this._devicesChanged));
|
|
this._devicesChanged();
|
|
},
|
|
|
|
setLockedState: function(locked) {
|
|
if (locked)
|
|
this.menu.close();
|
|
this.actor.reactive = !locked;
|
|
},
|
|
|
|
_readPrimaryDevice: function() {
|
|
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
|
|
if (error) {
|
|
this._hasPrimary = false;
|
|
this._primaryDeviceId = null;
|
|
this._batteryItem.actor.hide();
|
|
return;
|
|
}
|
|
let [[device_id, device_type, icon, percentage, state, seconds]] = result;
|
|
if (device_type == UPDeviceType.BATTERY) {
|
|
this._hasPrimary = true;
|
|
let time = Math.round(seconds / 60);
|
|
if (time == 0) {
|
|
// 0 is reported when UPower does not have enough data
|
|
// to estimate battery life
|
|
this._batteryItem.label.text = _("Estimating...");
|
|
} else {
|
|
let minutes = time % 60;
|
|
let hours = Math.floor(time / 60);
|
|
let timestring;
|
|
if (time > 60) {
|
|
if (minutes == 0) {
|
|
timestring = ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
|
|
} else {
|
|
/* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
|
|
let template = _("%d %s %d %s remaining");
|
|
|
|
timestring = template.format (hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes));
|
|
}
|
|
} else
|
|
timestring = ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
|
|
this._batteryItem.label.text = timestring;
|
|
}
|
|
this._primaryPercentage.text = C_("percent of battery remaining", "%d%%").format(Math.round(percentage));
|
|
this._batteryItem.actor.show();
|
|
} else {
|
|
this._hasPrimary = false;
|
|
this._batteryItem.actor.hide();
|
|
}
|
|
|
|
this._primaryDeviceId = device_id;
|
|
}));
|
|
},
|
|
|
|
_readOtherDevices: function() {
|
|
this._proxy.GetDevicesRemote(Lang.bind(this, function(result, error) {
|
|
this._deviceItems.forEach(function(i) { i.destroy(); });
|
|
this._deviceItems = [];
|
|
|
|
if (error) {
|
|
return;
|
|
}
|
|
|
|
let position = 0;
|
|
let [devices] = result;
|
|
for (let i = 0; i < devices.length; i++) {
|
|
let [device_id, device_type] = devices[i];
|
|
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)
|
|
continue;
|
|
|
|
let item = new DeviceItem (devices[i]);
|
|
this._deviceItems.push(item);
|
|
this.menu.addMenuItem(item, this._otherDevicePosition + position);
|
|
position++;
|
|
}
|
|
}));
|
|
},
|
|
|
|
_devicesChanged: function() {
|
|
let icon = this._proxy.Icon;
|
|
if (icon) {
|
|
let gicon = Gio.icon_new_for_string(icon);
|
|
this.setGIcon(gicon);
|
|
this.actor.show();
|
|
} else {
|
|
this.menu.close();
|
|
this.actor.hide();
|
|
}
|
|
this._readPrimaryDevice();
|
|
this._readOtherDevices();
|
|
}
|
|
});
|
|
|
|
const DeviceItem = new Lang.Class({
|
|
Name: 'DeviceItem',
|
|
Extends: PopupMenu.PopupBaseMenuItem,
|
|
|
|
_init: function(device) {
|
|
this.parent({ reactive: false });
|
|
|
|
let [device_id, device_type, icon, percentage, state, time] = device;
|
|
|
|
this._box = new St.BoxLayout({ style_class: 'popup-device-menu-item' });
|
|
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
|
|
|
|
this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon),
|
|
icon_type: St.IconType.SYMBOLIC,
|
|
style_class: 'popup-menu-icon' });
|
|
|
|
this._box.add_actor(this._icon);
|
|
this._box.add_actor(this._label);
|
|
this.addActor(this._box);
|
|
|
|
let percentLabel = new St.Label({ text: C_("percent of battery remaining", "%d%%").format(Math.round(percentage)) });
|
|
this.addActor(percentLabel, { align: St.Align.END });
|
|
},
|
|
|
|
_deviceTypeToString: function(type) {
|
|
switch (type) {
|
|
case UPDeviceType.AC_POWER:
|
|
return _("AC adapter");
|
|
case UPDeviceType.BATTERY:
|
|
return _("Laptop battery");
|
|
case UPDeviceType.UPS:
|
|
return _("UPS");
|
|
case UPDeviceType.MONITOR:
|
|
return _("Monitor");
|
|
case UPDeviceType.MOUSE:
|
|
return _("Mouse");
|
|
case UPDeviceType.KEYBOARD:
|
|
return _("Keyboard");
|
|
case UPDeviceType.PDA:
|
|
return _("PDA");
|
|
case UPDeviceType.PHONE:
|
|
return _("Cell phone");
|
|
case UPDeviceType.MEDIA_PLAYER:
|
|
return _("Media player");
|
|
case UPDeviceType.TABLET:
|
|
return _("Tablet");
|
|
case UPDeviceType.COMPUTER:
|
|
return _("Computer");
|
|
default:
|
|
return C_("device", "Unknown");
|
|
}
|
|
}
|
|
});
|