Skip to content

Commit

Permalink
Merge pull request #2338 from rolandpeelen/main
Browse files Browse the repository at this point in the history
Add an equivalent to iTerm's "show/hide all windows" hotkey (Fix for: #2205)
  • Loading branch information
mitchellh authored Oct 2, 2024
2 parents 03abc18 + 28ec11e commit 991cbce
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 2 deletions.
1 change: 1 addition & 0 deletions include/ghostty.h
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ typedef enum {
GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW,
GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS,
GHOSTTY_ACTION_TOGGLE_QUICK_TERMINAL,
GHOSTTY_ACTION_TOGGLE_VISIBILITY,
GHOSTTY_ACTION_GOTO_TAB,
GHOSTTY_ACTION_GOTO_SPLIT,
GHOSTTY_ACTION_RESIZE_SPLIT,
Expand Down
26 changes: 26 additions & 0 deletions macos/Sources/App/macOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ class AppDelegate: NSObject,
return ProcessInfo.processInfo.systemUptime - applicationLaunchTime
}

/// Tracks whether the application is currently visible. This can be gamed, i.e. if a user manually
/// brings each window one by one to the front. But at worst its off by one set of toggles and this
/// makes our logic very easy.
private var isVisible: Bool = true

override init() {
terminalManager = TerminalManager(ghostty)
updaterController = SPUStandardUpdaterController(
Expand Down Expand Up @@ -251,6 +256,7 @@ class AppDelegate: NSObject,
// Ghostty will validate as well but we can avoid creating an entirely new
// surface by doing our own validation here. We can also show a useful error
// this way.

var isDirectory = ObjCBool(true)
guard FileManager.default.fileExists(atPath: filename, isDirectory: &isDirectory) else { return false }

Expand Down Expand Up @@ -315,6 +321,7 @@ class AppDelegate: NSObject,
syncMenuShortcut(action: "decrease_font_size:1", menuItem: self.menuDecreaseFontSize)
syncMenuShortcut(action: "reset_font_size", menuItem: self.menuResetFontSize)
syncMenuShortcut(action: "toggle_quick_terminal", menuItem: self.menuQuickTerminal)
syncMenuShortcut(action: "toggle_visibility", menuItem: self.menuQuickTerminal)
syncMenuShortcut(action: "inspector:toggle", menuItem: self.menuTerminalInspector)

syncMenuShortcut(action: "toggle_secure_input", menuItem: self.menuSecureInput)
Expand Down Expand Up @@ -564,4 +571,23 @@ class AppDelegate: NSObject,

self.menuQuickTerminal?.state = if (quickController.visible) { .on } else { .off }
}

/// Toggles visibility of all Ghosty Terminal windows. When hidden, activates Ghostty as the frontmost application
@IBAction func toggleVisibility(_ sender: Any) {
// We only care about terminal windows.
for window in NSApp.windows.filter({ $0.windowController is BaseTerminalController }) {
if isVisible {
window.orderOut(nil)
} else {
window.makeKeyAndOrderFront(nil)
}
}

// After bringing them all to front we make sure our app is active too.
if !isVisible {
NSApp.activate(ignoringOtherApps: true)
}

isVisible.toggle()
}
}
10 changes: 8 additions & 2 deletions macos/Sources/App/macOS/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,16 @@
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="L3L-I8-sqk"/>
<menuItem title="Quick Terminal" id="kvF-d2-JsP">
<menuItem title="Toggle Visibility" id="kvF-d2-JsP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleQuickTerminal:" target="bbz-4X-AYv" id="gm3-mk-l8N"/>
<action selector="toggleVisibility" target="bbz-4X-AYv" id="RhV-3i-Xjz"/>
</connections>
</menuItem>
<menuItem title="Quick Terminal" id="1pv-LF-NBJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleQuickTerminal:" target="bbz-4X-AYv" id="qDV-sz-Agc"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bC9-n9-RbJ"/>
Expand Down
11 changes: 11 additions & 0 deletions macos/Sources/Ghostty/Ghostty.App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,9 @@ extension Ghostty {
case GHOSTTY_ACTION_TOGGLE_QUICK_TERMINAL:
toggleQuickTerminal(app, target: target)

case GHOSTTY_ACTION_TOGGLE_VISIBILITY:
toggleVisibility(app, target: target)

case GHOSTTY_ACTION_CLOSE_ALL_WINDOWS:
fallthrough
case GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW:
Expand Down Expand Up @@ -630,6 +633,14 @@ extension Ghostty {
}
}

private static func toggleVisibility(
_ app: ghostty_app_t,
target: ghostty_target_s
) {
guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else { return }
appDelegate.toggleVisibility(self)
}

private static func gotoTab(
_ app: ghostty_app_t,
target: ghostty_target_s,
Expand Down
1 change: 1 addition & 0 deletions src/App.zig
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ pub fn performAction(
.reload_config => try self.reloadConfig(rt_app),
.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, {}),
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/apprt/action.zig
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ pub const Action = union(Key) {
/// Toggle the quick terminal in or out.
toggle_quick_terminal,

/// Toggle the visibility of all Ghostty terminal windows.
toggle_visibility,

/// Jump to a specific tab. Must handle the scenario that the tab
/// value is invalid.
goto_tab: GotoTab,
Expand Down Expand Up @@ -180,6 +183,7 @@ pub const Action = union(Key) {
toggle_tab_overview,
toggle_window_decorations,
toggle_quick_terminal,
toggle_visibility,
goto_tab,
goto_split,
resize_split,
Expand Down
1 change: 1 addition & 0 deletions src/apprt/glfw.zig
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ pub const App = struct {
.toggle_tab_overview,
.toggle_window_decorations,
.toggle_quick_terminal,
.toggle_visibility,
.goto_tab,
.inspector,
.render_inspector,
Expand Down
1 change: 1 addition & 0 deletions src/apprt/gtk/App.zig
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ pub fn performAction(
.close_all_windows,
.toggle_split_zoom,
.toggle_quick_terminal,
.toggle_visibility,
.size_limit,
.cell_size,
.secure_input,
Expand Down
8 changes: 8 additions & 0 deletions src/input/Binding.zig
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,13 @@ pub const Action = union(enum) {
/// configuration file to customize its behavior.
toggle_quick_terminal: void,

/// Show/hide all windows. If all windows become shown, we also ensure
/// Ghostty is focused.
///
/// This currently only works on macOS. When hiding all windows, we do
/// not yield focus to the previous application.
toggle_visibility: void,

/// Quit ghostty.
quit: void,

Expand Down Expand Up @@ -588,6 +595,7 @@ pub const Action = union(enum) {
.close_all_windows,
.quit,
.toggle_quick_terminal,
.toggle_visibility,
=> .app,

// These are app but can be special-cased in a surface context.
Expand Down

0 comments on commit 991cbce

Please sign in to comment.