mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: enable secure input on password input
This commit is contained in:
@ -464,6 +464,7 @@ typedef void (*ghostty_runtime_show_desktop_notification_cb)(void*,
|
|||||||
typedef void (
|
typedef void (
|
||||||
*ghostty_runtime_update_renderer_health)(void*, ghostty_renderer_health_e);
|
*ghostty_runtime_update_renderer_health)(void*, ghostty_renderer_health_e);
|
||||||
typedef void (*ghostty_runtime_mouse_over_link_cb)(void*, const char*, size_t);
|
typedef void (*ghostty_runtime_mouse_over_link_cb)(void*, const char*, size_t);
|
||||||
|
typedef void (*ghostty_runtime_set_password_input_cb)(void*, bool);
|
||||||
typedef void (*ghostty_runtime_toggle_secure_input_cb)();
|
typedef void (*ghostty_runtime_toggle_secure_input_cb)();
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -495,6 +496,7 @@ typedef struct {
|
|||||||
ghostty_runtime_show_desktop_notification_cb show_desktop_notification_cb;
|
ghostty_runtime_show_desktop_notification_cb show_desktop_notification_cb;
|
||||||
ghostty_runtime_update_renderer_health update_renderer_health_cb;
|
ghostty_runtime_update_renderer_health update_renderer_health_cb;
|
||||||
ghostty_runtime_mouse_over_link_cb mouse_over_link_cb;
|
ghostty_runtime_mouse_over_link_cb mouse_over_link_cb;
|
||||||
|
ghostty_runtime_set_password_input_cb set_password_input_cb;
|
||||||
ghostty_runtime_toggle_secure_input_cb toggle_secure_input_cb;
|
ghostty_runtime_toggle_secure_input_cb toggle_secure_input_cb;
|
||||||
} ghostty_runtime_config_s;
|
} ghostty_runtime_config_s;
|
||||||
|
|
||||||
|
@ -95,6 +95,7 @@ extension Ghostty {
|
|||||||
App.showUserNotification(userdata, title: title, body: body) },
|
App.showUserNotification(userdata, title: title, body: body) },
|
||||||
update_renderer_health_cb: { userdata, health in App.updateRendererHealth(userdata, health: health) },
|
update_renderer_health_cb: { userdata, health in App.updateRendererHealth(userdata, health: health) },
|
||||||
mouse_over_link_cb: { userdata, ptr, len in App.mouseOverLink(userdata, uri: ptr, len: len) },
|
mouse_over_link_cb: { userdata, ptr, len in App.mouseOverLink(userdata, uri: ptr, len: len) },
|
||||||
|
set_password_input_cb: { userdata, value in App.setPasswordInput(userdata, value: value) },
|
||||||
toggle_secure_input_cb: { App.toggleSecureInput() }
|
toggle_secure_input_cb: { App.toggleSecureInput() }
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -300,6 +301,7 @@ extension Ghostty {
|
|||||||
static func showUserNotification(_ userdata: UnsafeMutableRawPointer?, title: UnsafePointer<CChar>?, body: UnsafePointer<CChar>?) {}
|
static func showUserNotification(_ userdata: UnsafeMutableRawPointer?, title: UnsafePointer<CChar>?, body: UnsafePointer<CChar>?) {}
|
||||||
static func updateRendererHealth(_ userdata: UnsafeMutableRawPointer?, health: ghostty_renderer_health_e) {}
|
static func updateRendererHealth(_ userdata: UnsafeMutableRawPointer?, health: ghostty_renderer_health_e) {}
|
||||||
static func mouseOverLink(_ userdata: UnsafeMutableRawPointer?, uri: UnsafePointer<CChar>?, len: Int) {}
|
static func mouseOverLink(_ userdata: UnsafeMutableRawPointer?, uri: UnsafePointer<CChar>?, len: Int) {}
|
||||||
|
static func setPasswordInput(_ userdata: UnsafeMutableRawPointer?, value: Bool) {}
|
||||||
static func toggleSecureInput() {}
|
static func toggleSecureInput() {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -546,6 +548,11 @@ extension Ghostty {
|
|||||||
surfaceView.hoverUrl = String(data: buffer, encoding: .utf8)
|
surfaceView.hoverUrl = String(data: buffer, encoding: .utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func setPasswordInput(_ userdata: UnsafeMutableRawPointer?, value: Bool) {
|
||||||
|
let surfaceView = self.surfaceUserdata(from: userdata)
|
||||||
|
surfaceView.passwordInput = value
|
||||||
|
}
|
||||||
|
|
||||||
static func toggleSecureInput() {
|
static func toggleSecureInput() {
|
||||||
guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else { return }
|
guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else { return }
|
||||||
appDelegate.toggleSecureInput(self)
|
appDelegate.toggleSecureInput(self)
|
||||||
|
@ -42,6 +42,21 @@ extension Ghostty {
|
|||||||
// then the view is moved to a new window.
|
// then the view is moved to a new window.
|
||||||
var initialSize: NSSize? = nil
|
var initialSize: NSSize? = nil
|
||||||
|
|
||||||
|
// Set whether the surface is currently on a password input or not. This is
|
||||||
|
// detected with the set_password_input_cb on the Ghostty state.
|
||||||
|
var passwordInput: Bool = false {
|
||||||
|
didSet {
|
||||||
|
// We need to update our state within the SecureInput manager.
|
||||||
|
let input = SecureInput.shared
|
||||||
|
let id = ObjectIdentifier(self)
|
||||||
|
if (passwordInput) {
|
||||||
|
input.setScoped(id, focused: focused)
|
||||||
|
} else {
|
||||||
|
input.removeScoped(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns true if quit confirmation is required for this surface to
|
// Returns true if quit confirmation is required for this surface to
|
||||||
// exit safely.
|
// exit safely.
|
||||||
var needsConfirmQuit: Bool {
|
var needsConfirmQuit: Bool {
|
||||||
@ -59,6 +74,7 @@ extension Ghostty {
|
|||||||
if (v.count == 0) { return nil }
|
if (v.count == 0) { return nil }
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the inspector instance for this surface, or nil if the
|
// Returns the inspector instance for this surface, or nil if the
|
||||||
// surface has been closed.
|
// surface has been closed.
|
||||||
var inspector: ghostty_inspector_t? {
|
var inspector: ghostty_inspector_t? {
|
||||||
@ -185,6 +201,9 @@ extension Ghostty {
|
|||||||
mouseExited(with: NSEvent())
|
mouseExited(with: NSEvent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove ourselves from secure input if we have to
|
||||||
|
SecureInput.shared.removeScoped(ObjectIdentifier(self))
|
||||||
|
|
||||||
guard let surface = self.surface else { return }
|
guard let surface = self.surface else { return }
|
||||||
ghostty_surface_free(surface)
|
ghostty_surface_free(surface)
|
||||||
}
|
}
|
||||||
@ -209,6 +228,11 @@ extension Ghostty {
|
|||||||
self.focused = focused
|
self.focused = focused
|
||||||
ghostty_surface_set_focus(surface, focused)
|
ghostty_surface_set_focus(surface, focused)
|
||||||
|
|
||||||
|
// Update our secure input state if we are a password input
|
||||||
|
if (passwordInput) {
|
||||||
|
SecureInput.shared.setScoped(ObjectIdentifier(self), focused: focused)
|
||||||
|
}
|
||||||
|
|
||||||
// On macOS 13+ we can store our continuous clock...
|
// On macOS 13+ we can store our continuous clock...
|
||||||
if #available(macOS 13, iOS 16, *) {
|
if #available(macOS 13, iOS 16, *) {
|
||||||
if (focused) {
|
if (focused) {
|
||||||
|
@ -837,6 +837,11 @@ fn passwordInput(self: *Surface, v: bool) !void {
|
|||||||
self.io.terminal.flags.password_input = v;
|
self.io.terminal.flags.password_input = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify our apprt so it can do whatever it wants.
|
||||||
|
if (@hasDecl(apprt.Surface, "setPasswordInput")) {
|
||||||
|
self.rt_surface.setPasswordInput(v);
|
||||||
|
}
|
||||||
|
|
||||||
try self.queueRender();
|
try self.queueRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +134,11 @@ pub const App = struct {
|
|||||||
/// over a link.
|
/// over a link.
|
||||||
mouse_over_link: ?*const fn (SurfaceUD, ?[*]const u8, usize) void = null,
|
mouse_over_link: ?*const fn (SurfaceUD, ?[*]const u8, usize) void = null,
|
||||||
|
|
||||||
|
/// Notifies that a password input has been started for the given
|
||||||
|
/// surface. The apprt can use this to modify UI, enable features
|
||||||
|
/// such as macOS secure input, etc.
|
||||||
|
set_password_input: ?*const fn (SurfaceUD, bool) callconv(.C) void = null,
|
||||||
|
|
||||||
/// Toggle secure input for the application.
|
/// Toggle secure input for the application.
|
||||||
toggle_secure_input: ?*const fn () callconv(.C) void = null,
|
toggle_secure_input: ?*const fn () callconv(.C) void = null,
|
||||||
};
|
};
|
||||||
@ -1017,6 +1022,15 @@ pub const Surface = struct {
|
|||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setPasswordInput(self: *Surface, v: bool) void {
|
||||||
|
const func = self.app.opts.set_password_input orelse {
|
||||||
|
log.info("runtime embedder does not set_password_input", .{});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
func(self.userdata, v);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn newTab(self: *const Surface) !void {
|
pub fn newTab(self: *const Surface) !void {
|
||||||
const func = self.app.opts.new_tab orelse {
|
const func = self.app.opts.new_tab orelse {
|
||||||
log.info("runtime embedder does not support new_tab", .{});
|
log.info("runtime embedder does not support new_tab", .{});
|
||||||
|
Reference in New Issue
Block a user