mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-18 17:56:09 +03:00
macos: use GeometryReader for terminal size for macOS 12
We were using the NSView resize func before but this isn't called by SwiftUI on macOS 12. Instead we wrap it in a GeometryReader and detect the size change in updateNSView so we can call the proper ghostty callback.
This commit is contained in:
@ -10,10 +10,25 @@ import GhosttyKit
|
|||||||
/// since that is what the Metal renderer in Ghostty expects. In the future, it may make more sense to
|
/// since that is what the Metal renderer in Ghostty expects. In the future, it may make more sense to
|
||||||
/// wrap an MTKView and use that, but for legacy reasons we didn't do that to begin with.
|
/// wrap an MTKView and use that, but for legacy reasons we didn't do that to begin with.
|
||||||
struct TerminalSurfaceView: NSViewRepresentable {
|
struct TerminalSurfaceView: NSViewRepresentable {
|
||||||
|
static let logger = Logger(
|
||||||
|
subsystem: Bundle.main.bundleIdentifier!,
|
||||||
|
category: String(describing: TerminalSurfaceView.self)
|
||||||
|
)
|
||||||
|
|
||||||
/// This should be set to true wen the surface has focus. This is up to the parent because
|
/// This should be set to true wen the surface has focus. This is up to the parent because
|
||||||
/// focus is also defined by window focus. It is important this is set correctly since if it is
|
/// focus is also defined by window focus. It is important this is set correctly since if it is
|
||||||
/// false then the surface will idle at almost 0% CPU.
|
/// false then the surface will idle at almost 0% CPU.
|
||||||
var hasFocus: Bool
|
let hasFocus: Bool
|
||||||
|
|
||||||
|
/// The size of the frame containing this view. We use this to update the the underlying
|
||||||
|
/// surface. This does not actually SET the size of our frame, this only sets the size
|
||||||
|
/// of our Metal surface for drawing.
|
||||||
|
///
|
||||||
|
/// Note: we do NOT use the NSView.resize function because SwiftUI on macOS 12
|
||||||
|
/// does not call this callback (macOS 13+ does).
|
||||||
|
///
|
||||||
|
/// The best approach is to wrap this view in a GeometryReader and pass in the geo.size.
|
||||||
|
let size: CGSize
|
||||||
|
|
||||||
/// This is set to the title of the surface as defined by the pty. Callers should use this to
|
/// This is set to the title of the surface as defined by the pty. Callers should use this to
|
||||||
/// set the appropriate title of the window/tab/split/etc. if they care.
|
/// set the appropriate title of the window/tab/split/etc. if they care.
|
||||||
@ -21,10 +36,11 @@ struct TerminalSurfaceView: NSViewRepresentable {
|
|||||||
|
|
||||||
@StateObject private var state: TerminalSurfaceView_Real
|
@StateObject private var state: TerminalSurfaceView_Real
|
||||||
|
|
||||||
init(_ app: ghostty_app_t, hasFocus: Bool, title: Binding<String>) {
|
init(_ app: ghostty_app_t, hasFocus: Bool, size: CGSize, title: Binding<String>) {
|
||||||
self._state = StateObject(wrappedValue: TerminalSurfaceView_Real(app))
|
self._state = StateObject(wrappedValue: TerminalSurfaceView_Real(app))
|
||||||
self._title = title
|
self._title = title
|
||||||
self.hasFocus = hasFocus
|
self.hasFocus = hasFocus
|
||||||
|
self.size = size
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeNSView(context: Context) -> TerminalSurfaceView_Real {
|
func makeNSView(context: Context) -> TerminalSurfaceView_Real {
|
||||||
@ -38,6 +54,7 @@ struct TerminalSurfaceView: NSViewRepresentable {
|
|||||||
func updateNSView(_ view: TerminalSurfaceView_Real, context: Context) {
|
func updateNSView(_ view: TerminalSurfaceView_Real, context: Context) {
|
||||||
state.delegate = context.coordinator
|
state.delegate = context.coordinator
|
||||||
state.focusDidChange(hasFocus)
|
state.focusDidChange(hasFocus)
|
||||||
|
state.sizeDidChange(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCoordinator() -> Coordinator {
|
func makeCoordinator() -> Coordinator {
|
||||||
@ -243,14 +260,12 @@ class TerminalSurfaceView_Real: NSView, NSTextInputClient, ObservableObject {
|
|||||||
ghostty_surface_set_focus(surface, focused)
|
ghostty_surface_set_focus(surface, focused)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func resize(withOldSuperviewSize oldSize: NSSize) {
|
func sizeDidChange(_ size: CGSize) {
|
||||||
super.resize(withOldSuperviewSize: oldSize)
|
guard let surface = self.surface else { return }
|
||||||
|
|
||||||
if let surface = self.surface {
|
// Ghostty wants to know the actual framebuffer size...
|
||||||
// Ghostty wants to know the actual framebuffer size...
|
let fbFrame = self.convertToBacking(self.frame);
|
||||||
let fbFrame = self.convertToBacking(self.frame);
|
ghostty_surface_set_size(surface, UInt32(fbFrame.size.width), UInt32(fbFrame.size.height))
|
||||||
ghostty_surface_set_size(surface, UInt32(fbFrame.size.width), UInt32(fbFrame.size.height))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateTrackingAreas() {
|
override func updateTrackingAreas() {
|
||||||
|
@ -12,8 +12,13 @@ struct TerminalView: View {
|
|||||||
private var hasFocus: Bool { surfaceFocus && isKeyWindow }
|
private var hasFocus: Bool { surfaceFocus && isKeyWindow }
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TerminalSurfaceView(app, hasFocus: hasFocus, title: $title)
|
// We use a GeometryReader to get the frame bounds so that our metal surface
|
||||||
.focused($surfaceFocus)
|
// is up to date. See TerminalSurfaceView for why we don't use the NSView
|
||||||
.navigationTitle(title)
|
// resize callback.
|
||||||
|
GeometryReader { geo in
|
||||||
|
TerminalSurfaceView(app, hasFocus: hasFocus, size: geo.size, title: $title)
|
||||||
|
.focused($surfaceFocus)
|
||||||
|
.navigationTitle(title)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user