This commit is contained in:
Daniel Pavel 2012-10-05 13:26:52 +03:00
parent cb3a42c04e
commit ecf3539ba2
7 changed files with 123 additions and 58 deletions

View File

@ -29,15 +29,15 @@ def _status_updated(watcher, icon, window):
# pass
def run():
def run(config):
GObject.threads_init()
ui.notify.start(APP_TITLE)
ui.notify.init(APP_TITLE, config.notifications)
watcher = WatcherThread(ui.notify.show)
watcher.start()
window = ui.window.create(APP_TITLE, watcher.devices[0])
window = ui.window.create(APP_TITLE, watcher.devices[0], not config.start_hidden, config.close_to_tray)
menu_actions = [('Scan all devices', watcher.full_scan),
# ('Pair new device', _pair_new_device, watcher),
@ -53,4 +53,4 @@ def run():
Gtk.main()
watcher.stop()
ui.notify.stop()
ui.notify.set_active(False)

View File

@ -2,35 +2,62 @@
# Optional desktop notifications.
#
import logging
try:
import notify2 as _notify
available = True
available = True # assumed to be working since the import succeeded
_active = False # not yet active
_app_title = None
_notifications = {}
def start(app_title):
def init(app_title, active=True):
"""Init the notifications system."""
_notify.init(app_title)
return True
global _app_title, _active
_app_title = app_title
return set_active(active)
def stop():
"""Stop the notifications system."""
def set_active(active=True):
global available, _active
if available:
if active:
if not _active:
try:
_notify.init(_app_title)
_active = True
except:
logging.exception("initializing desktop notifications")
available = False
else:
if _active:
for n in list(_notifications.values()):
try:
n.close()
except Exception:
logging.exception("closing open notification %s", n)
# DBUS
pass
_notifications.clear()
try:
_notify.uninit()
except:
logging.exception("stopping desktop notifications")
available = False
_active = False
return _active
def show(status_code, title, text, icon=None):
def active():
return _active
def show(status_code, title, text='', icon=None):
"""Show a notification with title and text."""
if not available:
if not available or not _active:
return
if title in _notifications:
@ -45,17 +72,20 @@ try:
icon = icon or title
notification.update(title, text, title)
try:
if text:
notification.show()
else:
notification.close()
except Exception:
# DBUS
pass
logging.exception("showing notification %s", notification)
except ImportError:
import logging
logging.exception("ouch")
logging.warn("python-notify2 not found, desktop notifications are disabled")
available = False
def start(app_title): pass
def stop(): pass
active = False
def init(app_title, active=True): return False
def active(): return False
def set_active(active=True): return False
def show(status_code, title, text, icon=None): pass

View File

@ -21,7 +21,10 @@ def update(window, devices):
first = controls[0].get_child()
icon, label = first.get_children()
rstatus = devices[0]
if rstatus.text:
label.set_markup('<big><b>%s</b></big>\n%s' % (rstatus.name, rstatus.text))
else:
label.set_markup('<big><b>%s</b></big>' % rstatus.name)
for index in range(1, 1 + _MAX_DEVICES):
devstatus = devices.get(index)
@ -120,7 +123,7 @@ def _device_box(title):
return frame
def create(title, rstatus):
def create(title, rstatus, show=True, close_to_tray=False):
vbox = Gtk.VBox(homogeneous=False, spacing=4)
vbox.set_border_width(4)
@ -130,6 +133,8 @@ def create(title, rstatus):
vbox.set_visible(True)
window = Gtk.Window()
window.add(vbox)
window.set_title(title)
window.set_icon_name(title)
window.set_keep_above(True)
@ -137,15 +142,20 @@ def create(title, rstatus):
# window.set_skip_pager_hint(True)
window.set_deletable(False)
window.set_resizable(False)
window.set_position(Gtk.WindowPosition.MOUSE)
window.set_type_hint(Gdk.WindowTypeHint.UTILITY)
window.set_wmclass(title, 'status-window')
window.set_role('status-window')
if close_to_tray:
window.connect('window-state-event', _state_event)
window.connect('delete-event', lambda w, e: toggle(None, window) or True)
else:
window.connect('delete-event', Gtk.main_quit)
window.add(vbox)
if show:
window.present()
return window

View File

@ -17,15 +17,15 @@ _THREAD_SLEEP = 5 # seconds
_UNIFYING_RECEIVER = 'Unifying Receiver'
_NO_DEVICES = 'No devices attached.'
_SCANNING = 'Initializing...'
_INITIALIZING = 'Initializing...'
_SCANNING = 'Scanning...'
_NO_RECEIVER = 'not found'
_FOUND_RECEIVER = 'found'
class _DevStatus(api.AttachedDeviceInfo):
timestamp = time.time()
code = devices.STATUS.UNKNOWN
text = ''
text = _INITIALIZING
refresh = None
@ -48,20 +48,23 @@ class WatcherThread(threading.Thread):
def run(self):
self.active = True
self._notify(0, _UNIFYING_RECEIVER, _SCANNING)
while self.active:
if self.listener is None:
self._device_status_changed(self.rstatus, (devices.STATUS.UNKNOWN, _INITIALIZING))
self._update_status_text()
receiver = api.open()
if receiver:
self._device_status_changed(self.rstatus, (devices.STATUS.CONNECTED, _FOUND_RECEIVER))
self._device_status_changed(self.rstatus, (devices.STATUS.CONNECTED, _SCANNING))
self._update_status_text()
for devinfo in api.list_devices(receiver):
self._new_device(devinfo)
if len(self.devices) == 1:
if len(self.devices) > 1:
self._device_status_changed(self.rstatus, (devices.STATUS.CONNECTED, ''))
else:
self._device_status_changed(self.rstatus, (devices.STATUS.CONNECTED, _NO_DEVICES))
self._update_status_text()
self.listener = EventsListener(receiver, self._events_callback)
@ -163,20 +166,30 @@ class WatcherThread(threading.Thread):
devstatus.timestamp = time.time()
if type(status) == int:
devstatus.code = status
if devstatus.code in devices.STATUS_NAME:
devstatus.text = devices.STATUS_NAME[devstatus.code]
status_code = status
if status_code in devices.STATUS_NAME:
status_text = devices.STATUS_NAME[status_code]
else:
devstatus.code = status[0]
status_code = status[0]
if isinstance(status[1], str):
devstatus.text = status[1]
status_text = status[1]
elif isinstance(status[1], dict):
status_text = ''
for key, value in status[1].items():
if key == 'text':
status_text = value
else:
setattr(devstatus, key, value)
else:
status_code = devices.STATUS.UNKNOWN
status_text = ''
if old_status_code != devstatus.code:
logging.debug("%s: device '%s' status changed %s => %s: %s", time.asctime(), devstatus.name, old_status_code, devstatus.code, devstatus.text)
if devstatus.code // 256 != old_status_code // 256:
if not (status_code == 0 and old_status_code > 0):
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 != status_code:
self._notify(devstatus.code, devstatus.name, devstatus.text)
return True

View File

@ -1,5 +1,8 @@
"""Generic Human Interface Device API.
"""
"""Generic Human Interface Device API."""
__author__ = "Daniel Pavel"
__license__ = "GPL"
__version__ = "0.3"
#
# In case a future pure-Python implementation is feasible.

View File

@ -1 +1,5 @@
# pass
#
__author__ = "Daniel Pavel"
__license__ = "GPL"
__version__ = "0.4"

View File

@ -6,18 +6,23 @@ __version__ = '0.4'
#
#
import logging
if __name__ == '__main__':
import argparse
arg_parser = argparse.ArgumentParser()
arg_parser = argparse.ArgumentParser(prog='Solaar')
arg_parser.add_argument('-v', '--verbose', action='count', default=0,
help='increase the logger verbosity')
arg_parser.add_argument('-N', '--disable-notifications', action='store_false', dest='notifications',
help='disable desktop notifications')
arg_parser.add_argument('-H', '--start-hidden', action='store_true', dest='start_hidden',
help='hide the application window on start')
arg_parser.add_argument('-t', '--close-to-tray', action='store_true',
help='closing the application window hides it')
arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__)
args = arg_parser.parse_args()
import logging
log_level = logging.root.level - 10 * args.verbose
logging.basicConfig(level=log_level if log_level > 0 else 1)
import app
app.run()
app.run(args)