Skip to content

Stack upgrade: .NET 10 + Avalonia 12#461

Merged
mgth merged 37 commits into
masterfrom
upgrade-2026
Jun 26, 2026
Merged

Stack upgrade: .NET 10 + Avalonia 12#461
mgth merged 37 commits into
masterfrom
upgrade-2026

Conversation

@mgth

@mgth mgth commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Stack upgrade: .NET 10 + Avalonia 12.0.5 + ReactiveUI 23.2.28. Voir commits.

mgth and others added 7 commits June 25, 2026 07:01
A monitor without EDID (Remote Desktop, virtual display, DisplayLink,
spacedesk, some panels) reports "Generic PnP Monitor" with a null Edid.
SetPnpDeviceName dereferenced monitor.Edid.Model and threw a
NullReferenceException on the first boot step (UpdateLayout), before the
tray icon and window were created, so the app silently showed nothing.

- guard monitor.Edid?.Model in SetPnpDeviceName and BrandLogo
- SetSizeFrom: when the GDI physical size is a bogus square placeholder
  (e.g. 1000x1000mm reported for an EDID-less display), fall back to the
  EDID size, then to an estimate derived from the resolution and DPI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The mouse hook daemon silently failed to start. Three issues:

- LaunchDaemon located the hook with a hardcoded "\net8.0\" path replace,
  broken by the net8->net9 migration. Replaced with FindHookPath, which
  finds LittleBigMouse.Hook.exe next to the UI (deployed) or by searching
  the hook project's bin folder (dev). Independent of the .NET target
  framework, platform (AnyCPU/x64) and configuration.

- CreateExcludedFile threw before the Process.Start try-block, aborting the
  whole launch; the exception was swallowed upstream. It is now wrapped so a
  failure to write the exclusion file no longer prevents the daemon launch,
  and it creates its parent directory before writing.

- Options.Load/Save built the exclusion-list path with GetConfigPath(...,
  true), which is meant for layout *folders* and so created "Excluded.txt"
  as a directory. That broke both the daemon launch and the process
  exclusion feature. Added ExcludedListPath() that returns a real file path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The debug logger wrote to a hardcoded "L:\log.txt", a drive that only
existed on the original developer's machine, so the trace silently went
nowhere for everyone else. Write to %ProgramData%\Mgth\LittleBigMouse\
hook.log instead (next to the daemon's config, created if missing).
Uses GetEnvironmentVariableA since getenv trips MSVC C4996. Debug-only
(the logger is compiled out of Release builds).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Users who ran an earlier buggy build still have "Excluded.txt" persisted as
a *directory* (from the GetConfigPath misuse), which keeps the process
exclusion broken even after the path fix. Delete that directory if present
before writing the file, in both places that build the path. Verified: a
pre-existing Excluded.txt directory is removed on startup and recreated as a
proper file with the default exclusions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
net8.0/net9.0 -> net10.0 across all solution projects (main repo + HLab.Core
and HLab.Avalonia submodules), prerequisite for the Avalonia 12 migration.
Managed build verified clean; the C++ hook is unaffected (no TFM, built
separately with VS2022 MSBuild).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Avalonia 11.3.4 -> 12.0.5, Avalonia.ReactiveUI -> ReactiveUI.Avalonia 12.0.3,
ReactiveUI 20 -> 23.2.28, plus HLab.Core / HLab.Avalonia submodule bumps.
Avalonia 12 / ReactiveUI 23 API changes:
- RxApp.MainThreadScheduler -> RxSchedulers.MainThreadScheduler
- SystemDecorations -> WindowDecorations
- IClipboard.SetTextAsync -> DataTransfer + SetDataAsync
- AvaloniaUseCompiledBindingsByDefault=false on MonitorVcp.Avalonia
- RxApp.DefaultExceptionHandler removed (now read-only RxState); TODO: reconfigure
  via RxAppBuilder.WithExceptionHandler if a custom handler is needed.

Managed build verified; runtime smoke-tested OK. C++ hook unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ReactiveUI

Adopt the libs' rearchitected boot system: port all bootloaders to the abstract Bootloader / override Task<BootState> LoadAsync() API (MainBootloader, VcpPlugin, MonitorLocationPlugin, ScreenSizePlugin, BorderResistancePlugin, AboutMonitorPlugin, MonitorDebugPlugin).

Rewire MVVM init: bootloaders are discovered by the AssemblyParser (As<Bootloader>); export Func<Type,object> locator for MvvmService/RegisterPlatform; MainBootloader waits via WaitingForServices(mvvm); parser.LoadDll(Ui.Core) so MainBootloader is found exactly once.

Remove dead Live.Avalonia (pulled incompatible Avalonia.ReactiveUI 11 -> Splat 19 MissingMethodException); switch init to ReactiveUI.Avalonia UseReactiveUI(_ => {}). Bump HLab.Core/HLab.Avalonia submodules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mgth mgth merged commit befea43 into master Jun 26, 2026
0 of 2 checks passed
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.

1 participant