headset RGB: re-overlay per-zone paint after onboard cluster writes
Writing the 0x0621 onboard cluster effect re-fills every LED uniformly, which the headset firmware treats as dropping the host per-zone buffer. HeadsetLEDControl.write already re-asserted the per-zone layer on re-claim, but HeadsetOnboardEffect.write did not — so changing the LEDs Primary color clobbered individually-painted zones with the flat base color and never restored them. Extract the re-assert logic into _headset_reassert_zone_layer (repaint every zone to LEDs Primary, then overlay the explicit per-zone overrides) and call it from both write paths. The helper is a no-op unless the onboard effect is Static, since a non-Static animation owns the LEDs and masks per-zone anyway.
This commit is contained in:
parent
e557c30ab2
commit
653f7aea18
|
|
@ -2378,6 +2378,26 @@ def _headset_per_zone_overrides(device):
|
|||
return overrides
|
||||
|
||||
|
||||
def _headset_reassert_zone_layer(device):
|
||||
"""Re-paint the per-zone layer: every zone to the LEDs Primary color,
|
||||
then the explicit per-zone overrides on top.
|
||||
|
||||
The headset firmware drops the host-painted per-zone buffer whenever a
|
||||
cluster layer is (re)written — so any path that re-asserts a cluster
|
||||
layer (LED Control re-claim, onboard Static color change) must call this
|
||||
to restore the per-zone paint. No-op unless the onboard effect is Fixed;
|
||||
a non-Static animation owns the LEDs and masks per-zone anyway.
|
||||
"""
|
||||
if not _headset_cluster_effect_is_fixed(device):
|
||||
return
|
||||
zones = headset_rgb.discover_zones(device)
|
||||
if not zones:
|
||||
return
|
||||
zone_map = {int(z): _headset_primary_color(device) for z in zones}
|
||||
zone_map.update(_headset_per_zone_overrides(device) or {})
|
||||
headset_rgb.write_zone_map(device, zone_map)
|
||||
|
||||
|
||||
def _headset_led_control_on(device):
|
||||
"""True when the headset LED Control is on (Solaar drives the LEDs).
|
||||
When off, the firmware owns the LEDs and host color writes are
|
||||
|
|
@ -2438,12 +2458,7 @@ class HeadsetLEDControl(settings.Setting):
|
|||
result = super().write(value, save)
|
||||
if result is not None and value and self._device.online:
|
||||
if _headset_cluster_effect_is_fixed(self._device):
|
||||
primary = _headset_primary_color(self._device)
|
||||
zones = headset_rgb.discover_zones(self._device)
|
||||
if zones:
|
||||
zone_map = {int(z): primary for z in zones}
|
||||
zone_map.update(_headset_per_zone_overrides(self._device) or {})
|
||||
headset_rgb.write_zone_map(self._device, zone_map)
|
||||
_headset_reassert_zone_layer(self._device)
|
||||
else:
|
||||
onboard = next((s for s in self._device.settings if s.name == "headset-onboard-effect"), None)
|
||||
if onboard is not None and onboard._value is not None:
|
||||
|
|
@ -2910,6 +2925,17 @@ class HeadsetOnboardEffect(settings.Setting):
|
|||
setting.fields_map = {eid: (id_choices[eid], {field: 1 for field in cls._EFFECT_FIELDS[eid]}) for eid in supported}
|
||||
return setting
|
||||
|
||||
def write(self, value, save=True):
|
||||
# Writing the 0x0621 cluster effect re-fills every LED uniformly; the
|
||||
# firmware treats that as dropping the host per-zone buffer. After a
|
||||
# Static write, re-overlay the per-zone paint so individually-colored
|
||||
# zones survive a LEDs Primary change. _headset_reassert_zone_layer is
|
||||
# a no-op for non-Static effects (the animation masks per-zone).
|
||||
result = super().write(value, save)
|
||||
if result is not None and self._device.online and _headset_led_control_on(self._device):
|
||||
_headset_reassert_zone_layer(self._device)
|
||||
return result
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# LogiVoice (0x0900 + 0x0901..0x0907) — read-only presentation pass.
|
||||
|
|
|
|||
Loading…
Reference in New Issue