Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ public final class TerminalSurface: Identifiable, ObservableObject {
/// on the main thread). A device mirror sends it to the Mac that runs the
/// terminal.
public var onFocusStateChange: ((Bool) -> Void)?
/// Read-only ``desiredFocusState`` for release builds, where the DEBUG-only
/// `debugDesiredFocusState()` does not exist.
public var isFocusDesired: Bool { desiredFocusState }
// SUPERMUX:end device-terminal-focus

/// Whether this model still owns its logical surface-registry entry.
Expand Down
2 changes: 1 addition & 1 deletion SUPERMUX-TOUCHPOINTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ Rules for adding a touchpoint:
| 814 | `Sources/Workspace.swift` | `device-terminal-focus` | In `makeRemoteTmuxPanePanel`, sets the new surface's `onFocusStateChange` (#817) to `SupermuxDeviceTerminalActions.focusChanged`, which sends a device mirror pane's settled focus to the owning Mac (`focus_in` / `focus_out`) |
| 815 | `Sources/Panels/TerminalPanel.swift` | `device-terminal-actions` | In `performBindingAction`, `SupermuxDeviceTerminalActions.perform(action, on: surface, locally:)` runs `clear_screen`/`reset` on another Mac's terminal too (the `surface.clear_history` socket path); `nil` keeps upstream's path |
| 816 | `Sources/GhosttyTerminalView.swift` | `device-terminal-actions` | Two fences. In `keyDown`, right after the surface is ready, a device mirror pane (`ioMode == .manualMirror`) with Cmd or Ctrl held asks `handleDeviceTerminalKey`; the second fence adds that helper next to `ghosttyConsumeMenuAction`: Ctrl+V with only an image on the clipboard runs `paste(nil)` (the Cmd+V upload), and a key bound to `clear_screen`/`reset` is consumed and runs `SupermuxDeviceTerminalActions.perform` (local clear + the owning Mac's) |
| 817 | `Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swift` | `device-terminal-focus` | `desiredFocusState` gets a `didSet` that calls the new `public var onFocusStateChange: ((Bool) -> Void)?` when the value changes (upstream: a plain stored `var desiredFocusState: Bool = false`) |
| 817 | `Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swift` | `device-terminal-focus` | `desiredFocusState` gets a `didSet` that calls the new `public var onFocusStateChange: ((Bool) -> Void)?` when the value changes, plus a read-only `public var isFocusDesired` for release builds (upstream: a plain stored `var desiredFocusState: Bool = false`) |
| 818 | `cmuxTests/SupermuxMobileAuthorizationTests.swift` | `device-terminal-actions-authz` | `classificationCoversWorkspacePaneAndMacWideMethods` expects `terminal.action` to be terminal-scoped (it names `workspace_id` and `terminal_id`, like `terminal.select`) |
| 830 | `Sources/AppDelegate.swift` | `remote-host-mode` | Remote Host Mode (`Sources/Supermux/RemoteHost/SupermuxRemoteHostMode.swift`). Five fenced sites: the top of `applicationShouldHandleReopen` (`showsWindowsOnReopen()`: reopening a headless host shows its windows), the end of `syncApplicationPresentationPreferences` after `syncMenuBarExtraVisibility` (`syncToSettings()`: the setting turning on hides every main window, off shows them), the show block near the end of `createMainWindow` (an `if keepsNewMainWindowHidden(window) { window.orderOut(nil) } else` prefix to upstream's `if !shouldActivate || …` so a new window stays hidden while headless), the top of `handleMainTerminalWindowCloseRequest` (the close button / `performClose` hides the window: `return false`), and `closeWindowWithConfirmation` after its `isMainTerminalWindow` guard (Close Window hides with no dialog) |
| 831 | `Sources/App/MenuBarExtraController.swift` | `remote-host-mode` | Four fenced sites: a stored `supermuxRemoteHostItems` (`SupermuxRemoteHostModeMenuItems`), installed right after `showMainWindowItem` in `buildMenu()` and refreshed after its `isHidden` line in `refreshUI(snapshot:)` (Show/Hide Supermux and Turn Off Remote Host Mode; hides upstream's Show cmux while the mode is on), `MenuBarExtraSettings.shouldInstallMenuBarExtra` returns true while the mode is on, and `MenuBarOnlySettings.activationPolicy` returns `.accessory` while the mode is on (no Dock icon) |
Expand Down
6 changes: 3 additions & 3 deletions Sources/Supermux/Devices/SupermuxDeviceTerminalActions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ enum SupermuxDeviceTerminalActions {
focusSettles[panelID] = nil
guard let surface, deviceTerminal(for: surface) != nil else { return }
let onScreen = SupermuxTerminalSizingVisibility.isOnScreen(surface)
let focused = surface.debugDesiredFocusState() && onScreen
let focused = surface.isFocusDesired && onScreen
applyGhosttyFocus(surface, onScreen: onScreen)
// Nothing sent yet counts as unfocused, so a pane built hidden
// never takes focus from whoever uses that terminal on its Mac.
Expand All @@ -118,11 +118,11 @@ enum SupermuxDeviceTerminalActions {
private static func applyGhosttyFocus(_ surface: TerminalSurface, onScreen: Bool) {
let panelID = surface.id
if !onScreen {
guard surface.debugDesiredFocusState(),
guard surface.isFocusDesired,
let live = surface.liveSurfaceForGhosttyAccess(reason: "supermux.mirrorFocus.offScreen") else { return }
ghostty_surface_set_focus(live, false)
unfocusedOffScreen.insert(panelID)
} else if unfocusedOffScreen.remove(panelID) != nil, surface.debugDesiredFocusState() {
} else if unfocusedOffScreen.remove(panelID) != nil, surface.isFocusDesired {
// `force`: cmux's record already says focused, so only the
// runtime surface (and its display id) is brought back.
surface.setFocus(true, force: true)
Expand Down
2 changes: 2 additions & 0 deletions Sources/Supermux/Devices/SupermuxRouteCandidateSync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ final class SupermuxRouteCandidateSync {
let outcome = await ask(device)
schedules[instance]?.finished(outcome.answer, at: Date())
if outcome == .stored { storedCount += 1 }
#if DEBUG
if outcome != .stored, outcome != .unsupported {
cmuxDebugLog("supermux.route candidates from \(instance.deviceID.prefix(8)): \(outcome.rawValue)")
}
#endif
return outcome
}

Expand Down
Loading