fix: quit in ::unlocked instead of after unlock() (v0.6.17)
The real cause of the unlock SIGSEGV: gtk4-session-lock destroys the lock windows itself when the lock ends (per its header), so unlock_callback's `unlock(); app.quit();` destroyed them a second time — surface already gone → gdk_surface_get_display NULL → crash in gtk_window_destroy. Reproduces on a plain single-monitor lock/unlock, no suspend needed. unlock_callback now calls only unlock(); a new connect_unlocked handler quits the app after the library finishes teardown. Mirrors the upstream examples/simple.rs exactly. Reverts the v0.6.15/v0.6.16 monitor-pruning + LockscreenHandles.monitor: it was a misdiagnosis (the crash is monitor-independent) and manually manipulated library-managed lock windows, which the upstream example explicitly warns against. Monitor removal is left to the library.
This commit is contained in:
@@ -2,6 +2,13 @@
|
||||
|
||||
Architectural and design decisions for Moonlock, in reverse chronological order.
|
||||
|
||||
## 2026-06-02 – Real fix for the unlock SIGSEGV: quit in ::unlocked, never destroy windows ourselves (v0.6.17)
|
||||
|
||||
- **Who**: ClaudeCode, Dom
|
||||
- **Why**: The v0.6.15 "stale per-monitor window" theory was a **misdiagnosis**. A clean manual `target/release/moonlock` lock→unlock (single monitor, no suspend, no monitor removal) still crashed, preceded by `Gdk-CRITICAL: gdk_surface_get_display: assertion 'GDK_IS_SURFACE (surface)' failed`. The v0.6.16 backtrace's top app frame is the `unlock_callback` closure, which ran `lock.unlock(); app.quit();`. Per the gtk4-session-lock header (`assign_window_to_monitor`: "the window will be unmapped and `gtk_window_destroy()` called on it when the current lock ends") the **library destroys the lock windows itself** on unlock. `app.quit()` then destroyed the same windows again — surface already gone → SIGSEGV. A double-destroy in the teardown sequence, entirely independent of monitors.
|
||||
- **Tradeoffs**: Reverted the v0.6.15/v0.6.16 monitor-pruning + `LockscreenHandles.monitor` field: it targeted the wrong cause, never fired in testing, and manually called `app.remove_window()` on library-managed lock windows — exactly what the upstream example warns against ("does NOT manually destroy or close the lock windows"). Monitor-removal-during-lock is left entirely to the library (which already auto-unmaps+dereferences such windows). Three attempts total: idle_add deferral (wrong: reentrancy theory), monitor-pruning (wrong: misdiagnosis), and this one — verified against both the C header and the upstream `examples/simple.rs`.
|
||||
- **How**: `unlock_callback` now calls only `lock.unlock()`. A new `lock.connect_unlocked(|_| app.quit())` quits the app only after the library finishes its teardown and fires `::unlocked`. Mirrors the canonical gtk4-session-lock usage exactly.
|
||||
|
||||
## 2026-06-02 – Prune per-monitor windows on monitor removal to fix resume-unlock SIGSEGV (v0.6.15)
|
||||
|
||||
- **Who**: ClaudeCode, Dom
|
||||
|
||||
Reference in New Issue
Block a user