Skip to content

Commit

Permalink
fix: ensure terminal windows don't part from parent window when toggl…
Browse files Browse the repository at this point in the history
…ing visibility (#4789)

As of version 1.0.1 (macOS build) when running the toggle visibility
action a window with tabs is made into multiple windows.

This PR ensures terminal tabs are reconstructed and correctly placed
into its parent window.

# Demo


https://github.com/user-attachments/assets/44f14bca-15a1-4717-ba0a-44f0767feec3


FYI: I will create another PR to ensure the right tab is focused after
the main window is restored.

Solves #4329
  • Loading branch information
mitchellh authored Jan 10, 2025
2 parents d3de344 + 200aee9 commit 126c050
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 28 deletions.
4 changes: 4 additions & 0 deletions macos/Ghostty.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
A5A6F72A2CC41B8900B232A5 /* Xcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A6F7292CC41B8700B232A5 /* Xcode.swift */; };
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
A5CA378C2D2A4DEB00931030 /* KeyboardLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */; };
A5CA378E2D31D6C300931030 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378D2D31D6C100931030 /* Weak.swift */; };
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; };
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; };
A5CBD0592C9F37B10017A1AE /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFFE29C2410700646FDA /* Backport.swift */; };
Expand Down Expand Up @@ -167,6 +168,7 @@
A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = "<group>"; };
A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardLayout.swift; sourceTree = "<group>"; };
A5CA378D2D31D6C100931030 /* Weak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = "<group>"; };
A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = "<group>"; };
A5CBD0572C9F30860017A1AE /* Cursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cursor.swift; sourceTree = "<group>"; };
A5CBD05B2CA0C5C70017A1AE /* QuickTerminal.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = QuickTerminal.xib; sourceTree = "<group>"; };
Expand Down Expand Up @@ -282,6 +284,7 @@
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */,
A5985CD62C320C4500C57AD3 /* String+Extension.swift */,
A5CC36142C9CDA03004D6760 /* View+Extension.swift */,
A5CA378D2D31D6C100931030 /* Weak.swift */,
C1F26EE72B76CBFC00404083 /* VibrantLayer.h */,
C1F26EE82B76CBFC00404083 /* VibrantLayer.m */,
A5CEAFDA29B8005900646FDA /* SplitView */,
Expand Down Expand Up @@ -647,6 +650,7 @@
A5A6F72A2CC41B8900B232A5 /* Xcode.swift in Sources */,
A52FFF5B2CAA54B1000C6A5B /* FullscreenMode+Extension.swift in Sources */,
A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */,
A5CA378E2D31D6C300931030 /* Weak.swift in Sources */,
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,
A5333E1C2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */,
Expand Down
55 changes: 30 additions & 25 deletions macos/Sources/App/macOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,8 @@ 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
/// Tracks the windows that we hid for toggleVisibility.
private var hiddenWindows: [Weak<NSWindow>] = []

/// The observer for the app appearance.
private var appearanceObserver: NSKeyValueObservation? = nil
Expand Down Expand Up @@ -219,15 +217,20 @@ class AppDelegate: NSObject,
}

func applicationDidBecomeActive(_ notification: Notification) {
guard !applicationHasBecomeActive else { return }
applicationHasBecomeActive = true

// Let's launch our first window. We only do this if we have no other windows. It
// is possible to have other windows in a few scenarios:
// - if we're opening a URL since `application(_:openFile:)` is called before this.
// - if we're restoring from persisted state
if terminalManager.windows.count == 0 && derivedConfig.initialWindow {
terminalManager.newWindow()
// If we're back then clear the hidden windows
self.hiddenWindows = []

// First launch stuff
if (!applicationHasBecomeActive) {
applicationHasBecomeActive = true

// Let's launch our first window. We only do this if we have no other windows. It
// is possible to have other windows in a few scenarios:
// - if we're opening a URL since `application(_:openFile:)` is called before this.
// - if we're restoring from persisted state
if terminalManager.windows.count == 0 && derivedConfig.initialWindow {
terminalManager.newWindow()
}
}
}

Expand Down Expand Up @@ -706,21 +709,23 @@ class AppDelegate: NSObject,

/// 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)
}
// If we have focus, then we hide all windows.
if NSApp.isActive {
// We need to keep track of the windows that were visible because we only
// want to bring back these windows if we remove the toggle.
self.hiddenWindows = NSApp.windows.filter { $0.isVisible }.map { Weak($0) }
NSApp.hide(nil)
return
}

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

isVisible.toggle()
// Bring all windows to the front. Note: we don't use NSApp.unhide because
// that will unhide ALL hidden windows. We want to only bring forward the
// ones that we hid.
self.hiddenWindows.forEach { $0.value?.orderFrontRegardless() }
self.hiddenWindows = []
}

private struct DerivedConfig {
Expand Down
9 changes: 9 additions & 0 deletions macos/Sources/Helpers/Weak.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/// A wrapper that holds a weak reference to an object. This lets us create native containers
/// of weak references.
class Weak<T: AnyObject> {
weak var value: T?

init(_ value: T) {
self.value = value
}
}
6 changes: 3 additions & 3 deletions src/input/Binding.zig
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,10 @@ pub const Action = union(enum) {
toggle_quick_terminal: void,

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

/// Quit ghostty.
Expand Down

1 comment on commit 126c050

@xcvh
Copy link

@xcvh xcvh commented on 126c050 Jan 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! 👍

Please sign in to comment.