device: remove status from Device and Receiver

This commit is contained in:
Peter F. Patel-Schneider 2024-03-10 09:17:26 -04:00
parent a1418cd834
commit 9c5ba6445e
11 changed files with 91 additions and 172 deletions

View File

@ -77,7 +77,8 @@ class Device:
self.hidpp_short = device_info.hidpp_short if device_info else None
self.hidpp_long = device_info.hidpp_long if device_info else None
self.bluetooth = device_info.bus_id == 0x0005 if device_info else False # Bluetooth needs long messages
self.setting_callback = setting_callback
self.setting_callback = setting_callback # for changes to settings
self.status_callback = None # for changes to other potentially visible aspects
self.wpid = pairing_info["wpid"] if pairing_info else None # the Wireless PID is unique per device model
self._kind = pairing_info["kind"] if pairing_info else None # mouse, keyboard, etc (see hidpp10.DEVICE_KIND)
self._serial = pairing_info["serial"] if pairing_info else None # serial number (an 8-char hex string)
@ -412,7 +413,6 @@ class Device:
def changed(self, active=None, alert=ALERT.NONE, reason=None, push=False):
"""The status of the device had changed, so invoke the status callback.
Also push notifications and settings to the device when necessary."""
changed_callback = self.status._changed_callback
if active is not None:
self.online = active
was_active, self._active = self._active, active
@ -434,7 +434,8 @@ class Device:
settings.apply_all_settings(self)
if logger.isEnabledFor(logging.DEBUG):
logger.debug("device %d changed: active=%s %s", self.number, self._active, self.battery_info)
changed_callback(self, alert, reason)
if self.status_callback is not None:
self.status_callback(self, alert, reason)
def add_notification_handler(self, id: str, fn):
"""Adds the notification handling callback `fn` to this device under name `id`.

View File

@ -495,20 +495,20 @@ class Rule(RuleComponent):
source = "(" + self.source + ")" if self.source else ""
return "Rule%s[%s]" % (source, ", ".join([c.__str__() for c in self.components]))
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate rule: %s", self)
result = True
for component in self.components:
result = component.evaluate(feature, notification, device, status, result)
result = component.evaluate(feature, notification, device, result)
if not isinstance(component, Action) and result is None:
return None
if isinstance(component, Condition) and not result:
return result
return result
def once(self, feature, notification, device, status, last_result):
self.evaluate(feature, notification, device, status, last_result)
def once(self, feature, notification, device, last_result):
self.evaluate(feature, notification, device, last_result)
return False
def data(self):
@ -522,7 +522,7 @@ class Condition(RuleComponent):
def __str__(self):
return "CONDITION"
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return False
@ -538,10 +538,10 @@ class Not(Condition):
def __str__(self):
return "Not: " + str(self.component)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
result = self.component.evaluate(feature, notification, device, status, last_result)
result = self.component.evaluate(feature, notification, device, last_result)
return None if result is None else not result
def data(self):
@ -555,12 +555,12 @@ class Or(Condition):
def __str__(self):
return "Or: [" + ", ".join(str(c) for c in self.components) + "]"
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
result = False
for component in self.components:
result = component.evaluate(feature, notification, device, status, last_result)
result = component.evaluate(feature, notification, device, last_result)
if not isinstance(component, Action) and result is None:
return None
if isinstance(component, Condition) and result:
@ -578,12 +578,12 @@ class And(Condition):
def __str__(self):
return "And: [" + ", ".join(str(c) for c in self.components) + "]"
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
result = True
for component in self.components:
result = component.evaluate(feature, notification, device, status, last_result)
result = component.evaluate(feature, notification, device, last_result)
if not isinstance(component, Action) and result is None:
return None
if isinstance(component, Condition) and not result:
@ -657,7 +657,7 @@ class Process(Condition):
def __str__(self):
return "Process: " + str(self.process)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
if not isinstance(self.process, str):
@ -688,7 +688,7 @@ class MouseProcess(Condition):
def __str__(self):
return "MouseProcess: " + str(self.process)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
if not isinstance(self.process, str):
@ -712,7 +712,7 @@ class Feature(Condition):
def __str__(self):
return "Feature: " + str(self.feature)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return feature == self.feature
@ -733,7 +733,7 @@ class Report(Condition):
def __str__(self):
return "Report: " + str(self.report)
def evaluate(self, report, notification, device, status, last_result):
def evaluate(self, report, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return (notification.address >> 4) == self.report
@ -755,7 +755,7 @@ class Setting(Condition):
def __str__(self):
return "Setting: " + " ".join([str(a) for a in self.args])
def evaluate(self, report, notification, device, status, last_result):
def evaluate(self, report, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
if len(self.args) < 3:
@ -806,7 +806,7 @@ class Modifiers(Condition):
def __str__(self):
return "Modifiers: " + str(self.desired)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
if gkeymap:
@ -863,7 +863,7 @@ class Key(Condition):
def __str__(self):
return "Key: %s (%s)" % ((str(self.key) if self.key else "None"), self.action)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return bool(self.key and self.key == (key_down if self.action == self.DOWN else key_up))
@ -895,7 +895,7 @@ class KeyIsDown(Condition):
def __str__(self):
return "KeyIsDown: %s" % (str(self.key) if self.key else "None")
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return key_is_down(self.key)
@ -949,7 +949,7 @@ class Test(Condition):
def __str__(self):
return "Test: " + str(self.test)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return self.function(feature, notification.address, notification.data, self.parameter)
@ -979,7 +979,7 @@ class TestBytes(Condition):
def __str__(self):
return "TestBytes: " + str(self.test)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return self.function(feature, notification.address, notification.data)
@ -1012,7 +1012,7 @@ class MouseGesture(Condition):
def __str__(self):
return "MouseGesture: " + " ".join(self.movements)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
if feature == _F.MOUSE_GESTURE:
@ -1054,7 +1054,7 @@ class Active(Condition):
def __str__(self):
return "Active: " + str(self.devID)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
dev = device.find(self.devID)
@ -1075,7 +1075,7 @@ class Device(Condition):
def __str__(self):
return "Device: " + str(self.devID)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
return device.unitId == self.devID or device.serial == self.devID
@ -1095,7 +1095,7 @@ class Host(Condition):
def __str__(self):
return "Host: " + str(self.host)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
hostname = socket.getfqdn()
@ -1109,7 +1109,7 @@ class Action(RuleComponent):
def __init__(self, *args):
pass
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
return None
@ -1189,7 +1189,7 @@ class KeyPress(Action):
simulate_key(keycode, _KEY_RELEASE)
self.mods(level, modifiers, _KEY_RELEASE)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if gkeymap:
current = gkeymap.get_modifier_state()
if logger.isEnabledFor(logging.INFO):
@ -1209,10 +1209,10 @@ class KeyPress(Action):
# KeyDown is dangerous as the key can auto-repeat and make your system unusable
# class KeyDown(KeyPress):
# def evaluate(self, feature, notification, device, status, last_result):
# def evaluate(self, feature, notification, device, last_result):
# super().keyDown(self.keys, current_key_modifiers)
# class KeyUp(KeyPress):
# def evaluate(self, feature, notification, device, status, last_result):
# def evaluate(self, feature, notification, device, last_result):
# super().keyUp(self.keys, current_key_modifiers)
@ -1229,7 +1229,7 @@ class MouseScroll(Action):
def __str__(self):
return "MouseScroll: " + " ".join([str(a) for a in self.amounts])
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
amounts = self.amounts
if isinstance(last_result, numbers.Number):
amounts = [math.floor(last_result * a) for a in self.amounts]
@ -1268,7 +1268,7 @@ class MouseClick(Action):
def __str__(self):
return "MouseClick: %s (%d)" % (self.button, self.count)
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.INFO):
logger.info("MouseClick action: %d %s" % (self.count, self.button))
if self.button and self.count:
@ -1292,7 +1292,7 @@ class Set(Action):
def __str__(self):
return "Set: " + " ".join([str(a) for a in self.args])
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if len(self.args) < 3:
return None
if logger.isEnabledFor(logging.INFO):
@ -1335,7 +1335,7 @@ class Execute(Action):
def __str__(self):
return "Execute: " + " ".join([a for a in self.args])
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if logger.isEnabledFor(logging.INFO):
logger.info("Execute action: %s", self.args)
subprocess.Popen(self.args)
@ -1366,9 +1366,9 @@ class Later(Action):
def __str__(self):
return "Later: [" + str(self.delay) + ", " + ", ".join(str(c) for c in self.components) + "]"
def evaluate(self, feature, notification, device, status, last_result):
def evaluate(self, feature, notification, device, last_result):
if self.delay and self.rule:
GLib.timeout_add_seconds(self.delay, Rule.once, self.rule, feature, notification, device, status, last_result)
GLib.timeout_add_seconds(self.delay, Rule.once, self.rule, feature, notification, device, last_result)
return None
def data(self):
@ -1435,14 +1435,14 @@ def key_is_down(key):
return key in keys_down
def evaluate_rules(feature, notification, device, status):
def evaluate_rules(feature, notification, device):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluating rules on %s", notification)
rules.evaluate(feature, notification, device, status, True)
rules.evaluate(feature, notification, device, True)
# process a notification
def process_notification(device, status, notification, feature):
def process_notification(device, notification, feature):
global keys_down, g_keys_down, m_keys_down, mr_key_down, key_down, key_up, thumb_wheel_displacement
key_down, key_up = None, None
# need to keep track of keys that are down to find a new key down
@ -1487,7 +1487,7 @@ def process_notification(device, status, notification, feature):
thumb_wheel_displacement = 0
thumb_wheel_displacement += signed(notification.data[0:2])
GLib.idle_add(evaluate_rules, feature, notification, device, status)
GLib.idle_add(evaluate_rules, feature, notification, device)
_XDG_CONFIG_HOME = _os.environ.get("XDG_CONFIG_HOME") or _path.expanduser(_path.join("~", ".config"))

View File

@ -15,8 +15,7 @@
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Handles incoming events from the receiver/devices, updating the related
# status object as appropriate.
# Handles incoming events from the receiver/devices, updating the object as appropriate.
import logging
import threading as _threading
@ -29,10 +28,10 @@ from . import hidpp10_constants as _hidpp10_constants
from . import hidpp20_constants as _hidpp20_constants
from . import settings_templates as _st
from .base import DJ_MESSAGE_ID as _DJ_MESSAGE_ID
from .common import ALERT as _ALERT
from .common import Battery as _Battery
from .common import strhex as _strhex
from .i18n import _
from .status import ALERT as _ALERT
logger = logging.getLogger(__name__)
@ -49,17 +48,12 @@ def process(device, notification):
assert device
assert notification
assert hasattr(device, "status")
status = device.status
assert status is not None
if not device.isDevice:
return _process_receiver_notification(device, status, notification)
return _process_device_notification(device, status, notification)
return _process_receiver_notification(device, notification)
return _process_device_notification(device, notification)
def _process_receiver_notification(receiver, status, n):
def _process_receiver_notification(receiver, n):
# supposedly only 0x4x notifications arrive for the receiver
assert n.sub_id & 0x40 == 0x40
@ -148,7 +142,7 @@ def _process_receiver_notification(receiver, status, n):
logger.warning("%s: unhandled notification %s", receiver, n)
def _process_device_notification(device, status, n):
def _process_device_notification(device, n):
# incoming packets with SubId >= 0x80 are supposedly replies from HID++ 1.0 requests, should never get here
assert n.sub_id & 0x80 == 0
@ -163,9 +157,9 @@ def _process_device_notification(device, status, n):
# 0x40 to 0x7F appear to be HID++ 1.0 or DJ notifications
if n.sub_id >= 0x40:
if n.report_id == _DJ_MESSAGE_ID:
return _process_dj_notification(device, status, n)
return _process_dj_notification(device, n)
else:
return _process_hidpp10_notification(device, status, n)
return _process_hidpp10_notification(device, n)
# These notifications are from the device itself, so it must be active
device.online = True
@ -174,7 +168,7 @@ def _process_device_notification(device, status, n):
# some custom battery events for HID++ 1.0 devices
if device.protocol < 2.0:
return _process_hidpp10_custom_notification(device, status, n)
return _process_hidpp10_custom_notification(device, n)
# assuming 0x00 to 0x3F are feature (HID++ 2.0) notifications
if not device.features:
@ -186,10 +180,10 @@ def _process_device_notification(device, status, n):
logger.warning("%s: notification from invalid feature index %02X: %s", device, n.sub_id, n)
return False
return _process_feature_notification(device, status, n, feature)
return _process_feature_notification(device, n, feature)
def _process_dj_notification(device, status, n):
def _process_dj_notification(device, n):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("%s (%s) DJ %s", device, device.protocol, n)
@ -215,7 +209,7 @@ def _process_dj_notification(device, status, n):
logger.warning("%s: unrecognized DJ %s", device, n)
def _process_hidpp10_custom_notification(device, status, n):
def _process_hidpp10_custom_notification(device, n):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("%s (%s) custom notification %s", device, device.protocol, n)
@ -228,7 +222,7 @@ def _process_hidpp10_custom_notification(device, status, n):
logger.warning("%s: unrecognized %s", device, n)
def _process_hidpp10_notification(device, status, n):
def _process_hidpp10_notification(device, n):
if n.sub_id == 0x40: # device unpairing
if n.address == 0x02:
# device un-paired
@ -236,7 +230,7 @@ def _process_hidpp10_notification(device, status, n):
if device.number in device.receiver:
del device.receiver[device.number]
device.changed(active=False, alert=_ALERT.ALL, reason=_("unpaired"))
device.status = None
## device.status = None
else:
logger.warning("%s: disconnection with unknown type %02X: %s", device, n.address, n)
return True
@ -289,7 +283,7 @@ def _process_hidpp10_notification(device, status, n):
logger.warning("%s: unrecognized %s", device, n)
def _process_feature_notification(device, status, n, feature):
def _process_feature_notification(device, n, feature):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("%s: notification for feature %s, report %s, data %s", device, feature, n.address >> 4, _strhex(n.data))
@ -440,5 +434,5 @@ def _process_feature_notification(device, status, n, feature):
device.setting_callback(device, _st.AdjustableDpi, [profile.resolutions[resolution_index]])
break
_diversion.process_notification(device, status, n, feature)
_diversion.process_notification(device, n, feature)
return True

View File

@ -66,7 +66,8 @@ class Receiver:
self.handle = handle
self.path = path
self.product_id = product_id
self.setting_callback = setting_callback
self.setting_callback = setting_callback # for changes to settings
self.status_callback = None # for changes to other potentially visible aspects
self.receiver_kind = receiver_kind
self.serial = None
self.max_devices = None
@ -105,7 +106,8 @@ class Receiver:
def changed(self, alert=ALERT.NOTIFICATION, reason=None):
"""The status of the device had changed, so invoke the status callback"""
self.status._changed_callback(self, alert=alert, reason=reason)
if self.status_callback is not None:
self.status_callback(self, alert=alert, reason=reason)
@property
def firmware(self):

View File

@ -841,7 +841,7 @@ class MouseGesturesXY(_RawXYProcessing):
logger.info("mouse gesture notification %s", self.data)
payload = _pack("!" + (len(self.data) * "h"), *self.data)
notification = _HIDPP_Notification(0, 0, 0, 0, payload)
_process_notification(self.device, self.device.status, notification, _F.MOUSE_GESTURE)
_process_notification(self.device, notification, _F.MOUSE_GESTURE)
self.fsmState = "idle"
def move_action(self, dx, dy):

View File

@ -1,70 +0,0 @@
## Copyright (C) 2012-2013 Daniel Pavel
## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import logging
from . import hidpp10
from . import hidpp10_constants as _hidpp10_constants
from .common import NamedInts
logger = logging.getLogger(__name__)
_R = _hidpp10_constants.REGISTERS
_hidpp10 = hidpp10.Hidpp10()
ALERT = NamedInts(NONE=0x00, NOTIFICATION=0x01, SHOW_WINDOW=0x02, ATTENTION=0x04, ALL=0xFF)
def attach_to(device, changed_callback):
assert device
assert changed_callback
if not hasattr(device, "status") or device.status is None:
if not device.isDevice:
device.status = ReceiverStatus(device, changed_callback)
else:
device.status = DeviceStatus(device, changed_callback)
class ReceiverStatus:
"""The 'runtime' status of a receiver, currently vestigial."""
def __init__(self, receiver, changed_callback):
assert receiver
self._receiver = receiver
assert changed_callback
self._changed_callback = changed_callback
class DeviceStatus:
"""Holds the 'runtime' status of a peripheral
Currently _active, battery, link_encrypted, notification_flags, error
Updates mostly come from incoming notification events from the device itself.
"""
def __init__(self, device, changed_callback):
assert device
self._device = device
assert changed_callback
self._changed_callback = changed_callback
self._active = None # is the device active?
def __bool__(self):
return bool(self._active)
__nonzero__ = __bool__

View File

@ -20,7 +20,6 @@ from logitech_receiver import base as _base
from logitech_receiver import hidpp10
from logitech_receiver import hidpp10_constants as _hidpp10_constants
from logitech_receiver import notifications as _notifications
from logitech_receiver import status as _status
_hidpp10 = hidpp10.Hidpp10()
_R = _hidpp10_constants.REGISTERS
@ -38,7 +37,6 @@ def run(receivers, args, find_receiver, _ignore):
receiver = receivers[0]
assert receiver
receiver.status = _status.ReceiverStatus(receiver, lambda *args, **kwargs: None)
# check if it's necessary to set the notification flags
old_notification_flags = _hidpp10.get_notification_flags(receiver) or 0

View File

@ -31,7 +31,6 @@ from logitech_receiver import exceptions
from logitech_receiver import hidpp10_constants as _hidpp10_constants
from logitech_receiver import listener as _listener
from logitech_receiver import notifications as _notifications
from logitech_receiver import status as _status
from . import configuration
@ -44,15 +43,13 @@ _R = _hidpp10_constants.REGISTERS
_IR = _hidpp10_constants.INFO_SUBREGISTERS
_GHOST_DEVICE = namedtuple("_GHOST_DEVICE", ("receiver", "number", "name", "kind", "status", "online"))
_GHOST_DEVICE = namedtuple("_GHOST_DEVICE", ("receiver", "number", "name", "kind", "online"))
_GHOST_DEVICE.__bool__ = lambda self: False
_GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__
def _ghost(device):
return _GHOST_DEVICE(
receiver=device.receiver, number=device.number, name=device.name, kind=device.kind, status=None, online=False
)
return _GHOST_DEVICE(receiver=device.receiver, number=device.number, name=device.name, kind=device.kind, online=False)
class ReceiverListener(_listener.EventsListener):
@ -62,7 +59,7 @@ class ReceiverListener(_listener.EventsListener):
assert status_changed_callback
super().__init__(receiver, self._notifications_handler)
self.status_changed_callback = status_changed_callback
_status.attach_to(receiver, self._status_changed)
receiver.status_callback = self._status_changed
def has_started(self):
if logger.isEnabledFor(logging.INFO):
@ -95,32 +92,30 @@ class ReceiverListener(_listener.EventsListener):
logger.exception("closing receiver %s" % r.path)
self.status_changed_callback(r)
def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None):
def _status_changed(self, device, alert=None, reason=None):
assert device is not None
if logger.isEnabledFor(logging.INFO):
try:
device.ping()
if device.kind is None:
logger.info(
"status_changed %r: %s, %s (%X) %s",
"status_changed %r: %s (%X) %s",
device,
"present" if bool(device) else "removed",
device.status,
alert,
alert if alert is not None else 0,
reason or "",
)
else:
device.ping()
logger.info(
"status_changed %r: %s %s, %s (%X) %s",
"status_changed %r: %s %s (%X) %s",
device,
"paired" if bool(device) else "unpaired",
"online" if device.online else "offline",
device.status,
alert,
alert if alert is not None else 0,
reason or "",
)
except Exception:
logger.info("status_changed for unknown device")
except Exception as e:
logger.info("status_changed for unknown device: %s", e)
if device.kind is None:
assert device == self.receiver
@ -214,15 +209,11 @@ class ReceiverListener(_listener.EventsListener):
# If there are saved configs, bring the device's settings up-to-date.
# They will be applied when the device is marked as online.
configuration.attach_to(dev)
_status.attach_to(dev, self._status_changed)
dev.status_callback = self._status_changed
# the receiver changed status as well
self._status_changed(self.receiver)
if not hasattr(dev, "status") or dev.status is None:
# notification before device status set up - don't process it
logger.warning("%s before device %s has status", n, dev)
else:
_notifications.process(dev, n)
_notifications.process(dev, n)
if self.receiver.pairing.lock_open and not already_known:
# this should be the first notification after a device was paired
@ -297,8 +288,8 @@ def ping_all(resuming=False):
count = listener_thread.receiver.count()
if count:
for dev in listener_thread.receiver:
if resuming and hasattr(dev, "status"):
dev.status._active = None # ensure that settings are pushed
if resuming:
dev._active = None # ensure that settings are pushed
if dev.ping():
dev.changed(active=True, push=True)
listener_thread._status_changed(dev)

View File

@ -19,7 +19,7 @@ import logging
import gi
import yaml as _yaml
from logitech_receiver.status import ALERT
from logitech_receiver.common import ALERT
from solaar.i18n import _
from solaar.ui.config_panel import change_setting, record_setting
@ -115,6 +115,8 @@ def _status_changed(device, alert, reason, refresh=False):
assert device is not None
if logger.isEnabledFor(logging.DEBUG):
logger.debug("status changed: %s (%s) %s", device, alert, reason)
if alert is None:
alert = ALERT.NONE
tray.update(device)
if alert & ALERT.ATTENTION:

View File

@ -113,20 +113,21 @@ if available:
if reason:
message = reason
elif dev.status is None:
message = _("unpaired")
elif bool(dev.status):
message = dev.status_string() or _("connected")
else:
message = _("offline")
message = _("unspecified reason")
# elif dev.status is None:
# message = _("unpaired")
# elif bool(dev.status):
# message = dev.status_string() or _("connected")
# else:
# message = _("offline")
# we need to use the filename here because the notifications daemon
# is an external application that does not know about our icon sets
icon_file = _icons.device_icon_file(dev.name, dev.kind) if icon is None else _icons.icon_file(icon)
n.update(summary, message, icon_file)
urgency = Notify.Urgency.LOW if dev.status else Notify.Urgency.NORMAL
n.set_urgency(urgency)
n.set_urgency(Notify.Urgency.NORMAL)
n.set_hint("desktop-entry", GLib.Variant("s", NAME.lower()))
if progress:
n.set_hint("value", GLib.Variant("i", progress))

View File

@ -420,7 +420,7 @@ def _remove_receiver(receiver):
def _update_menu_item(index, device):
if device is None or device.status is None:
if device is None:
logger.warning("updating an inactive device %s, assuming disconnected", device)
return None