v0.2.10
Features
-
Complete workspace state over the existing IPC subscription. Opt in with
lwm subscribe --events workspace_statefor coherent, byte-bounded snapshots
covering every connected monitor, all nine workspace slots, and tiled/floating
membership. Legacy default subscriptions remain unchanged.lwm query workspaces
returns one snapshot;lwm workspace N --monitor DEVICEselects a workspace on
an explicit monitor. IPC v4 adds this capability after v3 hotkey queries. See
agent_docs/ipc-events.mdfor schemas and recovery. -
Session-only ignore for the actual OS foreground window.
lwm toggle-ignore
(and the unboundtoggle_ignorehotkey catalog action) unmanages the live
foreground HWND without writing application rules or changing pause state.
The same command re-admits a previously ignored eligible window onto the
current monitor's active workspace. Persistent Ignore still wins. Memory is
session-only and is cleared when the daemon restarts.
Improvements
- Release every managed window from the CLI with
lwm release-all-windows.
The command pauses tiling, clears active decoration, restores off-screen windows,
and cascades tiled and floating memberships without removing them. Use
lwm toggle-pauseto resume; recovery failures and live windows that cannot be
restored, cascaded, or remain maximized leave tiling paused and are reported.
Release drains older placement work before cascading and orders final positions
after queued animation frames. A busy worker leaves tiling paused without a
cascade; explicitly retry the command once the worker finishes. Partial
off-screen recovery logs its restored-window count. - Confirmed, non-skipped ordinary visible landings now log origin drift greater than 2 px at warn level with both rectangles.
The warning excludes parked, failed, unreadable, and non-visible landings, drift of 2 px or less, and size-only mismatches. Eligible drift can be diagnosed from a default-level daemon log; placement behavior is unchanged. - Opt-in touchpad gesture diagnostic capture writes a bounded dedicated report.
[gestures] diagnostic_capture_secs(default 0, max 120) is startup-only;lwm reloaddoes not start a capture. Restart withlwm stopthenlwm run. The report distinguishes hook delivery, classifier pass/reject, accumulation, timeout, cooldown, recognized events, and daemon binding dispatch, including no-action. Capture can report disabled registration when gestures are disabled, but hook input is recorded only when gestures are enabled and registration succeeds.lwm collect-logsincludes the full capture file. Default-off does not truncate a previous report; a new capture replaces it.
Fixes
- Temporary ignore now distinguishes a recycled live HWND from a destroyed one.
A delayed Destroyed event no longer wipes a replacement managed window or a still-ignored lifetime. A dead identity read prunes the session ignore instead of keeping it forever; an injected transient identity failure still stays closed. Production identity reads areIsWindowplusGetPropW(property handle or NULL) and do not classify GetLastError. Unmanage and readmit report layout failures instead of returning success with contradictory membership. Unmanage restores geometry before clearing placement cloak and park, cancels an unfinished drag or resize so MoveSizeEnd cannot reinsert the window, and drops owned tab-title and snapshot state. Explicit readmit adopts internal focus, border, and broadcast to the OS foreground without setting native focus or switching workspace. A failed placement drain, an injected transient identity read after drain, or a rejected readmission after drain leaves a pending idle reapply. Every layout path now keeps that recovery pending until the animation barrier clears and placement succeeds; transient placement failures retry a bounded number of times before being logged as deferred. Reused HWND admission, delayed Destroyed, and explicit mismatch retirement each clear stale old-lifetime icon, move-origin, and stashed-layout cache entries before a replacement establishes its own state. Deferred recovery is distinct from a completed layout landing, including ghost and interrupted-animation handling, while paused and shutdown guards remain authoritative. Interrupted transitions and scrolls now settle to their final targets after the barrier clears rather than restarting the interrupted animation, retire active ghost ownership without exposing unsafe sources, and preserve the post-animation compositor nudge through a failed retry. Their matching focus-suppression one-shot is consumed by any successful recovered physical landing, including an empty or fullscreen-filtered landing and an explicit Apply after a failed automatic attempt. The animation-complete event-loop landing keeps that one-shot only while recovery is still pending, including a paused no-op apply, and consumes it on the successful retry. A non-recovery suppressed landing still consumes the one-shot if that apply fails, so a later ordinary landing can resync. Parked or unconfirmed pending ghost sources stay cloaked until a confirmed current-epoch landing. IPC Apply returnsapply_pendingfor a still-pending landing instead of claiming success or a generic error, including while tiling is paused with recovery still pending; a genuine layout failure still returns Error. A resume safely settles a now-idle interrupted transition or rolls back while its barrier remains busy, and reports the actual placement error on a failed recovery attempt instead of treating an early failure as a busy barrier. The event loop consumes recovery without starting concurrent placement or changing pause. - Toggle-ignore unmanage restores geometry before releasing membership.
A detected native restore failure leaves the window managed, keeps owned
metadata, does not ignore or uncloak, and requests idle reapply.SetWindowPos
is not transactional; a failed restore may still have moved the window, so
recovery retries placement. Peer-layout failure after a successful release
still leaves the window unmanaged and ignored. - Toggle-ignore unmanage cancels unfinished drag or resize only after geometry restore succeeds.
A detected restore failure keeps in-membership drag/resize tracking and overlay
state. Success still cancels before membership release so a delayed MoveSizeEnd
cannot reinsert. - Paused tiling no longer suppresses Snap Layouts on a newly tiled window.
disable_snap_for_windowis a no-op while paused. Successful resume still
suppresses all tiled windows; a failed resume stays paused without
re-suppression. - Daemon exit now best-effort clears matching ignore lifetime tokens.
Temporarily ignored windows are not managed, so their owned properties survived
normal cleanup. Graceful and panic-revert shutdown attempt a clear only after a
matching identity read. That is not an atomic no-race guarantee: a recycled HWND
can still appear between read and clear. Mismatch, missing, gone, and transient
reads skip clear. NativeRemovePropWtreats a missing property (NULL) as
success. A documented UIPI denial (GetLastError5) is logged and does not
block exit. A NULL return that does not set last error cannot be distinguished
from missing. Release All does not clear those tokens. - Gesture capture now preserves an existing report when duplicate daemon startup is rejected.
Closed captures no longer evaluate diagnostic trace fields, and admitted or in-flight deadline-boundary work prevents a falseno_input=trueresult. - The gesture capture's 256 KiB limit now includes the header and summary.
Space is reserved for the complete summary so capped records remain visible in its counters. - Closing the last window on a workspace keeps that workspace selected.
An attributable Windows replacement activation on another workspace or
monitor no longer follows away from a genuinely empty selection (no tiled
or floating windows, including minimized). Logical focus is cleared rather
than pointed at a fake target, including when tracking already names the
replacement or another window; the active border hides with that clear.
Tab-strip reconciliation removes the emptied workspace's strip while
retaining other monitors' strips on both the immediate and final-landing
paths. A strictly newer activation still wins, and the next new window
opens on the preserved selection.
Known limitations
- Last-window empty preservation cannot attribute every event order.
If a replacement Focused event arrives while the departing window still
appears live or stale-window pruning is throttled, that activation is
followed. Handler execution time is not a true departure timestamp, so a
user activation that occurred before the destroy or hide handler ran may
be treated as the replacement auto-activation. Eventless disappearance
can arm the same guard while handling the first cross-workspace
activation, so that first activation may be consumed and need to be
repeated. That eventless-disappearance case is deferred to 0.2.11. - Gesture capture cannot prove finger count, device origin, or Windows touchpad-setting compatibility.
A zero-event interval is not proof that the hook is dead. Dropped or capped records mean input may have been lost; do not treatno_input=trueas absent hardware when drops are reported. Elevated versus unelevated hook visibility is not guaranteed from this report. - Corrected Apply pending handling requires matching CLI and daemon from the same release.
A newer daemon returnsapply_pendingwhen recovery landing is still outstanding. An older CLI maps that status toUnknownand may run emergency visibility restore. Mixed CLI/daemon versions are not negotiated or isolated on the pipe. Pending handling does not change the Apply request shape. This release still advances the overall IPC protocol from v3 to v4 for workspace-state snapshots. - Ordinary managed HWND reuse is not lifetime-token identified.
Session ignore stamps a native token; ordinary tiled and floating windows
do not. A recycled ordinary managed HWND that is already live when a delayed
Destroyed arrives can keep the previous membership and caches. Ignore-to-replacement
protection after Created is unchanged. Generalized managed identity tracking
is not in this release. A bounded lifetime-identity policy for ordinary managed windows is deferred to 0.2.11. - Ignore lifetime tokens cannot be cleared after a crash, and matching-read
clear is not race-free.
Best-effort token cleanup runs only on daemon exit paths. A crash or kill
leaves the native property on any still-live ignored window. A later daemon
treats a leftover token as inert unless it matches a new session ignore.
Read andRemovePropWare separate calls, so a recycled HWND can appear
after a matching read.RemovePropWdocuments NULL as not found and UIPI
blocks asGetLastError5; a failure that returns NULL without setting last
error looks like missing and succeeds.
Internal
- IPC protocol v4 adds opt-in workspace-state snapshots and monitor-targeted
switching. Legacy empty-filter subscriptions remain unchanged; consumers
must also verify thatworkspace_stateappears in the acknowledged filter. - The repository now carries a placement-report triage record for #104 and #112.
The record atagent_docs/placement-report-triage.mdcaptures current evidence
state and the bounded next steps; no placement behavior changed. - The gesture diagnostic capture admission token is no longer externally constructible.
A private field means the admission counter can only be released by work that was
actually admitted; capture report content is unchanged. - Gesture diagnostic tests recover their serialization locks after a test panic.
A poisoned lock no longer turns one failure into unrelated lock-acquisition failures. is_known_windownow classifies ignored HWND liveness with one identity read.
Matching tokens stay known. Injected transient reads stay known. Gone stays
unknown even when tests inject window info. Mismatch and missing still fall
through to test-only injected info. Production reads useIsWindowand
GetPropW(handle or NULL);GetPropWhas no documented GetLastError or UIPI
failure.