diff --git a/macos/Sources/Ghostty/InspectorView.swift b/macos/Sources/Ghostty/InspectorView.swift index 5f0b92790..11c318a5c 100644 --- a/macos/Sources/Ghostty/InspectorView.swift +++ b/macos/Sources/Ghostty/InspectorView.swift @@ -13,58 +13,83 @@ extension Ghostty { SplitView(.vertical, left: { SurfaceWrapper(surfaceView: surfaceView, isSplit: isSplit) }, right: { - InspectorView() + SurfaceInspector() }) } } - struct InspectorView: View { + struct SurfaceInspector: View { var body: some View { - MetalView() + MetalView() } } - class Renderer: NSObject, MetalViewRenderer { - let device: MTLDevice + class InspectorView: MTKView { let commandQueue: MTLCommandQueue - required init(metalView: MTKView) { + override init(frame: CGRect, device: MTLDevice?) { // Initialize our Metal primitives guard - let device = MTLCreateSystemDefaultDevice(), + let device = device ?? MTLCreateSystemDefaultDevice(), let commandQueue = device.makeCommandQueue() else { fatalError("GPU not available") } - self.device = device + // Setup our properties before initializing the parent self.commandQueue = commandQueue - super.init() + super.init(frame: frame, device: device) - // Setup the view to point to this renderer - metalView.device = device - metalView.delegate = self - metalView.clearColor = MTLClearColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) + // After initializing the parent we can set our own properties + self.device = MTLCreateSystemDefaultDevice() + self.clearColor = MTLClearColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) + + // Setup our tracking areas for mouse events + updateTrackingAreas() + } + + required init(coder: NSCoder) { + fatalError("init(coder:) is not supported for this view") + } + + deinit { + trackingAreas.forEach { removeTrackingArea($0) } + } + + override func updateTrackingAreas() { + // To update our tracking area we just recreate it all. + trackingAreas.forEach { removeTrackingArea($0) } + + // This tracking area is across the entire frame to notify us of mouse movements. + addTrackingArea(NSTrackingArea( + rect: frame, + options: [ + .mouseMoved, + + // Only send mouse events that happen in our visible (not obscured) rect + .inVisibleRect, + + // We want active always because we want to still send mouse reports + // even if we're not focused or key. + .activeAlways, + ], + owner: self, + userInfo: nil)) + } + + override func draw(_ dirtyRect: NSRect) { + guard + let commandBuffer = self.commandQueue.makeCommandBuffer(), + let descriptor = self.currentRenderPassDescriptor, + let renderEncoder = + commandBuffer.makeRenderCommandEncoder( + descriptor: descriptor) else { + return + } + + renderEncoder.endEncoding() + guard let drawable = self.currentDrawable else { return } + commandBuffer.present(drawable) + commandBuffer.commit() } } } - -extension Ghostty.Renderer: MTKViewDelegate { - func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { - } - - func draw(in view: MTKView) { - guard - let commandBuffer = self.commandQueue.makeCommandBuffer(), - let descriptor = view.currentRenderPassDescriptor, - let renderEncoder = - commandBuffer.makeRenderCommandEncoder( - descriptor: descriptor) else { - return - } - - renderEncoder.endEncoding() - guard let drawable = view.currentDrawable else { return } - commandBuffer.present(drawable) - commandBuffer.commit() - } -} diff --git a/macos/Sources/Helpers/MetalView.swift b/macos/Sources/Helpers/MetalView.swift index b0dbe10ad..ddbf00d1a 100644 --- a/macos/Sources/Helpers/MetalView.swift +++ b/macos/Sources/Helpers/MetalView.swift @@ -1,24 +1,17 @@ import SwiftUI import MetalKit -/// Implements the logic for a metal view used by MetalView. -protocol MetalViewRenderer: MTKViewDelegate { - init(metalView: MTKView) -} - /// Renders an MTKView with the given renderer class. -struct MetalView: View { - @State private var metalView = MTKView() - @State private var renderer: R? +struct MetalView: View { + @State private var metalView = V() var body: some View { MetalViewRepresentable(metalView: $metalView) - .onAppear { renderer = R(metalView: metalView) } } } -fileprivate struct MetalViewRepresentable: NSViewRepresentable { - @Binding var metalView: MTKView +fileprivate struct MetalViewRepresentable: NSViewRepresentable { + @Binding var metalView: V func makeNSView(context: Context) -> some NSView { metalView