From 1e010b8e087ca9620924588455220fe8c552f3ee Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 26 Sep 2024 09:37:24 -0700 Subject: [PATCH] core: more actions --- src/Surface.zig | 48 +++++++++++++++--------------------- src/apprt.zig | 2 +- src/apprt/action.zig | 19 ++++++++++++++ src/apprt/embedded.zig | 56 +++++++++++++++++++++++++----------------- src/apprt/glfw.zig | 18 +++++++++----- src/apprt/structs.zig | 10 -------- 6 files changed, 85 insertions(+), 68 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index c8a50239e..309294e61 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -3663,35 +3663,27 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool v, ), - .new_tab => { - if (@hasDecl(apprt.Surface, "newTab")) { - try self.rt_surface.newTab(); - } else log.warn("runtime doesn't implement newTab", .{}); - }, + .new_tab => try self.rt_app.performAction( + .{ .surface = self }, + .new_tab, + {}, + ), - .previous_tab => { - if (@hasDecl(apprt.Surface, "gotoTab")) { - self.rt_surface.gotoTab(.previous); - } else log.warn("runtime doesn't implement gotoTab", .{}); - }, - - .next_tab => { - if (@hasDecl(apprt.Surface, "gotoTab")) { - self.rt_surface.gotoTab(.next); - } else log.warn("runtime doesn't implement gotoTab", .{}); - }, - - .last_tab => { - if (@hasDecl(apprt.Surface, "gotoTab")) { - self.rt_surface.gotoTab(.last); - } else log.warn("runtime doesn't implement gotoTab", .{}); - }, - - .goto_tab => |n| { - if (@hasDecl(apprt.Surface, "gotoTab")) { - self.rt_surface.gotoTab(@enumFromInt(n)); - } else log.warn("runtime doesn't implement gotoTab", .{}); - }, + inline .previous_tab, + .next_tab, + .last_tab, + .goto_tab, + => |v, tag| try self.rt_app.performAction( + .{ .surface = self }, + .goto_tab, + switch (tag) { + .previous_tab => .previous, + .next_tab => .next, + .last_tab => .last, + .goto_tab => @enumFromInt(v), + else => comptime unreachable, + }, + ), .new_split => |direction| { if (@hasDecl(apprt.Surface, "newSplit")) { diff --git a/src/apprt.zig b/src/apprt.zig index f6952c9ec..21a0e7805 100644 --- a/src/apprt.zig +++ b/src/apprt.zig @@ -12,9 +12,9 @@ const std = @import("std"); const builtin = @import("builtin"); const build_config = @import("build_config.zig"); -const action = @import("apprt/action.zig"); const structs = @import("apprt/structs.zig"); +pub const action = @import("apprt/action.zig"); pub const glfw = @import("apprt/glfw.zig"); pub const gtk = @import("apprt/gtk.zig"); pub const none = @import("apprt/none.zig"); diff --git a/src/apprt/action.zig b/src/apprt/action.zig index e1486130f..3f34ae8d8 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -16,6 +16,15 @@ pub const Action = union(enum) { /// as font size should be inherited. new_window, + /// Open a new tab. If the target is a surface it should be opened in + /// the same window as the surface. If the target is the app then + /// the tab should be opened in a new window. + new_tab, + + /// Jump to a specific tab. Must handle the scenario that the tab + /// value is invalid. + goto_tab: GotoTab, + /// Close all open windows. close_all_windows, @@ -58,3 +67,13 @@ pub const Target = union(enum) { app, surface: *CoreSurface, }; + +/// The tab to jump to. This is non-exhaustive so that integer values represent +/// the index (zero-based) of the tab to jump to. Negative values are special +/// values. +pub const GotoTab = enum(c_int) { + previous = -1, + next = -2, + last = -3, + _, +}; diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index e247a1934..8c602b5b0 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -83,7 +83,8 @@ pub const App = struct { /// views then this can be null. new_split: ?*const fn (SurfaceUD, apprt.SplitDirection, apprt.Surface.Options) callconv(.C) void = null, - /// New tab with options. + /// New tab with options. The surface may be null if there is no target + /// surface in which case the apprt is expected to create a new window. new_tab: ?*const fn (SurfaceUD, apprt.Surface.Options) callconv(.C) void = null, /// New window with options. The surface may be null if there is no @@ -109,7 +110,7 @@ pub const App = struct { toggle_split_zoom: ?*const fn (SurfaceUD) callconv(.C) void = null, /// Goto tab - goto_tab: ?*const fn (SurfaceUD, apprt.GotoTab) callconv(.C) void = null, + goto_tab: ?*const fn (SurfaceUD, apprt.action.GotoTab) callconv(.C) void = null, /// Toggle fullscreen for current window. toggle_fullscreen: ?*const fn (SurfaceUD, configpkg.NonNativeFullscreen) callconv(.C) void = null, @@ -506,9 +507,36 @@ pub const App = struct { func(null, .{}); } + 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", .{}); + return; + }; + + switch (target) { + .app => func(null, .{}), + .surface => |v| func( + v.rt_surface.userdata, + v.rt_surface.newSurfaceOptions(), + ), + } + } + + fn gotoTab(self: *App, target: apprt.Target, tab: apprt.action.GotoTab) void { + const func = self.opts.goto_tab orelse { + log.info("runtime embedder does not support goto_tab", .{}); + return; + }; + + switch (target) { + .app => {}, + .surface => |v| func(v.rt_surface.userdata, tab), + } + } + 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", .{}); + log.info("runtime embedder does not support set_password_input", .{}); return; }; @@ -531,8 +559,9 @@ pub const App = struct { .surface => |v| v, }), + .new_tab => self.newTab(target), + .goto_tab => self.gotoTab(target, value), .open_config => try configpkg.edit.open(self.core_app.alloc), - .secure_input => self.setPasswordInput(target, value), // Unimplemented @@ -1099,15 +1128,6 @@ pub const Surface = struct { }; } - pub fn gotoTab(self: *Surface, tab: apprt.GotoTab) void { - const func = self.app.opts.goto_tab orelse { - log.info("runtime embedder does not goto_tab", .{}); - return; - }; - - func(self.userdata, tab); - } - 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", .{}); @@ -1126,16 +1146,6 @@ pub const Surface = struct { func(); } - pub fn newTab(self: *const Surface) !void { - const func = self.app.opts.new_tab orelse { - log.info("runtime embedder does not support new_tab", .{}); - return; - }; - - const options = self.newSurfaceOptions(); - func(self.userdata, options); - } - fn newWindow(self: *const Surface) !void { const func = self.app.opts.new_window orelse { log.info("runtime embedder does not support new_window", .{}); diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 439efa3e4..a3854a173 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -142,10 +142,16 @@ pub const App = struct { .surface => |v| v, }), + .new_tab => try self.newTab(switch (target) { + .app => null, + .surface => |v| v, + }), + .open_config => try configpkg.edit.open(self.app.alloc), // Unimplemented .close_all_windows, + .goto_tab, .quit_timer, .secure_input, => log.info("unimplemented action={}", .{action}), @@ -216,12 +222,17 @@ pub const App = struct { } /// Create a new tab in the parent surface. - fn newTab(self: *App, parent: *CoreSurface) !void { + fn newTab(self: *App, parent_: ?*CoreSurface) !void { if (!Darwin.enabled) { log.warn("tabbing is not supported on this platform", .{}); return; } + const parent = parent_ orelse { + _ = try self.newSurface(null); + return; + }; + // Create the new window const window = try self.newSurface(parent); @@ -540,11 +551,6 @@ pub const Surface = struct { } } - /// Create a new tab in the window containing this surface. - pub fn newTab(self: *Surface) !void { - try self.app.newTab(&self.core_surface); - } - /// Checks if the glfw window is in fullscreen. pub fn isFullscreen(self: *Surface) bool { return self.window.getMonitor() != null; diff --git a/src/apprt/structs.zig b/src/apprt/structs.zig index 1e14b1b7c..1982cc497 100644 --- a/src/apprt/structs.zig +++ b/src/apprt/structs.zig @@ -62,16 +62,6 @@ pub const DesktopNotification = struct { body: []const u8, }; -/// The tab to jump to. This is non-exhaustive so that integer values represent -/// the index (zero-based) of the tab to jump to. Negative values are special -/// values. -pub const GotoTab = enum(c_int) { - previous = -1, - next = -2, - last = -3, - _, -}; - // This is made extern (c_int) to make interop easier with our embedded // runtime. The small size cost doesn't make a difference in our union. pub const SplitDirection = enum(c_int) {