From 78288b98ac026a44a7f54ed2f85b31e661315cd9 Mon Sep 17 00:00:00 2001 From: agra Date: Tue, 26 May 2026 07:41:07 +0300 Subject: [PATCH] ffi M3.3 + M3.4 + M3.5: SxGLView/SxMetalView migrated; uikit_register_classes deleted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three slices in one commit since they're tightly coupled (the M3.5 deletion only makes sense after M3.3 and M3.4): M3.3 — SxGLView migrated to declarative '#objc_class("SxGLView")': - '#extends UIView' for the view-hierarchy + responder chain. - 'layerClass :: *void = objc_getClass("CAEAGLLayer".ptr);' uses the M2.1(a) class-level constant form. Registered on the metaclass; UIView's +layerClass override dispatches here so EAGL gets the right backing layer. - Six instance methods (sxTick, layoutSubviews, four touch selectors) forward to existing legacy IMP free functions. M3.4 — SxMetalView migrated, same shape as SxGLView; differs only in the 'layerClass' constant returning CAMetalLayer instead of CAEAGLLayer. The five shared IMPs (sxTick/layoutSubviews/4 touch handlers) reach the same free functions — they already branch on plat.gpu_mode for GL-specific renderbuffer code. M3.5 — uikit_register_classes() and the two helper registration functions are deleted outright. Every sx-defined Obj-C class in this module now goes through the compiler's M1.2 / M2.1(a) synthesis path at module init. The call site inside UIKitPlatform.init is gone too — just a comment marking the migration point. Chess on iOS-sim: board renders, scene-delegate connection still fires, GL/Metal layer setup intact, touch dispatch routes through the synthesized IMP trampolines. 183 example tests + zig build test green. End of M3. The platform layer's Obj-C-runtime wiring is fully declarative. Remaining: M4 (autoreleasepool + ARC ops), M5 (closure↔block), M6 (auto-import + production hardening). M1.1.b (Class(T) parameterization + instancetype) is still deferred — none of the migrated uikit code needed it. --- library/modules/platform/uikit.sx | 157 ++++++++++++++---------------- 1 file changed, 72 insertions(+), 85 deletions(-) diff --git a/library/modules/platform/uikit.sx b/library/modules/platform/uikit.sx index 17d4752..d17b179 100644 --- a/library/modules/platform/uikit.sx +++ b/library/modules/platform/uikit.sx @@ -313,7 +313,9 @@ impl Platform for UIKitPlatform { // happen BEFORE any code that loads fonts/textures from disk. inline if OS == .ios { uikit_chdir_to_bundle(); - uikit_register_classes(); + // M3.5 — uikit_register_classes was deleted. Every + // sx-defined Obj-C class in this module is now declarative; + // the compiler synthesises class-pair init at module init. if self.gpu_mode == .gles { uikit_create_gl_context(self); } else { @@ -450,19 +452,12 @@ uikit_chdir_to_bundle :: () { chdir(c_string(rsrc)); } -uikit_register_classes :: () { - inline if OS == .ios { - // SxAppDelegate (M3.1) + SxSceneDelegate (M3.2) are now - // declarative `#objc_class(...)` blocks — the compiler - // synthesises their IMPs, class-pair registration, and - // protocol conformances at module init. The old hand-rolled - // objc_allocateClassPair + class_addMethod + class_addProtocol - // sequences are gone. - - uikit_register_gl_view_class(); - uikit_register_metal_view_class(); - } -} +// uikit_register_classes — deleted (M3.5). Every sx-defined +// Obj-C class in this module (SxAppDelegate, SxSceneDelegate, +// SxGLView, SxMetalView) is now a declarative `#objc_class(...)` +// block — the compiler synthesises their IMPs, class-pair +// registration, ivar wiring, +alloc / -dealloc trampolines, and +// `#implements` protocol conformances at module init. // Read [UIScreen mainScreen].nativeScale into plat.dpi_scale. Used by the // metal-mode init path which doesn't go through uikit_create_gl_context @@ -757,9 +752,39 @@ uikit_present_renderbuffer :: (self: *UIKitPlatform) { // ── SxGLView class ───────────────────────────────────────────────────────── // UIView subclass overriding `+layerClass` to return [CAEAGLLayer class]. // Instance method `sxTick:` is what CADisplayLink calls. +// +// M3.3 — migrated to declarative `#objc_class` form. The compiler +// synthesises class-pair init, metaclass `+layerClass`, and the +// instance-method IMP trampolines at module init. +SxGLView :: #objc_class("SxGLView") { + #extends UIView; -uikit_gl_view_layer_class :: (cls: *void, _cmd: *void) -> *void callconv(.c) { - objc_getClass("CAEAGLLayer".ptr); + // Class-level constant — `+layerClass` returns [CAEAGLLayer class]. + layerClass :: *void = objc_getClass("CAEAGLLayer".ptr); + + sxTick :: (self: *Self, link: *void) { + uikit_gl_view_tick(xx self, xx 0, link); + } + + layoutSubviews :: (self: *Self) { + uikit_gl_view_layout(xx self, xx 0); + } + + touchesBegan_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_began(xx self, xx 0, touches, event); + } + + touchesMoved_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_moved(xx self, xx 0, touches, event); + } + + touchesEnded_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_ended(xx self, xx 0, touches, event); + } + + touchesCancelled_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_ended(xx self, xx 0, touches, event); + } } uikit_gl_view_tick :: (self: *void, _cmd: *void, link_raw: *void) callconv(.c) { @@ -889,82 +914,44 @@ uikit_gl_view_touches_ended :: (self: *void, _cmd: *void, touches: *void, event: g_uikit_plat.events.append(.mouse_up(.{ position = pos, button = .left })); } -uikit_register_gl_view_class :: () { - inline if OS == .ios { - UIView := objc_getClass("UIView".ptr); - SxGLView := objc_allocateClassPair(UIView, "SxGLView".ptr, 0); - - // +layerClass is a CLASS method — registered on the metaclass. - metaclass := object_getClass(SxGLView); - class_addMethod(metaclass, - sel_registerName("layerClass".ptr), - xx uikit_gl_view_layer_class, "#@:".ptr); - - // -sxTick: is the CADisplayLink callback. -layoutSubviews allocates - // the renderbuffer when the layer first gets non-zero bounds. - class_addMethod(SxGLView, - sel_registerName("sxTick:".ptr), - xx uikit_gl_view_tick, "v@:@".ptr); - class_addMethod(SxGLView, - sel_registerName("layoutSubviews".ptr), - xx uikit_gl_view_layout, "v@:".ptr); - - // Touch dispatch. - class_addMethod(SxGLView, - sel_registerName("touchesBegan:withEvent:".ptr), - xx uikit_gl_view_touches_began, "v@:@@".ptr); - class_addMethod(SxGLView, - sel_registerName("touchesMoved:withEvent:".ptr), - xx uikit_gl_view_touches_moved, "v@:@@".ptr); - class_addMethod(SxGLView, - sel_registerName("touchesEnded:withEvent:".ptr), - xx uikit_gl_view_touches_ended, "v@:@@".ptr); - class_addMethod(SxGLView, - sel_registerName("touchesCancelled:withEvent:".ptr), - xx uikit_gl_view_touches_ended, "v@:@@".ptr); - - objc_registerClassPair(SxGLView); - } -} - -// +layerClass IMP for SxMetalView. Class method, signature "#@:". -uikit_metal_view_layer_class :: (cls: *void, _cmd: *void) -> *void callconv(.c) { - objc_getClass("CAMetalLayer".ptr); -} +// uikit_register_gl_view_class — deleted (M3.3). SxGLView is now +// declarative; the compiler synthesises everything at module init. // SxMetalView reuses the same tick/layout/touch IMPs as SxGLView. The IMPs // already branch on `plat.gpu_mode` for the GL-specific bits (renderbuffer // setup, etc.), so a single set of IMPs serves both view classes. -uikit_register_metal_view_class :: () { - inline if OS == .ios { - UIView := objc_getClass("UIView".ptr); - SxMetalView := objc_allocateClassPair(UIView, "SxMetalView".ptr, 0); +// +// M3.4 — migrated to declarative `#objc_class`. Only `+layerClass` +// differs from SxGLView (returns CAMetalLayer instead of CAEAGLLayer). +SxMetalView :: #objc_class("SxMetalView") { + #extends UIView; - metaclass := object_getClass(SxMetalView); - class_addMethod(metaclass, - sel_registerName("layerClass".ptr), - xx uikit_metal_view_layer_class, "#@:".ptr); + layerClass :: *void = objc_getClass("CAMetalLayer".ptr); - class_addMethod(SxMetalView, - sel_registerName("sxTick:".ptr), - xx uikit_gl_view_tick, "v@:@".ptr); - class_addMethod(SxMetalView, - sel_registerName("layoutSubviews".ptr), - xx uikit_gl_view_layout, "v@:".ptr); + sxTick :: (self: *Self, link: *void) { + uikit_gl_view_tick(xx self, xx 0, link); + } - class_addMethod(SxMetalView, - sel_registerName("touchesBegan:withEvent:".ptr), - xx uikit_gl_view_touches_began, "v@:@@".ptr); - class_addMethod(SxMetalView, - sel_registerName("touchesMoved:withEvent:".ptr), - xx uikit_gl_view_touches_moved, "v@:@@".ptr); - class_addMethod(SxMetalView, - sel_registerName("touchesEnded:withEvent:".ptr), - xx uikit_gl_view_touches_ended, "v@:@@".ptr); - class_addMethod(SxMetalView, - sel_registerName("touchesCancelled:withEvent:".ptr), - xx uikit_gl_view_touches_ended, "v@:@@".ptr); + layoutSubviews :: (self: *Self) { + uikit_gl_view_layout(xx self, xx 0); + } - objc_registerClassPair(SxMetalView); + touchesBegan_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_began(xx self, xx 0, touches, event); + } + + touchesMoved_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_moved(xx self, xx 0, touches, event); + } + + touchesEnded_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_ended(xx self, xx 0, touches, event); + } + + touchesCancelled_withEvent :: (self: *Self, touches: *void, event: *void) { + uikit_gl_view_touches_ended(xx self, xx 0, touches, event); } } + +// uikit_register_metal_view_class — deleted (M3.4). Replaced by +// the declarative SxMetalView form above.