From a82f309a0a1b3039168533673237c4d365860007 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 11 Feb 2026 23:13:48 +0800 Subject: [PATCH 1/5] Update UIKitDisplayList --- .../Render/DisplayList/UIKitDisplayList.swift | 47 ++++++++++++++----- .../DisplayList/DisplayListViewPlatform.swift | 1 + 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift index 849c4eaf1..78b3075a9 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift @@ -3,7 +3,7 @@ // OpenSwiftUI // // Audited for 6.5.4 -// Status: WIP +// Status: Complete // ID: A34643117F00277B93DEBAB70EC06971 (SwiftUI) #if os(iOS) || os(visionOS) @@ -12,9 +12,10 @@ import COpenSwiftUI import UIKit import OpenSwiftUISymbolDualTestsSupport import QuartzCore_Private +import OpenRenderBoxShims import OpenSwiftUI_SPI -// MARK: - UIViewPlatformViewDefinition [TODO] [6.0.87] +// MARK: - UIViewPlatformViewDefinition final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sendable { override final class var system: PlatformViewDefinition.System { .uiView } @@ -33,7 +34,6 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen return view } - // Audited for 6.5.4 override static func makeLayerView(type: CALayer.Type, kind: PlatformViewDefinition.ViewKind) -> AnyObject { let cls: UIView.Type if kind == .shape { @@ -47,11 +47,43 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen return view } + override class func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) { + Self.initView(view as! UIView, kind: kind) + } + + override class func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable { + let view: UIView & PlatformDrawable + if options.isAccelerated && ORBDevice.isSupported() { + view = RBDrawingView(options: options) + } else { + view = CGDrawingView(options: options) + } + view.contentMode = .topLeft + initView(view, kind: .drawing) + return view + } + override static func setPath(_ path: Path, shapeView: AnyObject) { let view = unsafeBitCast(shapeView, to: _UIShapeHitTestingView.self) view.path = path } + override class func setProjectionTransform(_ transform: ProjectionTransform, projectionView: AnyObject) { + let layer = CoreViewLayer(system: .uiView, view: projectionView) + layer.transform = CATransform3D(transform) + } + + override class func getRBLayer(drawingView: AnyObject) -> AnyObject? { + guard let rbView = drawingView as? RBDrawingView else { return nil } + return rbView.layer + } + + override class func setIgnoresEvents(_ state: Bool, of view: AnyObject) { + let view = unsafeBitCast(view, to: UIView.self) + view.isUserInteractionEnabled = !state + } + + private static func initView(_ view: UIView, kind: PlatformViewDefinition.ViewKind) { if kind != .platformView && kind != .platformGroup { view.autoresizesSubviews = false @@ -73,15 +105,6 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen break } } - - override class func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) { - Self.initView(view as! UIView, kind: kind) - } - - override class func setProjectionTransform(_ transform: ProjectionTransform, projectionView: AnyObject) { - let layer = CoreViewLayer(system: .uiView, view: projectionView) - layer.transform = .init(transform) - } } // MARK: - _UIGraphicsView diff --git a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift index 634a138ee..8c1add13d 100644 --- a/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift +++ b/Sources/OpenSwiftUICore/Render/DisplayList/DisplayListViewPlatform.swift @@ -14,6 +14,7 @@ import Foundation #endif @_spi(DisplayList_ViewSystem) +@available(OpenSwiftUI_v6_0, *) open class PlatformViewDefinition: @unchecked Sendable { public struct System: Hashable, Sendable { public static let uiView = PlatformViewDefinition.System(base: .uiView) From 4bd90b6c1d9985a029c0316c0e6357ccd72c4882 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 12 Feb 2026 01:02:12 +0800 Subject: [PATCH 2/5] Update SwitchToggleStyle --- .../Shims/AppKit/AppKit_Private.h | 1 + ...llowsWindowActivationEventsResponder.swift | 25 ++++ .../AppKitHitTestCustomizing.swift | 124 ++++++++++++++++++ .../LabelContent/TopAlignedFormValueKey.swift | 15 +++ .../View/Toggle/SwitchToggleStyle.swift | 55 +++----- 5 files changed, 184 insertions(+), 36 deletions(-) create mode 100644 Sources/OpenSwiftUI/Event/Responder/AllowsWindowActivationEventsResponder.swift create mode 100644 Sources/OpenSwiftUI/Render/DisplayList/AppKitHitTestCustomizing.swift create mode 100644 Sources/OpenSwiftUI/View/LabelContent/TopAlignedFormValueKey.swift diff --git a/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h b/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h index 6e960315a..10bd981a9 100644 --- a/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h +++ b/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h @@ -34,6 +34,7 @@ typedef OPENSWIFTUI_ENUM(NSInteger, NSViewVibrantBlendingStyle) { @interface NSView () @property (getter=isOpaque) BOOL opaque; +@property (nonatomic) BOOL ignoreHitTest; - (void)_updateLayerGeometryFromView; - (void)_updateLayerShadowFromView; - (void)_updateLayerShadowColorFromView; diff --git a/Sources/OpenSwiftUI/Event/Responder/AllowsWindowActivationEventsResponder.swift b/Sources/OpenSwiftUI/Event/Responder/AllowsWindowActivationEventsResponder.swift new file mode 100644 index 000000000..06b693481 --- /dev/null +++ b/Sources/OpenSwiftUI/Event/Responder/AllowsWindowActivationEventsResponder.swift @@ -0,0 +1,25 @@ +// +// AllowsWindowActivationEventsResponder.swift +// OpenSwiftUI +// +// Audited for 6.5.4 +// Status: WIP +// ID: 302179F1EB9AE99B83C6A183C0B4143E (?) + +#if os(macOS) +// TODO +class AllowsWindowActivationEventsResponder {} + +// MARK: - AllowsWindowActivationEventsKey + +private struct AllowsWindowActivationEventsKey: EnvironmentKey { + static var defaultValue: Bool? +} + +extension EnvironmentValues { + var allowsWindowActivationEvents: Bool? { + get { self[AllowsWindowActivationEventsKey.self] } + set { self[AllowsWindowActivationEventsKey.self] = newValue } + } +} +#endif diff --git a/Sources/OpenSwiftUI/Render/DisplayList/AppKitHitTestCustomizing.swift b/Sources/OpenSwiftUI/Render/DisplayList/AppKitHitTestCustomizing.swift new file mode 100644 index 000000000..3546a7e8e --- /dev/null +++ b/Sources/OpenSwiftUI/Render/DisplayList/AppKitHitTestCustomizing.swift @@ -0,0 +1,124 @@ +// +// AppKitHitTestCustomizing.swift +// OpenSwiftUI +// +// Audited for 6.5.4 +// Status: WIP +// ID: 289E697C76A45E2F2E3A5EE8124A4DEF + +#if os(macOS) +import AppKit +import COpenSwiftUI +@_spi(DisplayList_ViewSystem) +@_spi(ForOpenSwiftUIOnly) +import OpenSwiftUICore + +// MARK: - RecursiveIgnoreHitTestCustomizing + +protocol RecursiveIgnoreHitTestCustomizing: NSView { + var recursiveIgnoreHitTest: Bool { get set } +} + +// MARK: - AcceptsFirstMouseCustomizing + +protocol AcceptsFirstMouseCustomizing: NSView { + var customAcceptsFirstMouse: Bool? { get set } +} + +extension AcceptsFirstMouseCustomizing { + var effectiveAcceptsFirstMouse: Bool? { + if let value = customAcceptsFirstMouse { + return value + } + var current: NSView? = superview + while let view = current { + if let customizing = view as? AcceptsFirstMouseCustomizing { + return customizing.effectiveAcceptsFirstMouse + } + if view is HostingViewProtocol { + return nil + } + current = view.superview + } + return nil + } +} + +// MARK: - HitTestsAsOpaqueCustomizing + +protocol HitTestsAsOpaqueCustomizing: NSView { + var hitTestsAsOpaque: Bool { get set } +} + +// MARK: - HitTestingLeafPlatformView + +protocol HitTestingLeafPlatformView: NSView { + var usesResponderForHitTesting: Bool { get } + var responderForHitTesting: ViewResponder? { get } + var foreignSubviewsForHitTesting: [NSView] { get } + var isTransparentForHitTesting: Bool { get } + func hitTest(_ point: CGPoint, cacheKey: UInt32?) -> NSView? +} + +extension HitTestingLeafPlatformView { + var isTransparentForHitTesting: Bool { + ignoreHitTest + } + + func pointContainmentHitTest(_ point: CGPoint) -> NSView? { + guard !isHiddenOrHasHiddenAncestor else { return nil } + if let customizing = self as? RecursiveIgnoreHitTestCustomizing, + customizing.recursiveIgnoreHitTest { + return nil + } + let localPoint = convert(point, from: superview) + guard NSMouseInRect(localPoint, bounds, isFlipped) else { return nil } + return self + } + + func defaultHitTest( + _ point: CGPoint, + radius: CGFloat, + cacheKey: UInt32?, + super: () -> NSView? + ) -> NSView? { + if usesResponderForHitTesting { + return responderBasedHitTest( + point, + radius: radius, + cacheKey: cacheKey, + super: `super` + ) + } else { + let isTransparent = isTransparentForHitTesting + let result = `super`() + if isTransparent, let result, result === self { + return nil + } + return result + } + } + + func defaultAcceptsFirstMouse(for event: NSEvent?, super: () -> Bool) -> Bool { + // TODO: Blocked by ViewResponder.hitTest + _openSwiftUIUnimplementedWarning() + return `super`() + } + + func defaultShouldDelayWindowOrdering(for event: NSEvent, super: () -> Bool) -> Bool { + // TODO: Blocked by ViewResponder.hitTest + return `super`() + } + + private func responderBasedHitTest( + _ point: CGPoint, + radius: CGFloat, + cacheKey: UInt32?, + super: () -> NSView? + ) -> NSView? { + _openSwiftUIUnimplementedWarning() + return nil + } +} + +#endif diff --git a/Sources/OpenSwiftUI/View/LabelContent/TopAlignedFormValueKey.swift b/Sources/OpenSwiftUI/View/LabelContent/TopAlignedFormValueKey.swift new file mode 100644 index 000000000..38dd621da --- /dev/null +++ b/Sources/OpenSwiftUI/View/LabelContent/TopAlignedFormValueKey.swift @@ -0,0 +1,15 @@ +// +// TopAlignedFormValueKey.swift +// OpenSwiftUI +// +// Audited for 6.5.4 +// Status: Partial +// ID: 0481B0D26895C528738CA5BBB60A8193 (SwiftUI?) + +import OpenSwiftUICore + +// MARK: TopAlignedFormValueKey + +struct TopAlignedFormValueKey: LayoutValueKey { + static let defaultValue: Bool = false +} diff --git a/Sources/OpenSwiftUI/View/Toggle/SwitchToggleStyle.swift b/Sources/OpenSwiftUI/View/Toggle/SwitchToggleStyle.swift index ec137f5e6..5a28cd3db 100644 --- a/Sources/OpenSwiftUI/View/Toggle/SwitchToggleStyle.swift +++ b/Sources/OpenSwiftUI/View/Toggle/SwitchToggleStyle.swift @@ -65,29 +65,31 @@ public struct SwitchToggleStyle: ToggleStyle { self.tint = tint } + // TODO: iOS gesture public func makeBody(configuration: Configuration) -> some View { - #if os(iOS) || os(visionOS) - // FIXME + let switchView = { + #if os(iOS) || os(visionOS) + Switch(isOn: configuration.$isOn, tint: tint, thumbTint: placementTint[.switchThumb], font: font) + #elseif os(macOS) + Switch(isOn: configuration.$isOn, tint: tint, font: font) + #else + _openSwiftUIPlatformUnimplementedFailure() + #endif + } LabeledContent { - Switch(_isOn: configuration.$isOn, tint: tint, thumbTint: placementTint[.switchThumb], font: font) + switchView() .fixedSize() .modifier( _EnvironmentKeyWritingModifier(keyPath: \.controlSize, value: controlSize) - .requiring(GroupedFormStyleContext.self) + .requiring(GroupedFormStyleContext.self), ) - // TODO: TopAlignedFormValueKey + // TODO: + .layoutValue(key: TopAlignedFormValueKey.self, value: false) } label: { configuration.label } .listLabeledContentPrefersHorizontalLayout() .accessibilityLabeledContent() - #elseif os(macOS) - // FIXME - Switch(_isOn: configuration.$isOn, tint: tint, font: font, _acceptsFirstMouse: .init(\.acceptsFirstMouse)) - .fixedSize() - #else - _openSwiftUIPlatformUnimplementedFailure() - #endif } } @@ -106,7 +108,7 @@ import AppKit typealias PlatformSwitch = UISwitch private struct Switch: UIViewRepresentable { - var _isOn: Binding + @Binding var isOn: Bool var tint: Color? var thumbTint: AnyShapeStyle? var font: Font @@ -122,7 +124,7 @@ private struct Switch: UIViewRepresentable { } func updateUIView(_ uiView: PlatformSwitch, context: Context) { - let isOn = _isOn.wrappedValue + let isOn = isOn let transaction = context.transaction Update.enqueueAction(reason: nil) { [transaction] in uiView.setOn(isOn, animated: transaction.disablesAnimations) @@ -149,25 +151,6 @@ private struct Switch: UIViewRepresentable { } } #elseif os(macOS) -// FIXME -protocol AcceptsFirstMouseCustomizing { - var customAcceptsFirstMouse: Bool? { get } -} - -extension AcceptsFirstMouseCustomizing { - var effectiveAcceptsFirstMouse: Bool? { - // FIXME: Find via view hierarchy if not set directly - customAcceptsFirstMouse - } -} - -extension EnvironmentValues { - var acceptsFirstMouse: Bool? { - // FIXME - get { controlSize == .mini } - } -} - private final class PlatformSwitch: NSSwitch, AcceptsFirstMouseCustomizing { var customAcceptsFirstMouse: Bool? @@ -181,10 +164,10 @@ private final class PlatformSwitch: NSSwitch, AcceptsFirstMouseCustomizing { } private struct Switch: NSViewRepresentable { - var _isOn: Binding + @Binding var isOn: Bool var tint: Color? var font: Font - var _acceptsFirstMouse: Environment + @Environment(\.allowsWindowActivationEvents) var acceptsFirstMouse: Bool? func makeNSView(context: Context) -> PlatformSwitch { let view = PlatformSwitch() @@ -193,7 +176,7 @@ private struct Switch: NSViewRepresentable { } func updateNSView(_ nsView: PlatformSwitch, context: Context) { - let isOn = _isOn.wrappedValue + let isOn = isOn if context.transaction.disablesAnimations { nsView.state = isOn ? .on : .off } else { From 7742f5d62409db7b1fed469d44dc2b1a93bcca49 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 12 Feb 2026 01:10:59 +0800 Subject: [PATCH 3/5] Update AppKitDisplayList --- .../DisplayList/AppKitDisplayList.swift | 117 ++++++++++++------ .../Render/DisplayList/UIKitDisplayList.swift | 5 +- 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift index aa8058e7b..02bf72c5f 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift @@ -2,8 +2,8 @@ // AppKitDisplayList.swift // OpenSwiftUI // -// Audited for 6.0.87 -// Status: WIP +// Audited for 6.5.4 +// Status: Complete // ID: 33EEAA67E0460DA84AE814EA027152BA (SwiftUI) #if os(macOS) @@ -12,9 +12,10 @@ import AppKit import OpenSwiftUISymbolDualTestsSupport import COpenSwiftUI import QuartzCore_Private +import OpenRenderBoxShims import OpenSwiftUI_SPI -// MARK: - NSViewPlatformViewDefinition [TODO] +// MARK: - NSViewPlatformViewDefinition final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sendable { override final class var system: PlatformViewDefinition.System { .nsView } @@ -27,47 +28,25 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen case .projection: view = _NSProjectionView() case .mask: - view = _NSGraphicsView() - view.mask = _NSInheritedView() - initView(view.mask!, kind: kind) + view = _NSInheritedView() + let maskView = _NSInheritedView() + view.maskView = maskView + initView(maskView, kind: .inherited) default: view = kind.isContainer ? _NSInheritedView() : _NSGraphicsView() } initView(view, kind: kind) return view } - - private static func initView(_ view: NSView, kind: PlatformViewDefinition.ViewKind) { - view.wantsLayer = true - - if kind != .platformView && kind != .platformGroup { - view.setFlipped(true) - view.autoresizesSubviews = false - // TODO - UnifiedHitTestingFeature.isEnabled - // setIgnoreHitTest: true - } - - switch kind { - case .color, .image, .shape: - view.layer?.edgeAntialiasingMask = [.layerTopEdge, .layerBottomEdge, .layerLeftEdge, .layerRightEdge] - view.layer?.allowsEdgeAntialiasing = true - break - case .geometry, .projection, .mask: - view.layer?.allowsGroupOpacity = false - view.layer?.allowsGroupBlending = false - default: - break - } - } - // Audited for 6.5.4 override static func makeLayerView(type: CALayer.Type, kind: PlatformViewDefinition.ViewKind) -> AnyObject { let cls: NSView.Type - if kind == .shape { + switch kind { + case .shape: cls = _NSShapeHitTestingView.self - } else if kind == .platformLayer { + case .platformLayer: cls = _NSPlatformLayerView.self - } else { + default: cls = kind.isContainer ? _NSInheritedView.self : _NSGraphicsView.self } let view = cls.init() @@ -82,8 +61,21 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen Self.initView(view as! NSView, kind: kind) } + override class func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable { + let view: NSView & PlatformDrawable + if options.isAccelerated && ORBDevice.isSupported() { + view = RBDrawingView(options: options) + } else { + view = CGDrawingView(options: options) + } + view.layerContentsRedrawPolicy = .onSetNeedsDisplay + view.layerContentsPlacement = .topLeft + initView(view, kind: .drawing) + return view + } + override static func setPath(_ path: Path, shapeView: AnyObject) { - let view = unsafeBitCast(shapeView, to: _NSShapeHitTestingView.self) + guard let view = shapeView as? _NSShapeHitTestingView else { return } view.path = path } @@ -92,15 +84,62 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen return } view.projectionTransform = transform - view.layer?.transform = .init(transform) + view.layer?.transform = CATransform3D(transform) + } + + override class func getRBLayer(drawingView: AnyObject) -> AnyObject? { + guard let rbView = drawingView as? RBDrawingView else { return nil } + return rbView.layer + } + + override class func setIgnoresEvents(_ state: Bool, of view: AnyObject) { + guard !ResponderBasedHitTesting.enabled else { return } + if Semantics.UnifiedHitTesting.isEnabled { + if let customizing = view as? RecursiveIgnoreHitTestCustomizing { + customizing.recursiveIgnoreHitTest = state + } + } else { + let view = unsafeBitCast(view, to: NSView.self) + view.ignoreHitTest = state + } } override class func setAllowsWindowActivationEvents(_ value: Bool?, for view: AnyObject) { - _openSwiftUIUnimplementedWarning() + guard !ResponderBasedHitTesting.enabled else { return } + if let customizing = view as? AcceptsFirstMouseCustomizing { + customizing.customAcceptsFirstMouse = value + } } override class func setHitTestsAsOpaque(_ value: Bool, for view: AnyObject) { - _openSwiftUIUnimplementedWarning() + guard !ResponderBasedHitTesting.enabled else { return } + if let customizing = view as? HitTestsAsOpaqueCustomizing { + customizing.hitTestsAsOpaque = value + } + } + + private static func initView(_ view: NSView, kind: PlatformViewDefinition.ViewKind) { + view.wantsLayer = true + if kind != .platformView && kind != .platformGroup { + view.setFlipped(true) + view.autoresizesSubviews = false + view.clipsToBounds = false + if !Semantics.UnifiedHitTesting.isEnabled { + view.ignoreHitTest = true + } + } + switch kind { + case .color, .image, .shape: + let layer = view.layer! + layer.edgeAntialiasingMask = [.layerTopEdge, .layerBottomEdge, .layerLeftEdge, .layerRightEdge] + layer.allowsEdgeAntialiasing = true + case .inherited, .geometry, .projection, .mask: + let layer = view.layer! + layer.allowsGroupOpacity = false + layer.allowsGroupBlending = false + default: + break + } } } @@ -108,7 +147,7 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen typealias PlatformGraphicsView = _NSGraphicsView -class _NSGraphicsView: NSView { +class _NSGraphicsView: NSView, RecursiveIgnoreHitTestCustomizing, AcceptsFirstMouseCustomizing { var recursiveIgnoreHitTest: Bool = false var customAcceptsFirstMouse: Bool? @@ -126,7 +165,7 @@ class _NSGraphicsView: NSView { typealias PlatformInheritedView = _NSInheritedView -class _NSInheritedView: _NSGraphicsView { +class _NSInheritedView: _NSGraphicsView, HitTestsAsOpaqueCustomizing { var hitTestsAsOpaque: Bool = false override init(frame frameRect: NSRect) { diff --git a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift index 78b3075a9..a6764c644 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift @@ -36,9 +36,10 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen override static func makeLayerView(type: CALayer.Type, kind: PlatformViewDefinition.ViewKind) -> AnyObject { let cls: UIView.Type - if kind == .shape { + switch kind { + case .shape: cls = _UIShapeHitTestingView.self - } else { + default: cls = kind.isContainer ? _UIInheritedView.self : _UIGraphicsView.self } let layer = type.init() From e626f23314665885f78a8a182b9a1326e134802a Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 12 Feb 2026 02:08:08 +0800 Subject: [PATCH 4/5] Update NSView --- .../Shims/AppKit/AppKit_Private.h | 1 + .../DisplayList/AppKitDisplayList.swift | 82 ++++++++++++++++--- .../Gesture/GestureContainerFeature.swift | 11 --- .../Responder/HitTestBindingModifier.swift | 2 +- .../Semantic/CustomFeature.swift | 28 +++++++ 5 files changed, 100 insertions(+), 24 deletions(-) delete mode 100644 Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift create mode 100644 Sources/OpenSwiftUICore/Semantic/CustomFeature.swift diff --git a/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h b/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h index 10bd981a9..fcda62c22 100644 --- a/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h +++ b/Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h @@ -35,6 +35,7 @@ typedef OPENSWIFTUI_ENUM(NSInteger, NSViewVibrantBlendingStyle) { @interface NSView () @property (getter=isOpaque) BOOL opaque; @property (nonatomic) BOOL ignoreHitTest; +- (nullable NSResponder *)_nextResponderForEvent:(nullable NSEvent *)event; - (void)_updateLayerGeometryFromView; - (void)_updateLayerShadowFromView; - (void)_updateLayerShadowColorFromView; diff --git a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift index 02bf72c5f..7423cb419 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift @@ -7,7 +7,9 @@ // ID: 33EEAA67E0460DA84AE814EA027152BA (SwiftUI) #if os(macOS) -@_spi(DisplayList_ViewSystem) import OpenSwiftUICore +@_spi(ForOpenSwiftUIOnly) +@_spi(DisplayList_ViewSystem) +import OpenSwiftUICore import AppKit import OpenSwiftUISymbolDualTestsSupport import COpenSwiftUI @@ -30,7 +32,7 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen case .mask: view = _NSInheritedView() let maskView = _NSInheritedView() - view.maskView = maskView + view.mask = maskView initView(maskView, kind: .inherited) default: view = kind.isContainer ? _NSInheritedView() : _NSGraphicsView() @@ -94,7 +96,7 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen override class func setIgnoresEvents(_ state: Bool, of view: AnyObject) { guard !ResponderBasedHitTesting.enabled else { return } - if Semantics.UnifiedHitTesting.isEnabled { + if UnifiedHitTestingFeature.isEnabled { if let customizing = view as? RecursiveIgnoreHitTestCustomizing { customizing.recursiveIgnoreHitTest = state } @@ -124,7 +126,7 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen view.setFlipped(true) view.autoresizesSubviews = false view.clipsToBounds = false - if !Semantics.UnifiedHitTesting.isEnabled { + if !UnifiedHitTestingFeature.isEnabled { view.ignoreHitTest = true } } @@ -159,6 +161,36 @@ class _NSGraphicsView: NSView, RecursiveIgnoreHitTestCustomizing, AcceptsFirstMo required init?(coder: NSCoder) { super.init(coder: coder) } + + override func hitTest(_ point: NSPoint) -> NSView? { + guard !ResponderBasedHitTesting.enabled else { + return super.hitTest(point) + } + if UnifiedHitTestingFeature.isEnabled { + guard !recursiveIgnoreHitTest, + alphaValue >= ViewResponder.minOpacityForHitTest else { + return nil + } + return super.hitTest(point) + } else { + guard !ignoreHitTest, frame.contains(point) else { + return nil + } + return self + } + } + + override func _nextResponder(for event: NSEvent?) -> NSResponder? { + nextResponder + } + + override func acceptsFirstMouse(for event: NSEvent?) -> Bool { + guard !ResponderBasedHitTesting.enabled, + let value = effectiveAcceptsFirstMouse else { + return super.acceptsFirstMouse(for: event) + } + return value + } } // MARK: - _NSInheritedView @@ -175,11 +207,30 @@ class _NSInheritedView: _NSGraphicsView, HitTestsAsOpaqueCustomizing { required init?(coder: NSCoder) { super.init(coder: coder) } + + override func hitTest(_ point: NSPoint) -> NSView? { + guard !ResponderBasedHitTesting.enabled, + UnifiedHitTestingFeature.isEnabled else { + return super.hitTest(point) + } + guard !isHiddenOrHasHiddenAncestor, !recursiveIgnoreHitTest else { + return nil + } + for subview in subviews.reversed() { + let convertedPoint = convert(point, from: superview) + if let result = subview.hitTest(convertedPoint) { + return result + } + } + guard hitTestsAsOpaque, frame.contains(point) else { + return nil + } + return self + } } -// MARK: - _NSProjectionView [6.5.4] +// MARK: - _NSProjectionView -@objc private class _NSProjectionView: _NSInheritedView { var projectionTransform: ProjectionTransform @@ -197,11 +248,11 @@ private class _NSProjectionView: _NSInheritedView { override func _updateLayerGeometryFromView() { super._updateLayerGeometryFromView() - layer?.transform = .init(projectionTransform) + layer?.transform = CATransform3D(projectionTransform) } } -// MARK: - _NSShapeHitTestingView [WIP] +// MARK: - _NSShapeHitTestingView @objc private class _NSShapeHitTestingView: _NSGraphicsView { @@ -218,15 +269,22 @@ private class _NSShapeHitTestingView: _NSGraphicsView { } override func hitTest(_ point: NSPoint) -> NSView? { - // path.contains(, eoFill: false) - _openSwiftUIUnimplementedWarning() - return nil + guard !ResponderBasedHitTesting.enabled else { + return super.hitTest(point) + } + if UnifiedHitTestingFeature.isEnabled, super.hitTest(point) == nil { + return nil + } + let point = convert(point, from: superview) + guard path.contains(point, eoFill: false) else { + return nil + } + return self } } // MARK: - _NSPlatformLayerView -@objc private class _NSPlatformLayerView: _NSGraphicsView { override init(frame frameRect: NSRect) { super.init(frame: frameRect) diff --git a/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift b/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift deleted file mode 100644 index ba1c9b40b..000000000 --- a/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// GestureContainerFeature.swift -// OpenSwiftUICore -// -// Status: WIP - -struct GestureContainerFeature { - static var isEnabled: Bool { - false - } -} diff --git a/Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift b/Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift index 0aee99c35..df47bee96 100644 --- a/Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift +++ b/Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift @@ -25,7 +25,7 @@ package struct HitTestBindingModifier: ViewModifier, MultiViewModifier, Primitiv extension ViewResponder { package static var hitTestKey: UInt32 { _openSwiftUIUnimplementedFailure() } - package static let minOpacityForHitTest: Double = 0.0 + package static let minOpacityForHitTest: Double = 0.001 package func hitTest( globalPoint: PlatformPoint, diff --git a/Sources/OpenSwiftUICore/Semantic/CustomFeature.swift b/Sources/OpenSwiftUICore/Semantic/CustomFeature.swift new file mode 100644 index 000000000..99d96e1ff --- /dev/null +++ b/Sources/OpenSwiftUICore/Semantic/CustomFeature.swift @@ -0,0 +1,28 @@ +// +// UnifiedHitTestingFeature.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: Partial + +// MARK: - UnifiedHitTestingFeature + +package struct UnifiedHitTestingFeature: Feature { + package init() { + _openSwiftUIEmptyStub() + } + + package static var isEnabled: Bool { + Semantics.UnifiedHitTesting.isEnabled || GestureContainerFeature.isEnabled + } +} + +// TODO + +// MARK: GestureContainerFeature [TODO] + +struct GestureContainerFeature { + static var isEnabled: Bool { + false + } +} From 140f00051af4e41331054b982957e34887b118ab Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 12 Feb 2026 02:43:10 +0800 Subject: [PATCH 5/5] Optimize code style --- .../Render/DisplayList/AppKitDisplayList.swift | 16 ++++++++-------- .../Render/DisplayList/UIKitDisplayList.swift | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift index 7423cb419..767b04ccc 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/AppKitDisplayList.swift @@ -20,7 +20,7 @@ import OpenSwiftUI_SPI // MARK: - NSViewPlatformViewDefinition final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sendable { - override final class var system: PlatformViewDefinition.System { .nsView } + override static var system: PlatformViewDefinition.System { .nsView } override static func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject { let view: NSView @@ -59,11 +59,11 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen return view } - override class func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) { + override static func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) { Self.initView(view as! NSView, kind: kind) } - override class func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable { + override static func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable { let view: NSView & PlatformDrawable if options.isAccelerated && ORBDevice.isSupported() { view = RBDrawingView(options: options) @@ -81,7 +81,7 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen view.path = path } - override class func setProjectionTransform(_ transform: ProjectionTransform, projectionView: AnyObject) { + override static func setProjectionTransform(_ transform: ProjectionTransform, projectionView: AnyObject) { guard let view = projectionView as? _NSProjectionView else { return } @@ -89,12 +89,12 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen view.layer?.transform = CATransform3D(transform) } - override class func getRBLayer(drawingView: AnyObject) -> AnyObject? { + override static func getRBLayer(drawingView: AnyObject) -> AnyObject? { guard let rbView = drawingView as? RBDrawingView else { return nil } return rbView.layer } - override class func setIgnoresEvents(_ state: Bool, of view: AnyObject) { + override static func setIgnoresEvents(_ state: Bool, of view: AnyObject) { guard !ResponderBasedHitTesting.enabled else { return } if UnifiedHitTestingFeature.isEnabled { if let customizing = view as? RecursiveIgnoreHitTestCustomizing { @@ -106,14 +106,14 @@ final class NSViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen } } - override class func setAllowsWindowActivationEvents(_ value: Bool?, for view: AnyObject) { + override static func setAllowsWindowActivationEvents(_ value: Bool?, for view: AnyObject) { guard !ResponderBasedHitTesting.enabled else { return } if let customizing = view as? AcceptsFirstMouseCustomizing { customizing.customAcceptsFirstMouse = value } } - override class func setHitTestsAsOpaque(_ value: Bool, for view: AnyObject) { + override static func setHitTestsAsOpaque(_ value: Bool, for view: AnyObject) { guard !ResponderBasedHitTesting.enabled else { return } if let customizing = view as? HitTestsAsOpaqueCustomizing { customizing.hitTestsAsOpaque = value diff --git a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift index a6764c644..4f8db5a10 100644 --- a/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift +++ b/Sources/OpenSwiftUI/Render/DisplayList/UIKitDisplayList.swift @@ -18,7 +18,7 @@ import OpenSwiftUI_SPI // MARK: - UIViewPlatformViewDefinition final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sendable { - override final class var system: PlatformViewDefinition.System { .uiView } + override static var system: PlatformViewDefinition.System { .uiView } override static func makeView(kind: PlatformViewDefinition.ViewKind) -> AnyObject { let view: UIView @@ -48,11 +48,11 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen return view } - override class func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) { + override static func makePlatformView(view: AnyObject, kind: PlatformViewDefinition.ViewKind) { Self.initView(view as! UIView, kind: kind) } - override class func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable { + override static func makeDrawingView(options: PlatformDrawableOptions) -> any PlatformDrawable { let view: UIView & PlatformDrawable if options.isAccelerated && ORBDevice.isSupported() { view = RBDrawingView(options: options) @@ -69,17 +69,17 @@ final class UIViewPlatformViewDefinition: PlatformViewDefinition, @unchecked Sen view.path = path } - override class func setProjectionTransform(_ transform: ProjectionTransform, projectionView: AnyObject) { + override static func setProjectionTransform(_ transform: ProjectionTransform, projectionView: AnyObject) { let layer = CoreViewLayer(system: .uiView, view: projectionView) layer.transform = CATransform3D(transform) } - override class func getRBLayer(drawingView: AnyObject) -> AnyObject? { + override static func getRBLayer(drawingView: AnyObject) -> AnyObject? { guard let rbView = drawingView as? RBDrawingView else { return nil } return rbView.layer } - override class func setIgnoresEvents(_ state: Bool, of view: AnyObject) { + override static func setIgnoresEvents(_ state: Bool, of view: AnyObject) { let view = unsafeBitCast(view, to: UIView.self) view.isUserInteractionEnabled = !state }