diff --git a/Templates/大鱼人像美化/README.md b/Templates/大鱼人像美化/README.md
index 9a44b3e..cc81c48 100644
--- a/Templates/大鱼人像美化/README.md
+++ b/Templates/大鱼人像美化/README.md
@@ -1,6 +1,6 @@
# 大鱼人像美化 FCP 效果模板
-版本:1.1.0。滤镜 UUID:`FB14B0E6-59B2-4836-916F-CD0C559E9241`。需配套同版大鱼人像美化 FxPlug APP。
+版本:1.1.1。滤镜 UUID:`FB14B0E6-59B2-4836-916F-CD0C559E9241`。需配套同版大鱼人像美化 FxPlug APP。
## 三卡片与自动跟随
diff --git a/Templates/大鱼人像美化/VALIDATION.json b/Templates/大鱼人像美化/VALIDATION.json
index a3644fa..d88c137 100644
--- a/Templates/大鱼人像美化/VALIDATION.json
+++ b/Templates/大鱼人像美化/VALIDATION.json
@@ -1,6 +1,6 @@
{
- "version": "1.1.0",
- "sha256": "e1c0cff1dd3541ed97cab2cb39a76ad4f28dc659b3be7991cc7ac92dd8ea090b",
+ "version": "1.1.1",
+ "sha256": "7090c1fbe0d8310c0b092f7c56f72e9c3fe6503aa38753f3fd8d7adcbd9a27b3",
"filterUUID": "FB14B0E6-59B2-4836-916F-CD0C559E9241",
"publishedFunctionalControls": 1,
"informationalControls": 2,
@@ -58,10 +58,10 @@
"legacyValuesPreserved": true,
"publishOSC": 0,
"currentHostValidation": {
- "version": "1.1.0",
- "Motion": "pending user",
- "FCP": "pending user",
- "scope": "No Motion/FCP launch, quit, activation, UI operation or native save was performed. XML structure and standalone archive checks do not establish custom inspector loading."
+ "version": "1.1.1",
+ "Motion": "pending native retest",
+ "FCP": "1.1.0 reproduced: all parameter controls disabled and status waiting for host connection; 1.1.1 retest pending",
+ "scope": "User authorized Motion/FCP interaction for this regression investigation."
},
"customParameter": {
"id": 210,
@@ -156,14 +156,14 @@
},
"automatedInspectorValidation": {
"scope": "offscreen AppKit inspector, real production controller and mocked host callbacks; no Motion/FCP UI",
- "fullChecks": 1039,
+ "fullChecks": 1046,
"counts": {
"beauty": 49,
"face": 116,
"thinChin": 394,
"hostAdapterASan": 248,
"oscASan": 98,
- "inspectorASan": 134
+ "inspectorASan": 141
},
"nativeVisualQA": "pending user",
"manualAnalysisUI": "removed; legacy IDs hidden and buttons disabled",
@@ -188,19 +188,9 @@
"archives": "Own PGInspectorState secure payload; Foundation outer and inner decode and Motion alphabet roundtrip tested"
},
"installation": {
- "version": "1.1.0",
- "build": "9",
- "status": "installed",
- "appPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
- "templateAndSourceResourceByteVerified": true,
- "signatureVerified": true,
- "notarization": "Accepted",
- "stapleValidated": true,
- "gatekeeperAccepted": true,
- "formalPluginKitPathVerified": true,
- "UIOperated": false,
- "hostTerminationPerformed": false,
- "nativeLoadAndVisualQA": "pending user",
- "receipt": "../../docs/verification/v1.1.0/installed-verification.json"
+ "version": "1.1.1",
+ "build": "10",
+ "status": "pending",
+ "previousInstalledVersion": "1.1.0"
}
}
diff --git a/Templates/大鱼人像美化/大鱼人像美化.moef b/Templates/大鱼人像美化/大鱼人像美化.moef
index 28f9978..f2bfe8f 100644
--- a/Templates/大鱼人像美化/大鱼人像美化.moef
+++ b/Templates/大鱼人像美化/大鱼人像美化.moef
@@ -46,7 +46,7 @@
1
- 大鱼人像美化 1.1.0:磨皮、美白、瘦脸三卡片自定义面板,自动选择主体并实时跟随。模板局部磨皮默认为50%。
+ 大鱼人像美化 1.1.1:磨皮、美白、瘦脸三卡片自定义面板,自动选择主体并实时跟随。模板局部磨皮默认为50%。
1920
@@ -253,7 +253,7 @@
-
+
8589934608
diff --git a/beatygril/beatygril/Plugin/Info.plist b/beatygril/beatygril/Plugin/Info.plist
index 8276530..71c5bb9 100644
--- a/beatygril/beatygril/Plugin/Info.plist
+++ b/beatygril/beatygril/Plugin/Info.plist
@@ -17,9 +17,9 @@
CFBundlePackageType
XPC!
CFBundleShortVersionString
- 1.1.0
+ 1.1.1
CFBundleVersion
- 9
+ 10
NSHumanReadableCopyright
PlugInKit
@@ -72,7 +72,7 @@
uuid
FB14B0E6-59B2-4836-916F-CD0C559E9241
version
- 1.1.0
+ 1.1.1
className
@@ -84,7 +84,7 @@
uuid
E0E432C8-3D71-4ABA-B006-E7F519E06C87
version
- 1.1.0
+ 1.1.1
protocolNames
FxOnScreenControl
diff --git a/beatygril/beatygril/Plugin/PGInspectorState.h b/beatygril/beatygril/Plugin/PGInspectorState.h
index 25fab10..20e8ec2 100644
--- a/beatygril/beatygril/Plugin/PGInspectorState.h
+++ b/beatygril/beatygril/Plugin/PGInspectorState.h
@@ -30,6 +30,8 @@ FOUNDATION_EXPORT PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings
@property (nonatomic, strong, readonly) PGInspectorState *state;
@property (nonatomic, readonly) BOOL available;
@property (nonatomic, copy, readonly) NSString *statusMessage;
+/// The actual custom inspector view identifies the action to the native host.
+@property (nonatomic, weak, nullable) NSView *actionSender;
- (instancetype)initWithAPIManager:(id)manager;
- (void)refresh;
- (void)documentDidChange;
diff --git a/beatygril/beatygril/Plugin/PGInspectorState.m b/beatygril/beatygril/Plugin/PGInspectorState.m
index edb54d5..1fe4509 100644
--- a/beatygril/beatygril/Plugin/PGInspectorState.m
+++ b/beatygril/beatygril/Plugin/PGInspectorState.m
@@ -1,6 +1,7 @@
#import "PGInspectorState.h"
#import
#import
+#import
NSArray *PGInspectorControls(void) {
static NSArray *controls; static dispatch_once_t once;
@@ -129,6 +130,9 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
@property (nonatomic) BOOL interacting;
@property (nonatomic) NSTimeInterval pendingUntil;
@property (nonatomic) CMTime pendingTime;
+@property (nonatomic, strong) id activeSender;
+@property (nonatomic) BOOL reportedConnection;
+@property (nonatomic) BOOL reportedMissingAction;
@end
@implementation PGInspectorController
- (instancetype)initWithAPIManager:(id)manager {
@@ -138,13 +142,34 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
- (BOOL)start {
if(_interacting)return YES;
_action=[_manager apiForProtocol:@protocol(FxCustomParameterActionAPI_v4)];
- id retrieval=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)];
- id setting=[_manager apiForProtocol:@protocol(FxParameterSettingAPI_v5)];
- _available=_action && retrieval && setting;
- if(!_available){_statusMessage=@"等待宿主连接";return NO;}
- [_action startAction:self];_interacting=YES;return YES;
+ if(!_action){
+ _available=NO;_statusMessage=@"等待宿主连接";
+ if(!_reportedMissingAction){os_log(OS_LOG_DEFAULT,"PGInspector action API unavailable manager=%{public}d viewSender=%{public}d onMain=%{public}d",_manager!=nil,_actionSender!=nil,NSThread.isMainThread);_reportedMissingAction=YES;}
+ return NO;
+ }
+ // A native host can expose parameter APIs only after the custom view's
+ // action has established its document context. Never gate startAction on
+ // those APIs being available before entering the action.
+ BOOL readBefore=NO,writeBefore=NO;
+ if(!_reportedConnection){
+ readBefore=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)]!=nil;
+ writeBefore=[_manager apiForProtocol:@protocol(FxParameterSettingAPI_v5)]!=nil;
+ }
+ _activeSender=_actionSender ?: self;
+ [_action startAction:_activeSender];_interacting=YES;
+ @try {
+ id retrieval=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)];
+ id setting=[_manager apiForProtocol:@protocol(FxParameterSettingAPI_v5)];
+ _available=retrieval && setting;
+ if(!_reportedConnection){
+ os_log(OS_LOG_DEFAULT,"PGInspector connection readBefore=%{public}d writeBefore=%{public}d readInAction=%{public}d writeInAction=%{public}d viewSender=%{public}d onMain=%{public}d",readBefore,writeBefore,retrieval!=nil,setting!=nil,[_activeSender isKindOfClass:NSView.class],NSThread.isMainThread);
+ _reportedConnection=YES;
+ }
+ if(!_available){_statusMessage=@"等待宿主连接";[self finish];return NO;}
+ } @catch(NSException *exception) {[self finish];@throw exception;}
+ return YES;
}
-- (void)finish {if(_interacting){_interacting=NO;[_action endAction:self];_action=nil;}}
+- (void)finish {if(_interacting){_interacting=NO;[_action endAction:_activeSender];_action=nil;_activeSender=nil;}}
- (void)readAtTime:(CMTime)time {
if(_pendingUntil && CMTimeCompare(time,_pendingTime)!=0)_pendingUntil=0;
id api=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)];
@@ -241,5 +266,5 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
ok=[self commit:[PGInspectorState stateWithValues:values disabledParameters:disabled hasEdits:YES]];
} @finally {if(owned)[self finish];}return ok;
}
-- (void)dealloc {if(_interacting)[_action endAction:self];}
+- (void)dealloc {if(_interacting)[_action endAction:_activeSender];}
@end
diff --git a/beatygril/beatygril/Plugin/PGInspectorView.m b/beatygril/beatygril/Plugin/PGInspectorView.m
index a11542a..4e3be21 100644
--- a/beatygril/beatygril/Plugin/PGInspectorView.m
+++ b/beatygril/beatygril/Plugin/PGInspectorView.m
@@ -293,7 +293,7 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t
- (instancetype)initWithAPIManager:(id)manager { return [self initWithController:[[PGInspectorController alloc]initWithAPIManager:manager]]; }
- (instancetype)initWithController:(PGInspectorController *)controller {
if((self=[super initWithFrame:NSMakeRect(0,0,320,100)])){
- _controller=controller;self.appearance=[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
+ _controller=controller;_controller.actionSender=self;self.appearance=[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
NSArray *sections=@[@"smooth",@"color",@"shape",@"more"],*headings=@[@"磨皮",@"美白",@"瘦脸",@"更多设置"];
NSArray *colors=@[PGUIColor(.28,.83,.96,1),PGUIColor(.34,.89,.84,1),PGUIColor(.59,.69,.98,1),PGUIColor(.54,.64,.76,1)];
NSMutableArray *cards=[NSMutableArray new];
diff --git a/beatygril/beatygril/Wrapper Application/Info.plist b/beatygril/beatygril/Wrapper Application/Info.plist
index 5d41016..f2c29c1 100644
--- a/beatygril/beatygril/Wrapper Application/Info.plist
+++ b/beatygril/beatygril/Wrapper Application/Info.plist
@@ -17,9 +17,9 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.1.0
+ 1.1.1
CFBundleVersion
- 9
+ 10
LSMinimumSystemVersion
$(MACOSX_DEPLOYMENT_TARGET)
NSHumanReadableCopyright
diff --git a/docs/verification/v1.1.1/core-tests.txt b/docs/verification/v1.1.1/core-tests.txt
new file mode 100644
index 0000000..45a9615
--- /dev/null
+++ b/docs/verification/v1.1.1/core-tests.txt
@@ -0,0 +1,5 @@
+Beauty renderer: 49 checks, 0 failures (Metal).
+2026-10-21 23:20:16.950 face-tests[22007:5696503] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
+Face processing: 116 checks passed
+2026-10-21 23:20:21.817 slim-tests[22045:5696731] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
+PASS: 394 slim alignment checks; maximum UV oracle error 1.09828022e-05
diff --git a/docs/verification/v1.1.1/host-tests.txt b/docs/verification/v1.1.1/host-tests.txt
new file mode 100644
index 0000000..fd28b15
--- /dev/null
+++ b/docs/verification/v1.1.1/host-tests.txt
@@ -0,0 +1,21 @@
+2026-10-21 23:20:18.015 host-tests[22024:5696629] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
+Default IOSurface maximum byte difference: 0
+Alternate destination tag maximum byte difference: 0
+Anatomy default 0/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
+Anatomy default 0/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
+Anatomy default 1/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
+Anatomy default 1/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
+Anatomy big-eye 0/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
+Anatomy big-eye 0/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
+Anatomy big-eye 1/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
+Anatomy big-eye 1/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
+Anatomy chin-positive 0/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
+Anatomy chin-positive 0/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
+Anatomy chin-positive 1/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
+Anatomy chin-positive 1/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
+Anatomy chin-negative 0/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
+Anatomy chin-negative 0/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
+Anatomy chin-negative 1/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
+Anatomy chin-negative 1/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
+Legacy fallback upright comparison: max=2 mean=0.0010357
+Host adapter: 248 checks, 0 failures
diff --git a/docs/verification/v1.1.1/inspector-before-fix.txt b/docs/verification/v1.1.1/inspector-before-fix.txt
new file mode 100644
index 0000000..7accdd4
--- /dev/null
+++ b/docs/verification/v1.1.1/inspector-before-fix.txt
@@ -0,0 +1,6 @@
+FAIL: an action-scoped host connects and reads the actual template values
+FAIL: custom parameter actions identify their actual inspector NSView
+FAIL: action-scoped parameter APIs do not leave the whole native panel disabled
+FAIL: a connected native control writes through the action-scoped setting API
+FAIL: a later host connection restores controls after a transient API failure
+Inspector: 141 checks, 5 failures
diff --git a/docs/verification/v1.1.1/inspector-tests.txt b/docs/verification/v1.1.1/inspector-tests.txt
new file mode 100644
index 0000000..080b3ca
--- /dev/null
+++ b/docs/verification/v1.1.1/inspector-tests.txt
@@ -0,0 +1 @@
+Inspector: 141 checks, 0 failures
diff --git a/docs/verification/v1.1.1/osc-tests.txt b/docs/verification/v1.1.1/osc-tests.txt
new file mode 100644
index 0000000..8b80453
--- /dev/null
+++ b/docs/verification/v1.1.1/osc-tests.txt
@@ -0,0 +1,21 @@
+2026-10-21 23:20:17.783 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
+2026-10-21 23:20:17.791 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,180) surface=320x240 origin=0
+2026-10-21 23:20:18.509 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.8,0.3) setter=(1152,-432) readback=(0.8,0.3) mode=centered-pixels verified=1
+2026-10-21 23:20:18.509 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.7,0.4) objectBounds=(-1920,-1080,3840,2160) canvas=(152,78) surface=320x240 origin=0
+2026-10-21 23:20:18.607 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.8,0.3) setter=(0.8,0.3) readback=(0.12345,0.87654) mode=normalized verified=0
+2026-10-21 23:20:18.607 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.75,0.25) setter=(0.75,0.25) readback=(0.75,0.25) mode=normalized verified=1
+2026-10-21 23:20:18.607 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.75,0.25) objectBounds=(-100,-50,200,100) canvas=(160,60) surface=320x240 origin=0
+2026-10-21 23:20:18.684 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.625,0.375) setter=(0.625,0.375) readback=(0.625,0.375) mode=normalized verified=1
+2026-10-21 23:20:18.684 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.625,0.375) objectBounds=(-100,-50,200,100) canvas=(240,60) surface=320x240 origin=0
+2026-10-21 23:20:18.765 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
+2026-10-21 23:20:18.765 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(144,180) surface=320x240 origin=0
+2026-10-21 23:20:18.864 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
+2026-10-21 23:20:18.864 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0,1) objectBounds=(-100,-50,200,100) canvas=(100,140) surface=320x240 origin=0
+2026-10-21 23:20:18.947 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(nan,nan) surface=320x240 origin=0
+2026-10-21 23:20:19.044 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
+2026-10-21 23:20:19.044 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(inf,nan) surface=320x240 origin=0
+2026-10-21 23:20:19.123 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
+2026-10-21 23:20:19.123 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,nan) surface=320x240 origin=0
+2026-10-21 23:20:19.203 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
+2026-10-21 23:20:19.203 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
+OSC adapter: 98 checks, 0 failures
diff --git a/docs/验证记录.md b/docs/验证记录.md
index 78692f5..312824c 100644
--- a/docs/验证记录.md
+++ b/docs/验证记录.md
@@ -101,3 +101,11 @@ Motion:独立普通视频项目,源PTS0、1920×1080/25fps/10秒,媒体通
配套卡片版模板和Drop Zone.tiff已在宿主关闭时同步并逐字节核对,moef SHA256为`e1c0cff1dd3541ed97cab2cb39a76ad4f28dc659b3be7991cc7ac92dd8ea090b`。FCP发布入口为面板210及两项版权信息;旧参数定义隐藏保留,手动分析不再显示,输出保持实时自动跟随。自定义面板的真实嵌入、滚动、键盘/VoiceOver、保存重开及视觉均待用户自测。
临时APP、旧APP备份、公证ZIP已清理。项目、Codex工作树、DerivedData、桌面、下载、Applications、系统/用户FxPlug及paintfcp临时目录的有界扫描仅发现正式外层APP,扫描错误0;不将该范围扩张为全部挂载卷搜索。完整回执和扫描范围见`verification/v1.1.0/installed-verification.json`。最终恢复标签`v1.1.0`包含交付文档,签名产品源码保持f79d24eb0185f31feaae58b83b632f92dcb3ca91。
+
+## 1.1.1 面板交互修复(原生验收进行中)
+
+用户报告1.1.0界面无法交互并授权接手Motion/FCP测试。FCP中“大鱼人像美化验收-20261021”独立测试时间线复现:所有PG参数控件被禁用,页脚“等待宿主连接”;“更多设置”可展开,说明视图事件仍正常,故不是整张面板无法命中。失败AX与截图保留本机build/native-111,不上传用户测试画面或资源库内容。
+
+连接代码原先在开启自定义参数action之前就要求读写API存在,且action sender传NSObject控制器;现先用真实NSView sender开启action,再在其上下文里取得API,缺API时配对结束。新增action-scoped模拟宿主及sender校验用例:修改前141项中5项失败,修改后全通过,包含临时接口失败后重新连接。接口前后布尔日志保留为原生诊断,根因的实际宿主确认仍待新版加载。
+
+1.1.1(10)完整1046项回归通过(49美化、116人脸、394瘦脸/下巴、248宿主、98 OSC、141检查器),后三套启用ASan。正式编译、公证与原生Motion/FCP交互验收进行中,尚未把自动检查等同于原生通过。
diff --git a/tests/inspector_tests.m b/tests/inspector_tests.m
index f9161e9..d60577e 100644
--- a/tests/inspector_tests.m
+++ b/tests/inspector_tests.m
@@ -9,10 +9,24 @@
@property NSUInteger scalarWrites;
@property (strong) NSDictionary *actionBefore;
@property (strong) NSDictionary *undoValues;
+@property BOOL parameterAPIsRequireAction;
+@property BOOL actionRequiresView;
+@property NSUInteger invalidActionSenders;
+@property (weak) id lastActionSender;
@end
@implementation PGInspectorTestAPI
+- (id)apiForProtocol:(Protocol *)protocol {
+ NSString *name=NSStringFromProtocol(protocol);
+ if(_parameterAPIsRequireAction && !self.actionDepth &&
+ ([name isEqual:@"FxParameterRetrievalAPI_v6"] || [name isEqual:@"FxParameterSettingAPI_v5"]))return nil;
+ return [super apiForProtocol:protocol];
+}
- (void)guard {if(!self.actionDepth)_accessViolations++;}
-- (void)startAction:(id)sender {if(!self.actionDepth)_actionBefore=[self.values copy];[super startAction:sender];}
+- (void)startAction:(id)sender {
+ _lastActionSender=sender;
+ if(_actionRequiresView && ![sender isKindOfClass:NSView.class]){_invalidActionSenders++;return;}
+ if(!self.actionDepth)_actionBefore=[self.values copy];[super startAction:sender];
+}
- (void)endAction:(id)sender {if(self.actionDepth==1 && ![self.values isEqual:_actionBefore])_undoValues=_actionBefore;[super endAction:sender];}
- (CMTime)currentTime {[self guard];return [super currentTime];}
- (BOOL)getCustomParameterValue:(NSObject **)v fromParameter:(UInt32)i atTime:(CMTime)t {[self guard];return [super getCustomParameterValue:v fromParameter:i atTime:t];}
@@ -143,9 +157,26 @@ static void ViewInteractionTests(void) {
for(NSView *card in view.subviews)if(!card.hidden)Check(NSMaxY(card.frame)<=NSHeight(view.bounds)+1 && NSMaxX(card.frame)<=NSWidth(view.bounds)+1,@"every visible card and footer remains inside the panel at all inspector widths");
}
}
+static void HostHandshakeTests(void) {
+ PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil];
+ api.values[@(PGMidtone)]=@.5;
+ api.parameterAPIsRequireAction=YES;api.actionRequiresView=YES;
+ PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost];
+ Check(view.controller.available && Near([view.controller.state valueForParameter:PGMidtone],.5),@"an action-scoped host connects and reads the actual template values");
+ Check(api.lastActionSender==view && api.invalidActionSenders==0,@"custom parameter actions identify their actual inspector NSView");
+ NSSlider *brightness=(NSSlider *)FindControl(view,NSSlider.class,@"肤色亮度");
+ Check(brightness.enabled,@"action-scoped parameter APIs do not leave the whole native panel disabled");
+ brightness.doubleValue=.42;Fire(brightness);PGInspectorState *saved=api.values[@(PGInspectorPanel)];
+ Check(saved.hasEdits && Near([saved valueForParameter:PGBrightness],.42),@"a connected native control writes through the action-scoped setting API");
+ [api.disabledAPIs addObject:@"FxParameterSettingAPI_v5"];[view refreshFromHost];
+ Check(!view.controller.available && api.actionDepth==0 && api.actionStarts==api.actionEnds,@"a genuinely missing setting API closes the already-started host action");
+ [api.disabledAPIs removeObject:@"FxParameterSettingAPI_v5"];[view refreshFromHost];
+ Check(view.controller.available && brightness.enabled,@"a later host connection restores controls after a transient API failure");
+ Check(api.accessViolations==0 && api.actionDepth==0 && api.actionStarts==api.actionEnds,@"action-scoped connection, edits, failure and reconnection remain balanced");
+}
int main(int argc,const char **argv) {@autoreleasepool {
[NSApplication sharedApplication];[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
- RegistrationTests();ModelTests();ControllerTests();ViewInteractionTests();
+ RegistrationTests();ModelTests();ControllerTests();ViewInteractionTests();HostHandshakeTests();
if(argc>2) {
NSData *inner=[NSData dataWithContentsOfFile:@(argv[1])],*outer=[NSData dataWithContentsOfFile:@(argv[2])];NSError *error=nil;
NSKeyedUnarchiver *reader=[[NSKeyedUnarchiver alloc]initForReadingFromData:inner error:&error];reader.requiresSecureCoding=YES;