diff --git a/include/ghostty.h b/include/ghostty.h index 329ff6171..e27ed6f43 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -258,6 +258,8 @@ void ghostty_surface_mouse_scroll(ghostty_surface_t, double, double); void ghostty_surface_ime_point(ghostty_surface_t, double *, double *); void ghostty_surface_request_close(ghostty_surface_t); void ghostty_surface_split(ghostty_surface_t, ghostty_split_direction_e); +void ghostty_surface_split_focus_previous(ghostty_surface_t); +void ghostty_surface_split_focus_next(ghostty_surface_t); #ifdef __cplusplus } diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index 736ca915d..3d4b5f009 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -94,6 +94,16 @@ extension Ghostty { ghostty_surface_split(surface, direction) } + func splitMoveFocus(surface: ghostty_surface_t, direction: SplitFocusDirection) { + switch (direction) { + case .previous: + ghostty_surface_split_focus_previous(surface) + + case .next: + ghostty_surface_split_focus_next(surface) + } + } + // MARK: Ghostty Callbacks static func newSplit(_ userdata: UnsafeMutableRawPointer?, direction: ghostty_split_direction_e) { diff --git a/macos/Sources/GhosttyApp.swift b/macos/Sources/GhosttyApp.swift index 4a14e6fe6..8fb421e99 100644 --- a/macos/Sources/GhosttyApp.swift +++ b/macos/Sources/GhosttyApp.swift @@ -37,6 +37,13 @@ struct GhosttyApp: App { Button("Close", action: close).keyboardShortcut("w", modifiers: [.command]) Button("Close Window", action: Self.closeWindow).keyboardShortcut("w", modifiers: [.command, .shift]) } + + CommandGroup(before: .windowArrangement) { + Divider() + Button("Select Previous Split", action: splitMoveFocusPrevious).keyboardShortcut("[", modifiers: .command) + Button("Select Next Split", action: splitMoveFocusNext).keyboardShortcut("]", modifiers: .command) + Divider() + } } Settings { @@ -76,6 +83,18 @@ struct GhosttyApp: App { guard let surface = surfaceView.surface else { return } ghostty.split(surface: surface, direction: GHOSTTY_SPLIT_DOWN) } + + func splitMoveFocusPrevious() { + guard let surfaceView = focusedSurface else { return } + guard let surface = surfaceView.surface else { return } + ghostty.splitMoveFocus(surface: surface, direction: .previous) + } + + func splitMoveFocusNext() { + guard let surfaceView = focusedSurface else { return } + guard let surface = surfaceView.surface else { return } + ghostty.splitMoveFocus(surface: surface, direction: .next) + } } class AppDelegate: NSObject, NSApplicationDelegate { diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index bff1bb6cb..a8ffafbd6 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -503,4 +503,14 @@ pub const CAPI = struct { export fn ghostty_surface_split(ptr: *Surface, direction: input.SplitDirection) void { ptr.newSplit(direction) catch {}; } + + /// Focus on the next split (if any). + export fn ghostty_surface_split_focus_next(ptr: *Surface) void { + ptr.gotoNextSplit(); + } + + /// Focus on the previous split (if any). + export fn ghostty_surface_split_focus_previous(ptr: *Surface) void { + ptr.gotoPreviousSplit(); + } };