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,