From baa048a89e2a8b2679cd8678d527def26359a7a6 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Tue, 20 Oct 2026 08:33:29 -0700 Subject: [PATCH] Keep Escape from leaving full screen in the main window --- docs/macos.md | 2 +- mac/Sources/Byre/Dialogs.swift | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/macos.md b/docs/macos.md index 8212dee..657b80b 100644 --- a/docs/macos.md +++ b/docs/macos.md @@ -91,7 +91,7 @@ At launch the window shows the oldest saved server. A CloudKit import that bring Overlays (the switcher, alerts, confirmations, the merge dialog, keyboard help) are SwiftUI views drawn above the panes inside the window, not system sheets or alerts. The switcher and the Discard confirmation sit just below their anchor; the merge dialog is centred in the right pane. -Overlays live in `Overlays` (`Dialogs.swift`), one environment object for each server. An open overlay takes Escape (closing the topmost: alert, modal, image, switcher step or switcher, More menu) and Enter (the alert's OK, the modal's last button when its `canSubmit` holds, the switcher's highlighted row) through a local key monitor, which handles only key events for its own window and passes Enter on while an input method holds marked text. The switcher also takes ↑ and ↓ there. The left pane's selected tab lives in `Overlays` too, so ⌘L can switch to Lead and focus its composer. +Overlays live in `Overlays` (`Dialogs.swift`), one environment object for each server. An open overlay takes Escape (closing the topmost: alert, modal, image, switcher step or switcher, More menu) and Enter (the alert's OK, the modal's last button when its `canSubmit` holds, the switcher's highlighted row) through a local key monitor, which handles only key events for its own window and passes Enter on while an input method holds marked text. The switcher also takes ↑ and ↓ there. With no overlay open the monitor still swallows Escape, unless the terminal is the first responder (`terminalFocused`) or an input method holds marked text, so it never reaches the window, which would leave full screen. The left pane's selected tab lives in `Overlays` too, so ⌘L can switch to Lead and focus its composer. Connections belong to `Servers`, not to the window: every saved server's store and streams run whichever one the window shows, and closing the window leaves them all running (and the app running, `applicationShouldTerminateAfterLastWindowClosed` returns false), so notifications keep coming. Clicking the Dock icon with no window showing opens it again (`applicationShouldHandleReopen`). Quit flushes every server's drafts and reports pane focus false before exiting. diff --git a/mac/Sources/Byre/Dialogs.swift b/mac/Sources/Byre/Dialogs.swift index f747a4d..a0ed9a5 100644 --- a/mac/Sources/Byre/Dialogs.swift +++ b/mac/Sources/Byre/Dialogs.swift @@ -161,15 +161,18 @@ final class Overlays { if !dialogOpen && flags.contains(.control) && !flags.contains(.command) && goKeys.contains(chars) { return ctrl(chars) } + let marked = (NSApp.keyWindow?.firstResponder as? NSTextView)?.hasMarkedText() ?? false + if code == 53 { + if isOpen { + closeTop() + return true + } + return !marked && !terminalFocused() + } if !isOpen { return false } - if code == 53 { - closeTop() - return true - } let enter = code == 36 || code == 76 - let marked = (NSApp.keyWindow?.firstResponder as? NSTextView)?.hasMarkedText() ?? false if !alerts.isEmpty { if enter { alerts.removeLast()