use number instead of serial to pick devices in ui (faster start-up)
This commit is contained in:
parent
7102229937
commit
273284da39
|
@ -266,7 +266,7 @@ def make_notification(devnumber, data):
|
||||||
return a Notification tuple if it is."""
|
return a Notification tuple if it is."""
|
||||||
sub_id = ord(data[:1])
|
sub_id = ord(data[:1])
|
||||||
if sub_id & 0x80 == 0x80:
|
if sub_id & 0x80 == 0x80:
|
||||||
# if this is a HID++1.0 register r/w, bail out
|
# this is either a HID++1.0 register r/w, or an error reply
|
||||||
return
|
return
|
||||||
|
|
||||||
address = ord(data[1:2])
|
address = ord(data[1:2])
|
||||||
|
|
|
@ -158,6 +158,7 @@ def get_serial(device):
|
||||||
else:
|
else:
|
||||||
dev_id = 0x30 + device.number - 1
|
dev_id = 0x30 + device.number - 1
|
||||||
receiver = device.receiver
|
receiver = device.receiver
|
||||||
|
assert receiver.unifying_supported
|
||||||
|
|
||||||
serial = read_register(receiver, 0x2B5, dev_id)
|
serial = read_register(receiver, 0x2B5, dev_id)
|
||||||
if serial is not None:
|
if serial is not None:
|
||||||
|
|
|
@ -115,24 +115,19 @@ class PairedDevice(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def protocol(self):
|
def protocol(self):
|
||||||
|
if self._protocol is None:
|
||||||
|
descriptor = _descriptors.DEVICES.get(self.codename)
|
||||||
|
if descriptor:
|
||||||
|
if descriptor.protocol:
|
||||||
|
self._protocol = descriptor.protocol
|
||||||
|
else:
|
||||||
|
_log.warn("%s: descriptor has no protocol, should be %0.1f", self, self._protocol)
|
||||||
|
|
||||||
if self._protocol is None:
|
if self._protocol is None:
|
||||||
self._protocol = _base.ping(self.receiver.handle, self.number)
|
self._protocol = _base.ping(self.receiver.handle, self.number)
|
||||||
# if the ping failed, the peripheral is (almost) certainly offline
|
# if the ping failed, the peripheral is (almost) certainly offline
|
||||||
self.online = self._protocol is not None
|
self.online = self._protocol is not None
|
||||||
|
|
||||||
# use the descriptor only as a fallback, because it may not be 100% correct
|
|
||||||
descriptor = _descriptors.DEVICES.get(self.codename)
|
|
||||||
if self._protocol is None:
|
|
||||||
if descriptor and descriptor.protocol is not None:
|
|
||||||
self._protocol = descriptor.protocol
|
|
||||||
else:
|
|
||||||
if descriptor:
|
|
||||||
if descriptor.protocol is None:
|
|
||||||
_log.info("%s: descriptor has no protocol, should be %0.1f", self, self._protocol)
|
|
||||||
elif descriptor.protocol != self._protocol:
|
|
||||||
_log.error("%s: descriptor has wrong protocol %0.1f, should be %0.1f",
|
|
||||||
self, descriptor.protocol, self._protocol)
|
|
||||||
|
|
||||||
# _log.debug("device %d protocol %s", self.number, self._protocol)
|
# _log.debug("device %d protocol %s", self.number, self._protocol)
|
||||||
return self._protocol or 0
|
return self._protocol or 0
|
||||||
|
|
||||||
|
@ -160,15 +155,12 @@ class PairedDevice(object):
|
||||||
@property
|
@property
|
||||||
def kind(self):
|
def kind(self):
|
||||||
if self._kind is None:
|
if self._kind is None:
|
||||||
# already handled in the constructor
|
if self.receiver.unifying_supported:
|
||||||
# if self.receiver.unifying_supported:
|
pair_info = self.receiver.read_register(0x2B5, 0x20 + self.number - 1)
|
||||||
# pair_info = self.receiver.read_register(0x2B5, 0x20 + self.number - 1)
|
if pair_info:
|
||||||
# if pair_info:
|
kind = ord(pair_info[7:8]) & 0x0F
|
||||||
# kind = ord(pair_info[7:8]) & 0x0F
|
self._kind = _hidpp10.DEVICE_KIND[kind]
|
||||||
# self._kind = _hidpp10.DEVICE_KIND[kind]
|
if self._kind is None and self.protocol >= 2.0 and self.online:
|
||||||
# if self.wpid is None:
|
|
||||||
# self.wpid = _strhex(pair_info[3:5])
|
|
||||||
if self.protocol >= 2.0 and self.online:
|
|
||||||
self._kind = _hidpp20.get_kind(self)
|
self._kind = _hidpp20.get_kind(self)
|
||||||
if self._kind is None:
|
if self._kind is None:
|
||||||
descriptor = _descriptors.DEVICES.get(self.codename)
|
descriptor = _descriptors.DEVICES.get(self.codename)
|
||||||
|
@ -287,13 +279,13 @@ class PairedDevice(object):
|
||||||
__int__ = __index__
|
__int__ = __index__
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return other is not None and self.kind == other.kind and self.serial == other.serial
|
return other is not None and self.kind == other.kind and self.wpid == other.wpid
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return other is None or self.kind != other.kind or self.serial != other.serial
|
return other is None or self.kind != other.kind or self.wpid != other.wpid
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return self.serial.__hash__()
|
return self.wpid.__hash__()
|
||||||
|
|
||||||
__bool__ = __nonzero__ = lambda self: self.wpid is not None and self.number in self.receiver
|
__bool__ = __nonzero__ = lambda self: self.wpid is not None and self.number in self.receiver
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ class DeviceStatus(dict):
|
||||||
_log.debug("polling status of %s", d)
|
_log.debug("polling status of %s", d)
|
||||||
|
|
||||||
# read these from the device, the UI may need them later
|
# read these from the device, the UI may need them later
|
||||||
d.protocol, d.firmware, d.kind, d.name, d.settings, None
|
d.protocol, d.serial, d.firmware, d.kind, d.name, d.settings, None
|
||||||
|
|
||||||
# make sure we know all the features of the device
|
# make sure we know all the features of the device
|
||||||
# if d.features:
|
# if d.features:
|
||||||
|
|
|
@ -18,7 +18,7 @@ from logitech.unifying_receiver import (Receiver,
|
||||||
#
|
#
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
_GHOST_DEVICE = namedtuple('_GHOST_DEVICE', ['receiver', 'number', 'name', 'kind', 'serial', 'status', 'online'])
|
_GHOST_DEVICE = namedtuple('_GHOST_DEVICE', ['receiver', 'number', 'name', 'kind', 'status', 'online'])
|
||||||
_GHOST_DEVICE.__bool__ = lambda self: False
|
_GHOST_DEVICE.__bool__ = lambda self: False
|
||||||
_GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__
|
_GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__
|
||||||
del namedtuple
|
del namedtuple
|
||||||
|
@ -29,7 +29,6 @@ def _ghost(device):
|
||||||
number=device.number,
|
number=device.number,
|
||||||
name=device.name,
|
name=device.name,
|
||||||
kind=device.kind,
|
kind=device.kind,
|
||||||
serial=device.serial,
|
|
||||||
status=None,
|
status=None,
|
||||||
online=False)
|
online=False)
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ about = make('help-about', 'About ' + NAME, _show_about_window)
|
||||||
|
|
||||||
from . import pair_window
|
from . import pair_window
|
||||||
def pair(window, receiver):
|
def pair(window, receiver):
|
||||||
assert receiver is not None
|
assert receiver
|
||||||
assert receiver.kind is None
|
assert receiver.kind is None
|
||||||
|
|
||||||
pair_dialog = pair_window.create(receiver)
|
pair_dialog = pair_window.create(receiver)
|
||||||
|
@ -58,7 +58,7 @@ def pair(window, receiver):
|
||||||
|
|
||||||
from ..ui import error_dialog
|
from ..ui import error_dialog
|
||||||
def unpair(window, device):
|
def unpair(window, device):
|
||||||
assert device is not None
|
assert device
|
||||||
assert device.kind is not None
|
assert device.kind is not None
|
||||||
|
|
||||||
qdialog = Gtk.MessageDialog(window, 0,
|
qdialog = Gtk.MessageDialog(window, 0,
|
||||||
|
|
|
@ -81,9 +81,8 @@ def _combo_notify(cbbox, setting, spinner):
|
||||||
# return True
|
# return True
|
||||||
|
|
||||||
|
|
||||||
def _create_sbox(s, device_id):
|
def _create_sbox(s):
|
||||||
sbox = Gtk.HBox(homogeneous=False, spacing=6)
|
sbox = Gtk.HBox(homogeneous=False, spacing=6)
|
||||||
sbox.set_name(device_id)
|
|
||||||
sbox.pack_start(Gtk.Label(s.label), False, False, 0)
|
sbox.pack_start(Gtk.Label(s.label), False, False, 0)
|
||||||
|
|
||||||
spinner = Gtk.Spinner()
|
spinner = Gtk.Spinner()
|
||||||
|
@ -170,21 +169,24 @@ def create():
|
||||||
def update(device, is_online):
|
def update(device, is_online):
|
||||||
assert _box is not None
|
assert _box is not None
|
||||||
assert device
|
assert device
|
||||||
|
device_id = (device.receiver.path, device.number)
|
||||||
|
|
||||||
# if the device changed since last update, clear the box first
|
# if the device changed since last update, clear the box first
|
||||||
if device.serial != _box._last_device:
|
if device_id != _box._last_device:
|
||||||
_box.set_visible(False)
|
_box.set_visible(False)
|
||||||
_box._last_device = device.serial
|
_box._last_device = device_id
|
||||||
|
|
||||||
# hide
|
# hide controls belonging to other devices
|
||||||
_box.foreach(lambda x, s: x.set_visible(x.get_name() == s), device.serial)
|
for k, sbox in _items.items():
|
||||||
|
sbox = _items[k]
|
||||||
|
sbox.set_visible(k[0:2] == device_id)
|
||||||
|
|
||||||
for s in device.settings:
|
for s in device.settings:
|
||||||
k = device.serial + '_' + s.name
|
k = (device_id[0], device_id[1], s.name)
|
||||||
if k in _items:
|
if k in _items:
|
||||||
sbox = _items[k]
|
sbox = _items[k]
|
||||||
else:
|
else:
|
||||||
sbox = _items[k] = _create_sbox(s, device.serial)
|
sbox = _items[k] = _create_sbox(s)
|
||||||
_box.pack_start(sbox, False, False, 0)
|
_box.pack_start(sbox, False, False, 0)
|
||||||
|
|
||||||
if is_online:
|
if is_online:
|
||||||
|
@ -194,16 +196,16 @@ def update(device, is_online):
|
||||||
|
|
||||||
_box.set_visible(True)
|
_box.set_visible(True)
|
||||||
|
|
||||||
def clean(device_id):
|
def clean(device):
|
||||||
"""Remove the controls for a given device serial.
|
"""Remove the controls for a given device serial.
|
||||||
Needed after the device has been unpaired.
|
Needed after the device has been unpaired.
|
||||||
"""
|
"""
|
||||||
assert _box is not None
|
assert _box is not None
|
||||||
|
device_id = (device.receiver.path, device.number)
|
||||||
for k in list(_items.keys()):
|
for k in list(_items.keys()):
|
||||||
sbox = _items[k]
|
if k[0:2] == device_id:
|
||||||
if sbox.get_name() == device_id:
|
_box.remove(_items[k])
|
||||||
del _items[k]
|
del _items[k]
|
||||||
_box.remove(sbox)
|
|
||||||
|
|
||||||
|
|
||||||
def destroy():
|
def destroy():
|
||||||
|
|
|
@ -24,6 +24,7 @@ from .window import popup as _window_popup, toggle as _window_toggle
|
||||||
|
|
||||||
_TRAY_ICON_SIZE = 32 # pixels
|
_TRAY_ICON_SIZE = 32 # pixels
|
||||||
_MENU_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
|
_MENU_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
|
||||||
|
_RECEIVER_SEPARATOR = ('~', None, None, None)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -93,8 +94,8 @@ try:
|
||||||
if not info[1]:
|
if not info[1]:
|
||||||
# only conside peripherals
|
# only conside peripherals
|
||||||
continue
|
continue
|
||||||
# compare peripheral serials
|
# compare peripherals
|
||||||
if info[1] == _picked_device[1]:
|
if info[0:2] == _picked_device[0:2]:
|
||||||
if direction == ScrollDirection.UP and candidate:
|
if direction == ScrollDirection.UP and candidate:
|
||||||
# select previous device
|
# select previous device
|
||||||
break
|
break
|
||||||
|
@ -151,7 +152,7 @@ try:
|
||||||
|
|
||||||
def _update_tray_icon():
|
def _update_tray_icon():
|
||||||
if _picked_device:
|
if _picked_device:
|
||||||
_, _, name, _, device_status = _picked_device
|
_, _, name, device_status = _picked_device
|
||||||
battery_level = device_status.get(_K.BATTERY_LEVEL)
|
battery_level = device_status.get(_K.BATTERY_LEVEL)
|
||||||
battery_charging = device_status.get(_K.BATTERY_CHARGING)
|
battery_charging = device_status.get(_K.BATTERY_CHARGING)
|
||||||
tray_icon_name = _icons.battery(battery_level, battery_charging)
|
tray_icon_name = _icons.battery(battery_level, battery_charging)
|
||||||
|
@ -209,7 +210,7 @@ except ImportError:
|
||||||
_icon.set_tooltip_markup(tooltip)
|
_icon.set_tooltip_markup(tooltip)
|
||||||
|
|
||||||
if _picked_device:
|
if _picked_device:
|
||||||
_, _, name, _, device_status = _picked_device
|
_, _, name, device_status = _picked_device
|
||||||
battery_level = device_status.get(_K.BATTERY_LEVEL)
|
battery_level = device_status.get(_K.BATTERY_LEVEL)
|
||||||
battery_charging = device_status.get(_K.BATTERY_CHARGING)
|
battery_charging = device_status.get(_K.BATTERY_CHARGING)
|
||||||
tray_icon_name = _icons.battery(battery_level, battery_charging)
|
tray_icon_name = _icons.battery(battery_level, battery_charging)
|
||||||
|
@ -253,11 +254,10 @@ def _generate_tooltip_lines():
|
||||||
yield '<b>%s</b>' % NAME
|
yield '<b>%s</b>' % NAME
|
||||||
yield ''
|
yield ''
|
||||||
|
|
||||||
for _, serial, name, _, status in _devices_info:
|
for _, number, name, status in _devices_info:
|
||||||
if serial is None: # receiver
|
if number is None: # receiver
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
p = str(status)
|
p = str(status)
|
||||||
if p: # does it have any properties to print?
|
if p: # does it have any properties to print?
|
||||||
yield '<b>%s</b>' % name
|
yield '<b>%s</b>' % name
|
||||||
|
@ -306,7 +306,7 @@ def _add_device(device):
|
||||||
assert receiver_path
|
assert receiver_path
|
||||||
|
|
||||||
index = None
|
index = None
|
||||||
for idx, (path, _, _, _, _) in enumerate(_devices_info):
|
for idx, (path, _, _, _) in enumerate(_devices_info):
|
||||||
if path == receiver_path:
|
if path == receiver_path:
|
||||||
# the first entry matching the receiver serial should be for the receiver itself
|
# the first entry matching the receiver serial should be for the receiver itself
|
||||||
index = idx + 1
|
index = idx + 1
|
||||||
|
@ -315,8 +315,8 @@ def _add_device(device):
|
||||||
|
|
||||||
# proper ordering (according to device.number) for a receiver's devices
|
# proper ordering (according to device.number) for a receiver's devices
|
||||||
while True:
|
while True:
|
||||||
path, _, _, number, _ = _devices_info[index]
|
path, number, _, _ = _devices_info[index]
|
||||||
if path == '-':
|
if path == _RECEIVER_SEPARATOR[0]:
|
||||||
break
|
break
|
||||||
assert path == receiver_path
|
assert path == receiver_path
|
||||||
assert number != device.number
|
assert number != device.number
|
||||||
|
@ -324,7 +324,8 @@ def _add_device(device):
|
||||||
break
|
break
|
||||||
index = index + 1
|
index = index + 1
|
||||||
|
|
||||||
new_device_info = (receiver_path, device.serial, device.name, device.number, device.status)
|
new_device_info = (receiver_path, device.number, device.name, device.status)
|
||||||
|
assert len(new_device_info) == len(_RECEIVER_SEPARATOR)
|
||||||
_devices_info.insert(index, new_device_info)
|
_devices_info.insert(index, new_device_info)
|
||||||
|
|
||||||
# label_prefix = b'\xE2\x94\x84 '.decode('utf-8')
|
# label_prefix = b'\xE2\x94\x84 '.decode('utf-8')
|
||||||
|
@ -333,7 +334,7 @@ def _add_device(device):
|
||||||
new_menu_item = Gtk.ImageMenuItem.new_with_label(label_prefix + device.name)
|
new_menu_item = Gtk.ImageMenuItem.new_with_label(label_prefix + device.name)
|
||||||
new_menu_item.set_image(Gtk.Image())
|
new_menu_item.set_image(Gtk.Image())
|
||||||
new_menu_item.show_all()
|
new_menu_item.show_all()
|
||||||
new_menu_item.connect('activate', _window_popup, receiver_path, device.serial)
|
new_menu_item.connect('activate', _window_popup, receiver_path, device.number)
|
||||||
_menu.insert(new_menu_item, index)
|
_menu.insert(new_menu_item, index)
|
||||||
|
|
||||||
return index
|
return index
|
||||||
|
@ -347,7 +348,7 @@ def _remove_device(index):
|
||||||
|
|
||||||
removed_device = _devices_info.pop(index)
|
removed_device = _devices_info.pop(index)
|
||||||
global _picked_device
|
global _picked_device
|
||||||
if _picked_device and _picked_device[1] == removed_device[1]:
|
if _picked_device and _picked_device[0:2] == removed_device[0:2]:
|
||||||
# the current pick was unpaired
|
# the current pick was unpaired
|
||||||
_picked_device = None
|
_picked_device = None
|
||||||
|
|
||||||
|
@ -355,8 +356,9 @@ def _remove_device(index):
|
||||||
def _add_receiver(receiver):
|
def _add_receiver(receiver):
|
||||||
index = len(_devices_info)
|
index = len(_devices_info)
|
||||||
|
|
||||||
device_info = (receiver.path, None, receiver.name, None, None)
|
new_receiver_info = (receiver.path, None, receiver.name, None)
|
||||||
_devices_info.append(device_info)
|
assert len(new_receiver_info) == len(_RECEIVER_SEPARATOR)
|
||||||
|
_devices_info.append(new_receiver_info)
|
||||||
|
|
||||||
new_menu_item = Gtk.ImageMenuItem.new_with_label(receiver.name)
|
new_menu_item = Gtk.ImageMenuItem.new_with_label(receiver.name)
|
||||||
_menu.insert(new_menu_item, index)
|
_menu.insert(new_menu_item, index)
|
||||||
|
@ -365,7 +367,7 @@ def _add_receiver(receiver):
|
||||||
new_menu_item.show_all()
|
new_menu_item.show_all()
|
||||||
new_menu_item.connect('activate', _window_popup, receiver.path)
|
new_menu_item.connect('activate', _window_popup, receiver.path)
|
||||||
|
|
||||||
_devices_info.append(('-', None, None, None, None))
|
_devices_info.append(_RECEIVER_SEPARATOR)
|
||||||
separator = Gtk.SeparatorMenuItem.new()
|
separator = Gtk.SeparatorMenuItem.new()
|
||||||
separator.set_visible(True)
|
separator.set_visible(True)
|
||||||
_menu.insert(separator, index + 1)
|
_menu.insert(separator, index + 1)
|
||||||
|
@ -379,11 +381,11 @@ def _remove_receiver(receiver):
|
||||||
|
|
||||||
# remove all entries in devices_info that match this receiver
|
# remove all entries in devices_info that match this receiver
|
||||||
while index < len(_devices_info):
|
while index < len(_devices_info):
|
||||||
path, _, _, _, _ = _devices_info[index]
|
path, _, _, _ = _devices_info[index]
|
||||||
if path == receiver.path:
|
if path == receiver.path:
|
||||||
found = True
|
found = True
|
||||||
_remove_device(index)
|
_remove_device(index)
|
||||||
elif found and path == '-':
|
elif found and path == _RECEIVER_SEPARATOR[0]:
|
||||||
# the separator after this receiver
|
# the separator after this receiver
|
||||||
_remove_device(index)
|
_remove_device(index)
|
||||||
break
|
break
|
||||||
|
@ -411,10 +413,13 @@ def _update_menu_item(index, device):
|
||||||
#
|
#
|
||||||
|
|
||||||
# for which device to show the battery info in systray, if more than one
|
# for which device to show the battery info in systray, if more than one
|
||||||
|
# it's actually an entry in _devices_info
|
||||||
_picked_device = None
|
_picked_device = None
|
||||||
|
|
||||||
# cached list of devices and some of their properties
|
# cached list of devices and some of their properties
|
||||||
|
# contains tuples of (receiver path, device number, name, status)
|
||||||
_devices_info = []
|
_devices_info = []
|
||||||
|
|
||||||
_menu = None
|
_menu = None
|
||||||
_icon = None
|
_icon = None
|
||||||
|
|
||||||
|
@ -449,7 +454,7 @@ def update(device=None):
|
||||||
receiver_path = device.path
|
receiver_path = device.path
|
||||||
if is_alive:
|
if is_alive:
|
||||||
index = None
|
index = None
|
||||||
for idx, (path, _, _, _, _) in enumerate(_devices_info):
|
for idx, (path, _, _, _) in enumerate(_devices_info):
|
||||||
if path == receiver_path:
|
if path == receiver_path:
|
||||||
index = idx
|
index = idx
|
||||||
break
|
break
|
||||||
|
@ -464,8 +469,8 @@ def update(device=None):
|
||||||
is_paired = bool(device)
|
is_paired = bool(device)
|
||||||
receiver_path = device.receiver.path
|
receiver_path = device.receiver.path
|
||||||
index = None
|
index = None
|
||||||
for idx, (path, serial, name, _, _) in enumerate(_devices_info):
|
for idx, (path, number, _, _) in enumerate(_devices_info):
|
||||||
if path == receiver_path and serial == device.serial:
|
if path == receiver_path and number == device.number:
|
||||||
index = idx
|
index = idx
|
||||||
|
|
||||||
if is_paired:
|
if is_paired:
|
||||||
|
|
|
@ -8,7 +8,7 @@ from logging import getLogger, DEBUG as _DEBUG
|
||||||
_log = getLogger(__name__)
|
_log = getLogger(__name__)
|
||||||
del getLogger
|
del getLogger
|
||||||
|
|
||||||
from gi.repository import Gtk, Gdk
|
from gi.repository import Gtk, Gdk, GLib
|
||||||
from gi.repository.GObject import TYPE_PYOBJECT
|
from gi.repository.GObject import TYPE_PYOBJECT
|
||||||
|
|
||||||
from solaar import NAME
|
from solaar import NAME
|
||||||
|
@ -32,9 +32,9 @@ _INFO_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
|
||||||
_DEVICE_ICON_SIZE = Gtk.IconSize.DND
|
_DEVICE_ICON_SIZE = Gtk.IconSize.DND
|
||||||
|
|
||||||
# tree model columns
|
# tree model columns
|
||||||
_COLUMN = _NamedInts(ID=0, ACTIVE=1, NAME=2, ICON=3, STATUS_ICON=4, DEVICE=5)
|
_COLUMN = _NamedInts(PATH=0, NUMBER=1, ACTIVE=2, NAME=3, ICON=4, STATUS_ICON=5, DEVICE=6)
|
||||||
_COLUMN_TYPES = (str, bool, str, str, str, TYPE_PYOBJECT)
|
_COLUMN_TYPES = (str, int, bool, str, str, str, TYPE_PYOBJECT)
|
||||||
_TREE_SEPATATOR = (None, False, None, None, None, None)
|
_TREE_SEPATATOR = (None, 0, False, None, None, None, None)
|
||||||
|
|
||||||
_TOOLTIP_LINK_SECURE = 'The wireless link between this device and its receiver is not encrypted.'
|
_TOOLTIP_LINK_SECURE = 'The wireless link between this device and its receiver is not encrypted.'
|
||||||
_TOOLTIP_LINK_INSECURE = ('The wireless link between this device and its receiver is not encrypted.\n'
|
_TOOLTIP_LINK_INSECURE = ('The wireless link between this device and its receiver is not encrypted.\n'
|
||||||
|
@ -169,6 +169,7 @@ def _create_buttons_box():
|
||||||
assert _find_selected_device_id() is not None
|
assert _find_selected_device_id() is not None
|
||||||
receiver = _find_selected_device()
|
receiver = _find_selected_device()
|
||||||
assert receiver is not None
|
assert receiver is not None
|
||||||
|
assert bool(receiver)
|
||||||
assert receiver.kind is None
|
assert receiver.kind is None
|
||||||
_action.pair(_window, receiver)
|
_action.pair(_window, receiver)
|
||||||
|
|
||||||
|
@ -179,6 +180,7 @@ def _create_buttons_box():
|
||||||
assert _find_selected_device_id() is not None
|
assert _find_selected_device_id() is not None
|
||||||
device = _find_selected_device()
|
device = _find_selected_device()
|
||||||
assert device is not None
|
assert device is not None
|
||||||
|
assert bool(device)
|
||||||
assert device.kind is not None
|
assert device.kind is not None
|
||||||
_action.unpair(_window, device)
|
_action.unpair(_window, device)
|
||||||
|
|
||||||
|
@ -239,7 +241,7 @@ def _create_tree(model):
|
||||||
tree.set_model(model)
|
tree.set_model(model)
|
||||||
|
|
||||||
def _is_separator(model, item, _=None):
|
def _is_separator(model, item, _=None):
|
||||||
return model.get_value(item, _COLUMN.ID) is None
|
return model.get_value(item, _COLUMN.PATH) is None
|
||||||
tree.set_row_separator_func(_is_separator, None)
|
tree.set_row_separator_func(_is_separator, None)
|
||||||
|
|
||||||
icon_cell_renderer = Gtk.CellRendererPixbuf()
|
icon_cell_renderer = Gtk.CellRendererPixbuf()
|
||||||
|
@ -348,7 +350,8 @@ def _find_selected_device():
|
||||||
def _find_selected_device_id():
|
def _find_selected_device_id():
|
||||||
selection = _tree.get_selection()
|
selection = _tree.get_selection()
|
||||||
model, item = selection.get_selected()
|
model, item = selection.get_selected()
|
||||||
return model.get_value(item, _COLUMN.ID) if item else None
|
if item:
|
||||||
|
return _model.get_value(item, _COLUMN.PATH), _model.get_value(item, _COLUMN.NUMBER)
|
||||||
|
|
||||||
|
|
||||||
# triggered by changing selection in the tree
|
# triggered by changing selection in the tree
|
||||||
|
@ -363,17 +366,18 @@ def _receiver_row(receiver_path, receiver=None):
|
||||||
|
|
||||||
item = _model.get_iter_first()
|
item = _model.get_iter_first()
|
||||||
while item:
|
while item:
|
||||||
if _model.get_value(item, _COLUMN.ID) == receiver_path:
|
# first row matching the path must be the receiver one
|
||||||
|
if _model.get_value(item, _COLUMN.PATH) == receiver_path:
|
||||||
return item
|
return item
|
||||||
item = _model.iter_next(item)
|
item = _model.iter_next(item)
|
||||||
|
|
||||||
if not item and receiver:
|
if not item and receiver:
|
||||||
icon_name = _icons.device_icon_name(receiver.name)
|
icon_name = _icons.device_icon_name(receiver.name)
|
||||||
pairing_icon_name = ''
|
pairing_icon_name = ''
|
||||||
row_data = (receiver_path, True, receiver.name, icon_name, pairing_icon_name, receiver)
|
row_data = (receiver_path, 0, True, receiver.name, icon_name, pairing_icon_name, receiver)
|
||||||
if _log.isEnabledFor(_DEBUG):
|
assert len(row_data) == len(_TREE_SEPATATOR)
|
||||||
_log.debug("new receiver row %s", row_data)
|
# if _log.isEnabledFor(_DEBUG):
|
||||||
# _log.debug("receiver %s", receiver)
|
# _log.debug("new receiver row %s", row_data)
|
||||||
item = _model.append(None, row_data)
|
item = _model.append(None, row_data)
|
||||||
if _TREE_SEPATATOR:
|
if _TREE_SEPATATOR:
|
||||||
_model.append(None, _TREE_SEPATATOR)
|
_model.append(None, _TREE_SEPATATOR)
|
||||||
|
@ -381,24 +385,25 @@ def _receiver_row(receiver_path, receiver=None):
|
||||||
return item or None
|
return item or None
|
||||||
|
|
||||||
|
|
||||||
def _device_row(receiver_path, device_serial, device=None):
|
def _device_row(receiver_path, device_number, device=None):
|
||||||
assert receiver_path
|
assert receiver_path
|
||||||
assert device_serial
|
assert device_number is not None
|
||||||
|
|
||||||
receiver_row = _receiver_row(receiver_path, None if device is None else device.receiver)
|
receiver_row = _receiver_row(receiver_path, None if device is None else device.receiver)
|
||||||
item = _model.iter_children(receiver_row)
|
item = _model.iter_children(receiver_row)
|
||||||
while item:
|
while item:
|
||||||
if _model.get_value(item, _COLUMN.ID) == device_serial:
|
if ((_model.get_value(item, _COLUMN.PATH) == receiver_path) and
|
||||||
|
(_model.get_value(item, _COLUMN.NUMBER) == device_number)):
|
||||||
return item
|
return item
|
||||||
item = _model.iter_next(item)
|
item = _model.iter_next(item)
|
||||||
|
|
||||||
if not item and device:
|
if not item and device:
|
||||||
icon_name = _icons.device_icon_name(device.name, device.kind)
|
icon_name = _icons.device_icon_name(device.name, device.kind)
|
||||||
battery_icon_name = ''
|
battery_icon_name = ''
|
||||||
row_data = (device_serial, bool(device.online), device.codename, icon_name, battery_icon_name, device)
|
row_data = (receiver_path, device_number, bool(device.online), device.codename, icon_name, battery_icon_name, device)
|
||||||
if _log.isEnabledFor(_DEBUG):
|
assert len(row_data) == len(_TREE_SEPATATOR)
|
||||||
_log.debug("new device row %s", row_data)
|
# if _log.isEnabledFor(_DEBUG):
|
||||||
# _log.debug("device %s", device)
|
# _log.debug("new device row %s", row_data)
|
||||||
item = _model.append(receiver_row, row_data)
|
item = _model.append(receiver_row, row_data)
|
||||||
|
|
||||||
return item or None
|
return item or None
|
||||||
|
@ -407,18 +412,18 @@ def _device_row(receiver_path, device_serial, device=None):
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
def select(receiver_path, device_id=None):
|
def select(receiver_path, device_number=None):
|
||||||
assert _window
|
assert _window
|
||||||
assert receiver_path is not None
|
assert receiver_path is not None
|
||||||
if device_id is None:
|
if device_number is None:
|
||||||
item = _receiver_row(receiver_path)
|
item = _receiver_row(receiver_path)
|
||||||
else:
|
else:
|
||||||
item = _device_row(receiver_path, device_id)
|
item = _device_row(receiver_path, device_number)
|
||||||
if item:
|
if item:
|
||||||
selection = _tree.get_selection()
|
selection = _tree.get_selection()
|
||||||
selection.select_iter(item)
|
selection.select_iter(item)
|
||||||
else:
|
else:
|
||||||
_log.warn("select(%s, %s) failed to find an item", receiver_path, device_id)
|
_log.warn("select(%s, %s) failed to find an item", receiver_path, device_number)
|
||||||
|
|
||||||
|
|
||||||
def _hide(w, _=None):
|
def _hide(w, _=None):
|
||||||
|
@ -451,8 +456,6 @@ def toggle(trigger=None):
|
||||||
def _update_details(button):
|
def _update_details(button):
|
||||||
assert button
|
assert button
|
||||||
visible = button.get_active()
|
visible = button.get_active()
|
||||||
device = _find_selected_device()
|
|
||||||
assert device
|
|
||||||
|
|
||||||
if visible:
|
if visible:
|
||||||
# _details._text.set_markup('<small>reading...</small>')
|
# _details._text.set_markup('<small>reading...</small>')
|
||||||
|
@ -480,7 +483,9 @@ def _update_details(button):
|
||||||
flag_names = ('(none)',) if flag_bits == 0 else _hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)
|
flag_names = ('(none)',) if flag_bits == 0 else _hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)
|
||||||
yield ('Notifications', ('\n%15s' % ' ').join(flag_names))
|
yield ('Notifications', ('\n%15s' % ' ').join(flag_names))
|
||||||
|
|
||||||
items = _details_items(device)
|
selected_device = _find_selected_device()
|
||||||
|
assert selected_device
|
||||||
|
items = _details_items(selected_device)
|
||||||
text = '\n'.join('%-13s: %s' % i for i in items if i)
|
text = '\n'.join('%-13s: %s' % i for i in items if i)
|
||||||
_details._text.set_markup('<small><tt>' + text + '</tt></small>')
|
_details._text.set_markup('<small><tt>' + text + '</tt></small>')
|
||||||
|
|
||||||
|
@ -502,7 +507,7 @@ def _update_receiver_panel(receiver, panel, buttons, full=False):
|
||||||
else:
|
else:
|
||||||
panel._count.set_markup(_NANO_RECEIVER_TEXT[1])
|
panel._count.set_markup(_NANO_RECEIVER_TEXT[1])
|
||||||
|
|
||||||
is_pairing = receiver and receiver.status.lock_open
|
is_pairing = receiver.status.lock_open
|
||||||
if is_pairing:
|
if is_pairing:
|
||||||
panel._scanning.set_visible(True)
|
panel._scanning.set_visible(True)
|
||||||
if not panel._spinner.get_visible():
|
if not panel._spinner.get_visible():
|
||||||
|
@ -683,12 +688,13 @@ def update(device, need_popup=False):
|
||||||
assert item
|
assert item
|
||||||
|
|
||||||
if is_alive and item:
|
if is_alive and item:
|
||||||
_model.set_value(item, _COLUMN.ACTIVE, True)
|
was_pairing = bool(_model.get_value(item, _COLUMN.STATUS_ICON))
|
||||||
is_pairing = is_alive and device.status.lock_open
|
is_pairing = bool(device.status.lock_open)
|
||||||
_model.set_value(item, _COLUMN.STATUS_ICON, 'network-wireless' if is_pairing else '')
|
_model.set_value(item, _COLUMN.STATUS_ICON, 'network-wireless' if is_pairing else '')
|
||||||
|
|
||||||
if selected_device_id == device.path:
|
if selected_device_id == (device.path, 0):
|
||||||
_update_info_panel(device, need_popup)
|
full_update = need_popup or was_pairing != is_pairing
|
||||||
|
_update_info_panel(device, full=full_update)
|
||||||
|
|
||||||
elif item:
|
elif item:
|
||||||
if _TREE_SEPATATOR:
|
if _TREE_SEPATATOR:
|
||||||
|
@ -700,8 +706,8 @@ def update(device, need_popup=False):
|
||||||
# peripheral
|
# peripheral
|
||||||
is_paired = bool(device)
|
is_paired = bool(device)
|
||||||
assert device.receiver
|
assert device.receiver
|
||||||
assert device.serial
|
assert device.number is not None and device.number > 0, "invalid device number" + str(device.number)
|
||||||
item = _device_row(device.receiver.path, device.serial, device if is_paired else None)
|
item = _device_row(device.receiver.path, device.number, device if is_paired else None)
|
||||||
|
|
||||||
if is_paired and item:
|
if is_paired and item:
|
||||||
was_online = _model.get_value(item, _COLUMN.ACTIVE)
|
was_online = _model.get_value(item, _COLUMN.ACTIVE)
|
||||||
|
@ -717,14 +723,14 @@ def update(device, need_popup=False):
|
||||||
_model.set_value(item, _COLUMN.STATUS_ICON, icon_name)
|
_model.set_value(item, _COLUMN.STATUS_ICON, icon_name)
|
||||||
|
|
||||||
if selected_device_id is None:
|
if selected_device_id is None:
|
||||||
select(device.receiver.path, device.serial)
|
select(device.receiver.path, device.number)
|
||||||
elif selected_device_id == device.serial:
|
elif selected_device_id == (device.receiver.path, device.number):
|
||||||
full_update = need_popup or was_online != is_online
|
full_update = need_popup or was_online != is_online
|
||||||
_update_info_panel(device, full=full_update)
|
_update_info_panel(device, full=full_update)
|
||||||
|
|
||||||
elif item:
|
elif item:
|
||||||
_model.remove(item)
|
_model.remove(item)
|
||||||
_config_panel.clean(device.serial)
|
_config_panel.clean(device)
|
||||||
|
|
||||||
# make sure all rows are visible
|
# make sure all rows are visible
|
||||||
_tree.expand_all()
|
_tree.expand_all()
|
||||||
|
|
Loading…
Reference in New Issue