From 04c38ef3b0e5f8ca8cc514bf9de6217b0266091a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 11 Mar 2023 17:44:00 -0800 Subject: [PATCH] macos: change focus callback to use an enum so we can get other dirs --- include/ghostty.h | 18 +++++++++++------ macos/Sources/Ghostty/AppState.swift | 17 ++++++---------- macos/Sources/Ghostty/Package.swift | 25 ++++++++++++++++++++++++ src/Surface.zig | 14 ++++---------- src/apprt/embedded.zig | 29 +++++++--------------------- src/config.zig | 4 ++-- src/input.zig | 1 + src/input/Binding.zig | 18 ++++++++++++----- 8 files changed, 70 insertions(+), 56 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index e27ed6f43..66f001e06 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -32,8 +32,7 @@ typedef const char* (*ghostty_runtime_read_clipboard_cb)(void *); typedef void (*ghostty_runtime_write_clipboard_cb)(void *, const char *); typedef void (*ghostty_runtime_new_split_cb)(void *, ghostty_split_direction_e); typedef void (*ghostty_runtime_close_surface_cb)(void *); -typedef void (*ghostty_runtime_focus_next_split_cb)(void *); -typedef void (*ghostty_runtime_focus_previous_split_cb)(void *); +typedef void (*ghostty_runtime_focus_split_cb)(void *, ghostty_split_focus_direction_e); typedef struct { void *userdata; @@ -43,8 +42,7 @@ typedef struct { ghostty_runtime_write_clipboard_cb write_clipboard_cb; ghostty_runtime_new_split_cb new_split_cb; ghostty_runtime_close_surface_cb close_surface_cb; - ghostty_runtime_focus_next_split_cb focus_next_split_cb; - ghostty_runtime_focus_previous_split_cb focus_previous_split_cb; + ghostty_runtime_focus_split_cb focus_split_cb; } ghostty_runtime_config_s; typedef struct { @@ -58,6 +56,15 @@ typedef enum { GHOSTTY_SPLIT_DOWN } ghostty_split_direction_e; +typedef enum { + GHOSTTY_SPLIT_FOCUS_PREVIOUS, + GHOSTTY_SPLIT_FOCUS_NEXT, + GHOSTTY_SPLIT_FOCUS_TOP, + GHOSTTY_SPLIT_FOCUS_LEFT, + GHOSTTY_SPLIT_FOCUS_BOTTOM, + GHOSTTY_SPLIT_FOCUS_RIGHT, +} ghostty_split_focus_direction_e; + typedef enum { GHOSTTY_MOUSE_RELEASE, GHOSTTY_MOUSE_PRESS, @@ -258,8 +265,7 @@ 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); +void ghostty_surface_split_focus(ghostty_surface_t, ghostty_split_focus_direction_e); #ifdef __cplusplus } diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index 3d4b5f009..3ab7e25bb 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -59,8 +59,8 @@ extension Ghostty { write_clipboard_cb: { userdata, str in AppState.writeClipboard(userdata, string: str) }, new_split_cb: { userdata, direction in AppState.newSplit(userdata, direction: ghostty_split_direction_e(UInt32(direction))) }, close_surface_cb: { userdata in AppState.closeSurface(userdata) }, - focus_next_split_cb: { userdata in AppState.focusSplit(userdata, direction: .next) }, - focus_previous_split_cb: { userdata in AppState.focusSplit(userdata, direction: .previous) } + focus_split_cb: { userdata, direction in + AppState.focusSplit(userdata, direction: ghostty_split_focus_direction_e(UInt32(direction))) } ) // Create the ghostty app. @@ -95,13 +95,7 @@ extension Ghostty { } 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) - } + ghostty_surface_split_focus(surface, direction.toNative()) } // MARK: Ghostty Callbacks @@ -118,13 +112,14 @@ extension Ghostty { NotificationCenter.default.post(name: Notification.ghosttyCloseSurface, object: surface) } - static func focusSplit(_ userdata: UnsafeMutableRawPointer?, direction: SplitFocusDirection) { + static func focusSplit(_ userdata: UnsafeMutableRawPointer?, direction: ghostty_split_focus_direction_e) { guard let surface = self.surfaceUserdata(from: userdata) else { return } + guard let splitDirection = SplitFocusDirection.from(direction: direction) else { return } NotificationCenter.default.post( name: Notification.ghosttyFocusSplit, object: surface, userInfo: [ - Notification.SplitDirectionKey: direction, + Notification.SplitDirectionKey: splitDirection, ] ) } diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift index 603dec3e2..92f28b36a 100644 --- a/macos/Sources/Ghostty/Package.swift +++ b/macos/Sources/Ghostty/Package.swift @@ -1,4 +1,5 @@ import SwiftUI +import GhosttyKit struct Ghostty { // All the notifications that will be emitted will be put here. @@ -11,6 +12,30 @@ extension Ghostty { /// An enum that is used for the directions that a split focus event can change. enum SplitFocusDirection { case previous, next + + /// Initialize from a Ghostty API enum. + static func from(direction: ghostty_split_focus_direction_e) -> Self? { + switch (direction) { + case GHOSTTY_SPLIT_FOCUS_PREVIOUS: + return .previous + + case GHOSTTY_SPLIT_FOCUS_NEXT: + return .next + + default: + return nil + } + } + + func toNative() -> ghostty_split_focus_direction_e { + switch (self) { + case .previous: + return GHOSTTY_SPLIT_FOCUS_PREVIOUS + + case .next: + return GHOSTTY_SPLIT_FOCUS_NEXT + } + } } } diff --git a/src/Surface.zig b/src/Surface.zig index e9c007a96..5c1d51fe6 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -947,16 +947,10 @@ pub fn keyCallback( } else log.warn("runtime doesn't implement newSplit", .{}); }, - .next_split => { - if (@hasDecl(apprt.Surface, "gotoNextSplit")) { - self.rt_surface.gotoNextSplit(); - } else log.warn("runtime doesn't implement gotoNextSplit", .{}); - }, - - .previous_split => { - if (@hasDecl(apprt.Surface, "gotoPreviousSplit")) { - self.rt_surface.gotoPreviousSplit(); - } else log.warn("runtime doesn't implement gotoPreviousSplit", .{}); + .goto_split => |direction| { + if (@hasDecl(apprt.Surface, "gotoSplit")) { + self.rt_surface.gotoSplit(direction); + } else log.warn("runtime doesn't implement gotoSplit", .{}); }, .close_surface => { diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index a8ffafbd6..063743b44 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -53,8 +53,7 @@ pub const App = struct { close_surface: ?*const fn (SurfaceUD) callconv(.C) void = null, /// Focus the previous/next split (if any). - focus_next_split: ?*const fn (SurfaceUD) callconv(.C) void = null, - focus_previous_split: ?*const fn (SurfaceUD) callconv(.C) void = null, + focus_split: ?*const fn (SurfaceUD, input.SplitFocusDirection) callconv(.C) void = null, }; core_app: *CoreApp, @@ -177,22 +176,13 @@ pub const Surface = struct { func(self.opts.userdata); } - pub fn gotoNextSplit(self: *const Surface) void { - const func = self.app.opts.focus_next_split orelse { - log.info("runtime embedder does not support focus next split", .{}); + pub fn gotoSplit(self: *const Surface, direction: input.SplitFocusDirection) void { + const func = self.app.opts.focus_split orelse { + log.info("runtime embedder does not support focus split", .{}); return; }; - func(self.opts.userdata); - } - - pub fn gotoPreviousSplit(self: *const Surface) void { - const func = self.app.opts.focus_previous_split orelse { - log.info("runtime embedder does not support focus previous split", .{}); - return; - }; - - func(self.opts.userdata); + func(self.opts.userdata, direction); } pub fn getContentScale(self: *const Surface) !apprt.ContentScale { @@ -505,12 +495,7 @@ pub const CAPI = struct { } /// 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(); + export fn ghostty_surface_split_focus(ptr: *Surface, direction: input.SplitFocusDirection) void { + ptr.gotoSplit(direction); } }; diff --git a/src/config.zig b/src/config.zig index 193bd69a5..3df202cd4 100644 --- a/src/config.zig +++ b/src/config.zig @@ -314,12 +314,12 @@ pub const Config = struct { try result.keybind.set.put( alloc, .{ .key = .left_bracket, .mods = .{ .super = true } }, - .{ .previous_split = {} }, + .{ .goto_split = .previous }, ); try result.keybind.set.put( alloc, .{ .key = .right_bracket, .mods = .{ .super = true } }, - .{ .next_split = {} }, + .{ .goto_split = .next }, ); { // Cmd+N for goto tab N diff --git a/src/input.zig b/src/input.zig index 2bdcbe86a..53306eb26 100644 --- a/src/input.zig +++ b/src/input.zig @@ -4,6 +4,7 @@ pub usingnamespace @import("input/mouse.zig"); pub usingnamespace @import("input/key.zig"); pub const Binding = @import("input/Binding.zig"); pub const SplitDirection = Binding.Action.SplitDirection; +pub const SplitFocusDirection = Binding.Action.SplitFocusDirection; test { std.testing.refAllDecls(@This()); diff --git a/src/input/Binding.zig b/src/input/Binding.zig index 549e7a615..cac34826c 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -184,11 +184,8 @@ pub const Action = union(enum) { /// in the direction given. new_split: SplitDirection, - /// Go to the previous split. - previous_split: void, - - /// Go to the next split. - next_split: void, + /// Focus on a split in a given direction. + goto_split: SplitFocusDirection, /// Close the current "surface", whether that is a window, tab, split, /// etc. This only closes ONE surface. @@ -213,6 +210,17 @@ pub const Action = union(enum) { // Note: we don't support top or left yet }; + + // Extern because it is used in the embedded runtime ABI. + pub const SplitFocusDirection = enum(c_int) { + previous, + next, + + top, + left, + bottom, + right, + }; }; /// Trigger is the associated key state that can trigger an action.