Skip to content

Make monitor hotplug display update non-blocking - #3

Open
yottanami wants to merge 1 commit into
masterfrom
agent/20-hotplug-sleep
Open

Make monitor hotplug display update non-blocking#3
yottanami wants to merge 1 commit into
masterfrom
agent/20-hotplug-sleep

Conversation

@yottanami

Copy link
Copy Markdown
Owner

Summary

wm/update-displays (hooked to exwm-randr-screen-change-hook, which fires on every monitor connect/disconnect) called (sleep-for 2) synchronously. Since Emacs is single-threaded, this froze the entire WM/editor session for 2 full seconds every time.

Replaced with run-with-timer: the hook function now returns immediately, and the actual xrandr reconfiguration + workspace-monitor remapping runs 2 seconds later, off the blocking path. The 2s settle delay itself is preserved (per the issue: "if the delay exists to let hardware settle... keep the delay but make it async"), just non-blocking now.

Debounced via a module-level wm/--update-displays-timer variable: if the hook fires again while a wait is already pending (e.g. plugging in two monitors close together), the pending timer is cancelled and rescheduled rather than letting two reconfigurations run back-to-back. This wasn't strictly required by the issue, but it's the closest non-blocking equivalent to the old synchronous behavior, where a second hook firing simply couldn't start until the first sleep-for finished — without it, rapid hotplug events could double-run the xrandr command.

Closes Men-in-Black-5/ideas#20

Test plan

  • Parenthesis-balance check on the edited file — balanced
  • Read through the full new control flow against the original — same end state (xrandr command + workspace-monitor plist update), same 2s delay, just deferred
  • Actually plugging/unplugging a monitor and confirming Emacs stays responsive during the wait — no nix/emacs binary in my environment, needs a real check

@yottanami

Copy link
Copy Markdown
Owner Author

Reviewed. This one doesn't even depend on Nix package availability — run-with-timer/cancel-timer are core Emacs Lisp primitives (timer.el, always present, no package needed), so I'm quite confident in the mechanics:

  • run-with-timer 2 nil (lambda () ...) correctly defers the body 2s without blocking, matching the issue's "keep the delay but make it async."
  • The debounce (wm/--update-displays-timer, cancel-then-reschedule on a repeat hook firing) correctly prevents two overlapping xrandr runs from rapid hotplug events — a sensible addition beyond the issue's literal ask, and it mirrors the old code's actual behavior (a second sleep-for couldn't start until the first finished) more faithfully than doing nothing about it would.
  • Confirmed no other call site depends on wm/update-displays running synchronously — it's only ever invoked via the hook.
  • Parens balanced on the edited file.

Same caveat as the other PRs in this batch: no agent can trigger exwm-randr-screen-change-hook for real or watch Emacs stay responsive during the wait, so per policy this needs your confirmation on a real monitor plug/unplug before I merge. Everything I can check from the code is solid.

wm/update-displays called (sleep-for 2) synchronously on every
exwm-randr-screen-change-hook firing. Since Emacs is single-threaded,
this froze the entire WM/editor session for 2 full seconds on every
monitor connect/disconnect.

Replaced with run-with-timer: the hook returns immediately and the
actual xrandr reconfiguration runs 2 seconds later, off the main
thread's blocking path. Debounced via a module-level timer variable
so a second hotplug event during that 2s window (e.g. plugging in two
monitors close together) cancels and reschedules the wait instead of
running the reconfiguration twice.
@yottanami
yottanami force-pushed the agent/20-hotplug-sleep branch from a96c3b3 to 4cfc009 Compare July 29, 2026 11:59
@yottanami

Copy link
Copy Markdown
Owner Author

@yottanami This one's waiting on you — no agent can trigger a real monitor hotplug or watch Emacs stay responsive during the wait, so per policy it holds for your confirmation before merge (see the review comment above for what was statically verified). Steps:

  1. Load this branch's config in Emacs (or run nix flake check first if you want the Nix side confirmed too).
  2. Plug/unplug an external monitor and confirm Emacs doesn't freeze for the ~2s window (the whole point of this fix).
  3. Reply here or merge if it looks good.

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