diff --git a/app/solaar.py b/app/solaar.py
index cb2e51e5..8966d82c 100644
--- a/app/solaar.py
+++ b/app/solaar.py
@@ -61,6 +61,8 @@ if __name__ == '__main__':
if args.systray:
tray_icon = ui.icon.create(APP_TITLE, (ui.window.toggle, window))
tray_icon.set_from_icon_name(APP_TITLE + '-fail')
+ else:
+ window.present()
Gtk.main()
diff --git a/app/ui/window.py b/app/ui/window.py
index 505ab2ad..a788e5f0 100644
--- a/app/ui/window.py
+++ b/app/ui/window.py
@@ -7,8 +7,8 @@ from gi.repository import (Gtk, Gdk)
from logitech.devices import constants as C
-_DEVICE_ICON_SIZE = Gtk.IconSize.DND
-_STATUS_ICON_SIZE = Gtk.IconSize.DIALOG
+_DEVICE_ICON_SIZE = Gtk.IconSize.DIALOG
+_STATUS_ICON_SIZE = Gtk.IconSize.DND
_PLACEHOLDER = '~'
@@ -36,10 +36,10 @@ def _find_children(container, *child_names):
return result if count > 1 else result[0]
-def _update_receiver_box(box, receiver):
- label, buttons_box = _find_children(box, 'receiver-status', 'receiver-buttons')
- label.set_text(receiver.text or '')
- buttons_box.set_visible(receiver.code >= C.STATUS.CONNECTED)
+def _update_receiver_box(box, rstatus):
+ label, buttons_box = _find_children(box, 'label', 'buttons')
+ label.set_text(rstatus.text or '')
+ buttons_box.set_visible(rstatus.code >= C.STATUS.CONNECTED)
def _update_device_box(frame, devstatus):
@@ -48,147 +48,133 @@ def _update_device_box(frame, devstatus):
frame.set_name(_PLACEHOLDER)
return
+ icon, label = _find_children(frame, 'icon', 'label')
+
frame.set_visible(True)
if frame.get_name() != devstatus.name:
frame.set_name(devstatus.name)
- icon = _find_children(frame, 'device-icon')
icon.set_from_icon_name(devstatus.name, _DEVICE_ICON_SIZE)
icon.set_tooltip_text(devstatus.name)
+ label.set_markup('' + devstatus.name + '')
- expander = _find_children(frame, 'device-expander')
+ status = _find_children(frame, 'status')
if devstatus.code < C.STATUS.CONNECTED:
- expander.set_sensitive(False)
- expander.set_expanded(False)
- expander.set_label('%s\n%s' % (devstatus.name, devstatus.text))
+ icon.set_sensitive(False)
+ label.set_sensitive(False)
+ status.set_visible(False)
return
- expander.set_sensitive(True)
- status_icons = expander.get_child().get_children()
+ icon.set_sensitive(True)
+ label.set_sensitive(True)
+ status.set_visible(True)
+ status_icons = status.get_children()
- texts = []
-
- light_icon = status_icons[-2]
- light_level = getattr(devstatus, C.PROPS.LIGHT_LEVEL, None)
- if light_level is None:
- light_icon.set_visible(False)
- else:
- light_icon.set_visible(True)
- icon_name = 'light_%02d' % (20 * ((light_level + 50) // 100))
- light_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE)
- tooltip = 'Light: %d lux' % light_level
- light_icon.set_tooltip_text(tooltip)
- texts.append(tooltip)
-
- battery_icon = status_icons[-1]
+ battery_icon, battery_label = status_icons[0:2]
battery_level = getattr(devstatus, C.PROPS.BATTERY_LEVEL, None)
if battery_level is None:
battery_icon.set_sensitive(False)
battery_icon.set_from_icon_name('battery_unknown', _STATUS_ICON_SIZE)
- battery_icon.set_tooltip_text('Battery: unknown')
+ battery_label.set_sensitive(False)
+ battery_label.set_text('')
else:
battery_icon.set_sensitive(True)
icon_name = 'battery_%02d' % (20 * ((battery_level + 10) // 20))
battery_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE)
- tooltip = 'Battery: %d%%' % battery_level
- battery_icon.set_tooltip_text(tooltip)
- texts.append(tooltip)
+ battery_label.set_sensitive(True)
+ battery_label.set_text('%d%%' % battery_level)
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)
-
- if texts:
- expander.set_label('%s\n%s' % (devstatus.name, ', '.join(texts)))
+ if battery_status is None:
+ battery_icon.set_tooltip_text('')
else:
- expander.set_label('%s\n%s' % (devstatus.name, devstatus.text))
+ battery_icon.set_tooltip_text(battery_status)
+
+ light_icon, light_label = status_icons[2:4]
+ light_level = getattr(devstatus, C.PROPS.LIGHT_LEVEL, None)
+ if light_level is None:
+ light_icon.set_visible(False)
+ light_label.set_visible(False)
+ else:
+ light_icon.set_visible(True)
+ icon_name = 'light_%02d' % (20 * ((light_level + 50) // 100))
+ light_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE)
+ light_label.set_visible(True)
+ light_label.set_text('%d lux' % light_level)
-def update(window, receiver, devices, icon_name=None):
+def update(window, rstatus, devices, icon_name=None):
if window and window.get_child():
if icon_name is not None:
window.set_icon_name(icon_name)
vbox = window.get_child().get_child()
controls = list(vbox.get_children())
- _update_receiver_box(controls[0], receiver)
+ _update_receiver_box(controls[0], rstatus)
for index in range(1, len(controls)):
_update_device_box(controls[index], devices.get(index))
-def _receiver_box(rstatus):
- box = Gtk.HBox(homogeneous=False, spacing=8)
- box.set_border_width(4)
-
- icon = Gtk.Image.new_from_icon_name(rstatus.name, _DEVICE_ICON_SIZE)
- icon.set_alignment(0.5, 0)
- icon.set_tooltip_text(rstatus.name)
- box.pack_start(icon, False, False, 0)
-
- label = Gtk.Label('Initializing...')
- label.set_alignment(0, 0.5)
- label.set_name('receiver-status')
- box.pack_start(label, True, True, 0)
-
- toolbar = Gtk.Toolbar()
- toolbar.set_style(Gtk.ToolbarStyle.ICONS)
- toolbar.set_name('receiver-buttons')
- toolbar.set_show_arrow(False)
- toolbar.set_icon_size(Gtk.IconSize.BUTTON)
- box.pack_end(toolbar, False, False, 0)
-
- def _action(button, function, params):
- button.set_sensitive(False)
- function(button, *params)
- button.set_sensitive(True)
-
- def _add_button(name, icon, action):
- button = Gtk.ToolButton()
- button.set_icon_name(icon)
- button.set_tooltip_text(name)
- if action:
- function = action[0]
- params = action[1:]
- button.connect('clicked', _action, function, params)
- else:
- button.set_sensitive(False)
- toolbar.insert(button, -1)
-
- _add_button('Scan for devices', 'reload', rstatus.refresh)
- _add_button('Pair new device', 'add', rstatus.pair)
-
- box.show_all()
- toolbar.set_visible(False)
- return box
-
-
-def _device_box():
- box = Gtk.HBox(homogeneous=False, spacing=8)
+def _device_box(name=None, has_status_icons=True, has_frame=True):
+ box = Gtk.HBox(homogeneous=False, spacing=10)
box.set_border_width(4)
icon = Gtk.Image()
+ if name:
+ icon.set_from_icon_name(name, _DEVICE_ICON_SIZE)
+ icon.set_tooltip_text(name)
+ else:
+ icon.set_from_icon_name('dialog-question', _DEVICE_ICON_SIZE)
icon.set_alignment(0.5, 0)
- icon.set_name('device-icon')
+ icon.set_name('icon')
box.pack_start(icon, False, False, 0)
- expander = Gtk.Expander()
- expander.set_use_markup(True)
- expander.set_spacing(4)
- expander.set_name('device-expander')
- box.pack_start(expander, True, True, 1)
+ vbox = Gtk.VBox(homogeneous=False, spacing=8)
+ box.pack_start(vbox, True, True, 0)
- ebox = Gtk.HBox(False, 8)
- battery_icon = Gtk.Image.new_from_icon_name('battery_unknown', _STATUS_ICON_SIZE)
- ebox.pack_end(battery_icon, False, True, 0)
- light_icon = Gtk.Image.new_from_icon_name('light_unknown', _STATUS_ICON_SIZE)
- ebox.pack_end(light_icon, False, True, 0)
- expander.add(ebox)
+ label = Gtk.Label('...')
+ label.set_alignment(0, 0.5)
+ label.set_name('label')
- frame = Gtk.Frame()
- frame.add(box)
- frame.show_all()
- frame.set_visible(False)
- return frame
+ status_box = Gtk.HBox(homogeneous=False, spacing=0)
+ status_box.set_name('status')
+
+ if has_status_icons:
+ vbox.pack_start(label, True, True, 0)
+
+ battery_icon = Gtk.Image.new_from_icon_name('battery_unknown', _STATUS_ICON_SIZE)
+ status_box.pack_start(battery_icon, False, True, 0)
+ battery_label = Gtk.Label()
+ battery_label.set_width_chars(6)
+ battery_label.set_alignment(0, 0.5)
+ status_box.pack_start(battery_label, False, True, 0)
+
+ light_icon = Gtk.Image.new_from_icon_name('light_unknown', _STATUS_ICON_SIZE)
+ status_box.pack_start(light_icon, False, True, 0)
+ light_label = Gtk.Label()
+ light_label.set_alignment(0, 0.5)
+ light_label.set_width_chars(8)
+ status_box.pack_start(light_label, False, True, 0)
+ else:
+ status_box.pack_start(label, True, True, 0)
+
+ toolbar = Gtk.Toolbar()
+ toolbar.set_style(Gtk.ToolbarStyle.ICONS)
+ toolbar.set_icon_size(Gtk.IconSize.MENU)
+ toolbar.set_name('buttons')
+ toolbar.set_show_arrow(False)
+ status_box.pack_end(toolbar, False, False, 0)
+
+ vbox.pack_start(status_box, True, True, 0)
+
+ box.show_all()
+
+ if has_frame:
+ frame = Gtk.Frame()
+ frame.add(box)
+ return frame
+ else:
+ toolbar.set_visible(False)
+ return box
def create(title, rstatus, systray=False):
@@ -199,9 +185,11 @@ def create(title, rstatus, systray=False):
vbox = Gtk.VBox(homogeneous=False, spacing=4)
vbox.set_border_width(4)
- vbox.add(_receiver_box(rstatus))
+ rbox = _device_box(rstatus.name, False, False)
+ vbox.add(rbox)
for i in range(1, 1 + rstatus.max_devices):
- vbox.add(_device_box())
+ dbox = _device_box()
+ vbox.add(dbox)
vbox.set_visible(True)
frame = Gtk.Frame()
@@ -211,7 +199,7 @@ def create(title, rstatus, systray=False):
window.add(frame)
geometry = Gdk.Geometry()
- geometry.min_width = 300
+ geometry.min_width = 260
geometry.min_height = 40
window.set_geometry_hints(frame, geometry, Gdk.WindowHints.MIN_SIZE)
@@ -219,23 +207,35 @@ def create(title, rstatus, systray=False):
window.set_default_size(geometry.min_width, geometry.min_height)
if systray:
+ def _state_event(window, event):
+ if event.new_window_state & Gdk.WindowState.ICONIFIED:
+ # position = window.get_position()
+ window.hide()
+ window.deiconify()
+ # window.move(*position)
+ return True
+
window.set_keep_above(True)
- window.set_deletable(False)
- window.set_decorated(False)
+ # window.set_deletable(False)
+ # window.set_decorated(False)
window.set_position(Gtk.WindowPosition.MOUSE)
- window.set_type_hint(Gdk.WindowTypeHint.MENU)
+ # window.set_type_hint(Gdk.WindowTypeHint.MENU)
window.set_skip_taskbar_hint(True)
window.set_skip_pager_hint(True)
+
+ window.connect('window-state-event', _state_event)
+ window.connect('delete-event', lambda w, e: toggle(None, window) or True)
else:
window.set_position(Gtk.WindowPosition.CENTER)
window.connect('delete-event', Gtk.main_quit)
- window.present()
return window
def toggle(_, window):
if window.get_visible():
+ # position = window.get_position()
window.hide()
+ # window.move(*position)
else:
window.present()
diff --git a/app/watcher.py b/app/watcher.py
index 71f04d01..cf2594c0 100644
--- a/app/watcher.py
+++ b/app/watcher.py
@@ -43,7 +43,7 @@ class Watcher(Thread):
def __init__(self, status_changed_callback, notify_callback=None):
super(Watcher, self).__init__(group='Solaar', name='Watcher')
self.daemon = True
- self.active = False
+ self._active = False
self.notify = notify_callback
self.status_text = None
@@ -59,9 +59,9 @@ class Watcher(Thread):
self.devices = {}
def run(self):
- self.active = True
+ self._active = True
- while self.active:
+ while self._active:
if self.listener is None:
self._update_status_text()
@@ -97,7 +97,7 @@ class Watcher(Thread):
self._update_status_text()
for i in range(0, int(_THREAD_SLEEP / _SLEEP_QUANT)):
- if self.active:
+ if self._active:
time.sleep(_SLEEP_QUANT)
else:
break
@@ -107,8 +107,9 @@ class Watcher(Thread):
self.listener = None
def stop(self):
- self.active = False
- self.join()
+ if self._active:
+ self._active = False
+ self.join()
def _request_status(self, devstatus):
if self.listener and devstatus:
@@ -127,7 +128,7 @@ class Watcher(Thread):
return updated
def _new_device(self, dev):
- if not self.active:
+ if not self._active:
return None
if type(dev) == int: