Status area: introduce battery & power indicator

Add an indicator for battery charge and power indication in the
system status area, using the newly exported DBus API from
gnome-power-manager.

https://bugzilla.gnome.org/show_bug.cgi?id=622451
This commit is contained in:
Giovanni Campagna 2010-11-15 22:45:17 +01:00
parent 21ac225981
commit 8b3f05b6e3
6 changed files with 294 additions and 5 deletions

View File

@ -156,6 +156,10 @@ StTooltip StLabel {
-slider-handle-radius: 0.5em;
}
.popup-device-menu-item {
spacing: .5em;
}
.popup-menu-icon {
icon-size: 1em;
}

View File

@ -43,6 +43,7 @@ nobase_dist_js_DATA = \
ui/statusIconDispatcher.js \
ui/statusMenu.js \
ui/status/accessibility.js \
ui/status/power.js \
ui/status/volume.js \
ui/telepathyClient.js \
ui/tweener.js \

View File

@ -33,6 +33,7 @@ const STANDARD_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'blue
const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator,
'volume': imports.ui.status.volume.Indicator,
'battery': imports.ui.status.power.Indicator
};
const CLOCK_FORMAT_KEY = 'format';

230
js/ui/status/power.js Normal file
View File

@ -0,0 +1,230 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const DBus = imports.dbus;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const BUS_NAME = 'org.gnome.PowerManager';
const OBJECT_PATH = '/org/gnome/PowerManager';
const UPDeviceType = {
UNKNOWN: 0,
AC_POWER: 1,
BATTERY: 2,
UPS: 3,
MONITOR: 4,
MOUSE: 5,
KEYBOARD: 6,
PDA: 7,
PHONE: 8
};
const UPDeviceState = {
UNKNOWN: 0,
CHARGING: 1,
DISCHARGING: 2,
EMPTY: 3,
FULLY_CHARGED: 4,
PENDING_CHARGE: 5,
PENDING_DISCHARGE: 6
};
const PowerManagerInterface = {
name: 'org.gnome.PowerManager',
methods: [
{ name: 'GetDevices', inSignature: '', outSignature: 'a(susbut)' },
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
],
signals: [
{ name: 'Changed', outSignature: '' },
],
properties: [
{ name: 'Icon', signature: 's', access: 'read' },
{ name: 'Tooltip', signature: 's', access: 'read' },
]
};
let PowerManagerProxy = DBus.makeProxyClass(PowerManagerInterface);
function Indicator() {
this._init.apply(this, arguments);
}
Indicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() {
PanelMenu.SystemStatusButton.prototype._init.call(this, 'battery-missing');
this._proxy = new PowerManagerProxy(DBus.session, BUS_NAME, OBJECT_PATH);
this._deviceItems = [ ];
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem = new PopupMenu.PopupMenuItem('');
this.menu.addMenuItem(this._batteryItem);
this._deviceSep = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(this._deviceSep);
this._otherDevicePosition = 2;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("What's using power..."),function() {
GLib.spawn_command_line_async('gnome-power-statistics --device wakeups');
});
this.menu.addAction(_("Power Settings"),function() {
GLib.spawn_command_line_async('gnome-control-center power');
});
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
this._devicesChanged();
},
_readPrimaryDevice: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(device, error) {
if (error) {
this._checkError(error);
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem.actor.hide();
this._deviceSep.actor.hide();
return;
}
let [device_id, device_type, summary, percentage, state, time] = device;
if (device_type == UPDeviceType.BATTERY) {
this._hasPrimary = true;
this._batteryItem.label.text = summary;
this._batteryItem.actor.show();
if (this._deviceItems.length > 0)
this._deviceSep.actor.show();
} else {
this._hasPrimary = false;
this._batteryItem.actor.hide();
this._deviceSep.actor.hide();
}
this._primaryDeviceId = device_id;
}));
},
_readOtherDevices: function() {
this._proxy.GetDevicesRemote(Lang.bind(this, function(devices, error) {
this._deviceItems.forEach(function(i) { i.destroy(); });
this._deviceItems = [];
if (error) {
this._checkError(error);
this._deviceSep.actor.hide();
return;
}
let position = 0;
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]);
item.connect('activate', function() {
let p = new Shell.Process({ args: ['gnome-power-statistics', '--device', device_id] });
p.run();
});
this._deviceItems.push(item);
this.menu.addMenuItem(item, this._otherDevicePosition + position);
position++;
}
if (this._hasPrimary && position > 0)
this._deviceSep.actor.show();
else
this._deviceSep.actor.hide();
}));
},
_devicesChanged: function() {
this._proxy.GetRemote('Icon', Lang.bind(this, function(icon, error) {
if (icon) {
let gicon = Shell.util_icon_from_string (icon);
this.setGIcon(gicon);
this.actor.show();
} else {
this._checkError(error);
this.menu.close();
this.actor.hide();
}
}));
this._proxy.GetRemote('Tooltip', Lang.bind(this, function(tooltip) {
this.setTooltip(tooltip);
}));
this._readPrimaryDevice();
this._readOtherDevices();
},
_checkError: function(error) {
if (!this._restarted && error && error.message.match(/org\.freedesktop\.DBus\.Error\.(UnknownMethod|InvalidArgs)/)) {
GLib.spawn_command_line_sync('pkill -f "^gnome-power-manager$"');
GLib.spawn_command_line_async('gnome-power-manager');
this._restarted = true;
}
}
};
function DeviceItem() {
this._init.apply(this, arguments);
}
DeviceItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(device) {
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
let [device_id, device_type, summary, percentage, state, time] = device;
this._box = new St.BoxLayout({ style_class: 'popup-device-menu-item' });
this._label = new St.Label({ text: summary });
let icon;
switch (state) {
case UPDeviceState.FULLY_CHARGED:
icon = 'battery-full-charged';
break;
case UPDeviceState.UNKNOWN:
icon = 'battery-missing';
break;
default:
icon = this._percentageToIcon(percentage) + (state == UPDeviceState.CHARGING ? '-charging' : '');
}
this._icon = new St.Icon({ icon_name: 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 percentBin = new St.Bin({ x_align: St.Align.END });
let percentLabel = new St.Label({ text: '%d%%'.format(percentage) });
percentBin.child = percentLabel;
this.addActor(percentBin);
},
_percentageToIcon: function(p) {
if (p > 60)
return 'battery-full';
if (p > 30)
return 'battery-good';
if (p > 10)
return 'battery-low';
if (p > 0)
return 'battery-caution';
return 'battery-empty';
}
}

View File

@ -61,7 +61,7 @@ fi
# libjasper, libjpeg, libpng, libpulse, libtiff, libwnck,
# libxklavier, libxml2, ORBit2, pam, python, readline,
# spidermonkey ({mozilla,firefox,xulrunner}-js), startup-notification
# xdamage, icon-naming-utils, libtool-ltdl, libvorbis
# xdamage, icon-naming-utils, upower, libtool-ltdl, libvorbis
#
# Non-devel packages needed by gnome-shell and its deps:
# glxinfo, gstreamer-plugins-base, gstreamer-plugins-good,
@ -117,7 +117,8 @@ if test "x$system" = xFedora ; then
libXdamage-devel libcroco-devel libxml2-devel gstreamer-devel
gstreamer-plugins-base gstreamer-plugins-good glx-utils expat-devel
startup-notification-devel xorg-x11-server-Xephyr gnome-terminal zenity
icon-naming-utils libtool-ltdl-devel libvorbis-devel libxklavier-devel
icon-naming-utils upower-devel libtool-ltdl-devel libvorbis-devel
libxklavier-devel
"
if expr $version \>= 14 > /dev/null ; then

View File

@ -191,6 +191,59 @@
</dependencies>
</autotools>
<autotools id="gnome-keyring">
<branch repo="git.gnome.org" module="gnome-keyring"/>
<dependencies>
<dep package="glib"/>
</dependencies>
</autotools>
<autotools id="libnotify">
<branch repo="git.gnome.org" module="libnotify"/>
<dependencies>
<dep package="gtk3"/>
</dependencies>
</autotools>
<autotools id="libgnomekbd">
<branch repo="git.gnome.org" module="libgnomekbd"/>
<dependencies>
<dep package="gtk3"/>
</dependencies>
</autotools>
<autotools id="gnome-settings-daemon">
<branch repo="git.gnome.org" module="gnome-settings-daemon"/>
<dependencies>
<dep package="libnotify"/>
<dep package="gnome-desktop-3"/>
</dependencies>
</autotools>
<autotools id="gnome-control-center">
<branch repo="git.gnome.org" module="gnome-control-center"/>
<dependencies>
<dep package="gtk3"/>
<dep package="libcanberra"/>
<dep package="gnome-desktop-3"/>
<dep package="gnome-settings-daemon"/>
</dependencies>
</autotools>
<autotools id="gnome-power-manager">
<branch repo="git.gnome.org" module="gnome-power-manager" />
<dependencies>
<dep package="gtk3"/>
<dep package="glib"/>
<dep package="gconf"/>
<dep package="cairo"/>
<dep package="libnotify"/>
<dep package="gnome-keyring"/>
<dep package="libcanberra"/>
<dep package="gnome-control-center"/>
</dependencies>
</autotools>
<autotools id="gnome-shell">
<branch repo="git.gnome.org" module="gnome-shell"/>
<dependencies>
@ -214,9 +267,7 @@
change their ~/.jhbuildrc -->
<metamodule id="gnome-shell-using-gir-repository">
<dependencies>
<dep package="librsvg"/>
<dep package="gnome-themes-standard"/>
<dep package="gnome-shell"/>
<dep package="gnome-shell-full"/>
</dependencies>
</metamodule>
@ -225,6 +276,7 @@
<dep package="librsvg"/>
<dep package="gnome-themes-standard"/>
<dep package="gnome-shell"/>
<dep package="gnome-power-manager"/>
</dependencies>
</metamodule>