simplified window/icon code, reworked how device updates are signalled
This commit is contained in:
parent
2397c6c0ea
commit
e5a28ac64e
|
@ -45,67 +45,61 @@ def _run(args):
|
||||||
|
|
||||||
ui.notify.init()
|
ui.notify.init()
|
||||||
|
|
||||||
from solaar.listener import DUMMY, ReceiverListener
|
from solaar.listener import DUMMY_RECEIVER, ReceiverListener
|
||||||
window = ui.main_window.create(NAME, DUMMY.name, 6, True)
|
window = ui.main_window.create(NAME)
|
||||||
assert window
|
assert window
|
||||||
menu_actions = (ui.action.toggle_notifications,
|
icon = ui.status_icon.create(window)
|
||||||
ui.action.about)
|
|
||||||
icon = ui.status_icon.create(window, menu_actions)
|
|
||||||
assert icon
|
assert icon
|
||||||
|
|
||||||
listener = [None]
|
listeners = {}
|
||||||
|
|
||||||
# initializes the receiver listener
|
# initializes the receiver listener
|
||||||
def check_for_listener(notify=False):
|
def check_for_listener(notify=False):
|
||||||
# print ("check_for_listener", notify)
|
# print ("check_for_listener", notify)
|
||||||
listener[0] = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
listener[0] = ReceiverListener.open(status_changed)
|
l = ReceiverListener.open(status_changed)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
l = None
|
||||||
ui.error_dialog(window, 'Permissions error',
|
ui.error_dialog(window, 'Permissions error',
|
||||||
'Found a possible Unifying Receiver device,\n'
|
'Found a possible Unifying Receiver device,\n'
|
||||||
'but did not have permission to open it.')
|
'but did not have permission to open it.')
|
||||||
|
|
||||||
if listener[0] is None:
|
listeners.clear()
|
||||||
|
if l:
|
||||||
|
listeners[l.receiver.serial] = l
|
||||||
|
else:
|
||||||
if notify:
|
if notify:
|
||||||
status_changed(DUMMY)
|
status_changed(DUMMY_RECEIVER)
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
from gi.repository import Gtk, GObject
|
from gi.repository import Gtk, GLib
|
||||||
from logitech.unifying_receiver import status
|
from logitech.unifying_receiver.status import ALERT
|
||||||
|
|
||||||
# callback delivering status notifications from the receiver/devices to the UI
|
# callback delivering status notifications from the receiver/devices to the UI
|
||||||
def status_changed(receiver, device=None, alert=status.ALERT.NONE, reason=None):
|
def status_changed(device, alert=ALERT.NONE, reason=None):
|
||||||
if alert & status.ALERT.SHOW_WINDOW:
|
assert device is not None
|
||||||
GObject.idle_add(window.present)
|
|
||||||
if window:
|
if alert & ALERT.SHOW_WINDOW:
|
||||||
GObject.idle_add(ui.main_window.update, window, receiver, device)
|
GLib.idle_add(window.present)
|
||||||
if icon:
|
GLib.idle_add(ui.main_window.update, window, device)
|
||||||
GObject.idle_add(ui.status_icon.update, icon, receiver, device)
|
GLib.idle_add(ui.status_icon.update, icon, device)
|
||||||
|
|
||||||
if ui.notify.available:
|
if ui.notify.available:
|
||||||
# always notify on receiver updates
|
# always notify on receiver updates
|
||||||
if device is None or alert & status.ALERT.NOTIFICATION:
|
if device is DUMMY_RECEIVER or alert & ALERT.NOTIFICATION:
|
||||||
GObject.idle_add(ui.notify.show, device or receiver, reason)
|
GLib.idle_add(ui.notify.show, device, reason)
|
||||||
|
|
||||||
if receiver is DUMMY:
|
if device is DUMMY_RECEIVER:
|
||||||
GObject.timeout_add(3000, check_for_listener)
|
GLib.timeout_add(3000, check_for_listener)
|
||||||
|
|
||||||
GObject.timeout_add(10, check_for_listener, True)
|
GLib.timeout_add(10, check_for_listener, True)
|
||||||
if icon:
|
|
||||||
GObject.timeout_add(1000, ui.status_icon.check_systray, icon, window)
|
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
|
|
||||||
if listener[0]:
|
map(ReceiverListener.stop, listeners.values())
|
||||||
listener[0].stop()
|
|
||||||
|
|
||||||
ui.notify.uninit()
|
ui.notify.uninit()
|
||||||
|
map(ReceiverListener.join, listeners.values())
|
||||||
if listener[0]:
|
|
||||||
listener[0].join()
|
|
||||||
listener[0] = None
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -25,7 +25,7 @@ del namedtuple
|
||||||
def _ghost(device):
|
def _ghost(device):
|
||||||
return _GHOST_DEVICE(number=device.number, name=device.name, kind=device.kind, status=None, max_devices=None)
|
return _GHOST_DEVICE(number=device.number, name=device.name, kind=device.kind, status=None, max_devices=None)
|
||||||
|
|
||||||
DUMMY = _GHOST_DEVICE(Receiver.number, 'dialog-error', None, 'Receiver not found.', 6)
|
DUMMY_RECEIVER = _GHOST_DEVICE(0xFF, 'Solaar', None, 'Receiver not found.', 0)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -52,15 +52,15 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
_log.info("%s: notifications listener has started (%s)", self.receiver, self.receiver.handle)
|
_log.info("%s: notifications listener has started (%s)", self.receiver, self.receiver.handle)
|
||||||
self.receiver.enable_notifications()
|
self.receiver.enable_notifications()
|
||||||
self.receiver.notify_devices()
|
self.receiver.notify_devices()
|
||||||
self._status_changed(self.receiver, _status.ALERT.NOTIFICATION)
|
# self._status_changed(self.receiver, _status.ALERT.NOTIFICATION)
|
||||||
|
|
||||||
def has_stopped(self):
|
def has_stopped(self):
|
||||||
_log.info("%s: notifications listener has stopped", self.receiver)
|
_log.info("%s: notifications listener has stopped", self.receiver)
|
||||||
if self.receiver:
|
if self.receiver:
|
||||||
self.receiver.enable_notifications(False)
|
self.receiver.enable_notifications(False)
|
||||||
self.receiver.close()
|
self.receiver.close()
|
||||||
self._status_changed(self.receiver, _status.ALERT.NOTIFICATION)
|
|
||||||
self.receiver = None
|
self.receiver = None
|
||||||
|
self.status_changed_callback(DUMMY_RECEIVER, _status.ALERT.NOTIFICATION)
|
||||||
|
|
||||||
def tick(self, timestamp):
|
def tick(self, timestamp):
|
||||||
if _log.isEnabledFor(_DEBUG):
|
if _log.isEnabledFor(_DEBUG):
|
||||||
|
@ -76,7 +76,7 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
self._last_tick = timestamp
|
self._last_tick = timestamp
|
||||||
|
|
||||||
# read these in case they haven't been read already
|
# read these in case they haven't been read already
|
||||||
self.receiver.serial, self.receiver.firmware
|
# self.receiver.serial, self.receiver.firmware
|
||||||
if self.receiver.status.lock_open:
|
if self.receiver.status.lock_open:
|
||||||
# don't mess with stuff while pairing
|
# don't mess with stuff while pairing
|
||||||
return
|
return
|
||||||
|
@ -86,27 +86,36 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
dev.status.poll(timestamp)
|
dev.status.poll(timestamp)
|
||||||
|
|
||||||
def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None):
|
def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None):
|
||||||
|
assert device is not None
|
||||||
if _log.isEnabledFor(_DEBUG):
|
if _log.isEnabledFor(_DEBUG):
|
||||||
_log.debug("status_changed %s: %s %s (%X) %s", device,
|
_log.debug("%s: status_changed %s: %s, %s (%X) %s", self.receiver, device,
|
||||||
None if device is None else 'active' if device.status else 'inactive',
|
'active' if device.status else 'inactive',
|
||||||
None if device is None else device.status,
|
device.status, alert, reason or '')
|
||||||
alert, reason or '')
|
|
||||||
if self.status_changed_callback:
|
if device.kind is None:
|
||||||
r = self.receiver or DUMMY
|
# print ("self.receiver: ", self.receiver, id(self.receiver))
|
||||||
if device is None or device.kind is None:
|
# print ("device: ", device, id(device))
|
||||||
|
assert device == self.receiver
|
||||||
# the status of the receiver changed
|
# the status of the receiver changed
|
||||||
self.status_changed_callback(r, None, alert, reason)
|
self.status_changed_callback(device, alert, reason)
|
||||||
else:
|
else:
|
||||||
if device.status is None:
|
if device.status is None:
|
||||||
|
# the device may be paired later, possibly to another receiver?
|
||||||
|
# so maybe we shouldn't forget about it
|
||||||
|
# configuration.forget(device)
|
||||||
|
|
||||||
# device was unpaired, and since the object is weakref'ed
|
# device was unpaired, and since the object is weakref'ed
|
||||||
# it won't be valid for much longer
|
# it won't be valid for much longer
|
||||||
device = _ghost(device)
|
device = _ghost(device)
|
||||||
|
|
||||||
self.status_changed_callback(r, device, alert, reason)
|
# elif device.status:
|
||||||
|
# configuration.sync(device)
|
||||||
|
|
||||||
|
self.status_changed_callback(device, alert, reason)
|
||||||
|
|
||||||
if device.status is None:
|
if device.status is None:
|
||||||
# the receiver changed status as well
|
# the receiver changed status as well
|
||||||
self.status_changed_callback(r)
|
self.status_changed_callback(self.receiver)
|
||||||
|
|
||||||
def _notifications_handler(self, n):
|
def _notifications_handler(self, n):
|
||||||
assert self.receiver
|
assert self.receiver
|
||||||
|
|
|
@ -44,4 +44,5 @@ def error_dialog(window, title, text):
|
||||||
m.destroy()
|
m.destroy()
|
||||||
|
|
||||||
|
|
||||||
from . import notify, status_icon, main_window
|
from . import status_icon
|
||||||
|
from . import notify, main_window
|
||||||
|
|
|
@ -66,10 +66,12 @@ def _show_about_window(action):
|
||||||
))
|
))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# gtk3 < 3.6 has incorrect gi bindings
|
# gtk3 < 3.6 has incorrect gi bindings
|
||||||
pass
|
import logging
|
||||||
|
logging.exception("failed to fully create the about dialog")
|
||||||
except:
|
except:
|
||||||
# is the Gtk3 version too old?
|
# is the Gtk3 version too old?
|
||||||
pass
|
import logging
|
||||||
|
logging.exception("failed to fully create the about dialog")
|
||||||
|
|
||||||
about.set_website('http://pwr.github.io/Solaar/')
|
about.set_website('http://pwr.github.io/Solaar/')
|
||||||
about.set_website_label('Solaar')
|
about.set_website_label('Solaar')
|
||||||
|
@ -78,8 +80,6 @@ def _show_about_window(action):
|
||||||
about.destroy()
|
about.destroy()
|
||||||
about = make('help-about', 'About ' + _NAME, _show_about_window)
|
about = make('help-about', 'About ' + _NAME, _show_about_window)
|
||||||
|
|
||||||
quit = make('application-exit', 'Quit', Gtk.main_quit)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
|
@ -41,7 +41,7 @@ def lux(level):
|
||||||
|
|
||||||
_ICON_SETS = {}
|
_ICON_SETS = {}
|
||||||
|
|
||||||
def device_icon_set(name, kind=None):
|
def device_icon_set(name='_', kind=None):
|
||||||
icon_set = _ICON_SETS.get(name)
|
icon_set = _ICON_SETS.get(name)
|
||||||
if icon_set is None:
|
if icon_set is None:
|
||||||
icon_set = Gtk.IconSet.new()
|
icon_set = Gtk.IconSet.new()
|
||||||
|
@ -56,9 +56,6 @@ def device_icon_set(name, kind=None):
|
||||||
elif str(kind) == 'trackball':
|
elif str(kind) == 'trackball':
|
||||||
names += ('input-mouse',)
|
names += ('input-mouse',)
|
||||||
names += ('input-' + str(kind),)
|
names += ('input-' + str(kind),)
|
||||||
|
|
||||||
theme = Gtk.IconTheme.get_default()
|
|
||||||
if theme.has_icon(name):
|
|
||||||
names += (name,)
|
names += (name,)
|
||||||
|
|
||||||
source = Gtk.IconSource.new()
|
source = Gtk.IconSource.new()
|
||||||
|
|
|
@ -20,17 +20,17 @@ _STATUS_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
|
||||||
_TOOLBAR_ICON_SIZE = Gtk.IconSize.MENU
|
_TOOLBAR_ICON_SIZE = Gtk.IconSize.MENU
|
||||||
_PLACEHOLDER = '~'
|
_PLACEHOLDER = '~'
|
||||||
_FALLBACK_ICON = 'preferences-desktop-peripherals'
|
_FALLBACK_ICON = 'preferences-desktop-peripherals'
|
||||||
|
_MAX_DEVICES = 7
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
def _make_receiver_box(name):
|
def _make_receiver_box():
|
||||||
frame = Gtk.Frame()
|
frame = Gtk.Frame()
|
||||||
frame._device = None
|
frame._device = None
|
||||||
frame.set_name(name)
|
|
||||||
|
|
||||||
icon_set = _icons.device_icon_set(name)
|
icon_set = _icons.device_icon_set()
|
||||||
icon = Gtk.Image.new_from_icon_set(icon_set, _RECEIVER_ICON_SIZE)
|
icon = Gtk.Image.new_from_icon_set(icon_set, _RECEIVER_ICON_SIZE)
|
||||||
icon.set_padding(2, 2)
|
icon.set_padding(2, 2)
|
||||||
frame._icon = icon
|
frame._icon = icon
|
||||||
|
@ -39,7 +39,7 @@ def _make_receiver_box(name):
|
||||||
label.set_alignment(0, 0.5)
|
label.set_alignment(0, 0.5)
|
||||||
frame._label = label
|
frame._label = label
|
||||||
|
|
||||||
pairing_icon = Gtk.Image.new_from_icon_name('network-wireless', _RECEIVER_ICON_SIZE)
|
pairing_icon = Gtk.Image.new_from_icon_name('network-wireless', _TOOLBAR_ICON_SIZE)
|
||||||
pairing_icon.set_tooltip_text('The pairing lock is open.')
|
pairing_icon.set_tooltip_text('The pairing lock is open.')
|
||||||
pairing_icon._tick = 0
|
pairing_icon._tick = 0
|
||||||
frame._pairing_icon = pairing_icon
|
frame._pairing_icon = pairing_icon
|
||||||
|
@ -242,18 +242,48 @@ def _make_device_box(index):
|
||||||
return frame
|
return frame
|
||||||
|
|
||||||
|
|
||||||
def create(title, name, max_devices, systray=False):
|
def hide(w, trigger):
|
||||||
|
position = w.get_position()
|
||||||
|
w.hide()
|
||||||
|
w.move(*position)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def toggle(trigger, w):
|
||||||
|
if w.get_visible():
|
||||||
|
return hide(w, trigger)
|
||||||
|
|
||||||
|
if isinstance(trigger, Gtk.StatusIcon):
|
||||||
|
x, y = w.get_position()
|
||||||
|
if x == 0 and y == 0:
|
||||||
|
# if the window hasn't been shown yet, position it next to the status icon
|
||||||
|
x, y, _ = Gtk.StatusIcon.position_menu(Gtk.Menu(), trigger)
|
||||||
|
w.move(x, y)
|
||||||
|
w.present()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def set_icon_name(window, icon_name):
|
||||||
|
icon_file = _icons.icon_file(icon_name)
|
||||||
|
if icon_file:
|
||||||
|
window.set_icon_from_file(icon_file)
|
||||||
|
else:
|
||||||
|
window.set_icon_name(icon_name)
|
||||||
|
|
||||||
|
|
||||||
|
def create(title):
|
||||||
window = Gtk.Window()
|
window = Gtk.Window()
|
||||||
window.set_title(title)
|
window.set_title(title)
|
||||||
window.set_icon_name(_icons.APP_ICON[0])
|
set_icon_name(window, _icons.APP_ICON[0])
|
||||||
window.set_role('status-window')
|
window.set_role('status-window')
|
||||||
|
window.set_type_hint(Gdk.WindowTypeHint.UTILITY)
|
||||||
|
|
||||||
vbox = Gtk.VBox(homogeneous=False, spacing=12)
|
vbox = Gtk.VBox(homogeneous=False, spacing=12)
|
||||||
vbox.set_border_width(4)
|
vbox.set_border_width(4)
|
||||||
|
|
||||||
rbox = _make_receiver_box(name)
|
rbox = _make_receiver_box()
|
||||||
vbox.add(rbox)
|
vbox.add(rbox)
|
||||||
for i in range(1, 1 + max_devices):
|
for i in range(1, _MAX_DEVICES):
|
||||||
dbox = _make_device_box(i)
|
dbox = _make_device_box(i)
|
||||||
vbox.add(dbox)
|
vbox.add(dbox)
|
||||||
vbox.set_visible(True)
|
vbox.set_visible(True)
|
||||||
|
@ -264,53 +294,13 @@ def create(title, name, max_devices, systray=False):
|
||||||
geometry.min_width = 320
|
geometry.min_width = 320
|
||||||
geometry.min_height = 32
|
geometry.min_height = 32
|
||||||
window.set_geometry_hints(vbox, geometry, Gdk.WindowHints.MIN_SIZE)
|
window.set_geometry_hints(vbox, geometry, Gdk.WindowHints.MIN_SIZE)
|
||||||
|
|
||||||
window.set_resizable(False)
|
window.set_resizable(False)
|
||||||
|
window.set_skip_taskbar_hint(True)
|
||||||
def _toggle_visible(w, trigger):
|
window.set_skip_pager_hint(True)
|
||||||
if w.get_visible():
|
|
||||||
# hiding moves the window to 0,0
|
|
||||||
position = w.get_position()
|
|
||||||
w.hide()
|
|
||||||
w.move(*position)
|
|
||||||
else:
|
|
||||||
if isinstance(trigger, Gtk.StatusIcon):
|
|
||||||
x, y = w.get_position()
|
|
||||||
if x == 0 and y == 0:
|
|
||||||
# if the window hasn't been shown yet, position it next to the status icon
|
|
||||||
x, y, _ = Gtk.StatusIcon.position_menu(Gtk.Menu(), trigger)
|
|
||||||
w.move(x, y)
|
|
||||||
w.present()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _set_has_systray(w, systray):
|
|
||||||
# print ("set has systray", systray, w._has_systray)
|
|
||||||
if systray != w._has_systray:
|
|
||||||
w._has_systray = systray
|
|
||||||
if systray:
|
|
||||||
if w._delete_event_connection is None or not w.get_skip_taskbar_hint():
|
|
||||||
w.set_skip_taskbar_hint(True)
|
|
||||||
w.set_skip_pager_hint(True)
|
|
||||||
if w._delete_event_connection:
|
|
||||||
w.disconnect(w._delete_event_connection)
|
|
||||||
w._delete_event_connection = w.connect('delete-event', _toggle_visible)
|
|
||||||
else:
|
|
||||||
if w._delete_event_connection is None or w.get_skip_taskbar_hint():
|
|
||||||
w.set_skip_taskbar_hint(False)
|
|
||||||
w.set_skip_pager_hint(False)
|
|
||||||
if w._delete_event_connection:
|
|
||||||
w.disconnect(w._delete_event_connection)
|
|
||||||
w._delete_event_connection = w.connect('delete-event', Gtk.main_quit)
|
|
||||||
w.present()
|
|
||||||
|
|
||||||
from types import MethodType
|
|
||||||
window.toggle_visible = MethodType(_toggle_visible, window)
|
|
||||||
window.set_has_systray = MethodType(_set_has_systray, window)
|
|
||||||
del MethodType
|
|
||||||
|
|
||||||
window.set_keep_above(True)
|
window.set_keep_above(True)
|
||||||
window._delete_event_connection = None
|
# window.set_decorations(Gdk.DECOR_BORDER | Gdk.DECOR_TITLE)
|
||||||
window._has_systray = None
|
window.connect('delete-event', hide)
|
||||||
window.set_has_systray(systray)
|
|
||||||
|
|
||||||
return window
|
return window
|
||||||
|
|
||||||
|
@ -322,6 +312,8 @@ def _update_receiver_box(frame, receiver):
|
||||||
frame._label.set_text(str(receiver.status))
|
frame._label.set_text(str(receiver.status))
|
||||||
if receiver:
|
if receiver:
|
||||||
frame._device = receiver
|
frame._device = receiver
|
||||||
|
icon_set = _icons.device_icon_set(receiver.name)
|
||||||
|
frame._icon.set_from_icon_set(icon_set, _RECEIVER_ICON_SIZE)
|
||||||
frame._icon.set_sensitive(True)
|
frame._icon.set_sensitive(True)
|
||||||
if receiver.status.lock_open:
|
if receiver.status.lock_open:
|
||||||
if frame._pairing_icon._tick == 0:
|
if frame._pairing_icon._tick == 0:
|
||||||
|
@ -342,6 +334,7 @@ def _update_receiver_box(frame, receiver):
|
||||||
frame._toolbar.set_sensitive(True)
|
frame._toolbar.set_sensitive(True)
|
||||||
else:
|
else:
|
||||||
frame._device = None
|
frame._device = None
|
||||||
|
frame._icon.set_from_icon_name('dialog-error', _RECEIVER_ICON_SIZE)
|
||||||
frame._icon.set_sensitive(False)
|
frame._icon.set_sensitive(False)
|
||||||
frame._pairing_icon.set_visible(False)
|
frame._pairing_icon.set_visible(False)
|
||||||
frame._toolbar.set_sensitive(False)
|
frame._toolbar.set_sensitive(False)
|
||||||
|
@ -420,19 +413,21 @@ def _update_device_box(frame, dev):
|
||||||
_config_panel.update(frame)
|
_config_panel.update(frame)
|
||||||
|
|
||||||
|
|
||||||
def update(window, receiver, device=None):
|
def update(window, device):
|
||||||
assert receiver is not None
|
assert device is not None
|
||||||
# print ("update", receiver, receiver.status, len(receiver), device)
|
# print ("main_window.update", device)
|
||||||
window.set_icon_name(_icons.APP_ICON[1 if receiver else -1])
|
|
||||||
|
|
||||||
vbox = window.get_child()
|
vbox = window.get_child()
|
||||||
frames = list(vbox.get_children())
|
frames = list(vbox.get_children())
|
||||||
assert len(frames) == 1 + receiver.max_devices, frames
|
|
||||||
|
|
||||||
if device is None:
|
if device.kind is None:
|
||||||
_update_receiver_box(frames[0], receiver)
|
# update on the receiver
|
||||||
if not receiver:
|
_update_receiver_box(frames[0], device)
|
||||||
|
if device:
|
||||||
|
set_icon_name(window, _icons.APP_ICON[1])
|
||||||
|
else:
|
||||||
for frame in frames[1:]:
|
for frame in frames[1:]:
|
||||||
_update_device_box(frame, None)
|
_update_device_box(frame, None)
|
||||||
|
set_icon_name(window, _icons.APP_ICON[-1])
|
||||||
else:
|
else:
|
||||||
_update_device_box(frames[device.number], None if device.status is None else device)
|
_update_device_box(frames[device.number], None if device.status is None else device)
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
from gi.repository import Gtk, GLib, GdkPixbuf
|
from gi.repository import Gtk, GdkPixbuf
|
||||||
|
|
||||||
from . import action as _action, icons as _icons
|
from . import (action as _action,
|
||||||
|
icons as _icons,
|
||||||
|
main_window as _main_window)
|
||||||
from logitech.unifying_receiver import status as _status
|
from logitech.unifying_receiver import status as _status
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -15,8 +17,9 @@ from logitech.unifying_receiver import status as _status
|
||||||
|
|
||||||
_NO_DEVICES = [None] * 6
|
_NO_DEVICES = [None] * 6
|
||||||
|
|
||||||
def create(window, menu_actions=None):
|
def create(window):
|
||||||
name = window.get_title()
|
name = window.get_title()
|
||||||
|
|
||||||
icon = Gtk.StatusIcon()
|
icon = Gtk.StatusIcon()
|
||||||
icon.set_title(name)
|
icon.set_title(name)
|
||||||
icon.set_name(name)
|
icon.set_name(name)
|
||||||
|
@ -24,16 +27,21 @@ def create(window, menu_actions=None):
|
||||||
icon._devices = list(_NO_DEVICES)
|
icon._devices = list(_NO_DEVICES)
|
||||||
|
|
||||||
icon.set_tooltip_text(name)
|
icon.set_tooltip_text(name)
|
||||||
icon.connect('activate', window.toggle_visible)
|
icon.connect('activate', _main_window.toggle, window)
|
||||||
|
|
||||||
menu = Gtk.Menu()
|
menu = Gtk.Menu()
|
||||||
for a in menu_actions or ():
|
|
||||||
if a:
|
|
||||||
menu.append(a.create_menu_item())
|
|
||||||
|
|
||||||
menu.append(_action.quit.create_menu_item())
|
menu.append(Gtk.SeparatorMenuItem.new())
|
||||||
|
|
||||||
|
menu.append(_action.about.create_menu_item())
|
||||||
|
menu.append(_action.make('application-exit', 'Quit', Gtk.main_quit).create_menu_item())
|
||||||
menu.show_all()
|
menu.show_all()
|
||||||
|
|
||||||
|
for x in _NO_DEVICES:
|
||||||
|
m = Gtk.ImageMenuItem()
|
||||||
|
m.set_sensitive(False)
|
||||||
|
menu.insert(m, 0)
|
||||||
|
|
||||||
icon.connect('popup_menu',
|
icon.connect('popup_menu',
|
||||||
lambda icon, button, time, menu:
|
lambda icon, button, time, menu:
|
||||||
menu.popup(None, None, icon.position_menu, icon, button, time),
|
menu.popup(None, None, icon.position_menu, icon, button, time),
|
||||||
|
@ -41,23 +49,6 @@ def create(window, menu_actions=None):
|
||||||
return icon
|
return icon
|
||||||
|
|
||||||
|
|
||||||
def check_systray(icon, window):
|
|
||||||
# use size-changed to detect if the systray is available or not
|
|
||||||
def _size_changed(i, size, w):
|
|
||||||
import logging
|
|
||||||
logging.info("size-chagend %s %s", size, w)
|
|
||||||
def _check_systray(i2, w2):
|
|
||||||
logging.info("check_systray %s %s", i2.is_embedded(), i2.get_visible())
|
|
||||||
w2.set_has_systray(i2.is_embedded() and i2.get_visible())
|
|
||||||
# first guess
|
|
||||||
GLib.timeout_add(250, _check_systray, i, w)
|
|
||||||
# just to make sure...
|
|
||||||
# GLib.timeout_add(1000, _check_systray, i, w)
|
|
||||||
|
|
||||||
_size_changed(icon, None, window)
|
|
||||||
icon.connect('size-changed', _size_changed, window)
|
|
||||||
|
|
||||||
|
|
||||||
_PIXMAPS = {}
|
_PIXMAPS = {}
|
||||||
def _icon_with_battery(level, active):
|
def _icon_with_battery(level, active):
|
||||||
battery_icon = _icons.battery(level)
|
battery_icon = _icons.battery(level)
|
||||||
|
@ -82,12 +73,18 @@ def _icon_with_battery(level, active):
|
||||||
|
|
||||||
return _PIXMAPS[name]
|
return _PIXMAPS[name]
|
||||||
|
|
||||||
def update(icon, receiver, device=None):
|
def update(icon, device):
|
||||||
# print ("icon update", receiver, receiver.status, len(receiver), device)
|
assert device is not None
|
||||||
if device is not None:
|
# print ("icon update", device)
|
||||||
icon._devices[device.number] = None if device.status is None else device
|
|
||||||
if not receiver:
|
if device.kind is None:
|
||||||
|
receiver = device
|
||||||
|
if not device:
|
||||||
icon._devices[:] = _NO_DEVICES
|
icon._devices[:] = _NO_DEVICES
|
||||||
|
else:
|
||||||
|
icon._devices[device.number] = None if device.status is None else device
|
||||||
|
receiver = device.receiver
|
||||||
|
|
||||||
if not icon.is_embedded():
|
if not icon.is_embedded():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue