mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +03:00
macos: support cursor style
This commit is contained in:
@ -70,6 +70,43 @@ typedef enum {
|
||||
GHOSTTY_MOUSE_MOMENTUM_MAY_BEGIN,
|
||||
} ghostty_input_mouse_momentum_e;
|
||||
|
||||
typedef enum {
|
||||
GHOSTTY_CURSOR_SHAPE_DEFAULT,
|
||||
GHOSTTY_CURSOR_SHAPE_CONTEXT_MENU,
|
||||
GHOSTTY_CURSOR_SHAPE_HELP,
|
||||
GHOSTTY_CURSOR_SHAPE_POINTER,
|
||||
GHOSTTY_CURSOR_SHAPE_PROGRESS,
|
||||
GHOSTTY_CURSOR_SHAPE_WAIT,
|
||||
GHOSTTY_CURSOR_SHAPE_CELL,
|
||||
GHOSTTY_CURSOR_SHAPE_CROSSHAIR,
|
||||
GHOSTTY_CURSOR_SHAPE_TEXT,
|
||||
GHOSTTY_CURSOR_SHAPE_VERTICAL_TEXT,
|
||||
GHOSTTY_CURSOR_SHAPE_ALIAS,
|
||||
GHOSTTY_CURSOR_SHAPE_COPY,
|
||||
GHOSTTY_CURSOR_SHAPE_MOVE,
|
||||
GHOSTTY_CURSOR_SHAPE_NO_DROP,
|
||||
GHOSTTY_CURSOR_SHAPE_NOT_ALLOWED,
|
||||
GHOSTTY_CURSOR_SHAPE_GRAB,
|
||||
GHOSTTY_CURSOR_SHAPE_GRABBING,
|
||||
GHOSTTY_CURSOR_SHAPE_ALL_SCROLL,
|
||||
GHOSTTY_CURSOR_SHAPE_COL_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_ROW_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_N_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_E_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_S_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_W_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_NE_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_NW_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_SE_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_SW_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_EW_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_NS_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_NESW_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_NWSE_RESIZE,
|
||||
GHOSTTY_CURSOR_SHAPE_ZOOM_IN,
|
||||
GHOSTTY_CURSOR_SHAPE_ZOOM_OUT,
|
||||
} ghostty_cursor_shape_e;
|
||||
|
||||
typedef enum {
|
||||
GHOSTTY_NON_NATIVE_FULLSCREEN_FALSE,
|
||||
GHOSTTY_NON_NATIVE_FULLSCREEN_TRUE,
|
||||
@ -264,6 +301,7 @@ typedef struct {
|
||||
typedef void (*ghostty_runtime_wakeup_cb)(void *);
|
||||
typedef const ghostty_config_t (*ghostty_runtime_reload_config_cb)(void *);
|
||||
typedef void (*ghostty_runtime_set_title_cb)(void *, const char *);
|
||||
typedef void (*ghostty_runtime_set_cursor_shape_cb)(void *, ghostty_cursor_shape_e);
|
||||
typedef const char* (*ghostty_runtime_read_clipboard_cb)(void *, ghostty_clipboard_e);
|
||||
typedef void (*ghostty_runtime_write_clipboard_cb)(void *, const char *, ghostty_clipboard_e);
|
||||
typedef void (*ghostty_runtime_new_split_cb)(void *, ghostty_split_direction_e, ghostty_surface_config_s);
|
||||
@ -281,6 +319,7 @@ typedef struct {
|
||||
ghostty_runtime_wakeup_cb wakeup_cb;
|
||||
ghostty_runtime_reload_config_cb reload_config_cb;
|
||||
ghostty_runtime_set_title_cb set_title_cb;
|
||||
ghostty_runtime_set_cursor_shape_cb set_cursor_shape_cb;
|
||||
ghostty_runtime_read_clipboard_cb read_clipboard_cb;
|
||||
ghostty_runtime_write_clipboard_cb write_clipboard_cb;
|
||||
ghostty_runtime_new_split_cb new_split_cb;
|
||||
|
@ -72,6 +72,7 @@ extension Ghostty {
|
||||
wakeup_cb: { userdata in AppState.wakeup(userdata) },
|
||||
reload_config_cb: { userdata in AppState.reloadConfig(userdata) },
|
||||
set_title_cb: { userdata, title in AppState.setTitle(userdata, title: title) },
|
||||
set_cursor_shape_cb: { userdata, shape in AppState.setCursorShape(userdata, shape: shape) },
|
||||
read_clipboard_cb: { userdata, loc in AppState.readClipboard(userdata, location: loc) },
|
||||
write_clipboard_cb: { userdata, str, loc in AppState.writeClipboard(userdata, string: str, location: loc) },
|
||||
new_split_cb: { userdata, direction, surfaceConfig in AppState.newSplit(userdata, direction: direction, config: surfaceConfig) },
|
||||
@ -333,6 +334,11 @@ extension Ghostty {
|
||||
}
|
||||
}
|
||||
|
||||
static func setCursorShape(_ userdata: UnsafeMutableRawPointer?, shape: ghostty_cursor_shape_e) {
|
||||
let surfaceView = Unmanaged<SurfaceView>.fromOpaque(userdata!).takeUnretainedValue()
|
||||
surfaceView.setCursorShape(shape)
|
||||
}
|
||||
|
||||
static func toggleFullscreen(_ userdata: UnsafeMutableRawPointer?, nonNativeFullscreen: ghostty_non_native_fullscreen_e) {
|
||||
guard let surface = self.surfaceUserdata(from: userdata) else { return }
|
||||
NotificationCenter.default.post(
|
||||
|
@ -195,7 +195,9 @@ extension Ghostty {
|
||||
private(set) var surface: ghostty_surface_t?
|
||||
var error: Error? = nil
|
||||
|
||||
private var markedText: NSMutableAttributedString;
|
||||
private var markedText: NSMutableAttributedString
|
||||
private var mouseEntered: Bool = false
|
||||
private var cursor: NSCursor = .arrow
|
||||
|
||||
// We need to support being a first responder so that we can get input events
|
||||
override var acceptsFirstResponder: Bool { return true }
|
||||
@ -265,6 +267,64 @@ extension Ghostty {
|
||||
ghostty_surface_set_size(surface, UInt32(scaledSize.width), UInt32(scaledSize.height))
|
||||
}
|
||||
|
||||
func setCursorShape(_ shape: ghostty_cursor_shape_e) {
|
||||
switch (shape) {
|
||||
case GHOSTTY_CURSOR_SHAPE_DEFAULT:
|
||||
cursor = .arrow
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_CONTEXT_MENU:
|
||||
cursor = .contextualMenu
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_TEXT:
|
||||
cursor = .iBeam
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_CROSSHAIR:
|
||||
cursor = .crosshair
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_GRAB:
|
||||
cursor = .openHand
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_GRABBING:
|
||||
cursor = .closedHand
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_POINTER:
|
||||
cursor = .pointingHand
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_W_RESIZE:
|
||||
cursor = .resizeLeft
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_E_RESIZE:
|
||||
cursor = .resizeRight
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_N_RESIZE:
|
||||
cursor = .resizeUp
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_S_RESIZE:
|
||||
cursor = .resizeDown
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_NS_RESIZE:
|
||||
cursor = .resizeUpDown
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_EW_RESIZE:
|
||||
cursor = .resizeLeftRight
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_VERTICAL_TEXT:
|
||||
cursor = .iBeamCursorForVerticalLayout
|
||||
|
||||
case GHOSTTY_CURSOR_SHAPE_NOT_ALLOWED:
|
||||
cursor = .operationNotAllowed
|
||||
|
||||
default:
|
||||
// We ignore unknown shapes.
|
||||
return
|
||||
}
|
||||
|
||||
// Set our cursor immediately if our mouse is over our window
|
||||
if (mouseEntered) {
|
||||
cursor.set()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidMoveToWindow() {
|
||||
guard let window = self.window else { return }
|
||||
guard let surface = self.surface else { return }
|
||||
@ -370,6 +430,14 @@ extension Ghostty {
|
||||
self.mouseMoved(with: event)
|
||||
}
|
||||
|
||||
override func mouseEntered(with event: NSEvent) {
|
||||
mouseEntered = true
|
||||
}
|
||||
|
||||
override func mouseExited(with event: NSEvent) {
|
||||
mouseEntered = false
|
||||
}
|
||||
|
||||
override func scrollWheel(with event: NSEvent) {
|
||||
guard let surface = self.surface else { return }
|
||||
|
||||
@ -413,6 +481,10 @@ extension Ghostty {
|
||||
ghostty_surface_mouse_scroll(surface, x, y, mods)
|
||||
}
|
||||
|
||||
override func cursorUpdate(with event: NSEvent) {
|
||||
cursor.set()
|
||||
}
|
||||
|
||||
override func keyDown(with event: NSEvent) {
|
||||
let action = event.isARepeat ? GHOSTTY_ACTION_REPEAT : GHOSTTY_ACTION_PRESS
|
||||
keyAction(action, event: event)
|
||||
|
@ -11,6 +11,7 @@ const Allocator = std.mem.Allocator;
|
||||
const objc = @import("objc");
|
||||
const apprt = @import("../apprt.zig");
|
||||
const input = @import("../input.zig");
|
||||
const terminal = @import("../terminal/main.zig");
|
||||
const CoreApp = @import("../App.zig");
|
||||
const CoreSurface = @import("../Surface.zig");
|
||||
const configpkg = @import("../config.zig");
|
||||
@ -48,6 +49,9 @@ pub const App = struct {
|
||||
/// Called to set the title of the window.
|
||||
set_title: *const fn (SurfaceUD, [*]const u8) callconv(.C) void,
|
||||
|
||||
/// Called to set the cursor shape.
|
||||
set_cursor_shape: *const fn (SurfaceUD, terminal.CursorShape) callconv(.C) void,
|
||||
|
||||
/// Read the clipboard value. The return value must be preserved
|
||||
/// by the host until the next call. If there is no valid clipboard
|
||||
/// value then this should return null.
|
||||
@ -310,6 +314,13 @@ pub const Surface = struct {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn setCursorShape(self: *Surface, shape: terminal.CursorShape) !void {
|
||||
self.app.opts.set_cursor_shape(
|
||||
self.opts.userdata,
|
||||
shape,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn supportsClipboard(
|
||||
self: *const Surface,
|
||||
clipboard_type: apprt.Clipboard,
|
||||
|
@ -3,6 +3,8 @@ const std = @import("std");
|
||||
/// The possible cursor shapes. Not all app runtimes support these shapes.
|
||||
/// The shapes are always based on the W3C supported cursor styles so we
|
||||
/// can have a cross platform list.
|
||||
//
|
||||
// Must be kept in sync with ghostty_cursor_shape_e
|
||||
pub const CursorShape = enum(c_int) {
|
||||
default,
|
||||
context_menu,
|
||||
|
Reference in New Issue
Block a user