diff --git a/macos/Sources/Ghostty/Ghostty.App.swift b/macos/Sources/Ghostty/Ghostty.App.swift index 30efb289e..3b3dd9626 100644 --- a/macos/Sources/Ghostty/Ghostty.App.swift +++ b/macos/Sources/Ghostty/Ghostty.App.swift @@ -549,6 +549,9 @@ extension Ghostty { } static func setPasswordInput(_ userdata: UnsafeMutableRawPointer?, value: Bool) { + // We don't currently allow global password input being set from this. + guard let userdata else { return } + let surfaceView = self.surfaceUserdata(from: userdata) guard let appState = self.appState(fromView: surfaceView) else { return } guard appState.config.autoSecureInput else { return } diff --git a/src/Surface.zig b/src/Surface.zig index 85a5face0..72b5a7060 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -838,9 +838,16 @@ fn passwordInput(self: *Surface, v: bool) !void { } // Notify our apprt so it can do whatever it wants. - if (@hasDecl(apprt.Surface, "setPasswordInput")) { - self.rt_surface.setPasswordInput(v); - } + self.rt_app.performAction( + .{ .surface = self }, + .secure_input, + v, + ) catch |err| { + // We ignore this error because we don't want to fail this + // entire operation just because the apprt failed to set + // the secure input state. + log.warn("apprt failed to set secure input state err={}", .{err}); + }; try self.queueRender(); } diff --git a/src/apprt/action.zig b/src/apprt/action.zig index d0f551646..e1486130f 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -30,6 +30,13 @@ pub const Action = union(enum) { /// happen and can be ignored or cause a restart it isn't that important. quit_timer: enum { start, stop }, + /// Set the secure input functionality on or off. "Secure input" means + /// that the user is currently at some sort of prompt where they may be + /// entering a password or other sensitive information. This can be used + /// by the app runtime to change the appearance of the cursor, setup + /// system APIs to not log the input, etc. + secure_input: bool, + /// The enum of keys in the tagged union. pub const Key = @typeInfo(Action).Union.tag_type.?; diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 61b798bfa..e247a1934 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -138,6 +138,8 @@ pub const App = struct { /// 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. + /// + /// The surface userdata will be null if a surface isn't focused. set_password_input: ?*const fn (SurfaceUD, bool) callconv(.C) void = null, /// Toggle secure input for the application. @@ -504,6 +506,18 @@ pub const App = struct { func(null, .{}); } + fn setPasswordInput(self: *App, target: apprt.Target, v: bool) void { + const func = self.opts.set_password_input orelse { + log.info("runtime embedder does not set_password_input", .{}); + return; + }; + + func(switch (target) { + .app => null, + .surface => |surface| surface.rt_surface.userdata, + }, v); + } + /// Perform a given action. pub fn performAction( self: *App, @@ -511,8 +525,6 @@ pub const App = struct { comptime action: apprt.Action.Key, value: apprt.Action.Value(action), ) !void { - _ = value; - switch (action) { .new_window => _ = try self.newWindow(switch (target) { .app => null, @@ -521,6 +533,8 @@ pub const App = struct { .open_config => try configpkg.edit.open(self.core_app.alloc), + .secure_input => self.setPasswordInput(target, value), + // Unimplemented .close_all_windows, .quit_timer, @@ -1112,15 +1126,6 @@ pub const Surface = struct { 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 { const func = self.app.opts.new_tab orelse { log.info("runtime embedder does not support new_tab", .{}); diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 8bf07c8a4..439efa3e4 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -147,7 +147,8 @@ pub const App = struct { // Unimplemented .close_all_windows, .quit_timer, - => log.warn("unimplemented action={}", .{action}), + .secure_input, + => log.info("unimplemented action={}", .{action}), } }