small updates to the app

This commit is contained in:
Daniel Pavel 2012-10-09 15:13:31 +03:00
parent 9b2c1bdef6
commit 9111afcd6b
6 changed files with 74 additions and 53 deletions

View File

@ -4,6 +4,7 @@
from gi.repository import Gtk
from logitech.devices import constants as C
_ICON_OK = 'Solaar'
_ICON_FAIL = _ICON_OK + '-fail'
@ -36,9 +37,9 @@ def create(title, click_action=None):
return icon
def update(icon, rstatus, tooltip):
def update(icon, receiver, tooltip):
icon.set_tooltip_markup(tooltip)
if rstatus.code < 0:
if receiver.code < C.STATUS.CONNECTED:
icon.set_from_icon_name(_ICON_FAIL)
else:
icon.set_from_icon_name(_ICON_OK)

View File

@ -5,6 +5,8 @@
from gi.repository import Gtk
from gi.repository import Gdk
from logitech.devices import constants as C
_DEVICE_ICON_SIZE = Gtk.IconSize.DIALOG
_STATUS_ICON_SIZE = Gtk.IconSize.DIALOG
@ -16,7 +18,7 @@ def _update_receiver_box(box, receiver):
icon, vbox = box.get_children()
label, buttons_box = vbox.get_children()
label.set_text(receiver.text or '')
buttons_box.set_visible(receiver.code >= 0)
buttons_box.set_visible(receiver.code >= C.STATUS.CONNECTED)
def _update_device_box(frame, devstatus):
@ -30,7 +32,7 @@ def _update_device_box(frame, devstatus):
icon.set_name(devstatus.name)
icon.set_from_icon_name(devstatus.name, _DEVICE_ICON_SIZE)
if devstatus.code < 0:
if devstatus.code < C.STATUS.CONNECTED:
expander.set_sensitive(False)
expander.set_expanded(False)
expander.set_label('<big><b>%s</b></big>\n%s' % (devstatus.name, devstatus.text))
@ -41,7 +43,7 @@ def _update_device_box(frame, devstatus):
texts = []
light_icon = ebox.get_children()[-2]
light_level = getattr(devstatus, 'light_level', None)
light_level = getattr(devstatus, C.PROPS.LIGHT_LEVEL, None)
light_icon.set_visible(light_level is not None)
if light_level is not None:
texts.append('Light: %d lux' % light_level)
@ -50,7 +52,7 @@ def _update_device_box(frame, devstatus):
light_icon.set_tooltip_text(texts[-1])
battery_icon = ebox.get_children()[-1]
battery_level = getattr(devstatus, 'battery_level', None)
battery_level = getattr(devstatus, C.PROPS.BATTERY_LEVEL, None)
battery_icon.set_sensitive(battery_level is not None)
if battery_level is None:
battery_icon.set_from_icon_name('battery_unknown', _STATUS_ICON_SIZE)
@ -61,7 +63,7 @@ def _update_device_box(frame, devstatus):
battery_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE)
battery_icon.set_tooltip_text(texts[-1])
battery_status = getattr(devstatus, 'battery_status', None)
battery_status = getattr(devstatus, C.PROPS.BATTERY_STATUS, None)
if battery_status is not None:
texts.append(battery_status)
battery_icon.set_tooltip_text(battery_icon.get_tooltip_text() + '\n' + battery_status)
@ -163,16 +165,7 @@ def _device_box():
def create(title, rstatus, show=True, close_to_tray=False):
vbox = Gtk.VBox(homogeneous=False, spacing=4)
vbox.set_border_width(4)
vbox.add(_receiver_box(rstatus))
for i in range(1, 1 + _MAX_DEVICES):
vbox.add(_device_box())
vbox.set_visible(True)
window = Gtk.Window()
window.add(vbox)
Gtk.Window.set_default_icon_name('mouse')
window.set_icon_name(title)
@ -181,6 +174,8 @@ def create(title, rstatus, show=True, close_to_tray=False):
window.set_keep_above(True)
window.set_deletable(False)
window.set_resizable(False)
window.set_size_request(200, 50)
window.set_default_size(200, 50)
window.set_position(Gtk.WindowPosition.MOUSE)
window.set_type_hint(Gdk.WindowTypeHint.UTILITY)
@ -190,6 +185,15 @@ def create(title, rstatus, show=True, close_to_tray=False):
# window.set_wmclass(title, 'status-window')
# window.set_role('status-window')
vbox = Gtk.VBox(homogeneous=False, spacing=4)
vbox.set_border_width(4)
vbox.add(_receiver_box(rstatus))
for i in range(1, 1 + _MAX_DEVICES):
vbox.add(_device_box())
vbox.set_visible(True)
window.add(vbox)
if close_to_tray:
def _state_event(window, event):
if event.new_window_state & Gdk.WindowState.ICONIFIED:

View File

@ -10,23 +10,23 @@ from binascii import hexlify as _hexlify
from logitech.unifying_receiver import api
from logitech.unifying_receiver.listener import EventsListener
from logitech import devices
from logitech.devices import constants as C
_STATUS_TIMEOUT = 31 # seconds
_THREAD_SLEEP = 2 # seconds
_UNIFYING_RECEIVER = 'Unifying Receiver'
_NO_RECEIVER = 'Receiver not found.'
_INITIALIZING = 'Initializing...'
_SCANNING = 'Scanning...'
_NO_DEVICES = 'No devices found.'
_OKAY = 'Status okay.'
_OKAY = 'Status ok.'
class _DevStatus(api.AttachedDeviceInfo):
timestamp = time.time()
code = devices.STATUS.UNKNOWN
code = C.STATUS.UNKNOWN
text = _INITIALIZING
refresh = None
@ -55,28 +55,30 @@ class WatcherThread(threading.Thread):
while self.active:
if self.listener is None:
self._device_status_changed(self.rstatus, (devices.STATUS.UNKNOWN, _INITIALIZING))
self._device_status_changed(self.rstatus, (C.STATUS.UNKNOWN, _INITIALIZING))
self._update_status_text()
receiver = api.open()
if receiver:
self._device_status_changed(self.rstatus, (-10, _SCANNING))
self._device_status_changed(self.rstatus, (C.STATUS.BOOTING, _SCANNING))
self._update_status_text()
for devinfo in api.list_devices(receiver):
self._new_device(devinfo)
logging.debug("initial scan finished: %s", self.devices)
if self.devices:
self._device_status_changed(self.rstatus, (devices.STATUS.CONNECTED, _OKAY))
self._device_status_changed(self.rstatus, (C.STATUS.CONNECTED, _OKAY))
else:
self._device_status_changed(self.rstatus, (devices.STATUS.CONNECTED, _NO_DEVICES))
self._device_status_changed(self.rstatus, (C.STATUS.CONNECTED, _NO_DEVICES))
self._update_status_text()
self.listener = EventsListener(receiver, self._events_callback)
self.listener.start()
else:
self._device_status_changed(self.rstatus, (devices.STATUS.UNAVAILABLE, _NO_RECEIVER))
self._device_status_changed(self.rstatus, (C.STATUS.UNAVAILABLE, _NO_RECEIVER))
elif not self.listener.active:
self.listener = None
self._device_status_changed(self.rstatus, (devices.STATUS.UNAVAILABLE, _NO_RECEIVER))
self._device_status_changed(self.rstatus, (C.STATUS.UNAVAILABLE, _NO_RECEIVER))
self.devices.clear()
if self.active:
@ -134,15 +136,14 @@ class WatcherThread(threading.Thread):
if not self.active:
return None
logging.debug("new devstatus from %s", dev)
if type(dev) == int:
dev = self.listener.request(api.get_device_info, dev)
logging.debug("new devstatus from %s", dev)
if dev:
devstatus = _DevStatus(*dev)
devstatus.refresh = self._request_status
self.devices[dev.number] = devstatus
self._device_status_changed(devstatus, devices.STATUS.CONNECTED)
self._device_status_changed(devstatus, C.STATUS.CONNECTED)
logging.debug("new devstatus %s", devstatus)
return devstatus
def _events_callback(self, code, devnumber, data):
@ -154,7 +155,7 @@ class WatcherThread(threading.Thread):
devstatus = self.devices[devnumber]
if code == 0x10 and data[:1] == b'\x8F':
updated = True
self._device_status_changed(devstatus, devices.STATUS.UNAVAILABLE)
self._device_status_changed(devstatus, C.STATUS.UNAVAILABLE)
elif code == 0x11:
status = devices.process_event(devstatus, self.listener, data)
updated |= self._device_status_changed(devstatus, status)
@ -178,8 +179,8 @@ class WatcherThread(threading.Thread):
if type(status) == int:
status_code = status
if status_code in devices.STATUS_NAME:
status_text = devices.STATUS_NAME[status_code]
if status_code in C.STATUS_NAME:
status_text = C.STATUS_NAME[status_code]
else:
status_code = status[0]
if isinstance(status[1], str):
@ -192,15 +193,16 @@ class WatcherThread(threading.Thread):
else:
setattr(devstatus, key, value)
else:
status_code = devices.STATUS.UNKNOWN
status_code = C.STATUS.UNKNOWN
status_text = ''
if not (status_code == 0 and old_status_code > 0):
if not (status_code == C.STATUS.CONNECTED and old_status_code > C.STATUS.CONNECTED):
# if this is not just a ping for a device with an already known status
devstatus.code = status_code
devstatus.text = status_text
logging.debug("%s: device '%s' status update %s => %s: %s", time.asctime(), devstatus.name, old_status_code, status_code, status_text)
if status_code <= 0 or old_status_code <= 0 or status_code < old_status_code:
if status_code < C.STATUS.CONNECTED or old_status_code < C.STATUS.CONNECTED or status_code < old_status_code:
self._notify(devstatus.code, devstatus.name, devstatus.text)
return True
@ -214,7 +216,7 @@ class WatcherThread(threading.Thread):
if self.devices:
lines = []
if self.rstatus.code < 0:
if self.rstatus.code < C.STATUS.CONNECTED:
lines += (self.rstatus.text, '')
devstatuses = [self.devices[d] for d in range(1, 1 + api.C.MAX_ATTACHED_DEVICES) if d in self.devices]
@ -224,7 +226,7 @@ class WatcherThread(threading.Thread):
lines.append('<b>' + devstatus.name + '</b>')
lines.append(' ' + devstatus.text)
else:
lines.append('<b>' + devstatus.name + '</b>: ' + devstatus.text)
lines.append('<b>' + devstatus.name + '</b> ' + devstatus.text)
else:
lines.append('<b>' + devstatus.name + '</b>')
lines.append('')

View File

@ -2,16 +2,17 @@
#
#
import logging
from . import k750
from .constants import *
from . import constants as C
from ..unifying_receiver import api as _api
from ..unifying_receiver.common import FallbackDict as _FDict
def ping(devinfo, listener):
reply = listener.request(_api.ping, devinfo.number)
return STATUS.CONNECTED if reply else STATUS.UNAVAILABLE
return C.STATUS.CONNECTED if reply else C.STATUS.UNAVAILABLE
def default_request_status(devinfo, listener):
@ -19,43 +20,54 @@ def default_request_status(devinfo, listener):
reply = listener.request(_api.get_device_battery_level, devinfo.number, features_array=devinfo.features)
if reply:
discharge, dischargeNext, status = reply
return STATUS.CONNECTED, {PROPS.BATTERY_LEVEL: discharge}
return C.STATUS.CONNECTED, {C.PROPS.BATTERY_LEVEL: discharge}
def default_process_event(devinfo, listener, data):
feature_index = ord(data[0:1])
feature = devinfo.features[feature_index]
feature_function = ord(data[1:2]) & 0xF0
if feature == _api.C.FEATURE.BATTERY:
if ord(data[1:2]) & 0xF0 == 0:
if feature_function == 0:
discharge = ord(data[2:3])
status = _api.C.BATTERY_STATUS[ord(data[3:4])]
return STATUS.CONNECTED, {BATTERY_LEVEL: discharge, BATTERY_STATUS: status}
return C.STATUS.CONNECTED, {C.PROPS.BATTERY_LEVEL: discharge, C.PROPS.BATTERY_STATUS: status}
# ?
elif feature == _api.C.FEATURE.REPROGRAMMABLE_KEYS:
if ord(data[1:2]) & 0xF0 == 0:
print 'reprogrammable key', repr(data)
if feature_function == 0:
logging.debug('reprogrammable key: %s', repr(data))
# TODO
pass
# ?
elif feature == _api.C.FEATURE.WIRELESS:
if ord(data[1:2]) & 0xF0 == 0:
if feature_function == 0:
logging.debug("wireless status: %s", repr(data))
# TODO
pass
# ?
_REQUEST_STATUS_FUNCTIONS = _FDict()
_REQUEST_STATUS_FUNCTIONS[k750.NAME] = k750.request_status
_REQUEST_STATUS_FUNCTIONS = {
k750.NAME: k750.request_status
}
def request_status(devinfo, listener):
if listener:
return _REQUEST_STATUS_FUNCTIONS[devinfo.name](devinfo, listener) or default_request_status(devinfo, listener) or ping(devinfo, listener)
if devinfo.name in _REQUEST_STATUS_FUNCTIONS:
return _REQUEST_STATUS_FUNCTIONS[devinfo.name](devinfo, listener)
return default_request_status(devinfo, listener) or ping(devinfo, listener)
_PROCESS_EVENT_FUNCTIONS = _FDict()
_PROCESS_EVENT_FUNCTIONS[k750.NAME] = k750.process_event
_PROCESS_EVENT_FUNCTIONS = {
k750.NAME: k750.process_event
}
def process_event(devinfo, listener, data):
if listener:
return default_process_event(devinfo, listener, data) or _PROCESS_EVENT_FUNCTIONS[devinfo.name](devinfo, listener, data)
default_result = default_process_event(devinfo, listener, data)
if default_result is not None:
return default_result
if devinfo.name in _PROCESS_EVENT_FUNCTIONS:
return _PROCESS_EVENT_FUNCTIONS[devinfo.name](devinfo, listener, data)

View File

@ -6,11 +6,13 @@ STATUS = type('STATUS', (),
dict(
UNKNOWN=-9999,
UNAVAILABLE=-1,
CONNECTED=0,
BOOTING=0,
CONNECTED=1,
))
STATUS_NAME = {
STATUS.UNAVAILABLE: 'inactive',
STATUS.BOOTING: 'initializing',
STATUS.CONNECTED: 'connected',
}

View File

@ -189,7 +189,7 @@ def read(handle, timeout=DEFAULT_TIMEOUT):
devnumber = ord(data[1:2])
return code, devnumber, data[2:]
_l.log(_LOG_LEVEL, "(%d,*) => r[]", handle)
# _l.log(_LOG_LEVEL, "(%d,*) => r[]", handle)
def request(handle, devnumber, feature_index_function, params=b'', features_array=None):