better battery icon in the systray

This commit is contained in:
Daniel Pavel 2012-11-29 20:13:25 +02:00
parent d6b18cd426
commit 932a015e49
9 changed files with 63 additions and 30 deletions

View File

@ -77,29 +77,39 @@ class ReceiverListener(_lur.listener.EventsListener):
self.receiver.close() self.receiver.close()
self.receiver = None self.receiver = None
self._status_changed(DUMMY, _lur.status.ALERT.LOW) self._status_changed(None, alert=_lur.status.ALERT.LOW)
def tick(self, timestamp): def tick(self, timestamp):
if _log.isEnabledFor(_DEBUG): if _log.isEnabledFor(_DEBUG):
_log.debug("tick: polling status") _log.debug("tick: polling status")
# read these in case they haven't been read already
self.receiver.serial, self.receiver.firmware
if self.receiver.status.lock_open:
# don't mess with stuff while pairing
return
for dev in self.receiver: for dev in self.receiver:
if dev.status: if dev.status:
dev.serial, dev.firmware # read these in case they haven't been read already
dev.wpid, dev.serial, dev.protocol, dev.firmware
if dev.status.get(_lur.status.BATTERY_LEVEL) is None: if dev.status.get(_lur.status.BATTERY_LEVEL) is None:
battery = _lur.hidpp20.get_battery(dev) or _lur.hidpp10.get_battery(dev) battery = _lur.hidpp20.get_battery(dev) or _lur.hidpp10.get_battery(dev)
if battery: if battery:
dev.status[_lur.status.BATTERY_LEVEL], dev.status[_lur.status.BATTERY_STATUS] = battery dev.status[_lur.status.BATTERY_LEVEL], dev.status[_lur.status.BATTERY_STATUS] = battery
self._status_changed(dev) self._status_changed(dev)
elif len(dev.status) > 0 and timestamp - dev.status.updated > _DEVICE_TIMEOUT: elif len(dev.status) > 0 and timestamp - dev.status.updated > _DEVICE_TIMEOUT:
dev.status.clear() dev.status.clear()
self._status_changed(dev, _lur.status.ALERT.LOW) self._status_changed(dev, _lur.status.ALERT.LOW)
def _status_changed(self, device, alert=_lur.status.ALERT.NONE, reason=None): def _status_changed(self, device, alert=_lur.status.ALERT.NONE, reason=None):
assert device is not None
if _log.isEnabledFor(_DEBUG): if _log.isEnabledFor(_DEBUG):
_log.debug("status_changed %s: %s (%X) %s", device, device.status, alert, reason or '') _log.debug("status_changed %s: %s (%X) %s", device, None if device is None else device.status, alert, reason or '')
if self.status_changed_callback: if self.status_changed_callback:
if device is self.receiver: if device is None or device is self.receiver:
self.status_changed_callback(self.receiver or DUMMY, None, alert, reason) self.status_changed_callback(self.receiver or DUMMY, None, alert, reason)
else: else:
self.status_changed_callback(self.receiver or DUMMY, device, alert, reason) self.status_changed_callback(self.receiver or DUMMY, device, alert, reason)
@ -133,6 +143,7 @@ class ReceiverListener(_lur.listener.EventsListener):
receiver = _lur.Receiver.open() receiver = _lur.Receiver.open()
if receiver: if receiver:
receiver.handle = _lur.listener.ThreadedHandle(receiver.handle, receiver.path) receiver.handle = _lur.listener.ThreadedHandle(receiver.handle, receiver.path)
receiver.kind = 'applications-system'
rl = ReceiverListener(receiver, status_changed_callback) rl = ReceiverListener(receiver, status_changed_callback)
rl.start() rl.start()
return rl return rl

View File

@ -9,15 +9,17 @@ GObject.threads_init()
from solaar import NAME from solaar import NAME
_APP_ICONS = (NAME + '-init', NAME + '-fail', NAME) _APP_ICONS = (NAME + '-init', NAME + '-fail', NAME)
def appicon(receiver_status): def appicon(receiver_status):
return (_APP_ICONS[1] if type(receiver_status) == str else return (_APP_ICONS[1] if type(receiver_status) == str
_APP_ICONS[2] if receiver_status else else _APP_ICONS[2] if receiver_status
_APP_ICONS[0]) else _APP_ICONS[0])
_ICON_THEME = Gtk.IconTheme.get_default()
def get_icon(name, fallback): def get_icon(name, *fallback):
return name if name and _ICON_THEME.has_icon(name) else fallback theme = Gtk.IconTheme.get_default()
return (str(name) if name and theme.has_icon(str(name))
else get_icon(*fallback) if fallback
else None)
def get_battery_icon(level): def get_battery_icon(level):
if level < 0: if level < 0:
@ -25,9 +27,9 @@ def get_battery_icon(level):
return 'battery_%03d' % (10 * ((level + 5) // 10)) return 'battery_%03d' % (10 * ((level + 5) // 10))
def icon_file(name): def icon_file(name):
if name and _ICON_THEME.has_icon(name): theme = Gtk.IconTheme.get_default()
return _ICON_THEME.lookup_icon(name, 0, 0).get_filename() return (theme.lookup_icon(str(name), 0, 0).get_filename() if name and theme.has_icon(str(name))
return None else None)
def error(window, title, text): def error(window, title, text):

View File

@ -89,7 +89,7 @@ def _make_device_box(index):
label.set_alignment(0, 0.5) label.set_alignment(0, 0.5)
label.set_padding(4, 4) label.set_padding(4, 4)
battery_icon = Gtk.Image.new_from_icon_name('battery_unknown', _STATUS_ICON_SIZE) battery_icon = Gtk.Image.new_from_icon_name(ui.get_battery_icon(-1), _STATUS_ICON_SIZE)
battery_label = Gtk.Label() battery_label = Gtk.Label()
battery_label.set_width_chars(6) battery_label.set_width_chars(6)
@ -186,6 +186,7 @@ def create(title, name, max_devices, systray=False):
vbox.set_visible(True) vbox.set_visible(True)
window.add(vbox) window.add(vbox)
window._vbox = vbox
geometry = Gdk.Geometry() geometry = Gdk.Geometry()
geometry.min_width = 320 geometry.min_width = 320
@ -198,6 +199,10 @@ def create(title, name, max_devices, systray=False):
if systray: if systray:
window.set_keep_above(True) window.set_keep_above(True)
# window.set_decorated(False)
# window.set_type_hint(Gdk.WindowTypeHint.TOOLTIP)
# window.set_skip_taskbar_hint(True)
# window.set_skip_pager_hint(True)
window.connect('delete-event', toggle) window.connect('delete-event', toggle)
else: else:
window.connect('delete-event', Gtk.main_quit) window.connect('delete-event', Gtk.main_quit)
@ -248,14 +253,14 @@ def _update_device_info_label(label, dev):
if firmware: if firmware:
items += [(f.kind, f.name + ' ' + f.version) for f in firmware] items += [(f.kind, f.name + ' ' + f.version) for f in firmware]
label.set_markup('<small><tt>%s</tt></small>' % '\n'.join('%-12s: %s' % (item[0], str(item[1])) for item in items)) label.set_markup('<small><tt>' + '\n'.join('%-12s: %s' % item for item in items) + '</tt></small>')
def _update_receiver_info_label(label, dev): def _update_receiver_info_label(label, dev):
if label.get_visible() and '\n' not in label.get_text(): if label.get_visible() and '\n' not in label.get_text():
items = [('Serial', dev.serial)] + \ items = [('Serial', dev.serial)] + \
[(f.kind, f.version) for f in dev.firmware] [(f.kind, f.version) for f in dev.firmware]
label.set_markup('<small><tt>%s</tt></small>' % '\n'.join('%-10s: %s' % (item[0], str(item[1])) for item in items)) label.set_markup('<small><tt>' + '\n'.join('%-10s: %s' % item for item in items) + '</tt></small>')
def _toggle_info_box(action, label_widget, box_widget, frame, update_function): def _toggle_info_box(action, label_widget, box_widget, frame, update_function):
@ -319,7 +324,7 @@ def _update_device_box(frame, dev):
if battery_level is None: if battery_level is None:
battery_icon.set_sensitive(False) battery_icon.set_sensitive(False)
battery_icon.set_from_icon_name('battery_unknown', _STATUS_ICON_SIZE) battery_icon.set_from_icon_name(ui.get_battery_icon(-1), _STATUS_ICON_SIZE)
text = 'no status' if dev.protocol < 2.0 else 'waiting for status...' text = 'no status' if dev.protocol < 2.0 else 'waiting for status...'
battery_label.set_markup('<small>%s</small>' % text) battery_label.set_markup('<small>%s</small>' % text)
battery_label.set_sensitive(True) battery_label.set_sensitive(True)
@ -355,8 +360,9 @@ def update(window, receiver, device=None):
assert receiver is not None assert receiver is not None
window.set_icon_name(ui.appicon(receiver.status)) window.set_icon_name(ui.appicon(receiver.status))
vbox = window.get_child() vbox = window._vbox
frames = list(vbox.get_children()) frames = list(vbox.get_children())
assert len(frames) == 1 + receiver.max_devices, frames
if device is None: if device is None:
_update_receiver_box(frames[0], receiver) _update_receiver_box(frames[0], receiver)

View File

@ -58,7 +58,7 @@ try:
message = reason or ('unpaired' if dev.status is None else message = reason or ('unpaired' if dev.status is None else
(str(dev.status) or ('connected' if dev.status else 'inactive'))) (str(dev.status) or ('connected' if dev.status else 'inactive')))
n.update(summary, message, _icon(summary) or dev.kind) n.update(summary, message, _icon(summary) or str(dev.kind))
urgency = Notify.Urgency.LOW if dev.status else Notify.Urgency.NORMAL urgency = Notify.Urgency.LOW if dev.status else Notify.Urgency.NORMAL
n.set_urgency(urgency) n.set_urgency(urgency)

View File

@ -2,18 +2,20 @@
# #
# #
from gi.repository import Gtk from gi.repository import Gtk, GdkPixbuf
import ui import ui
from logitech.unifying_receiver import status as _status from logitech.unifying_receiver import status as _status
def create(window, menu_actions=None): def create(window, menu_actions=None):
name = window.get_title()
icon = Gtk.StatusIcon() icon = Gtk.StatusIcon()
icon.set_title(window.get_title()) icon.set_title(name)
icon.set_name(window.get_title()) icon.set_name(name)
icon.set_from_icon_name(ui.appicon(0)) icon.set_from_icon_name(ui.appicon(False))
icon.set_tooltip_text(name)
icon.connect('activate', window.toggle_visible) icon.connect('activate', window.toggle_visible)
menu = Gtk.Menu() menu = Gtk.Menu()
@ -66,4 +68,15 @@ def update(icon, receiver, device=None):
if battery_level is None: if battery_level is None:
icon.set_from_icon_name(ui.appicon(receiver.status)) icon.set_from_icon_name(ui.appicon(receiver.status))
else: else:
icon.set_from_icon_name(ui.get_battery_icon(battery_level)) appicon = ui.icon_file(ui.appicon(True) + '-mask')
assert appicon
pbuf = GdkPixbuf.Pixbuf.new_from_file(appicon)
assert pbuf.get_width() == 128 and pbuf.get_height() == 128
baticon = ui.icon_file(ui.get_battery_icon(battery_level))
assert baticon
pbuf2 = GdkPixbuf.Pixbuf.new_from_file(baticon)
assert pbuf2.get_width() == 128 and pbuf2.get_height() == 128
pbuf2.composite(pbuf, 0, 7, 80, 121, -32, 7, 1, 1, GdkPixbuf.InterpType.NEAREST, 255)
icon.set_from_pixbuf(pbuf)

View File

@ -109,7 +109,7 @@ def close(handle):
# _log.info("closed receiver handle %s", repr(handle)) # _log.info("closed receiver handle %s", repr(handle))
return True return True
except: except:
_log.exception("closing receiver handle %s", repr(handle)) # _log.exception("closing receiver handle %s", repr(handle))
pass pass
return False return False

View File

@ -129,7 +129,8 @@ class EventsListener(_threading.Thread):
event = self._queued_events.get() event = self._queued_events.get()
if event: if event:
_log.debug("processing event %s", event) # if _log.isEnabledFor(_DEBUG):
# _log.debug("processing event %s", event)
try: try:
self._events_callback(event) self._events_callback(event)
except: except:
@ -164,7 +165,7 @@ class EventsListener(_threading.Thread):
def _events_hook(self, event): def _events_hook(self, event):
# only consider unhandled events that were sent from this thread, # only consider unhandled events that were sent from this thread,
# i.e. triggered during a callback of a previous event # i.e. triggered during a callback of a previous event
if _threading.current_thread() == self: if self._active and _threading.current_thread() == self:
_log.info("queueing unhandled event %s", event) _log.info("queueing unhandled event %s", event)
self._queued_events.put(event) self._queued_events.put(event)

View File

@ -107,8 +107,8 @@ class DeviceStatus(dict):
if self.updated == 0: if self.updated == 0:
alert |= ALERT.LOW alert |= ALERT.LOW
self.updated = _timestamp() self.updated = _timestamp()
if _log.isEnabledFor(_DEBUG): # if _log.isEnabledFor(_DEBUG):
_log.debug("device %d changed: active=%s %s", self._device.number, self._active, dict(self)) # _log.debug("device %d changed: active=%s %s", self._device.number, self._active, dict(self))
self._changed_callback(self._device, alert, reason) self._changed_callback(self._device, alert, reason)
# @property # @property

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B