cleanups
This commit is contained in:
parent
cb3a42c04e
commit
ecf3539ba2
|
@ -29,15 +29,15 @@ def _status_updated(watcher, icon, window):
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run(config):
|
||||||
GObject.threads_init()
|
GObject.threads_init()
|
||||||
|
|
||||||
ui.notify.start(APP_TITLE)
|
ui.notify.init(APP_TITLE, config.notifications)
|
||||||
|
|
||||||
watcher = WatcherThread(ui.notify.show)
|
watcher = WatcherThread(ui.notify.show)
|
||||||
watcher.start()
|
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),
|
menu_actions = [('Scan all devices', watcher.full_scan),
|
||||||
# ('Pair new device', _pair_new_device, watcher),
|
# ('Pair new device', _pair_new_device, watcher),
|
||||||
|
@ -53,4 +53,4 @@ def run():
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
|
|
||||||
watcher.stop()
|
watcher.stop()
|
||||||
ui.notify.stop()
|
ui.notify.set_active(False)
|
||||||
|
|
|
@ -2,35 +2,62 @@
|
||||||
# Optional desktop notifications.
|
# Optional desktop notifications.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import notify2 as _notify
|
import notify2 as _notify
|
||||||
|
|
||||||
|
available = True # assumed to be working since the import succeeded
|
||||||
available = True
|
_active = False # not yet active
|
||||||
|
_app_title = None
|
||||||
_notifications = {}
|
_notifications = {}
|
||||||
|
|
||||||
|
|
||||||
def start(app_title):
|
def init(app_title, active=True):
|
||||||
"""Init the notifications system."""
|
"""Init the notifications system."""
|
||||||
_notify.init(app_title)
|
global _app_title, _active
|
||||||
return True
|
_app_title = app_title
|
||||||
|
return set_active(active)
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
def set_active(active=True):
|
||||||
"""Stop the notifications system."""
|
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()):
|
for n in list(_notifications.values()):
|
||||||
try:
|
try:
|
||||||
n.close()
|
n.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
|
logging.exception("closing open notification %s", n)
|
||||||
# DBUS
|
# DBUS
|
||||||
pass
|
pass
|
||||||
_notifications.clear()
|
_notifications.clear()
|
||||||
|
try:
|
||||||
_notify.uninit()
|
_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."""
|
"""Show a notification with title and text."""
|
||||||
if not available:
|
if not available or not _active:
|
||||||
return
|
return
|
||||||
|
|
||||||
if title in _notifications:
|
if title in _notifications:
|
||||||
|
@ -45,17 +72,20 @@ try:
|
||||||
icon = icon or title
|
icon = icon or title
|
||||||
notification.update(title, text, title)
|
notification.update(title, text, title)
|
||||||
try:
|
try:
|
||||||
|
if text:
|
||||||
notification.show()
|
notification.show()
|
||||||
|
else:
|
||||||
|
notification.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
# DBUS
|
logging.exception("showing notification %s", notification)
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import logging
|
|
||||||
logging.exception("ouch")
|
logging.exception("ouch")
|
||||||
logging.warn("python-notify2 not found, desktop notifications are disabled")
|
logging.warn("python-notify2 not found, desktop notifications are disabled")
|
||||||
available = False
|
available = False
|
||||||
def start(app_title): pass
|
active = False
|
||||||
def stop(): pass
|
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
|
def show(status_code, title, text, icon=None): pass
|
||||||
|
|
|
@ -21,7 +21,10 @@ def update(window, devices):
|
||||||
first = controls[0].get_child()
|
first = controls[0].get_child()
|
||||||
icon, label = first.get_children()
|
icon, label = first.get_children()
|
||||||
rstatus = devices[0]
|
rstatus = devices[0]
|
||||||
|
if rstatus.text:
|
||||||
label.set_markup('<big><b>%s</b></big>\n%s' % (rstatus.name, 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):
|
for index in range(1, 1 + _MAX_DEVICES):
|
||||||
devstatus = devices.get(index)
|
devstatus = devices.get(index)
|
||||||
|
@ -120,7 +123,7 @@ def _device_box(title):
|
||||||
return frame
|
return frame
|
||||||
|
|
||||||
|
|
||||||
def create(title, rstatus):
|
def create(title, rstatus, show=True, close_to_tray=False):
|
||||||
vbox = Gtk.VBox(homogeneous=False, spacing=4)
|
vbox = Gtk.VBox(homogeneous=False, spacing=4)
|
||||||
vbox.set_border_width(4)
|
vbox.set_border_width(4)
|
||||||
|
|
||||||
|
@ -130,6 +133,8 @@ def create(title, rstatus):
|
||||||
vbox.set_visible(True)
|
vbox.set_visible(True)
|
||||||
|
|
||||||
window = Gtk.Window()
|
window = Gtk.Window()
|
||||||
|
window.add(vbox)
|
||||||
|
|
||||||
window.set_title(title)
|
window.set_title(title)
|
||||||
window.set_icon_name(title)
|
window.set_icon_name(title)
|
||||||
window.set_keep_above(True)
|
window.set_keep_above(True)
|
||||||
|
@ -137,15 +142,20 @@ def create(title, rstatus):
|
||||||
# window.set_skip_pager_hint(True)
|
# window.set_skip_pager_hint(True)
|
||||||
window.set_deletable(False)
|
window.set_deletable(False)
|
||||||
window.set_resizable(False)
|
window.set_resizable(False)
|
||||||
|
|
||||||
window.set_position(Gtk.WindowPosition.MOUSE)
|
window.set_position(Gtk.WindowPosition.MOUSE)
|
||||||
window.set_type_hint(Gdk.WindowTypeHint.UTILITY)
|
window.set_type_hint(Gdk.WindowTypeHint.UTILITY)
|
||||||
|
|
||||||
window.set_wmclass(title, 'status-window')
|
window.set_wmclass(title, 'status-window')
|
||||||
window.set_role('status-window')
|
window.set_role('status-window')
|
||||||
|
|
||||||
|
if close_to_tray:
|
||||||
window.connect('window-state-event', _state_event)
|
window.connect('window-state-event', _state_event)
|
||||||
window.connect('delete-event', lambda w, e: toggle(None, window) or True)
|
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()
|
window.present()
|
||||||
return window
|
return window
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,15 @@ _THREAD_SLEEP = 5 # seconds
|
||||||
|
|
||||||
_UNIFYING_RECEIVER = 'Unifying Receiver'
|
_UNIFYING_RECEIVER = 'Unifying Receiver'
|
||||||
_NO_DEVICES = 'No devices attached.'
|
_NO_DEVICES = 'No devices attached.'
|
||||||
_SCANNING = 'Initializing...'
|
_INITIALIZING = 'Initializing...'
|
||||||
|
_SCANNING = 'Scanning...'
|
||||||
_NO_RECEIVER = 'not found'
|
_NO_RECEIVER = 'not found'
|
||||||
_FOUND_RECEIVER = 'found'
|
|
||||||
|
|
||||||
|
|
||||||
class _DevStatus(api.AttachedDeviceInfo):
|
class _DevStatus(api.AttachedDeviceInfo):
|
||||||
timestamp = time.time()
|
timestamp = time.time()
|
||||||
code = devices.STATUS.UNKNOWN
|
code = devices.STATUS.UNKNOWN
|
||||||
text = ''
|
text = _INITIALIZING
|
||||||
refresh = None
|
refresh = None
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,20 +48,23 @@ class WatcherThread(threading.Thread):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.active = True
|
self.active = True
|
||||||
self._notify(0, _UNIFYING_RECEIVER, _SCANNING)
|
|
||||||
|
|
||||||
while self.active:
|
while self.active:
|
||||||
if self.listener is None:
|
if self.listener is None:
|
||||||
|
self._device_status_changed(self.rstatus, (devices.STATUS.UNKNOWN, _INITIALIZING))
|
||||||
|
self._update_status_text()
|
||||||
|
|
||||||
receiver = api.open()
|
receiver = api.open()
|
||||||
if receiver:
|
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):
|
for devinfo in api.list_devices(receiver):
|
||||||
self._new_device(devinfo)
|
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._device_status_changed(self.rstatus, (devices.STATUS.CONNECTED, _NO_DEVICES))
|
||||||
|
|
||||||
self._update_status_text()
|
self._update_status_text()
|
||||||
|
|
||||||
self.listener = EventsListener(receiver, self._events_callback)
|
self.listener = EventsListener(receiver, self._events_callback)
|
||||||
|
@ -163,20 +166,30 @@ class WatcherThread(threading.Thread):
|
||||||
devstatus.timestamp = time.time()
|
devstatus.timestamp = time.time()
|
||||||
|
|
||||||
if type(status) == int:
|
if type(status) == int:
|
||||||
devstatus.code = status
|
status_code = status
|
||||||
if devstatus.code in devices.STATUS_NAME:
|
if status_code in devices.STATUS_NAME:
|
||||||
devstatus.text = devices.STATUS_NAME[devstatus.code]
|
status_text = devices.STATUS_NAME[status_code]
|
||||||
else:
|
else:
|
||||||
devstatus.code = status[0]
|
status_code = status[0]
|
||||||
if isinstance(status[1], str):
|
if isinstance(status[1], str):
|
||||||
devstatus.text = status[1]
|
status_text = status[1]
|
||||||
elif isinstance(status[1], dict):
|
elif isinstance(status[1], dict):
|
||||||
|
status_text = ''
|
||||||
for key, value in status[1].items():
|
for key, value in status[1].items():
|
||||||
|
if key == 'text':
|
||||||
|
status_text = value
|
||||||
|
else:
|
||||||
setattr(devstatus, key, value)
|
setattr(devstatus, key, value)
|
||||||
|
else:
|
||||||
|
status_code = devices.STATUS.UNKNOWN
|
||||||
|
status_text = ''
|
||||||
|
|
||||||
if old_status_code != devstatus.code:
|
if not (status_code == 0 and old_status_code > 0):
|
||||||
logging.debug("%s: device '%s' status changed %s => %s: %s", time.asctime(), devstatus.name, old_status_code, devstatus.code, devstatus.text)
|
devstatus.code = status_code
|
||||||
if devstatus.code // 256 != old_status_code // 256:
|
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)
|
self._notify(devstatus.code, devstatus.name, devstatus.text)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -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.
|
# In case a future pure-Python implementation is feasible.
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
# pass
|
#
|
||||||
|
|
||||||
|
__author__ = "Daniel Pavel"
|
||||||
|
__license__ = "GPL"
|
||||||
|
__version__ = "0.4"
|
||||||
|
|
15
solaar.py
15
solaar.py
|
@ -6,18 +6,23 @@ __version__ = '0.4'
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import argparse
|
import argparse
|
||||||
arg_parser = argparse.ArgumentParser()
|
arg_parser = argparse.ArgumentParser(prog='Solaar')
|
||||||
arg_parser.add_argument('-v', '--verbose', action='count', default=0,
|
arg_parser.add_argument('-v', '--verbose', action='count', default=0,
|
||||||
help='increase the logger verbosity')
|
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()
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
import logging
|
||||||
log_level = logging.root.level - 10 * args.verbose
|
log_level = logging.root.level - 10 * args.verbose
|
||||||
logging.basicConfig(level=log_level if log_level > 0 else 1)
|
logging.basicConfig(level=log_level if log_level > 0 else 1)
|
||||||
|
|
||||||
import app
|
import app
|
||||||
app.run()
|
app.run(args)
|
||||||
|
|
Loading…
Reference in New Issue