mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 16:26:08 +03:00
Merge pull request #2463 from ghostty-org/push-zynwrqnmkryv
macos: clamp window size to screen size on screen parameter changes
This commit is contained in:
@ -61,6 +61,7 @@
|
|||||||
A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */; };
|
A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */; };
|
||||||
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; };
|
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; };
|
||||||
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
|
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
|
||||||
|
A5A6F72A2CC41B8900B232A5 /* Xcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A6F7292CC41B8700B232A5 /* Xcode.swift */; };
|
||||||
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
|
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
|
||||||
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; };
|
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; };
|
||||||
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; };
|
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; };
|
||||||
@ -139,6 +140,7 @@
|
|||||||
A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; };
|
A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; };
|
||||||
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; };
|
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; };
|
||||||
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
|
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
|
||||||
|
A5A6F7292CC41B8700B232A5 /* Xcode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Xcode.swift; sourceTree = "<group>"; };
|
||||||
A5B30531299BEAAA0047F10C /* Ghostty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ghostty.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
A5B30531299BEAAA0047F10C /* Ghostty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ghostty.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
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>"; };
|
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = "<group>"; };
|
||||||
@ -233,6 +235,7 @@
|
|||||||
A534263D2A7DCBB000EBB7A2 /* Helpers */ = {
|
A534263D2A7DCBB000EBB7A2 /* Helpers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
A5A6F7292CC41B8700B232A5 /* Xcode.swift */,
|
||||||
A5CEAFFE29C2410700646FDA /* Backport.swift */,
|
A5CEAFFE29C2410700646FDA /* Backport.swift */,
|
||||||
A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */,
|
A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */,
|
||||||
A5CBD0572C9F30860017A1AE /* Cursor.swift */,
|
A5CBD0572C9F30860017A1AE /* Cursor.swift */,
|
||||||
@ -582,6 +585,7 @@
|
|||||||
A52FFF5D2CAB4D08000C6A5B /* NSScreen+Extension.swift in Sources */,
|
A52FFF5D2CAB4D08000C6A5B /* NSScreen+Extension.swift in Sources */,
|
||||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
||||||
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */,
|
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */,
|
||||||
|
A5A6F72A2CC41B8900B232A5 /* Xcode.swift in Sources */,
|
||||||
A52FFF5B2CAA54B1000C6A5B /* FullscreenMode+Extension.swift in Sources */,
|
A52FFF5B2CAA54B1000C6A5B /* FullscreenMode+Extension.swift in Sources */,
|
||||||
A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */,
|
A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */,
|
||||||
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
|
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
|
||||||
|
@ -57,6 +57,14 @@ class BaseTerminalController: NSWindowController,
|
|||||||
/// Event monitor (see individual events for why)
|
/// Event monitor (see individual events for why)
|
||||||
private var eventMonitor: Any? = nil
|
private var eventMonitor: Any? = nil
|
||||||
|
|
||||||
|
/// The previous frame information from the window
|
||||||
|
private var savedFrame: SavedFrame? = nil
|
||||||
|
|
||||||
|
struct SavedFrame {
|
||||||
|
let window: NSRect
|
||||||
|
let screen: NSRect
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) is not supported for this view")
|
fatalError("init(coder:) is not supported for this view")
|
||||||
}
|
}
|
||||||
@ -80,6 +88,11 @@ class BaseTerminalController: NSWindowController,
|
|||||||
selector: #selector(onConfirmClipboardRequest),
|
selector: #selector(onConfirmClipboardRequest),
|
||||||
name: Ghostty.Notification.confirmClipboard,
|
name: Ghostty.Notification.confirmClipboard,
|
||||||
object: nil)
|
object: nil)
|
||||||
|
center.addObserver(
|
||||||
|
self,
|
||||||
|
selector: #selector(didChangeScreenParametersNotification),
|
||||||
|
name: NSApplication.didChangeScreenParametersNotification,
|
||||||
|
object: nil)
|
||||||
|
|
||||||
// Listen for local events that we need to know of outside of
|
// Listen for local events that we need to know of outside of
|
||||||
// single surface handlers.
|
// single surface handlers.
|
||||||
@ -89,6 +102,8 @@ class BaseTerminalController: NSWindowController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
|
||||||
if let eventMonitor {
|
if let eventMonitor {
|
||||||
NSEvent.removeMonitor(eventMonitor)
|
NSEvent.removeMonitor(eventMonitor)
|
||||||
}
|
}
|
||||||
@ -121,6 +136,57 @@ class BaseTerminalController: NSWindowController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call this whenever the frame changes
|
||||||
|
private func windowFrameDidChange() {
|
||||||
|
// We need to update our saved frame information in case of monitor
|
||||||
|
// changes (see didChangeScreenParameters notification).
|
||||||
|
savedFrame = nil
|
||||||
|
guard let window, let screen = window.screen else { return }
|
||||||
|
savedFrame = .init(window: window.frame, screen: screen.visibleFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Notifications
|
||||||
|
|
||||||
|
@objc private func didChangeScreenParametersNotification(_ notification: Notification) {
|
||||||
|
// If we have a window that is visible and it is outside the bounds of the
|
||||||
|
// screen then we clamp it back to within the screen.
|
||||||
|
guard let window else { return }
|
||||||
|
guard window.isVisible else { return }
|
||||||
|
guard let screen = window.screen else { return }
|
||||||
|
|
||||||
|
let visibleFrame = screen.visibleFrame
|
||||||
|
var newFrame = window.frame
|
||||||
|
|
||||||
|
// Clamp width/height
|
||||||
|
if newFrame.size.width > visibleFrame.size.width {
|
||||||
|
newFrame.size.width = visibleFrame.size.width
|
||||||
|
}
|
||||||
|
if newFrame.size.height > visibleFrame.size.height {
|
||||||
|
newFrame.size.height = visibleFrame.size.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the window is on-screen. We only do this if the previous frame
|
||||||
|
// was also on screen. If a user explicitly wanted their window off screen
|
||||||
|
// then we let it stay that way.
|
||||||
|
x: if newFrame.origin.x < visibleFrame.origin.x {
|
||||||
|
if let savedFrame, savedFrame.window.origin.x < savedFrame.screen.origin.x {
|
||||||
|
break x;
|
||||||
|
}
|
||||||
|
|
||||||
|
newFrame.origin.x = visibleFrame.origin.x
|
||||||
|
}
|
||||||
|
y: if newFrame.origin.y < visibleFrame.origin.y {
|
||||||
|
if let savedFrame, savedFrame.window.origin.y < savedFrame.screen.origin.y {
|
||||||
|
break y;
|
||||||
|
}
|
||||||
|
|
||||||
|
newFrame.origin.y = visibleFrame.origin.y
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the new window frame
|
||||||
|
window.setFrame(newFrame, display: true)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Local Events
|
// MARK: Local Events
|
||||||
|
|
||||||
private func localEventHandler(_ event: NSEvent) -> NSEvent? {
|
private func localEventHandler(_ event: NSEvent) -> NSEvent? {
|
||||||
@ -371,6 +437,14 @@ class BaseTerminalController: NSWindowController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func windowDidResize(_ notification: Notification) {
|
||||||
|
windowFrameDidChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
func windowDidMove(_ notification: Notification) {
|
||||||
|
windowFrameDidChange()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: First Responder
|
// MARK: First Responder
|
||||||
|
|
||||||
@IBAction func close(_ sender: Any) {
|
@IBAction func close(_ sender: Any) {
|
||||||
|
@ -358,7 +358,8 @@ class TerminalController: BaseTerminalController {
|
|||||||
self.fixTabBar()
|
self.fixTabBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
func windowDidMove(_ notification: Notification) {
|
override func windowDidMove(_ notification: Notification) {
|
||||||
|
super.windowDidMove(notification)
|
||||||
self.fixTabBar()
|
self.fixTabBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,13 @@ extension Ghostty {
|
|||||||
// same filesystem concept.
|
// same filesystem concept.
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
ghostty_config_load_default_files(cfg);
|
ghostty_config_load_default_files(cfg);
|
||||||
ghostty_config_load_cli_args(cfg);
|
|
||||||
|
// We only load CLI args when not running in Xcode because in Xcode we
|
||||||
|
// pass some special parameters to control the debugger.
|
||||||
|
if !isRunningInXcode() {
|
||||||
|
ghostty_config_load_cli_args(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
ghostty_config_load_recursive_files(cfg);
|
ghostty_config_load_recursive_files(cfg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
10
macos/Sources/Helpers/Xcode.swift
Normal file
10
macos/Sources/Helpers/Xcode.swift
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// True if we appear to be running in Xcode.
|
||||||
|
func isRunningInXcode() -> Bool {
|
||||||
|
if let _ = ProcessInfo.processInfo.environment["__XCODE_BUILT_PRODUCTS_DIR_PATHS"] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
Reference in New Issue
Block a user