core: more actions

This commit is contained in:
Mitchell Hashimoto
2024-09-26 10:20:40 -07:00
parent 9202cba1f5
commit e29918ebb8
5 changed files with 140 additions and 59 deletions

View File

@ -3735,11 +3735,15 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
{},
),
.toggle_fullscreen => {
if (@hasDecl(apprt.Surface, "toggleFullscreen")) {
self.rt_surface.toggleFullscreen(self.config.macos_non_native_fullscreen);
} else log.warn("runtime doesn't implement toggleFullscreen", .{});
},
.toggle_fullscreen => try self.rt_app.performAction(
.{ .surface = self },
.toggle_fullscreen,
switch (self.config.macos_non_native_fullscreen) {
.false => .native,
.true => .macos_non_native,
.@"visible-menu" => .macos_non_native_visible_menu,
},
),
.toggle_window_decorations => try self.rt_app.performAction(
.{ .surface = self },
@ -3761,11 +3765,16 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
}
},
.inspector => |mode| {
if (@hasDecl(apprt.Surface, "controlInspector")) {
self.rt_surface.controlInspector(mode);
} else log.warn("runtime doesn't implement controlInspector", .{});
},
.inspector => |mode| try self.rt_app.performAction(
.{ .surface = self },
.inspector,
switch (mode) {
inline else => |tag| @field(
apprt.action.Inspector,
@tagName(tag),
),
},
),
.close_surface => self.close(),
@ -4152,11 +4161,6 @@ fn completeClipboardReadOSC52(
}
fn showDesktopNotification(self: *Surface, title: [:0]const u8, body: [:0]const u8) !void {
if (comptime !@hasDecl(apprt.Surface, "showDesktopNotification")) {
log.warn("runtime doesn't support desktop notifications", .{});
return;
}
// Wyhash is used to hash the contents of the desktop notification to limit
// how fast identical notifications can be sent sequentially.
const hash_algorithm = std.hash.Wyhash;
@ -4192,7 +4196,14 @@ fn showDesktopNotification(self: *Surface, title: [:0]const u8, body: [:0]const
self.app.last_notification_time = now;
self.app.last_notification_digest = new_digest;
try self.rt_surface.showDesktopNotification(title, body);
try self.rt_app.performAction(
.{ .surface = self },
.desktop_notification,
.{
.title = title,
.body = body,
},
);
}
fn crashThreadState(self: *Surface) crash.sentry.ThreadState {
@ -4205,9 +4216,11 @@ fn crashThreadState(self: *Surface) crash.sentry.ThreadState {
/// Tell the surface to present itself to the user. This may involve raising the
/// window and switching tabs.
fn presentSurface(self: *Surface) !void {
if (@hasDecl(apprt.Surface, "presentSurface")) {
self.rt_surface.presentSurface();
} else log.warn("runtime doesn't support presentSurface", .{});
try self.rt_app.performAction(
.{ .surface = self },
.present_terminal,
{},
);
}
pub const face_ttf = @embedFile("font/res/JetBrainsMono-Regular.ttf");

View File

@ -28,6 +28,9 @@ pub const Action = union(enum) {
/// Close all open windows.
close_all_windows,
/// Toggle fullscreen mode.
toggle_fullscreen: Fullscreen,
/// Toggle whether window directions are shown.
toggle_window_decorations,
@ -48,6 +51,15 @@ pub const Action = union(enum) {
/// to take up the entire window.
toggle_split_zoom,
/// Present the target terminal whether its a tab, split, or window.
present_terminal,
/// Control whether the inspector is shown or hidden.
inspector: Inspector,
/// Show a desktop notification.
desktop_notification: DesktopNotification,
/// Open the Ghostty configuration. This is platform-specific about
/// what it means; it can mean opening a dedicated UI or just opening
/// a file in a text editor.
@ -130,8 +142,31 @@ pub const GotoTab = enum(c_int) {
_,
};
/// The fullscreen mode to toggle to if we're moving to fullscreen.
pub const Fullscreen = enum(c_int) {
native,
/// macOS has a non-native fullscreen mode that is more like a maximized
/// window. This is much faster to enter and exit than the native mode.
macos_non_native,
macos_non_native_visible_menu,
};
pub const SecureInput = enum(c_int) {
on,
off,
toggle,
};
/// The inspector mode to toggle to if we're toggling the inspector.
pub const Inspector = enum(c_int) {
toggle,
show,
hide,
};
/// The desktop notification to show.
pub const DesktopNotification = struct {
title: [:0]const u8,
body: [:0]const u8,
};

View File

@ -92,7 +92,7 @@ pub const App = struct {
new_window: ?*const fn (SurfaceUD, apprt.Surface.Options) callconv(.C) void = null,
/// Control the inspector visibility
control_inspector: ?*const fn (SurfaceUD, input.InspectorMode) callconv(.C) void = null,
control_inspector: ?*const fn (SurfaceUD, apprt.action.Inspector) callconv(.C) void = null,
/// Close the current surface given by this function.
close_surface: ?*const fn (SurfaceUD, bool) callconv(.C) void = null,
@ -125,7 +125,8 @@ pub const App = struct {
/// Called when the cell size changes.
set_cell_size: ?*const fn (SurfaceUD, u32, u32) callconv(.C) void = null,
/// Show a desktop notification to the user.
/// Show a desktop notification to the user. The surface may be null
/// if the notification is global.
show_desktop_notification: ?*const fn (SurfaceUD, [*:0]const u8, [*:0]const u8) void = null,
/// Called when the health of the renderer changes.
@ -507,6 +508,29 @@ pub const App = struct {
func(null, .{});
}
fn toggleFullscreen(
self: *App,
target: apprt.Target,
fullscreen: apprt.action.Fullscreen,
) void {
const func = self.opts.toggle_fullscreen orelse {
log.info("runtime embedder does not toggle_fullscreen", .{});
return;
};
switch (target) {
.app => {},
.surface => |v| func(
v.rt_surface.userdata,
switch (fullscreen) {
.native => .false,
.macos_non_native => .true,
.macos_non_native_visible_menu => .@"visible-menu",
},
),
}
}
fn newTab(self: *const App, target: apprt.Target) void {
const func = self.opts.new_tab orelse {
log.info("runtime embedder does not support new_tab", .{});
@ -614,6 +638,38 @@ pub const App = struct {
}
}
fn controlInspector(
self: *const App,
target: apprt.Target,
value: apprt.action.Inspector,
) void {
const func = self.opts.control_inspector orelse {
log.info("runtime embedder does not support the terminal inspector", .{});
return;
};
switch (target) {
.app => {},
.surface => |v| func(v.rt_surface.userdata, value),
}
}
fn showDesktopNotification(
self: *const App,
target: apprt.Target,
notification: apprt.action.DesktopNotification,
) void {
const func = self.opts.show_desktop_notification orelse {
log.info("runtime embedder does not support show_desktop_notification", .{});
return;
};
func(switch (target) {
.app => null,
.surface => |v| v.rt_surface.userdata,
}, notification.title, notification.body);
}
fn setPasswordInput(self: *App, target: apprt.Target, v: apprt.action.SecureInput) void {
switch (v) {
inline .on, .off => |tag| {
@ -655,6 +711,7 @@ pub const App = struct {
.app => null,
.surface => |v| v,
}),
.toggle_fullscreen => self.toggleFullscreen(target, value),
.new_tab => self.newTab(target),
.goto_tab => self.gotoTab(target, value),
@ -664,9 +721,12 @@ pub const App = struct {
.toggle_split_zoom => self.toggleSplitZoom(target),
.goto_split => self.gotoSplit(target, value),
.open_config => try configpkg.edit.open(self.core_app.alloc),
.inspector => self.controlInspector(target, value),
.desktop_notification => self.showDesktopNotification(target, value),
.secure_input => self.setPasswordInput(target, value),
// Unimplemented
.present_terminal,
.close_all_windows,
.toggle_window_decorations,
.quit_timer,
@ -889,15 +949,6 @@ pub const Surface = struct {
}
}
pub fn controlInspector(self: *const Surface, mode: input.InspectorMode) void {
const func = self.app.opts.control_inspector orelse {
log.info("runtime embedder does not support the terminal inspector", .{});
return;
};
func(self.userdata, mode);
}
pub fn close(self: *const Surface, process_alive: bool) void {
const func = self.app.opts.close_surface orelse {
log.info("runtime embedder does not support closing a surface", .{});
@ -1185,15 +1236,6 @@ pub const Surface = struct {
};
}
pub fn toggleFullscreen(self: *Surface, nonNativeFullscreen: configpkg.NonNativeFullscreen) void {
const func = self.app.opts.toggle_fullscreen orelse {
log.info("runtime embedder does not toggle_fullscreen", .{});
return;
};
func(self.userdata, nonNativeFullscreen);
}
fn newWindow(self: *const Surface) !void {
const func = self.app.opts.new_window orelse {
log.info("runtime embedder does not support new_window", .{});
@ -1249,20 +1291,6 @@ pub const Surface = struct {
return .{ .x = pos.x * scale.x, .y = pos.y * scale.y };
}
/// Show a desktop notification.
pub fn showDesktopNotification(
self: *const Surface,
title: [:0]const u8,
body: [:0]const u8,
) !void {
const func = self.app.opts.show_desktop_notification orelse {
log.info("runtime embedder does not support show_desktop_notification", .{});
return;
};
func(self.userdata, title, body);
}
/// Update the health of the renderer.
pub fn updateRendererHealth(self: *const Surface, health: renderer.Health) void {
const func = self.app.opts.update_renderer_health orelse {

View File

@ -147,6 +147,8 @@ pub const App = struct {
.surface => |v| v,
}),
.toggle_fullscreen => self.toggleFullscreen(target),
.open_config => try configpkg.edit.open(self.app.alloc),
// Unimplemented
@ -155,11 +157,14 @@ pub const App = struct {
.resize_split,
.equalize_splits,
.toggle_split_zoom,
.present_terminal,
.close_all_windows,
.toggle_window_decorations,
.goto_tab,
.inspector,
.quit_timer,
.secure_input,
.desktop_notification,
=> log.info("unimplemented action={}", .{action}),
}
}
@ -182,8 +187,12 @@ pub const App = struct {
}
/// Toggle the window to fullscreen mode.
pub fn toggleFullscreen(self: *App, surface: *Surface) void {
fn toggleFullscreen(self: *App, target: apprt.Target) void {
_ = self;
const surface: *Surface = switch (target) {
.app => return,
.surface => |v| v.rt_surface,
};
const win = surface.window;
if (surface.isFullscreen()) {
@ -562,10 +571,6 @@ pub const Surface = struct {
return self.window.getMonitor() != null;
}
pub fn toggleFullscreen(self: *Surface, _: Config.NonNativeFullscreen) void {
self.app.toggleFullscreen(self);
}
/// Close this surface.
pub fn close(self: *Surface, processActive: bool) void {
_ = processActive;

View File

@ -438,7 +438,7 @@ pub const Action = union(enum) {
};
// Extern because it is used in the embedded runtime ABI.
pub const InspectorMode = enum(c_int) {
pub const InspectorMode = enum {
toggle,
show,
hide,