mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
fix: respect notch in MacOS non-native fullscreen mode
This patch adds top padding to respect macOS notch cutout in non-native fullscreen mode. I do not have any experience with swift & swiftui, so please let me know if there's a better way to implement this!
This commit is contained in:
@ -333,7 +333,15 @@ class BaseTerminalController: NSWindowController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullscreenDidChange() {
|
func fullscreenDidChange(mode: FullscreenMode, enabled: Bool) {
|
||||||
|
NotificationCenter.default.post(
|
||||||
|
name: Ghostty.Notification.ghosttyDidToggleFullscreen,
|
||||||
|
object: self.window,
|
||||||
|
userInfo: [
|
||||||
|
Ghostty.Notification.FullscreenEnabledKey: enabled,
|
||||||
|
Ghostty.Notification.FullscreenModeKey: mode,
|
||||||
|
]
|
||||||
|
)
|
||||||
// For some reason focus can get lost when we change fullscreen. Regardless of
|
// For some reason focus can get lost when we change fullscreen. Regardless of
|
||||||
// mode above we just move it back.
|
// mode above we just move it back.
|
||||||
if let focusedSurface {
|
if let focusedSurface {
|
||||||
|
@ -95,8 +95,8 @@ class TerminalController: BaseTerminalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override func fullscreenDidChange() {
|
override func fullscreenDidChange(mode: FullscreenMode, enabled: Bool) {
|
||||||
super.fullscreenDidChange()
|
super.fullscreenDidChange(mode: mode, enabled: enabled)
|
||||||
|
|
||||||
// When our fullscreen state changes, we resync our appearance because some
|
// When our fullscreen state changes, we resync our appearance because some
|
||||||
// properties change when fullscreen or not.
|
// properties change when fullscreen or not.
|
||||||
|
@ -269,6 +269,10 @@ extension Ghostty.Notification {
|
|||||||
static let ghosttyToggleFullscreen = Notification.Name("com.mitchellh.ghostty.toggleFullscreen")
|
static let ghosttyToggleFullscreen = Notification.Name("com.mitchellh.ghostty.toggleFullscreen")
|
||||||
static let FullscreenModeKey = ghosttyToggleFullscreen.rawValue
|
static let FullscreenModeKey = ghosttyToggleFullscreen.rawValue
|
||||||
|
|
||||||
|
/// Toggle fullscreen of current window
|
||||||
|
static let ghosttyDidToggleFullscreen = Notification.Name("com.mitchellh.ghostty.didToggleFullscreen")
|
||||||
|
static let FullscreenEnabledKey = ghosttyDidToggleFullscreen.rawValue + ".bool"
|
||||||
|
|
||||||
/// Notification sent to toggle split maximize/unmaximize.
|
/// Notification sent to toggle split maximize/unmaximize.
|
||||||
static let didToggleSplitZoom = Notification.Name("com.mitchellh.ghostty.didToggleSplitZoom")
|
static let didToggleSplitZoom = Notification.Name("com.mitchellh.ghostty.didToggleSplitZoom")
|
||||||
|
|
||||||
|
@ -49,6 +49,9 @@ extension Ghostty {
|
|||||||
// Maintain whether our window has focus (is key) or not
|
// Maintain whether our window has focus (is key) or not
|
||||||
@State private var windowFocus: Bool = true
|
@State private var windowFocus: Bool = true
|
||||||
|
|
||||||
|
// Maintain whether our window is fullscreen or not
|
||||||
|
@State private var paddingTop: CGFloat = 0
|
||||||
|
|
||||||
// True if we're hovering over the left URL view, so we can show it on the right.
|
// True if we're hovering over the left URL view, so we can show it on the right.
|
||||||
@State private var isHoveringURLLeft: Bool = false
|
@State private var isHoveringURLLeft: Bool = false
|
||||||
|
|
||||||
@ -70,9 +73,11 @@ extension Ghostty {
|
|||||||
#if canImport(AppKit)
|
#if canImport(AppKit)
|
||||||
let pubBecomeKey = center.publisher(for: NSWindow.didBecomeKeyNotification)
|
let pubBecomeKey = center.publisher(for: NSWindow.didBecomeKeyNotification)
|
||||||
let pubResign = center.publisher(for: NSWindow.didResignKeyNotification)
|
let pubResign = center.publisher(for: NSWindow.didResignKeyNotification)
|
||||||
|
let pubFullscreen = center.publisher(for: Ghostty.Notification.ghosttyDidToggleFullscreen)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Surface(view: surfaceView, size: geo.size)
|
let adjustedSize = CGSize(width: geo.size.width, height: geo.size.height - paddingTop)
|
||||||
|
Surface(view: surfaceView, size: adjustedSize)
|
||||||
.focused($surfaceFocus)
|
.focused($surfaceFocus)
|
||||||
.focusedValue(\.ghosttySurfaceTitle, surfaceView.title)
|
.focusedValue(\.ghosttySurfaceTitle, surfaceView.title)
|
||||||
.focusedValue(\.ghosttySurfacePwd, surfaceView.pwd)
|
.focusedValue(\.ghosttySurfacePwd, surfaceView.pwd)
|
||||||
@ -80,6 +85,19 @@ extension Ghostty {
|
|||||||
.focusedValue(\.ghosttySurfaceCellSize, surfaceView.cellSize)
|
.focusedValue(\.ghosttySurfaceCellSize, surfaceView.cellSize)
|
||||||
#if canImport(AppKit)
|
#if canImport(AppKit)
|
||||||
.backport.pointerStyle(surfaceView.pointerStyle)
|
.backport.pointerStyle(surfaceView.pointerStyle)
|
||||||
|
.onReceive(pubFullscreen) { notification in
|
||||||
|
guard let enabled = notification.userInfo?[Ghostty.Notification.FullscreenEnabledKey] as? Bool else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let mode = notification.userInfo?[Ghostty.Notification.FullscreenModeKey] as? FullscreenMode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let window = notification.object as? NSWindow else { return }
|
||||||
|
guard let screen = window.screen else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
paddingTop = enabled && mode == FullscreenMode.nonNative ? screen.safeAreaInsets.top : 0;
|
||||||
|
}
|
||||||
.onReceive(pubBecomeKey) { notification in
|
.onReceive(pubBecomeKey) { notification in
|
||||||
guard let window = notification.object as? NSWindow else { return }
|
guard let window = notification.object as? NSWindow else { return }
|
||||||
guard let surfaceWindow = surfaceView.window else { return }
|
guard let surfaceWindow = surfaceView.window else { return }
|
||||||
@ -92,6 +110,7 @@ extension Ghostty {
|
|||||||
windowFocus = false
|
windowFocus = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.top, paddingTop)
|
||||||
.onDrop(of: [.fileURL], isTargeted: nil) { providers in
|
.onDrop(of: [.fileURL], isTargeted: nil) { providers in
|
||||||
providers.forEach { provider in
|
providers.forEach { provider in
|
||||||
_ = provider.loadObject(ofClass: URL.self) { url, _ in
|
_ = provider.loadObject(ofClass: URL.self) { url, _ in
|
||||||
@ -125,6 +144,7 @@ extension Ghostty {
|
|||||||
.ghosttySurfaceView(surfaceView)
|
.ghosttySurfaceView(surfaceView)
|
||||||
|
|
||||||
#if canImport(AppKit)
|
#if canImport(AppKit)
|
||||||
|
|
||||||
// If we are in the middle of a key sequence, then we show a visual element. We only
|
// If we are in the middle of a key sequence, then we show a visual element. We only
|
||||||
// support this on macOS currently although in theory we can support mobile with keyboards!
|
// support this on macOS currently although in theory we can support mobile with keyboards!
|
||||||
if !surfaceView.keySequence.isEmpty {
|
if !surfaceView.keySequence.isEmpty {
|
||||||
|
@ -38,11 +38,11 @@ protocol FullscreenStyle {
|
|||||||
protocol FullscreenDelegate: AnyObject {
|
protocol FullscreenDelegate: AnyObject {
|
||||||
/// Called whenever the fullscreen state changed. You can call isFullscreen to see
|
/// Called whenever the fullscreen state changed. You can call isFullscreen to see
|
||||||
/// the current state.
|
/// the current state.
|
||||||
func fullscreenDidChange()
|
func fullscreenDidChange(mode: FullscreenMode, enabled: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FullscreenDelegate {
|
extension FullscreenDelegate {
|
||||||
func fullscreenDidChange() {}
|
func fullscreenDidChange(mode: FullscreenMode, enabled: Bool) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The base class for fullscreen implementations, cannot be used as a FullscreenStyle on its own.
|
/// The base class for fullscreen implementations, cannot be used as a FullscreenStyle on its own.
|
||||||
@ -74,11 +74,11 @@ class FullscreenBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func didEnterFullScreenNotification(_ notification: Notification) {
|
@objc private func didEnterFullScreenNotification(_ notification: Notification) {
|
||||||
delegate?.fullscreenDidChange()
|
delegate?.fullscreenDidChange(mode: FullscreenMode.native, enabled: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func didExitFullScreenNotification(_ notification: Notification) {
|
@objc private func didExitFullScreenNotification(_ notification: Notification) {
|
||||||
delegate?.fullscreenDidChange()
|
delegate?.fullscreenDidChange(mode: FullscreenMode.native, enabled: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
|
|||||||
// https://github.com/ghostty-org/ghostty/issues/1996
|
// https://github.com/ghostty-org/ghostty/issues/1996
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.window.setFrame(self.fullscreenFrame(screen), display: true)
|
self.window.setFrame(self.fullscreenFrame(screen), display: true)
|
||||||
self.delegate?.fullscreenDidChange()
|
self.delegate?.fullscreenDidChange(mode: FullscreenMode.nonNative, enabled: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
|
|||||||
window.makeKeyAndOrderFront(nil)
|
window.makeKeyAndOrderFront(nil)
|
||||||
|
|
||||||
// Notify the delegate
|
// Notify the delegate
|
||||||
self.delegate?.fullscreenDidChange()
|
self.delegate?.fullscreenDidChange(mode: FullscreenMode.nonNative, enabled: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func fullscreenFrame(_ screen: NSScreen) -> NSRect {
|
private func fullscreenFrame(_ screen: NSScreen) -> NSRect {
|
||||||
|
Reference in New Issue
Block a user