mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
Merge pull request #2083 from ghostty-org/macos-resize
macOS: resize overlay improvements
This commit is contained in:
@ -153,7 +153,8 @@ extension Ghostty {
|
|||||||
size: surfaceSize,
|
size: surfaceSize,
|
||||||
overlay: ghostty.config.resizeOverlay,
|
overlay: ghostty.config.resizeOverlay,
|
||||||
position: ghostty.config.resizeOverlayPosition,
|
position: ghostty.config.resizeOverlayPosition,
|
||||||
duration: ghostty.config.resizeOverlayDuration)
|
duration: ghostty.config.resizeOverlayDuration,
|
||||||
|
focusInstant: surfaceView.focusInstant)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,19 +275,40 @@ extension Ghostty {
|
|||||||
let overlay: Ghostty.Config.ResizeOverlay
|
let overlay: Ghostty.Config.ResizeOverlay
|
||||||
let position: Ghostty.Config.ResizeOverlayPosition
|
let position: Ghostty.Config.ResizeOverlayPosition
|
||||||
let duration: UInt
|
let duration: UInt
|
||||||
|
let focusInstant: Any?
|
||||||
|
|
||||||
// This is the last size that we processed. This is how we handle our
|
// This is the last size that we processed. This is how we handle our
|
||||||
// timer state.
|
// timer state.
|
||||||
@State var lastSize: CGSize? = nil
|
@State var lastSize: CGSize? = nil
|
||||||
|
|
||||||
|
// Ready is set to true after a short delay. This avoids some of the
|
||||||
|
// challenges of initial view sizing from SwiftUI.
|
||||||
|
@State var ready: Bool = false
|
||||||
|
|
||||||
// Fixed value set based on personal taste.
|
// Fixed value set based on personal taste.
|
||||||
private let padding: CGFloat = 5
|
private let padding: CGFloat = 5
|
||||||
|
|
||||||
// This computed boolean is set to true when the overlay should be hidden.
|
// This computed boolean is set to true when the overlay should be hidden.
|
||||||
private var hidden: Bool {
|
private var hidden: Bool {
|
||||||
|
// If we aren't ready yet then we wait...
|
||||||
|
if (!ready) { return true; }
|
||||||
|
|
||||||
// Hidden if we already processed this size.
|
// Hidden if we already processed this size.
|
||||||
if (lastSize == geoSize) { return true; }
|
if (lastSize == geoSize) { return true; }
|
||||||
|
|
||||||
|
// If we were focused recently we hide it as well. This avoids showing
|
||||||
|
// the resize overlay when SwiftUI is lazily resizing.
|
||||||
|
if #available(macOS 13, iOS 16, *) {
|
||||||
|
if let instant = focusInstant as? ContinuousClock.Instant {
|
||||||
|
let d = instant.duration(to: ContinuousClock.now)
|
||||||
|
if (d < .milliseconds(500)) {
|
||||||
|
// Avoid this size completely.
|
||||||
|
lastSize = geoSize
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hidden depending on overlay config
|
// Hidden depending on overlay config
|
||||||
switch (overlay) {
|
switch (overlay) {
|
||||||
case .never: return true;
|
case .never: return true;
|
||||||
@ -327,11 +349,24 @@ extension Ghostty {
|
|||||||
}
|
}
|
||||||
.allowsHitTesting(false)
|
.allowsHitTesting(false)
|
||||||
.opacity(hidden ? 0 : 1)
|
.opacity(hidden ? 0 : 1)
|
||||||
|
.task {
|
||||||
|
// Sleep chosen arbitrarily... a better long term solution would be to detect
|
||||||
|
// when the size stabilizes (coalesce a value) for the first time and then after
|
||||||
|
// that show the resize overlay consistently.
|
||||||
|
try? await Task.sleep(nanoseconds: 500 * 1_000_000)
|
||||||
|
ready = true
|
||||||
|
}
|
||||||
.task(id: geoSize) {
|
.task(id: geoSize) {
|
||||||
// By ID-ing the task on the geoSize, we get the task to restart if our
|
// By ID-ing the task on the geoSize, we get the task to restart if our
|
||||||
// geoSize changes. This also ensures that future resize overlays are shown
|
// geoSize changes. This also ensures that future resize overlays are shown
|
||||||
// properly.
|
// properly.
|
||||||
|
|
||||||
|
// We only sleep if we're ready. If we're not ready then we want to set
|
||||||
|
// our last size right away to avoid a flash.
|
||||||
|
if (ready) {
|
||||||
try? await Task.sleep(nanoseconds: UInt64(duration) * 1_000_000)
|
try? await Task.sleep(nanoseconds: UInt64(duration) * 1_000_000)
|
||||||
|
}
|
||||||
|
|
||||||
lastSize = geoSize
|
lastSize = geoSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,10 @@ extension Ghostty {
|
|||||||
// The hovered URL string
|
// The hovered URL string
|
||||||
@Published var hoverUrl: String? = nil
|
@Published var hoverUrl: String? = nil
|
||||||
|
|
||||||
|
// The time this surface last became focused. This is a ContinuousClock.Instant
|
||||||
|
// on supported platforms.
|
||||||
|
@Published var focusInstant: Any? = nil
|
||||||
|
|
||||||
// An initial size to request for a window. This will only affect
|
// An initial size to request for a window. This will only affect
|
||||||
// then the view is moved to a new window.
|
// then the view is moved to a new window.
|
||||||
var initialSize: NSSize? = nil
|
var initialSize: NSSize? = nil
|
||||||
@ -208,6 +212,13 @@ extension Ghostty {
|
|||||||
guard self.focused != focused else { return }
|
guard self.focused != focused else { return }
|
||||||
self.focused = focused
|
self.focused = focused
|
||||||
ghostty_surface_set_focus(surface, focused)
|
ghostty_surface_set_focus(surface, focused)
|
||||||
|
|
||||||
|
// On macOS 13+ we can store our continuous clock...
|
||||||
|
if #available(macOS 13, iOS 16, *) {
|
||||||
|
if (focused) {
|
||||||
|
focusInstant = ContinuousClock.now
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeDidChange(_ size: CGSize) {
|
func sizeDidChange(_ size: CGSize) {
|
||||||
|
@ -28,6 +28,10 @@ extension Ghostty {
|
|||||||
// The hovered URL
|
// The hovered URL
|
||||||
@Published var hoverUrl: String? = nil
|
@Published var hoverUrl: String? = nil
|
||||||
|
|
||||||
|
// The time this surface last became focused. This is a ContinuousClock.Instant
|
||||||
|
// on supported platforms.
|
||||||
|
@Published var focusInstant: Any? = nil
|
||||||
|
|
||||||
// Returns sizing information for the surface. This is the raw C
|
// Returns sizing information for the surface. This is the raw C
|
||||||
// structure because I'm lazy.
|
// structure because I'm lazy.
|
||||||
var surfaceSize: ghostty_surface_size_s? {
|
var surfaceSize: ghostty_surface_size_s? {
|
||||||
@ -67,6 +71,13 @@ extension Ghostty {
|
|||||||
func focusDidChange(_ focused: Bool) {
|
func focusDidChange(_ focused: Bool) {
|
||||||
guard let surface = self.surface else { return }
|
guard let surface = self.surface else { return }
|
||||||
ghostty_surface_set_focus(surface, focused)
|
ghostty_surface_set_focus(surface, focused)
|
||||||
|
|
||||||
|
// On macOS 13+ we can store our continuous clock...
|
||||||
|
if #available(macOS 13, iOS 16, *) {
|
||||||
|
if (focused) {
|
||||||
|
focusInstant = ContinuousClock.now
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeDidChange(_ size: CGSize) {
|
func sizeDidChange(_ size: CGSize) {
|
||||||
|
Reference in New Issue
Block a user