From 17cae57f510cd9f11ca83cec3f24f3563a2674ae Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 28 Feb 2025 15:25:14 -0800 Subject: [PATCH] Introduce `reset_window_size` keybinding and apprt action Related to #6035 This implements the keybind/action portion of #5974 so that this can have a binding and so that other apprts can respond to this and implement it this way. --- include/ghostty.h | 1 + macos/Sources/App/macOS/AppDelegate.swift | 2 ++ macos/Sources/App/macOS/MainMenu.xib | 1 + .../Terminal/TerminalController.swift | 14 +++++++++- macos/Sources/Ghostty/Ghostty.App.swift | 27 ++++++++++++++++++- macos/Sources/Ghostty/Package.swift | 3 +++ src/Surface.zig | 6 +++++ src/apprt/action.zig | 5 ++++ src/apprt/glfw.zig | 1 + src/apprt/gtk/App.zig | 1 + src/input/Binding.zig | 6 +++++ 11 files changed, 65 insertions(+), 2 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 86de4266d..29c779f2c 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -580,6 +580,7 @@ typedef enum { GHOSTTY_ACTION_TOGGLE_SPLIT_ZOOM, GHOSTTY_ACTION_PRESENT_TERMINAL, GHOSTTY_ACTION_SIZE_LIMIT, + GHOSTTY_ACTION_RESET_WINDOW_SIZE, GHOSTTY_ACTION_INITIAL_SIZE, GHOSTTY_ACTION_CELL_SIZE, GHOSTTY_ACTION_INSPECTOR, diff --git a/macos/Sources/App/macOS/AppDelegate.swift b/macos/Sources/App/macOS/AppDelegate.swift index 7caa04659..7d5e7cd25 100644 --- a/macos/Sources/App/macOS/AppDelegate.swift +++ b/macos/Sources/App/macOS/AppDelegate.swift @@ -51,6 +51,7 @@ class AppDelegate: NSObject, @IBOutlet private var menuSelectSplitBelow: NSMenuItem? @IBOutlet private var menuSelectSplitLeft: NSMenuItem? @IBOutlet private var menuSelectSplitRight: NSMenuItem? + @IBOutlet private var menuReturnToDefaultSize: NSMenuItem? @IBOutlet private var menuIncreaseFontSize: NSMenuItem? @IBOutlet private var menuDecreaseFontSize: NSMenuItem? @@ -386,6 +387,7 @@ class AppDelegate: NSObject, syncMenuShortcut(config, action: "resize_split:right,10", menuItem: self.menuMoveSplitDividerRight) syncMenuShortcut(config, action: "resize_split:left,10", menuItem: self.menuMoveSplitDividerLeft) syncMenuShortcut(config, action: "equalize_splits", menuItem: self.menuEqualizeSplits) + syncMenuShortcut(config, action: "reset_window_size", menuItem: self.menuReturnToDefaultSize) syncMenuShortcut(config, action: "increase_font_size:1", menuItem: self.menuIncreaseFontSize) syncMenuShortcut(config, action: "decrease_font_size:1", menuItem: self.menuDecreaseFontSize) diff --git a/macos/Sources/App/macOS/MainMenu.xib b/macos/Sources/App/macOS/MainMenu.xib index 94ced4890..88db6ed01 100644 --- a/macos/Sources/App/macOS/MainMenu.xib +++ b/macos/Sources/App/macOS/MainMenu.xib @@ -40,6 +40,7 @@ + diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index b06c19d34..40fe3ffe3 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -68,6 +68,12 @@ class TerminalController: BaseTerminalController { selector: #selector(onCloseTab), name: .ghosttyCloseTab, object: nil) + center.addObserver( + self, + selector: #selector(onResetWindowSize), + name: .ghosttyResetWindowSize, + object: nil + ) center.addObserver( self, selector: #selector(ghosttyConfigDidChange(_:)), @@ -612,7 +618,7 @@ class TerminalController: BaseTerminalController { window.close() } - @IBAction func returnToDefaultSize(_ sender: Any) { + @IBAction func returnToDefaultSize(_ sender: Any?) { guard let defaultSize else { return } window?.setFrame(defaultSize, display: true) } @@ -830,6 +836,12 @@ class TerminalController: BaseTerminalController { closeTab(self) } + @objc private func onResetWindowSize(notification: SwiftUI.Notification) { + guard let target = notification.object as? Ghostty.SurfaceView else { return } + guard surfaceTree?.contains(view: target) ?? false else { return } + returnToDefaultSize(nil) + } + @objc private func onToggleFullscreen(notification: SwiftUI.Notification) { guard let target = notification.object as? Ghostty.SurfaceView else { return } guard target == self.focusedSurface else { return } diff --git a/macos/Sources/Ghostty/Ghostty.App.swift b/macos/Sources/Ghostty/Ghostty.App.swift index ba249e3d1..88f8d1dc9 100644 --- a/macos/Sources/Ghostty/Ghostty.App.swift +++ b/macos/Sources/Ghostty/Ghostty.App.swift @@ -508,6 +508,9 @@ extension Ghostty { case GHOSTTY_ACTION_INITIAL_SIZE: setInitialSize(app, target: target, v: action.action.initial_size) + case GHOSTTY_ACTION_RESET_WINDOW_SIZE: + resetWindowSize(app, target: target) + case GHOSTTY_ACTION_CELL_SIZE: setCellSize(app, target: target, v: action.action.cell_size) @@ -1131,7 +1134,7 @@ extension Ghostty { v: ghostty_action_initial_size_s) { switch (target.tag) { case GHOSTTY_TARGET_APP: - Ghostty.logger.warning("mouse over link does nothing with an app target") + Ghostty.logger.warning("initial size does nothing with an app target") return case GHOSTTY_TARGET_SURFACE: @@ -1145,6 +1148,28 @@ extension Ghostty { } } + private static func resetWindowSize( + _ app: ghostty_app_t, + target: ghostty_target_s) { + switch (target.tag) { + case GHOSTTY_TARGET_APP: + Ghostty.logger.warning("reset window size does nothing with an app target") + return + + case GHOSTTY_TARGET_SURFACE: + guard let surface = target.target.surface else { return } + guard let surfaceView = self.surfaceView(from: surface) else { return } + NotificationCenter.default.post( + name: .ghosttyResetWindowSize, + object: surfaceView + ) + + + default: + assertionFailure() + } + } + private static func setCellSize( _ app: ghostty_app_t, target: ghostty_target_s, diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift index 18ef3f3a7..ca37002b0 100644 --- a/macos/Sources/Ghostty/Package.swift +++ b/macos/Sources/Ghostty/Package.swift @@ -247,6 +247,9 @@ extension Notification.Name { /// Close tab static let ghosttyCloseTab = Notification.Name("com.mitchellh.ghostty.closeTab") + + /// Resize the window to a default size. + static let ghosttyResetWindowSize = Notification.Name("com.mitchellh.ghostty.resetWindowSize") } // NOTE: I am moving all of these to Notification.Name extensions over time. This diff --git a/src/Surface.zig b/src/Surface.zig index 7e6aa2d0d..6651dd8c2 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -4228,6 +4228,12 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool {}, ), + .reset_window_size => return try self.rt_app.performAction( + .{ .surface = self }, + .reset_window_size, + {}, + ), + .toggle_maximize => return try self.rt_app.performAction( .{ .surface = self }, .toggle_maximize, diff --git a/src/apprt/action.zig b/src/apprt/action.zig index 02a8a0a81..62410a5a1 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -140,6 +140,10 @@ pub const Action = union(Key) { /// Sets a size limit (in pixels) for the target terminal. size_limit: SizeLimit, + /// Resets the window size to the default size. See the + /// `reset_window_size` keybinding for more information. + reset_window_size, + /// Specifies the initial size of the target terminal. /// /// This may be sent once during the initialization of a surface @@ -259,6 +263,7 @@ pub const Action = union(Key) { toggle_split_zoom, present_terminal, size_limit, + reset_window_size, initial_size, cell_size, inspector, diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 531269ee1..bc4d32bd7 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -240,6 +240,7 @@ pub const App = struct { .config_change, .toggle_maximize, .prompt_title, + .reset_window_size, => { log.info("unimplemented action={}", .{action}); return false; diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 0bcb5aad3..50b15f6a3 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -512,6 +512,7 @@ pub fn performAction( .render_inspector, .renderer_health, .color_change, + .reset_window_size, => { log.warn("unimplemented action={}", .{action}); return false; diff --git a/src/input/Binding.zig b/src/input/Binding.zig index d1e66210b..ddee672a5 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -380,6 +380,11 @@ pub const Action = union(enum) { /// Equalize all splits in the current window equalize_splits: void, + /// Reset the window to the default size. The "default size" is the + /// size that a new window would be created with. This has no effect + /// if the window is fullscreen. + reset_window_size: void, + /// Control the terminal inspector visibility. /// /// Arguments: @@ -772,6 +777,7 @@ pub const Action = union(enum) { .toggle_fullscreen, .toggle_window_decorations, .toggle_secure_input, + .reset_window_size, .crash, => .surface,