diff --git a/include/ghostty.h b/include/ghostty.h index 29da8f37bd..8fc16f6907 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -596,6 +596,7 @@ typedef enum { GHOSTTY_ACTION_COLOR_CHANGE, GHOSTTY_ACTION_RELOAD_CONFIG, GHOSTTY_ACTION_CONFIG_CHANGE, + GHOSTTY_ACTION_BRING_ALL_TO_FRONT, } ghostty_action_tag_e; typedef union { diff --git a/macos/Sources/App/macOS/AppDelegate.swift b/macos/Sources/App/macOS/AppDelegate.swift index 4b11b68aa6..8bc4d6b2ef 100644 --- a/macos/Sources/App/macOS/AppDelegate.swift +++ b/macos/Sources/App/macOS/AppDelegate.swift @@ -41,6 +41,7 @@ class AppDelegate: NSObject, @IBOutlet private var menuToggleVisibility: NSMenuItem? @IBOutlet private var menuToggleFullScreen: NSMenuItem? + @IBOutlet private var menuBringAllToFront: NSMenuItem? @IBOutlet private var menuZoomSplit: NSMenuItem? @IBOutlet private var menuPreviousSplit: NSMenuItem? @IBOutlet private var menuNextSplit: NSMenuItem? @@ -383,6 +384,7 @@ class AppDelegate: NSObject, syncMenuShortcut(config, action: "inspector:toggle", menuItem: self.menuTerminalInspector) syncMenuShortcut(config, action: "toggle_secure_input", menuItem: self.menuSecureInput) + syncMenuShortcut(config, action: "bring_all_to_front", menuItem: self.menuBringAllToFront) // This menu item is NOT synced with the configuration because it disables macOS // global fullscreen keyboard shortcut. The shortcut in the Ghostty config will continue @@ -727,6 +729,16 @@ class AppDelegate: NSObject, self.hiddenWindows.forEach { $0.value?.orderFrontRegardless() } self.hiddenWindows = [] } + + @IBAction func bringAllToFront(_ sender: Any) { + NSApp.activate(ignoringOtherApps: true) + + for window in NSApp.windows.filter({ $0.windowController is BaseTerminalController }) { + if window.isVisible { + window.makeKeyAndOrderFront(nil) + } + } + } private struct DerivedConfig { let initialWindow: Bool diff --git a/macos/Sources/App/macOS/MainMenu.xib b/macos/Sources/App/macOS/MainMenu.xib index 4a01d5c62e..99e3fbef6d 100644 --- a/macos/Sources/App/macOS/MainMenu.xib +++ b/macos/Sources/App/macOS/MainMenu.xib @@ -14,6 +14,7 @@ + diff --git a/macos/Sources/Ghostty/Ghostty.App.swift b/macos/Sources/Ghostty/Ghostty.App.swift index 43c0f245aa..4e4678fc58 100644 --- a/macos/Sources/Ghostty/Ghostty.App.swift +++ b/macos/Sources/Ghostty/Ghostty.App.swift @@ -541,6 +541,9 @@ extension Ghostty { fallthrough case GHOSTTY_ACTION_QUIT_TIMER: Ghostty.logger.info("known but unimplemented action action=\(action.tag.rawValue)") + + case GHOSTTY_ACTION_BRING_ALL_TO_FRONT: + bringAllToFront(app, target: target) default: Ghostty.logger.warning("unknown action action=\(action.tag.rawValue)") @@ -712,6 +715,15 @@ extension Ghostty { guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else { return } appDelegate.toggleVisibility(self) } + + private static func bringAllToFront( + _ app: ghostty_app_t, + target: ghostty_target_s + ) { + guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else { return } + appDelegate.bringAllToFront(self) + } + private static func moveTab( _ app: ghostty_app_t, diff --git a/src/App.zig b/src/App.zig index a6b54db232..36b2c8f2c3 100644 --- a/src/App.zig +++ b/src/App.zig @@ -444,6 +444,7 @@ pub fn performAction( .close_all_windows => try rt_app.performAction(.app, .close_all_windows, {}), .toggle_quick_terminal => try rt_app.performAction(.app, .toggle_quick_terminal, {}), .toggle_visibility => try rt_app.performAction(.app, .toggle_visibility, {}), + .bring_all_to_front => try rt_app.performAction(.app, .bring_all_to_front, {}), } } diff --git a/src/apprt/action.zig b/src/apprt/action.zig index 25e1cd6407..47cc76cf5f 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -223,6 +223,9 @@ pub const Action = union(Key) { /// for changes. config_change: ConfigChange, + /// Bring all ghostty windows in front of all other windows. + bring_all_to_front, + /// Sync with: ghostty_action_tag_e pub const Key = enum(c_int) { quit, @@ -262,6 +265,7 @@ pub const Action = union(Key) { color_change, reload_config, config_change, + bring_all_to_front, }; /// Sync with: ghostty_action_u diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 8094baeb86..f19a056ce9 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -237,6 +237,7 @@ pub const App = struct { .color_change, .pwd, .config_change, + .bring_all_to_front, => log.info("unimplemented action={}", .{action}), } } diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 70fc182e5c..d8f6fa0f09 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -545,6 +545,7 @@ pub fn performAction( .render_inspector, .renderer_health, .color_change, + .bring_all_to_front, => log.warn("unimplemented action={}", .{action}), } } diff --git a/src/input/Binding.zig b/src/input/Binding.zig index 2fdbc4cbaa..34a93434bc 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -466,6 +466,9 @@ pub const Action = union(enum) { /// crash: CrashThread, + /// Bring all ghostty windows in front of all other windows. + bring_all_to_front: void, + pub const Key = @typeInfo(Action).Union.tag_type.?; pub const CrashThread = enum { @@ -702,6 +705,7 @@ pub const Action = union(enum) { .quit, .toggle_quick_terminal, .toggle_visibility, + .bring_all_to_front, => .app, // These are app but can be special-cased in a surface context.