@@ -19,6 +19,9 @@ static mut UI_VIEW: Option<Retained<AnyObject>> = None;
1919static mut TOUCH_MAP : [ * const c_void ; 10 ] = [ std:: ptr:: null ( ) ; 10 ] ;
2020static mut BUNDLE_PATH : Option < String > = None ;
2121static mut SCREEN_SCALE : f64 = 1.0 ;
22+ /// UIInterfaceOrientationMask for the root view controller.
23+ /// Default: all (0x1E). Set to landscape (0x18) from bloom_init_window when width > height.
24+ static mut ORIENTATION_MASK : u64 = 0x1E ; // UIInterfaceOrientationMaskAll
2225
2326
2427/// Resolve a relative asset path to the app bundle path.
@@ -209,6 +212,29 @@ fn register_metal_view_class() {
209212 }
210213}
211214
215+ // ============================================================
216+ // Register BloomViewController — UIViewController with orientation lock
217+ // ============================================================
218+
219+ unsafe extern "C" fn bloom_vc_supported_orientations ( _this : * const c_void , _sel : Sel ) -> u64 {
220+ unsafe { ORIENTATION_MASK }
221+ }
222+
223+ fn register_view_controller_class ( ) {
224+ if AnyClass :: get ( c"BloomViewController" ) . is_some ( ) { return ; }
225+
226+ unsafe {
227+ let superclass = AnyClass :: get ( c"UIViewController" ) . unwrap ( ) ;
228+ let cls = objc_allocateClassPair ( superclass as * const AnyClass , b"BloomViewController\0 " . as_ptr ( ) , 0 ) ;
229+ if cls. is_null ( ) { return ; }
230+
231+ let sel = Sel :: register ( c"supportedInterfaceOrientations" ) ;
232+ class_addMethod ( cls, sel, bloom_vc_supported_orientations as * const c_void , b"Q16@0:8\0 " . as_ptr ( ) ) ;
233+
234+ objc_registerClassPair ( cls) ;
235+ }
236+ }
237+
212238// ============================================================
213239// Scene delegate — creates UIWindow + Metal view + wgpu engine
214240// ============================================================
@@ -236,8 +262,9 @@ unsafe extern "C" fn scene_will_connect(
236262 let window: Allocated < AnyObject > = msg_send ! [ window_cls, alloc] ;
237263 let window: Retained < AnyObject > = msg_send ! [ window, initWithWindowScene: scene] ;
238264
239- // Create UIViewController
240- let vc_cls = AnyClass :: get ( c"UIViewController" ) . unwrap ( ) ;
265+ // Create BloomViewController (with orientation lock support)
266+ let vc_cls = AnyClass :: get ( c"BloomViewController" )
267+ . unwrap_or_else ( || AnyClass :: get ( c"UIViewController" ) . unwrap ( ) ) ;
241268 let vc: Allocated < AnyObject > = msg_send ! [ vc_cls, alloc] ;
242269 let vc: Retained < AnyObject > = msg_send ! [ vc, init] ;
243270
@@ -345,6 +372,7 @@ unsafe extern "C" fn scene_will_connect(
345372#[ no_mangle]
346373pub unsafe extern "C" fn perry_register_native_classes ( ) {
347374 register_metal_view_class ( ) ;
375+ register_view_controller_class ( ) ;
348376 register_scene_delegate ( ) ;
349377}
350378
@@ -373,8 +401,9 @@ pub unsafe extern "C" fn perry_scene_will_connect(scene: *const c_void) {
373401 msg_send ! [ w, initWithFrame: bounds]
374402 } ;
375403
376- // Create UIViewController
377- let vc_cls = AnyClass :: get ( c"UIViewController" ) . unwrap ( ) ;
404+ // Create BloomViewController (with orientation lock support)
405+ let vc_cls = AnyClass :: get ( c"BloomViewController" )
406+ . unwrap_or_else ( || AnyClass :: get ( c"UIViewController" ) . unwrap ( ) ) ;
378407 let vc: Allocated < AnyObject > = msg_send ! [ vc_cls, alloc] ;
379408 let vc: Retained < AnyObject > = msg_send ! [ vc, init] ;
380409
@@ -512,8 +541,15 @@ fn pollster_block_on<F: std::future::Future>(future: F) -> F::Output {
512541pub extern "C" fn bloom_init_window ( _width : f64 , _height : f64 , title_ptr : * const u8 , _fullscreen : f64 ) {
513542 let _title = str_from_header ( title_ptr) ;
514543
544+ // Set orientation mask based on requested dimensions
545+ // width > height → landscape, otherwise all orientations
546+ if _width > _height {
547+ unsafe { ORIENTATION_MASK = 0x18 ; } // UIInterfaceOrientationMaskLandscape
548+ }
549+
515550 // Register ObjC classes for the scene delegate (window/view creation)
516551 register_metal_view_class ( ) ;
552+ register_view_controller_class ( ) ;
517553 register_scene_delegate ( ) ;
518554
519555 // Signal the main thread that our ObjC classes are ready.
0 commit comments