Skip to content

fix: restore device settings after sleep/wake + home view UI polish - #133

Open
m-wilkowski wants to merge 3 commits into
mmaher88:masterfrom
m-wilkowski:fix/issue-132-dpi-not-restored-after-sleep
Open

fix: restore device settings after sleep/wake + home view UI polish#133
m-wilkowski wants to merge 3 commits into
mmaher88:masterfrom
m-wilkowski:fix/issue-132-dpi-not-restored-after-sleep

Conversation

@m-wilkowski

Copy link
Copy Markdown

Summary

  • Restore DPI, SmartShift and scroll settings after device wakes from sleep (issue Pointer speed not restored after laptop wakes from sleep #132)
  • Replace time-based greeting in HomeView with centered logo + wordmark
  • New logitune-logo.png app icon (teal, mouse + L)
  • DeviceCard: 180×280 → 280×420 for better presence at typical window sizes
  • SideNav: tighter left margin (35→20px) and tab spacing (17→6px)
  • Theme dark mode: slightly deeper border/input/card/hover colors
  • SettingsPage: "Active" label uses accent color instead of battery green

Test plan

  • All 731 C++ tests pass
  • All 9 tray tests pass
  • All 72 QML tests pass (SideNav formula updated for 6px spacing)
  • DPI restores correctly after MX Master wakes from sleep
  • HomeView shows logo + wordmark, gear icon on right
  • DeviceCard clicks through to device detail page

@mwilkowski added 3 commits June 7, 2026 22:21
Three related fixes for DPI and other settings not being restored
after the laptop wakes from sleep.

1. DeviceSession::enumerateAndSetup() – always reset and recreate
   m_commandProcessor so it always points to the fresh FeatureDispatcher
   built at the top of the function.  The old guard (if !m_commandProcessor)
   kept the stale pointer alive after m_features was replaced, causing
   use-after-free when the CommandProcessor later called m_features->callAsync().
   This was latent in the checkSleepWake path and any future caller that
   re-enumerates without a full disconnect/reconnect cycle.

2. DeviceManager – emit physicalDeviceTransportReady when a new session
   attaches to an already-existing PhysicalDevice.  In that path
   enumerateAndSetup() emits setupComplete() BEFORE attachTransport()
   connects the PhysicalDevice signal fan-in, so transportSetupComplete
   is never emitted and onTransportSetupComplete is never called.
   The new signal closes that gap (multi-transport setups: Bolt + BT,
   or rapid udev remove+add where PhysicalDevice is not destroyed).

3. AppRoot – subscribe to the systemd-logind PrepareForSleep DBus signal.
   On resume (before=false), wait 2 s for HID++ to stabilise and then
   call onTransportSetupComplete for every known device.  This is the
   primary fix for the common single-transport case where the Bolt
   receiver does not send a 0x41 reconnect notification after wake,
   leaving the session connected but with factory-default firmware state.
- HomeView: centered logo + "Logitune" wordmark replaces time-based greeting
- logitune-logo.png: new app icon (teal, mouse + L)
- logitune-icon.svg: simplified geometry
- DeviceCard: 180×280 → 280×420 for better presence at larger window sizes
- SideNav: tighten left margin (35→20px) and tab spacing (17→6px)
- Theme dark mode: slightly deeper border/input/card/hover colors
- SettingsPage: "Active" label uses accent color instead of battery green

@mmaher88 mmaher88 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-wilkowski Thanks for digging into this — the core of this PR is genuinely valuable, and you've found two real bugs, one of which is a memory-safety issue:

  1. Use-after-free in DeviceSession::enumerateAndSetup. The old if (!m_commandProcessor && ...) guard meant that on re-enumeration the existing CommandProcessor was kept while the FeatureDispatcher it points at got rebuilt underneath it — a dangling pointer. Always recreating it is correct.

  2. The actual sleep/wake root cause. When a transport re-attaches to an existing PhysicalDevice, physicalDeviceAdded isn't re-emitted, so nothing re-applies the profile. Adding physicalDeviceTransportReady is the right shape of fix, and the comment explaining the setupComplete()-before-attachTransport() ordering is exactly the kind of note that keeps this from regressing.

What I'd like to change: please split this into two PRs.

As it stands the PR bundles those core fixes with unrelated UI/branding work — HomeView.qml, Theme.qml, SideNav.qml margins, DeviceCard.qml, SettingsPage.qml, a replaced logitune-icon.svg and a new logitune-logo.png. That's where nearly all of the 148 deletions live. Two problems with shipping them together:

  • The core fixes are objectively verifiable and I want to merge them quickly. The UI/branding changes are subjective and need a different kind of review (and the icon/logo replacement is a branding decision, not just polish).
  • If anything regresses, a bisect lands on a commit that changed both device lifecycle handling and the entire home view.

PR 1 — the fix (please open this first, I'll prioritise it):
src/core/DeviceManager.{h,cpp}, src/core/DeviceSession.cpp, and the AppRoot wiring for the new signal.

PR 2 — the UI/branding work: everything under src/app/qml/ plus the asset changes and the tst_SideNav.qml expectation update (that test only changed because of the 17→6 margin change, so it belongs with the UI PR).

One more ask on PR 1: please add tests. Right now the only test touched is the QML nav-margin one, so neither core fix is covered. Both are testable without hardware — tests/services/ProfileOrchestratorFixture.h and tests/helpers/AppRootFixture.h already fake a PhysicalDevice/DeviceSession, so a test can attach a second transport to an existing PhysicalDevice and assert that the profile gets re-applied (i.e. that physicalDeviceTransportReady fires and settings are restored). That's the regression guard that stops this bug coming back after the next refactor.

Heads-up on conflicts: your AppRoot::wireSignals change touches the same region as #148, which is currently open. Whichever lands second will need a rebase — not a problem, just so it isn't a surprise.

Really good find on the dangling pointer especially. Ping me when PR 1 is up and I'll review it straight away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants