diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-04 12:38:10 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-04 12:38:10 -0500 |
| commit | 140e3b9f0757b8bc413c4b13f060f24f5eebd03c (patch) | |
| tree | 91a305410cd89455c10f1a130ef536ddbc38ed53 /docs/design/2026-07-02-file-manager-swallow-spec.org | |
| parent | 6d25b93d442c1ae74bf1bdc9e7aecc2374868b87 (diff) | |
| download | archsetup-140e3b9f0757b8bc413c4b13f060f24f5eebd03c.tar.gz archsetup-140e3b9f0757b8bc413c4b13f060f24f5eebd03c.zip | |
docs(spec): sort formal specs into docs/specs/ with lifecycle status
Moved the seven formal specs from docs/design/ into docs/specs/, each stamped with a lifecycle status heading: four IMPLEMENTED (bluetooth, net-other-interfaces, audio, instrument-console), one CANCELLED (file-manager-swallow), two DRAFT (desktop-settings, timer). Rewrote the seven todo.org links to the new paths. The two -spec.org files without the spec spine (waybar-network-module, waybar-timer-module) stayed in docs/design/ as notes.
Diffstat (limited to 'docs/design/2026-07-02-file-manager-swallow-spec.org')
| -rw-r--r-- | docs/design/2026-07-02-file-manager-swallow-spec.org | 141 |
1 files changed, 0 insertions, 141 deletions
diff --git a/docs/design/2026-07-02-file-manager-swallow-spec.org b/docs/design/2026-07-02-file-manager-swallow-spec.org deleted file mode 100644 index 4c61be1..0000000 --- a/docs/design/2026-07-02-file-manager-swallow-spec.org +++ /dev/null @@ -1,141 +0,0 @@ -#+TITLE: File-Manager Swallow Pattern -#+AUTHOR: Craig Jennings -#+DATE: 2026-07-02 -#+TODO: TODO | DONE -#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED - -* CANCELLED Status -:PROPERTIES: -:ID: d92e0074-f594-4e83-81a0-faf282e15ed0 -:END: -- [2026-07-02 Thu] CANCELLED — targeted the wrong file manager. Craig's ask - is about the dirvish popup (Super+F, an Emacs frame), not nautilus (the - Super+Shift+F bind that misled the grounding). For dirvish the right - design is elisp-side and strictly better: Emacs is the launcher, so it - can spawn the handler directly (=start-process=), hide the popup frame, - and restore it from a process sentinel — exact exit tracking plus a - failure notify, no window-event heuristics. Reassigned to .emacs.d via - its inbox (2026-07-02-2231-from-archsetup-dirvish-popup-swallow-handoff). - The gio double-fork finding below stands for any gio-launching file - manager; the daemon design is kept for reference only. -- [2026-07-02 Thu] DRAFT — initial spec from Craig's roam capture ("when the - file manager launches another app, it should hide and return when that - process ends"). Feasibility ground truth sampled live on velox same - evening: Hyprland's native swallow cannot work here (see Problem), so the - design is an event-listener daemon. - -* Metadata - -| Field | Value | -|--------+----------------------------------------------------| -| Status | cancelled | -|--------+----------------------------------------------------| -| Owner | Craig Jennings | -|--------+----------------------------------------------------| -| Repo | dotfiles (daemon + config); archsetup (none) | -|--------+----------------------------------------------------| -| Kin | touchpad-auto (socket-listener donor), | -| | hypr-refocus-scratchpad (event-daemon sibling) | -|--------+----------------------------------------------------| - -* Problem - -Opening a file from nautilus (Super+Shift+F, tiled, class -=org.gnome.Nautilus=) spawns a viewer window while nautilus stays in the -layout. The wanted behavior is the swallow pattern: the file manager hides -while the app it launched runs, and returns when that app exits. Today -there's no signal connecting the two windows — the viewer lands wherever -the layout puts it, nautilus lingers, and quitting is manual. - -*Hyprland's native swallow is ruled out — measured, not assumed.* -=misc:enable_swallow= + =swallow_regex= would be exactly this feature in two -config lines, but it matches by walking the new window's PID ancestry to -the swallow candidate's PID. Nautilus launches handlers through GLib -(=g_app_info_launch_default_for_uri=), and that path orphans the child: -reproduced live on velox 2026-07-02 with a python-gi launcher — feh came up -with PPID 1 (reparented to init) while the launcher was still alive. The -ancestry walk hits init before it hits nautilus, every time, for every -handler. Any design that depends on PID parentage is dead on arrival; the -signal has to come from window events instead. - -Ground truth on handlers (velox, 2026-07-02): pdf → zathura, image → feh, -video → mpv, text/code → emacsclient (window belongs to the emacs daemon). -Side-note, out of scope here: feh is X11 — an XWayland viewer on a -no-XWayland-by-preference setup; a default-handler review is its own task. - -* Goals - -- Double-click a file in nautilus → the viewer takes its place; nautilus is - gone (special workspace, not killed — state and tabs survive). -- Quit the viewer → nautilus returns and has focus. -- Nothing else changes: terminals, scratchpads, and every other window keep - their current behavior. -- Config-driven, testable logic, one small daemon — the touchpad-auto shape. - -* Design sketch - -A =hypr-swallow= daemon (dotfiles, =hyprland/.local/bin/=) listening on the -Hyprland IPC event socket (socket2), same as =touchpad-auto=: - -- Track the active window (=activewindow>>= events carry class + title; - =activewindowv2>>= carries the address). -- On =openwindow>>= (address, workspace, class, title) while the active - window's class is a configured *parent* (nautilus): dispatch - =movetoworkspacesilent special:swallow,address:0x<parent>=, record - child-address → {parent-address, origin workspace}. -- On =closewindow>>= of a recorded child: bring the parent back - (=movetoworkspace=) and focus it; drop the record. -- On =closewindow>>= of a hidden parent (nautilus quit while hidden): drop - the record, nothing to restore. -- Exception classes (fuzzel, dunst, scratchpad classes, the panels) never - trigger a swallow even when they open over nautilus. -- Pure event-machine core (parse lines → state transitions → dispatch list), - unit-tested against recorded event streams; a thin socket loop around it. - -Known edge, handled: Super+Shift+F while nautilus is hidden re-runs -=nautilus=, which activates the existing (hidden) instance instead of -opening a window. The daemon (or the bind) must restore-and-untrack in that -case so the bind never appears dead. - -Known limitation, accepted: the emacsclient case never swallows — the -window belongs to the long-running emacs daemon and =closewindow= for it -means a frame closed, not "the file is done." The parent-class trigger plus -exception list naturally leaves it alone only if we exclude it explicitly — -see decision 2. - -* Decisions (Craig) - -** TODO Trigger breadth: any new window while nautilus is active, or an allowlist of viewer classes? -"Any window" is simple and catches every handler, but a false positive -exists: an app you launched seconds earlier from elsewhere finishes starting -while you're focused on nautilus → nautilus gets swallowed by an unrelated -window. An allowlist (zathura, mpv, imv, feh, …) can't be surprised but -needs maintaining. Recommendation: any-window + exception list — the false -positive is rare and self-healing (close the window or refocus). - -** TODO The emacs frame case: swallow or exempt? -Opening a text file from nautilus raises/creates an emacs frame. Swallowing -nautilus under it "works" going in, but the restore fires when *any* frame -closes, which may be much later or never. Recommendation: exempt =emacs= — -text files just open, nautilus stays. - -** TODO Restore destination: the workspace nautilus came from, or the one you're on when the viewer closes? -If you move the viewer to another workspace and quit it there, "origin" -teleports you back; "current" brings nautilus to you. Recommendation: -current workspace — the restore should land where your attention is. - -** TODO Multiple children: refcount or single-slot? -You can only launch a second file after restoring nautilus manually, so -overlap is rare — but a fast double-launch can record two children. -Recommendation: refcount — restore when the last tracked child closes. - -* Implementation phases - -1. =hypr-swallow= core: pure event-machine (TDD over recorded event - streams; fake hyprctl for dispatch assertions), config block at the top - (parent classes, exception classes), unittest suite in =tests/=. -2. Socket loop + wiring: exec-once in hyprland.conf, the Super+Shift+F - restore-if-hidden interplay, daemon single-instance guard. -3. Live verification on velox (zathura + mpv round-trips, the emacs case, - the false-positive probe) + manual-testing entries; ratio rides the - dotfiles pull. |
