mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Merge pull request #1901 from ghostty-org/macos-context
macOS: Context Menu
This commit is contained in:
@ -533,7 +533,8 @@ ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t,
|
|||||||
ghostty_input_mods_e);
|
ghostty_input_mods_e);
|
||||||
void ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
|
void ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
|
||||||
void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
|
void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
|
||||||
void ghostty_surface_mouse_button(ghostty_surface_t,
|
bool ghostty_surface_mouse_captured(ghostty_surface_t);
|
||||||
|
bool ghostty_surface_mouse_button(ghostty_surface_t,
|
||||||
ghostty_input_mouse_state_e,
|
ghostty_input_mouse_state_e,
|
||||||
ghostty_input_mouse_button_e,
|
ghostty_input_mouse_button_e,
|
||||||
ghostty_input_mods_e);
|
ghostty_input_mods_e);
|
||||||
|
@ -50,6 +50,8 @@
|
|||||||
A59630A02AEF6AEB00D64628 /* TerminalManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A596309F2AEF6AEB00D64628 /* TerminalManager.swift */; };
|
A59630A02AEF6AEB00D64628 /* TerminalManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A596309F2AEF6AEB00D64628 /* TerminalManager.swift */; };
|
||||||
A59630A22AF0415000D64628 /* Ghostty.TerminalSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59630A12AF0415000D64628 /* Ghostty.TerminalSplit.swift */; };
|
A59630A22AF0415000D64628 /* Ghostty.TerminalSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59630A12AF0415000D64628 /* Ghostty.TerminalSplit.swift */; };
|
||||||
A59630A42AF059BB00D64628 /* Ghostty.SplitNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59630A32AF059BB00D64628 /* Ghostty.SplitNode.swift */; };
|
A59630A42AF059BB00D64628 /* Ghostty.SplitNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59630A32AF059BB00D64628 /* Ghostty.SplitNode.swift */; };
|
||||||
|
A5985CD72C320C4500C57AD3 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5985CD62C320C4500C57AD3 /* String+Extension.swift */; };
|
||||||
|
A5985CD82C320C4500C57AD3 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5985CD62C320C4500C57AD3 /* String+Extension.swift */; };
|
||||||
A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */; };
|
A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */; };
|
||||||
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; };
|
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; };
|
||||||
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
|
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
|
||||||
@ -111,6 +113,7 @@
|
|||||||
A596309F2AEF6AEB00D64628 /* TerminalManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalManager.swift; sourceTree = "<group>"; };
|
A596309F2AEF6AEB00D64628 /* TerminalManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalManager.swift; sourceTree = "<group>"; };
|
||||||
A59630A12AF0415000D64628 /* Ghostty.TerminalSplit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.TerminalSplit.swift; sourceTree = "<group>"; };
|
A59630A12AF0415000D64628 /* Ghostty.TerminalSplit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.TerminalSplit.swift; sourceTree = "<group>"; };
|
||||||
A59630A32AF059BB00D64628 /* Ghostty.SplitNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.SplitNode.swift; sourceTree = "<group>"; };
|
A59630A32AF059BB00D64628 /* Ghostty.SplitNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.SplitNode.swift; sourceTree = "<group>"; };
|
||||||
|
A5985CD62C320C4500C57AD3 /* String+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
|
||||||
A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; };
|
A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; };
|
||||||
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; };
|
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; };
|
||||||
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
|
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
|
||||||
@ -205,6 +208,7 @@
|
|||||||
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */,
|
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */,
|
||||||
C1F26EA62B738B9900404083 /* NSView+Extension.swift */,
|
C1F26EA62B738B9900404083 /* NSView+Extension.swift */,
|
||||||
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */,
|
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */,
|
||||||
|
A5985CD62C320C4500C57AD3 /* String+Extension.swift */,
|
||||||
C1F26EE72B76CBFC00404083 /* VibrantLayer.h */,
|
C1F26EE72B76CBFC00404083 /* VibrantLayer.h */,
|
||||||
C1F26EE82B76CBFC00404083 /* VibrantLayer.m */,
|
C1F26EE82B76CBFC00404083 /* VibrantLayer.m */,
|
||||||
A5CEAFDA29B8005900646FDA /* SplitView */,
|
A5CEAFDA29B8005900646FDA /* SplitView */,
|
||||||
@ -503,6 +507,7 @@
|
|||||||
A5333E1C2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */,
|
A5333E1C2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */,
|
||||||
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */,
|
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */,
|
||||||
A56D58862ACDDB4100508D2C /* Ghostty.Shell.swift in Sources */,
|
A56D58862ACDDB4100508D2C /* Ghostty.Shell.swift in Sources */,
|
||||||
|
A5985CD72C320C4500C57AD3 /* String+Extension.swift in Sources */,
|
||||||
A59630A22AF0415000D64628 /* Ghostty.TerminalSplit.swift in Sources */,
|
A59630A22AF0415000D64628 /* Ghostty.TerminalSplit.swift in Sources */,
|
||||||
A5FEB3002ABB69450068369E /* main.swift in Sources */,
|
A5FEB3002ABB69450068369E /* main.swift in Sources */,
|
||||||
A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */,
|
A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */,
|
||||||
@ -537,6 +542,7 @@
|
|||||||
A53D0C9C2B543F7B00305CE6 /* Package.swift in Sources */,
|
A53D0C9C2B543F7B00305CE6 /* Package.swift in Sources */,
|
||||||
A53D0C9B2B543F3B00305CE6 /* Ghostty.App.swift in Sources */,
|
A53D0C9B2B543F3B00305CE6 /* Ghostty.App.swift in Sources */,
|
||||||
A5333E242B5A22D9008AEFF7 /* Ghostty.Shell.swift in Sources */,
|
A5333E242B5A22D9008AEFF7 /* Ghostty.Shell.swift in Sources */,
|
||||||
|
A5985CD82C320C4500C57AD3 /* String+Extension.swift in Sources */,
|
||||||
C159E89D2B69A2EF00FDFE9C /* OSColor+Extension.swift in Sources */,
|
C159E89D2B69A2EF00FDFE9C /* OSColor+Extension.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -471,15 +471,39 @@ extension Ghostty {
|
|||||||
|
|
||||||
|
|
||||||
override func rightMouseDown(with event: NSEvent) {
|
override func rightMouseDown(with event: NSEvent) {
|
||||||
guard let surface = self.surface else { return }
|
guard let surface = self.surface else { return super.rightMouseDown(with: event) }
|
||||||
|
|
||||||
let mods = Ghostty.ghosttyMods(event.modifierFlags)
|
let mods = Ghostty.ghosttyMods(event.modifierFlags)
|
||||||
ghostty_surface_mouse_button(surface, GHOSTTY_MOUSE_PRESS, GHOSTTY_MOUSE_RIGHT, mods)
|
if (ghostty_surface_mouse_button(
|
||||||
|
surface,
|
||||||
|
GHOSTTY_MOUSE_PRESS,
|
||||||
|
GHOSTTY_MOUSE_RIGHT,
|
||||||
|
mods
|
||||||
|
)) {
|
||||||
|
// Consumed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse event not consumed
|
||||||
|
super.rightMouseDown(with: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func rightMouseUp(with event: NSEvent) {
|
override func rightMouseUp(with event: NSEvent) {
|
||||||
guard let surface = self.surface else { return }
|
guard let surface = self.surface else { return super.rightMouseUp(with: event) }
|
||||||
|
|
||||||
let mods = Ghostty.ghosttyMods(event.modifierFlags)
|
let mods = Ghostty.ghosttyMods(event.modifierFlags)
|
||||||
ghostty_surface_mouse_button(surface, GHOSTTY_MOUSE_RELEASE, GHOSTTY_MOUSE_RIGHT, mods)
|
if (ghostty_surface_mouse_button(
|
||||||
|
surface,
|
||||||
|
GHOSTTY_MOUSE_RELEASE,
|
||||||
|
GHOSTTY_MOUSE_RIGHT,
|
||||||
|
mods
|
||||||
|
)) {
|
||||||
|
// Handled
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse event not consumed
|
||||||
|
super.rightMouseUp(with: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func mouseMoved(with event: NSEvent) {
|
override func mouseMoved(with event: NSEvent) {
|
||||||
@ -843,6 +867,58 @@ extension Ghostty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func menu(for event: NSEvent) -> NSMenu? {
|
||||||
|
// We only support right-click menus
|
||||||
|
switch event.type {
|
||||||
|
case .rightMouseDown:
|
||||||
|
// Good
|
||||||
|
break
|
||||||
|
|
||||||
|
case .leftMouseDown:
|
||||||
|
if !event.modifierFlags.contains(.control) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// In this case, AppKit calls menu BEFORE calling any mouse events.
|
||||||
|
// If mouse capturing is enabled then we never show the context menu
|
||||||
|
// so that we can handle ctrl+left-click in the terminal app.
|
||||||
|
guard let surface = self.surface else { return nil }
|
||||||
|
if ghostty_surface_mouse_captured(surface) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we return a non-nil menu then mouse events will never be
|
||||||
|
// processed by the core, so we need to manually send a right
|
||||||
|
// mouse down event.
|
||||||
|
//
|
||||||
|
// Note this never sounds a right mouse up event but that's the
|
||||||
|
// same as normal right-click with capturing disabled from AppKit.
|
||||||
|
let mods = Ghostty.ghosttyMods(event.modifierFlags)
|
||||||
|
ghostty_surface_mouse_button(
|
||||||
|
surface,
|
||||||
|
GHOSTTY_MOUSE_PRESS,
|
||||||
|
GHOSTTY_MOUSE_RIGHT,
|
||||||
|
mods
|
||||||
|
)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let menu = NSMenu()
|
||||||
|
|
||||||
|
// If we have a selection, add copy
|
||||||
|
if self.selectedRange().length > 0 {
|
||||||
|
menu.addItem(withTitle: "Copy", action: #selector(copy(_:)), keyEquivalent: "")
|
||||||
|
}
|
||||||
|
menu.addItem(withTitle: "Paste", action: #selector(paste(_:)), keyEquivalent: "")
|
||||||
|
|
||||||
|
menu.addItem(.separator())
|
||||||
|
menu.addItem(withTitle: "Toggle Terminal Inspector", action: #selector(TerminalController.toggleTerminalInspector(_:)), keyEquivalent: "")
|
||||||
|
|
||||||
|
return menu
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Menu Handlers
|
// MARK: Menu Handlers
|
||||||
|
|
||||||
@IBAction func copy(_ sender: Any?) {
|
@IBAction func copy(_ sender: Any?) {
|
||||||
|
20
macos/Sources/Helpers/String+Extension.swift
Normal file
20
macos/Sources/Helpers/String+Extension.swift
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
extension String {
|
||||||
|
func truncate(length: Int, trailing: String = "…") -> String {
|
||||||
|
let maxLength = length - trailing.count
|
||||||
|
guard maxLength > 0, !self.isEmpty, self.count > length else {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
return self.prefix(maxLength) + trailing
|
||||||
|
}
|
||||||
|
|
||||||
|
#if canImport(AppKit)
|
||||||
|
func temporaryFile(_ filename: String = "temp") -> URL {
|
||||||
|
let url = FileManager.default.temporaryDirectory
|
||||||
|
.appendingPathComponent(filename)
|
||||||
|
.appendingPathExtension("txt")
|
||||||
|
let string = self
|
||||||
|
try? string.write(to: url, atomically: true, encoding: .utf8)
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
@ -2129,12 +2129,23 @@ fn mouseShiftCapture(self: *const Surface, lock: bool) bool {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the mouse is currently captured by the terminal
|
||||||
|
/// (i.e. reporting events).
|
||||||
|
pub fn mouseCaptured(self: *Surface) bool {
|
||||||
|
self.renderer_state.mutex.lock();
|
||||||
|
defer self.renderer_state.mutex.unlock();
|
||||||
|
return self.io.terminal.flags.mouse_event != .none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called for mouse button press/release events. This will return true
|
||||||
|
/// if the mouse event was consumed in some way (i.e. the program is capturing
|
||||||
|
/// mouse events). If the event was not consumed, then false is returned.
|
||||||
pub fn mouseButtonCallback(
|
pub fn mouseButtonCallback(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
action: input.MouseButtonState,
|
action: input.MouseButtonState,
|
||||||
button: input.MouseButton,
|
button: input.MouseButton,
|
||||||
mods: input.Mods,
|
mods: input.Mods,
|
||||||
) !void {
|
) !bool {
|
||||||
// log.debug("mouse action={} button={} mods={}", .{ action, button, mods });
|
// log.debug("mouse action={} button={} mods={}", .{ action, button, mods });
|
||||||
|
|
||||||
// If we have an inspector, we always queue a render
|
// If we have an inspector, we always queue a render
|
||||||
@ -2155,7 +2166,7 @@ pub fn mouseButtonCallback(
|
|||||||
const screen = &self.renderer_state.terminal.screen;
|
const screen = &self.renderer_state.terminal.screen;
|
||||||
const p = screen.pages.pin(.{ .viewport = point }) orelse {
|
const p = screen.pages.pin(.{ .viewport = point }) orelse {
|
||||||
log.warn("failed to get pin for clicked point", .{});
|
log.warn("failed to get pin for clicked point", .{});
|
||||||
return;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
insp.cell.select(
|
insp.cell.select(
|
||||||
@ -2166,7 +2177,7 @@ pub fn mouseButtonCallback(
|
|||||||
) catch |err| {
|
) catch |err| {
|
||||||
log.warn("error selecting cell for inspector err={}", .{err});
|
log.warn("error selecting cell for inspector err={}", .{err});
|
||||||
};
|
};
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2205,7 +2216,7 @@ pub fn mouseButtonCallback(
|
|||||||
if (selection) {
|
if (selection) {
|
||||||
const pos = try self.rt_surface.getCursorPos();
|
const pos = try self.rt_surface.getCursorPos();
|
||||||
try self.cursorPosCallback(pos);
|
try self.cursorPosCallback(pos);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2216,7 +2227,7 @@ pub fn mouseButtonCallback(
|
|||||||
if (button == .left and action == .release and self.mouse.over_link) {
|
if (button == .left and action == .release and self.mouse.over_link) {
|
||||||
const pos = try self.rt_surface.getCursorPos();
|
const pos = try self.rt_surface.getCursorPos();
|
||||||
if (self.processLinks(pos)) |processed| {
|
if (self.processLinks(pos)) |processed| {
|
||||||
if (processed) return;
|
if (processed) return true;
|
||||||
} else |err| {
|
} else |err| {
|
||||||
log.warn("error processing links err={}", .{err});
|
log.warn("error processing links err={}", .{err});
|
||||||
}
|
}
|
||||||
@ -2257,7 +2268,7 @@ pub fn mouseButtonCallback(
|
|||||||
|
|
||||||
// If we're doing mouse reporting, we do not support any other
|
// If we're doing mouse reporting, we do not support any other
|
||||||
// selection or highlighting.
|
// selection or highlighting.
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2269,7 +2280,7 @@ pub fn mouseButtonCallback(
|
|||||||
self.renderer_state.mutex.lock();
|
self.renderer_state.mutex.lock();
|
||||||
defer self.renderer_state.mutex.unlock();
|
defer self.renderer_state.mutex.unlock();
|
||||||
try self.clickMoveCursor(pin.*);
|
try self.clickMoveCursor(pin.*);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For left button clicks we always record some information for
|
// For left button clicks we always record some information for
|
||||||
@ -2398,6 +2409,53 @@ pub fn mouseButtonCallback(
|
|||||||
try self.startClipboardRequest(clipboard, .{ .paste = {} });
|
try self.startClipboardRequest(clipboard, .{ .paste = {} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Right-click down selects word for context menus. If the apprt
|
||||||
|
// doesn't implement context menus this can be a bit weird but they
|
||||||
|
// are supported by our two main apprts so we always do this. If we
|
||||||
|
// want to be careful in the future we can add a function to apprts
|
||||||
|
// that let's us know.
|
||||||
|
if (button == .right and action == .press) sel: {
|
||||||
|
self.renderer_state.mutex.lock();
|
||||||
|
defer self.renderer_state.mutex.unlock();
|
||||||
|
|
||||||
|
// Get our viewport pin
|
||||||
|
const screen = &self.renderer_state.terminal.screen;
|
||||||
|
const pin = pin: {
|
||||||
|
const pos = try self.rt_surface.getCursorPos();
|
||||||
|
const pt_viewport = self.posToViewport(pos.x, pos.y);
|
||||||
|
const pin = screen.pages.pin(.{
|
||||||
|
.viewport = .{
|
||||||
|
.x = pt_viewport.x,
|
||||||
|
.y = pt_viewport.y,
|
||||||
|
},
|
||||||
|
}) orelse {
|
||||||
|
// Weird... our viewport x/y that we just converted isn't
|
||||||
|
// found in our pages. This is probably a bug but we don't
|
||||||
|
// want to crash in releases because its harmless. So, we
|
||||||
|
// only assert in debug mode.
|
||||||
|
if (comptime std.debug.runtime_safety) unreachable;
|
||||||
|
break :sel;
|
||||||
|
};
|
||||||
|
|
||||||
|
break :pin pin;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we already have a selection and the selection contains
|
||||||
|
// where we clicked then we don't want to modify the selection.
|
||||||
|
if (self.io.terminal.screen.selection) |prev_sel| {
|
||||||
|
if (prev_sel.contains(screen, pin)) break :sel;
|
||||||
|
|
||||||
|
// The selection doesn't contain our pin, so we create a new
|
||||||
|
// word selection where we clicked.
|
||||||
|
}
|
||||||
|
|
||||||
|
const sel = screen.selectWord(pin) orelse break :sel;
|
||||||
|
try self.setSelection(sel);
|
||||||
|
try self.queueRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs the "click-to-move" logic to move the cursor to the given
|
/// Performs the "click-to-move" logic to move the cursor to the given
|
||||||
|
@ -710,10 +710,10 @@ pub const Surface = struct {
|
|||||||
action: input.MouseButtonState,
|
action: input.MouseButtonState,
|
||||||
button: input.MouseButton,
|
button: input.MouseButton,
|
||||||
mods: input.Mods,
|
mods: input.Mods,
|
||||||
) void {
|
) bool {
|
||||||
self.core_surface.mouseButtonCallback(action, button, mods) catch |err| {
|
return self.core_surface.mouseButtonCallback(action, button, mods) catch |err| {
|
||||||
log.err("error in mouse button callback err={}", .{err});
|
log.err("error in mouse button callback err={}", .{err});
|
||||||
return;
|
return false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1632,14 +1632,20 @@ pub const CAPI = struct {
|
|||||||
surface.textCallback(ptr[0..len]);
|
surface.textCallback(ptr[0..len]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the surface currently has mouse capturing
|
||||||
|
/// enabled.
|
||||||
|
export fn ghostty_surface_mouse_captured(surface: *Surface) bool {
|
||||||
|
return surface.core_surface.mouseCaptured();
|
||||||
|
}
|
||||||
|
|
||||||
/// Tell the surface that it needs to schedule a render
|
/// Tell the surface that it needs to schedule a render
|
||||||
export fn ghostty_surface_mouse_button(
|
export fn ghostty_surface_mouse_button(
|
||||||
surface: *Surface,
|
surface: *Surface,
|
||||||
action: input.MouseButtonState,
|
action: input.MouseButtonState,
|
||||||
button: input.MouseButton,
|
button: input.MouseButton,
|
||||||
mods: c_int,
|
mods: c_int,
|
||||||
) void {
|
) bool {
|
||||||
surface.mouseButtonCallback(
|
return surface.mouseButtonCallback(
|
||||||
action,
|
action,
|
||||||
button,
|
button,
|
||||||
@bitCast(@as(
|
@bitCast(@as(
|
||||||
|
@ -1048,7 +1048,7 @@ pub const Surface = struct {
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
core_win.mouseButtonCallback(action, button, mods) catch |err| {
|
_ = core_win.mouseButtonCallback(action, button, mods) catch |err| {
|
||||||
log.err("error in scroll callback err={}", .{err});
|
log.err("error in scroll callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -1164,7 +1164,7 @@ fn gtkMouseDown(
|
|||||||
self.grabFocus();
|
self.grabFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.core_surface.mouseButtonCallback(.press, button, mods) catch |err| {
|
_ = self.core_surface.mouseButtonCallback(.press, button, mods) catch |err| {
|
||||||
log.err("error in key callback err={}", .{err});
|
log.err("error in key callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@ -1184,7 +1184,7 @@ fn gtkMouseUp(
|
|||||||
const mods = translateMods(gtk_mods);
|
const mods = translateMods(gtk_mods);
|
||||||
|
|
||||||
const self = userdataSelf(ud.?);
|
const self = userdataSelf(ud.?);
|
||||||
self.core_surface.mouseButtonCallback(.release, button, mods) catch |err| {
|
_ = self.core_surface.mouseButtonCallback(.release, button, mods) catch |err| {
|
||||||
log.err("error in key callback err={}", .{err});
|
log.err("error in key callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user