Merge pull request #2083 from ghostty-org/macos-resize

macOS: resize overlay improvements
This commit is contained in:
Mitchell Hashimoto
2024-08-11 11:41:56 -07:00
committed by GitHub
3 changed files with 61 additions and 4 deletions

View File

@ -153,7 +153,8 @@ extension Ghostty {
size: surfaceSize,
overlay: ghostty.config.resizeOverlay,
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 position: Ghostty.Config.ResizeOverlayPosition
let duration: UInt
let focusInstant: Any?
// This is the last size that we processed. This is how we handle our
// timer state.
@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.
private let padding: CGFloat = 5
// This computed boolean is set to true when the overlay should be hidden.
private var hidden: Bool {
// If we aren't ready yet then we wait...
if (!ready) { return true; }
// Hidden if we already processed this size.
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
switch (overlay) {
case .never: return true;
@ -327,11 +349,24 @@ extension Ghostty {
}
.allowsHitTesting(false)
.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) {
// 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
// properly.
try? await Task.sleep(nanoseconds: UInt64(duration) * 1_000_000)
// 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)
}
lastSize = geoSize
}
}

View File

@ -30,6 +30,10 @@ extension Ghostty {
// The hovered URL string
@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
// then the view is moved to a new window.
var initialSize: NSSize? = nil
@ -208,6 +212,13 @@ extension Ghostty {
guard self.focused != focused else { return }
self.focused = 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) {

View File

@ -28,6 +28,10 @@ extension Ghostty {
// The hovered URL
@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
// structure because I'm lazy.
var surfaceSize: ghostty_surface_size_s? {
@ -67,6 +71,13 @@ extension Ghostty {
func focusDidChange(_ focused: Bool) {
guard let surface = self.surface else { return }
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) {