Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions Sources/AgentsNotch/Utilities/NotchPanelController.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import AppKit
import SwiftUI

/// Keeps AppKit in sole control of the panel frame while the hosted SwiftUI
/// hierarchy animates its own layout inside these fixed bounds.
final class NotchPanelContentView: NSView {}

@MainActor
final class NotchPanelController: NSWindowController {
private let runtime: AppRuntime
Expand Down Expand Up @@ -143,12 +147,18 @@ final class NotchPanelController: NSWindowController {
let hostingView = NSHostingView(rootView: rootView)
hostingView.wantsLayer = true
hostingView.layer?.backgroundColor = NSColor.clear.cgColor
hostingView.safeAreaRegions = []
// Don't size the window from SwiftUI intrinsic content — the panel
// frame is the single source of truth for bounds during animation.
if #available(macOS 13.0, *) {
hostingView.sizingOptions = []
}
panel.contentView = hostingView
hostingView.sizingOptions = []

let contentView = NotchPanelContentView(frame: panel.contentLayoutRect)
contentView.wantsLayer = true
contentView.layer?.backgroundColor = NSColor.clear.cgColor
hostingView.frame = contentView.bounds
hostingView.autoresizingMask = [.width, .height]
contentView.addSubview(hostingView)
panel.contentView = contentView
}

private func observeDisplayChanges() {
Expand Down
11 changes: 11 additions & 0 deletions Tests/AgentsNotchTests/NotchPanelControllerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@
import XCTest

final class NotchPanelControllerTests: XCTestCase {
@MainActor
func testPanelKeepsHostingViewBehindAppKitSizingBoundary() throws {
let controller = NotchPanelController(runtime: AppRuntime(monitorProviders: false))
let contentView = try XCTUnwrap(controller.window?.contentView)

XCTAssertTrue(contentView is NotchPanelContentView)
XCTAssertEqual(contentView.subviews.count, 1)
XCTAssertEqual(contentView.subviews[0].autoresizingMask, [.width, .height])
XCTAssertEqual(contentView.subviews[0].frame, contentView.bounds)
}

@MainActor
func testSurfaceAvailabilityCallbackTracksPreferenceChanges() {
let defaults = UserDefaults.standard
Expand Down
Loading