ghostty/macos/Sources/TerminalSurfaceView.swift
2023-02-19 10:44:56 -08:00

91 lines
2.9 KiB
Swift

import OSLog
import SwiftUI
import GhosttyKit
/// A surface is terminology in Ghostty for a terminal surface, or a place where a terminal is actually drawn
/// and interacted with. The word "surface" is used because a surface may represent a window, a tab,
/// a split, a small preview pane, etc. It is ANYTHING that has a terminal drawn to it.
///
/// We just wrap an AppKit NSView here at the moment so that we can behave as low level as possible
/// 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.
struct TerminalSurfaceView: NSViewRepresentable {
@StateObject private var state: TerminalSurfaceState
init(app: ghostty_app_t) {
self._state = StateObject(wrappedValue: TerminalSurfaceState(app))
}
func makeNSView(context: Context) -> TerminalSurfaceView_Real {
// We need the view as part of the state to be created previously because
// the view is sent to the Ghostty API so that it can manipulate it
// directly since we draw on a render thread.
return state.view;
}
func updateNSView(_ view: TerminalSurfaceView_Real, context: Context) {
// Nothing we need to do here.
}
}
/// The state for the terminal surface view.
class TerminalSurfaceState: ObservableObject {
static let logger = Logger(
subsystem: Bundle.main.bundleIdentifier!,
category: String(describing: TerminalSurfaceState.self)
)
var view: TerminalSurfaceView_Real
private var surface: ghostty_surface_t? = nil
private var error: Error? = nil
init(_ app: ghostty_app_t) {
view = TerminalSurfaceView_Real()
var surface_cfg = ghostty_surface_config_s(
nsview: Unmanaged.passUnretained(view).toOpaque(),
scale_factor: 2.0)
guard let surface = ghostty_surface_new(app, &surface_cfg) else {
self.error = AppError.surfaceCreateError
return
}
self.surface = surface;
}
deinit {
if let surface = self.surface {
ghostty_surface_free(surface)
}
}
}
// The actual NSView implementation for the terminal surface.
class TerminalSurfaceView_Real: NSView {
// We need to support being a first responder so that we can get input events
override var acceptsFirstResponder: Bool { return true }
override func draw(_ dirtyRect: NSRect) {
print("DRAW: \(dirtyRect)")
NSColor.green.setFill()
dirtyRect.fill()
super.draw(dirtyRect)
}
override func mouseDown(with event: NSEvent) {
print("Mouse down: \(event)")
}
override func keyDown(with event: NSEvent) {
print("Key down: \(event)")
}
}
/*
struct TerminalSurfaceView_Previews: PreviewProvider {
static var previews: some View {
TerminalSurfaceView()
}
}
*/