Atlas - SDL_uikitappdelegate.m

Home / ext / SDL / src / video / uikit Lines: 1 | Size: 22817 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_DRIVER_UIKIT 24 25#include "../SDL_sysvideo.h" 26 27#import "SDL_uikitappdelegate.h" 28#import "SDL_uikitmodes.h" 29#import "SDL_uikitwindow.h" 30 31#include "../../events/SDL_events_c.h" 32#include "../../main/SDL_main_callbacks.h" 33 34#ifdef main 35#undef main 36#endif 37 38static SDL_main_func forward_main; 39static int forward_argc; 40static char **forward_argv; 41static int exit_status; 42 43int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved) 44{ 45 // store arguments 46 forward_main = mainFunction; 47 forward_argc = argc; 48 forward_argv = argv; 49 50 // Give over control to run loop, SDLUIKitDelegate will handle most things from here 51 @autoreleasepool { 52 NSString *name = nil; 53 54 if (@available(iOS 13.0, tvOS 13.0, *)) { 55 name = [SDLUIKitSceneDelegate getSceneDelegateClassName]; 56 } 57 if (!name) { 58 name = [SDLUIKitDelegate getAppDelegateClassName]; 59 } 60 UIApplicationMain(argc, argv, nil, name); 61 } 62 63 return exit_status; 64} 65 66#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 67// Load a launch image using the old UILaunchImageFile-era naming rules. 68static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) 69{ 70#pragma clang diagnostic push 71#pragma clang diagnostic ignored "-Wdeprecated-declarations" 72 UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; 73#pragma clang diagnostic pop 74 UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom; 75 UIImage *image = nil; 76 77 if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) { 78 // The image name for the iPhone 5 uses its height as a suffix. 79 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]]; 80 } else if (idiom == UIUserInterfaceIdiomPad) { 81 // iPad apps can launch in any orientation. 82 if (UIInterfaceOrientationIsLandscape(curorient)) { 83 if (curorient == UIInterfaceOrientationLandscapeLeft) { 84 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]]; 85 } else { 86 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]]; 87 } 88 if (!image) { 89 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]]; 90 } 91 } else { 92 if (curorient == UIInterfaceOrientationPortraitUpsideDown) { 93 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]]; 94 } 95 if (!image) { 96 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]]; 97 } 98 } 99 } 100 101 if (!image) { 102 image = [UIImage imageNamed:name]; 103 } 104 105 return image; 106} 107 108@interface SDLLaunchStoryboardViewController : UIViewController 109@property(nonatomic, strong) UIViewController *storyboardViewController; 110- (instancetype)initWithStoryboardViewController:(UIViewController *)storyboardViewController; 111@end 112 113@implementation SDLLaunchStoryboardViewController 114 115- (instancetype)initWithStoryboardViewController:(UIViewController *)storyboardViewController 116{ 117 self = [super init]; 118 self.storyboardViewController = storyboardViewController; 119 return self; 120} 121 122- (void)viewDidLoad 123{ 124 [super viewDidLoad]; 125 126 [self addChildViewController:self.storyboardViewController]; 127 [self.view addSubview:self.storyboardViewController.view]; 128 self.storyboardViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 129 self.storyboardViewController.view.frame = self.view.bounds; 130 [self.storyboardViewController didMoveToParentViewController:self]; 131 132#ifndef SDL_PLATFORM_VISIONOS 133#pragma clang diagnostic push 134#pragma clang diagnostic ignored "-Wdeprecated-declarations" 135 UIApplication.sharedApplication.statusBarHidden = self.prefersStatusBarHidden; 136 UIApplication.sharedApplication.statusBarStyle = self.preferredStatusBarStyle; 137#pragma clang diagnostic pop 138#endif 139} 140 141- (BOOL)prefersStatusBarHidden 142{ 143 return [[NSBundle.mainBundle objectForInfoDictionaryKey:@"UIStatusBarHidden"] boolValue]; 144} 145 146- (UIStatusBarStyle)preferredStatusBarStyle 147{ 148 NSString *statusBarStyle = [NSBundle.mainBundle objectForInfoDictionaryKey:@"UIStatusBarStyle"]; 149 if ([statusBarStyle isEqualToString:@"UIStatusBarStyleLightContent"]) { 150 return UIStatusBarStyleLightContent; 151 } 152 if (@available(iOS 13.0, *)) { 153 if ([statusBarStyle isEqualToString:@"UIStatusBarStyleDarkContent"]) { 154 return UIStatusBarStyleDarkContent; 155 } 156 } 157 return UIStatusBarStyleDefault; 158} 159 160@end 161#endif // !SDL_PLATFORM_TVOS 162 163 164@interface SDLLaunchScreenController () 165 166#ifndef SDL_PLATFORM_TVOS 167- (NSUInteger)supportedInterfaceOrientations; 168#endif 169 170@end 171 172@implementation SDLLaunchScreenController 173 174- (instancetype)init 175{ 176 return [self initWithNibName:nil bundle:[NSBundle mainBundle]]; 177} 178 179- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 180{ 181 if (!(self = [super initWithNibName:nil bundle:nil])) { 182 return nil; 183 } 184 185 NSString *screenname = nibNameOrNil; 186 NSBundle *bundle = nibBundleOrNil; 187 188 // A launch screen may not exist. Fall back to launch images in that case. 189 if (screenname) { 190 @try { 191 self.view = [bundle loadNibNamed:screenname owner:self options:nil][0]; 192 } 193 @catch (NSException *exception) { 194 /* If a launch screen name is specified but it fails to load, iOS 195 * displays a blank screen rather than falling back to an image. */ 196 return nil; 197 } 198 } 199 200 if (!self.view) { 201 NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"]; 202 NSString *imagename = nil; 203 UIImage *image = nil; 204 205#ifdef SDL_PLATFORM_VISIONOS 206 int screenw = SDL_XR_SCREENWIDTH; 207 int screenh = SDL_XR_SCREENHEIGHT; 208#else 209 int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5); 210 int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5); 211#endif 212 213 214 215#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 216#pragma clang diagnostic push 217#pragma clang diagnostic ignored "-Wdeprecated-declarations" 218 UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; 219#pragma clang diagnostic pop 220 221 // We always want portrait-oriented size, to match UILaunchImageSize. 222 if (screenw > screenh) { 223 int width = screenw; 224 screenw = screenh; 225 screenh = width; 226 } 227#endif 228 229 // Xcode 5 introduced a dictionary of launch images in Info.plist. 230 if (launchimages) { 231 for (NSDictionary *dict in launchimages) { 232 NSString *minversion = dict[@"UILaunchImageMinimumOSVersion"]; 233 NSString *sizestring = dict[@"UILaunchImageSize"]; 234 235 // Ignore this image if the current version is too low. 236 if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) { 237 continue; 238 } 239 240 // Ignore this image if the size doesn't match. 241 if (sizestring) { 242 CGSize size = CGSizeFromString(sizestring); 243 if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) { 244 continue; 245 } 246 } 247 248#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 249 UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; 250 NSString *orientstring = dict[@"UILaunchImageOrientation"]; 251 252 if (orientstring) { 253 if ([orientstring isEqualToString:@"PortraitUpsideDown"]) { 254 orientmask = UIInterfaceOrientationMaskPortraitUpsideDown; 255 } else if ([orientstring isEqualToString:@"Landscape"]) { 256 orientmask = UIInterfaceOrientationMaskLandscape; 257 } else if ([orientstring isEqualToString:@"LandscapeLeft"]) { 258 orientmask = UIInterfaceOrientationMaskLandscapeLeft; 259 } else if ([orientstring isEqualToString:@"LandscapeRight"]) { 260 orientmask = UIInterfaceOrientationMaskLandscapeRight; 261 } 262 } 263 264 // Ignore this image if the orientation doesn't match. 265 if ((orientmask & (1 << curorient)) == 0) { 266 continue; 267 } 268#endif 269 270 imagename = dict[@"UILaunchImageName"]; 271 } 272 273 if (imagename) { 274 image = [UIImage imageNamed:imagename]; 275 } 276 } 277#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 278 else { 279 imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"]; 280 281 if (imagename) { 282 image = SDL_LoadLaunchImageNamed(imagename, screenh); 283 } 284 285 if (!image) { 286 image = SDL_LoadLaunchImageNamed(@"Default", screenh); 287 } 288 } 289#endif 290 291 if (image) { 292#ifdef SDL_PLATFORM_VISIONOS 293 CGRect viewFrame = CGRectMake(0, 0, screenw, screenh); 294#else 295 CGRect viewFrame = [UIScreen mainScreen].bounds; 296#endif 297 UIImageView *view = [[UIImageView alloc] initWithFrame:viewFrame]; 298 UIImageOrientation imageorient = UIImageOrientationUp; 299 300#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 301 // Bugs observed / workaround tested in iOS 8.3. 302 if (UIInterfaceOrientationIsLandscape(curorient)) { 303 if (image.size.width < image.size.height) { 304 /* On iOS 8, portrait launch images displayed in forced- 305 * landscape mode (e.g. a standard Default.png on an iPhone 306 * when Info.plist only supports landscape orientations) need 307 * to be rotated to display in the expected orientation. */ 308 if (curorient == UIInterfaceOrientationLandscapeLeft) { 309 imageorient = UIImageOrientationRight; 310 } else if (curorient == UIInterfaceOrientationLandscapeRight) { 311 imageorient = UIImageOrientationLeft; 312 } 313 } 314 } 315#endif 316 317 // Create the properly oriented image. 318 view.image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:imageorient]; 319 320 self.view = view; 321 } 322 } 323 324 return self; 325} 326 327- (void)loadView 328{ 329 // Do nothing. 330} 331 332#ifndef SDL_PLATFORM_TVOS 333- (BOOL)shouldAutorotate 334{ 335 // If YES, the launch image will be incorrectly rotated in some cases. 336 return NO; 337} 338 339- (NSUInteger)supportedInterfaceOrientations 340{ 341 /* We keep the supported orientations unrestricted to avoid the case where 342 * there are no common orientations between the ones set in Info.plist and 343 * the ones set here (it will cause an exception in that case.) */ 344 return UIInterfaceOrientationMaskAll; 345} 346#endif // !SDL_PLATFORM_TVOS 347 348@end // SDLLaunchScreenController 349 350 351API_AVAILABLE(ios(13.0)) 352@implementation SDLUIKitSceneDelegate 353{ 354 UIWindow *launchWindow; 355} 356 357+ (NSString *)getSceneDelegateClassName 358{ 359 return @"SDLUIKitSceneDelegate"; 360} 361 362- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions 363{ 364 if (![scene isKindOfClass:[UIWindowScene class]]) { 365 return; 366 } 367 368 UIWindowScene *windowScene = (UIWindowScene *)scene; 369 windowScene.delegate = self; 370 371 NSBundle *bundle = [NSBundle mainBundle]; 372 373#ifdef SDL_IPHONE_LAUNCHSCREEN 374 UIViewController *vc = nil; 375 NSString *screenname = nil; 376 377#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 378 screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; 379 380 if (screenname) { 381 @try { 382 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:screenname bundle:bundle]; 383 __auto_type storyboardVc = [storyboard instantiateInitialViewController]; 384 vc = [[SDLLaunchStoryboardViewController alloc] initWithStoryboardViewController:storyboardVc]; 385 } 386 @catch (NSException *exception) { 387 // Do nothing (there's more code to execute below). 388 } 389 } 390#endif 391 392 if (vc == nil) { 393 vc = [[SDLLaunchScreenController alloc] initWithNibName:screenname bundle:bundle]; 394 } 395 396 if (vc.view) { 397#ifdef SDL_PLATFORM_VISIONOS 398 CGRect viewFrame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT); 399#else 400 CGRect viewFrame = windowScene.coordinateSpace.bounds; 401#endif 402 launchWindow = [[UIWindow alloc] initWithWindowScene:windowScene]; 403 launchWindow.frame = viewFrame; 404 405 launchWindow.windowLevel = UIWindowLevelNormal + 1.0; 406 launchWindow.hidden = NO; 407 launchWindow.rootViewController = vc; 408 } 409#endif 410 411 // Set working directory to resource path 412 [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]]; 413 414 // Handle any connection options (like opening URLs) 415 for (NSUserActivity *activity in connectionOptions.userActivities) { 416 if (activity.webpageURL) { 417 [self handleURL:activity.webpageURL]; 418 } 419 } 420 421 for (UIOpenURLContext *urlContext in connectionOptions.URLContexts) { 422 [self handleURL:urlContext.URL]; 423 } 424 425 SDL_SetMainReady(); 426 [self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:0.0]; 427} 428 429- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts 430{ 431 for (UIOpenURLContext *context in URLContexts) { 432 [self handleURL:context.URL]; 433 } 434} 435 436- (void)sceneDidBecomeActive:(UIScene *)scene 437{ 438 SDL_OnApplicationDidEnterForeground(); 439} 440 441- (void)sceneWillResignActive:(UIScene *)scene 442{ 443 SDL_OnApplicationWillEnterBackground(); 444} 445 446- (void)sceneWillEnterForeground:(UIScene *)scene 447{ 448 SDL_OnApplicationWillEnterForeground(); 449} 450 451- (void)sceneDidEnterBackground:(UIScene *)scene 452{ 453 SDL_OnApplicationDidEnterBackground(); 454} 455 456- (void)handleURL:(NSURL *)url 457{ 458 const char *sourceApplicationCString = NULL; 459 NSURL *fileURL = url.filePathURL; 460 if (fileURL != nil) { 461 SDL_SendDropFile(NULL, sourceApplicationCString, fileURL.path.UTF8String); 462 } else { 463 SDL_SendDropFile(NULL, sourceApplicationCString, url.absoluteString.UTF8String); 464 } 465 SDL_SendDropComplete(NULL); 466} 467 468- (void)hideLaunchScreen 469{ 470 UIWindow *window = launchWindow; 471 472 if (!window || window.hidden) { 473 return; 474 } 475 476 launchWindow = nil; 477 478 [UIView animateWithDuration:0.2 479 animations:^{ 480 window.alpha = 0.0; 481 } 482 completion:^(BOOL finished) { 483 window.hidden = YES; 484 UIKit_ForceUpdateHomeIndicator(); 485 }]; 486} 487 488- (void)postFinishLaunch 489{ 490 [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0]; 491 492 SDL_SetiOSEventPump(true); 493 exit_status = SDL_CallMainFunction(forward_argc, forward_argv, forward_main); 494 SDL_SetiOSEventPump(false); 495 496 if (launchWindow) { 497 launchWindow.hidden = YES; 498 launchWindow = nil; 499 } 500} 501 502- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)) 503{ 504 // This doesn't appear to be called, but it needs to be implemented to signal that we support the UIScene life cycle 505 UISceneConfiguration *config = [[UISceneConfiguration alloc] initWithName:@"SDLSceneConfiguration" sessionRole:connectingSceneSession.role]; 506 config.delegateClass = [SDLUIKitSceneDelegate class]; 507 return config; 508} 509 510@end // SDLUIKitSceneDelegate 511 512 513@implementation SDLUIKitDelegate 514{ 515 UIWindow *launchWindow; 516} 517 518// convenience method 519+ (id)sharedAppDelegate 520{ 521 /* the delegate is set in UIApplicationMain(), which is guaranteed to be 522 * called before this method */ 523 return [UIApplication sharedApplication].delegate; 524} 525 526+ (NSString *)getAppDelegateClassName 527{ 528 /* subclassing notice: when you subclass this appdelegate, make sure to add 529 * a category to override this method and return the actual name of the 530 * delegate */ 531 return @"SDLUIKitDelegate"; 532} 533 534- (void)hideLaunchScreen 535{ 536 UIWindow *window = launchWindow; 537 538 if (!window || window.hidden) { 539 return; 540 } 541 542 launchWindow = nil; 543 544 // Do a nice animated fade-out (roughly matches the real launch behavior.) 545 [UIView animateWithDuration:0.2 546 animations:^{ 547 window.alpha = 0.0; 548 } 549 completion:^(BOOL finished) { 550 window.hidden = YES; 551 UIKit_ForceUpdateHomeIndicator(); // Wait for launch screen to hide so settings are applied to the actual view controller. 552 }]; 553} 554 555- (void)postFinishLaunch 556{ 557 /* Hide the launch screen the next time the run loop is run. SDL apps will 558 * have a chance to load resources while the launch screen is still up. */ 559 [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0]; 560 561 // run the user's application, passing argc and argv 562 SDL_SetiOSEventPump(true); 563 exit_status = SDL_CallMainFunction(forward_argc, forward_argv, forward_main); 564 SDL_SetiOSEventPump(false); 565 566 if (launchWindow) { 567 launchWindow.hidden = YES; 568 launchWindow = nil; 569 } 570 571 // exit, passing the return status from the user's application 572 /* We don't actually exit to support applications that do setup in their 573 * main function and then allow the Cocoa event loop to run. */ 574 // exit(exit_status); 575} 576 577- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 578{ 579 NSBundle *bundle = [NSBundle mainBundle]; 580 581#ifdef SDL_IPHONE_LAUNCHSCREEN 582 /* The normal launch screen is displayed until didFinishLaunching returns, 583 * but SDL_main is called after that happens and there may be a noticeable 584 * delay between the start of SDL_main and when the first real frame is 585 * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is 586 * called), so we show the launch screen programmatically until the first 587 * time events are pumped. */ 588 UIViewController *vc = nil; 589 NSString *screenname = nil; 590 591 // tvOS only uses a plain launch image. 592#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 593 screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; 594 595 if (screenname) { 596 @try { 597 /* The launch storyboard is actually a nib in some older versions of 598 * Xcode. We'll try to load it as a storyboard first, as it's more 599 * modern. */ 600 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:screenname bundle:bundle]; 601 __auto_type storyboardVc = [storyboard instantiateInitialViewController]; 602 vc = [[SDLLaunchStoryboardViewController alloc] initWithStoryboardViewController:storyboardVc]; 603 } 604 @catch (NSException *exception) { 605 // Do nothing (there's more code to execute below). 606 } 607 } 608#endif 609 610 if (vc == nil) { 611 vc = [[SDLLaunchScreenController alloc] initWithNibName:screenname bundle:bundle]; 612 } 613 614 if (vc.view) { 615#ifdef SDL_PLATFORM_VISIONOS 616 CGRect viewFrame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT); 617#else 618 CGRect viewFrame = [UIScreen mainScreen].bounds; 619#endif 620 launchWindow = [[UIWindow alloc] initWithFrame:viewFrame]; 621 622 /* We don't want the launch window immediately hidden when a real SDL 623 * window is shown - we fade it out ourselves when we're ready. */ 624 launchWindow.windowLevel = UIWindowLevelNormal + 1.0; 625 626 /* Show the window but don't make it key. Events should always go to 627 * other windows when possible. */ 628 launchWindow.hidden = NO; 629 630 launchWindow.rootViewController = vc; 631 } 632#endif 633 634 // Set working directory to resource path 635 [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]]; 636 637 SDL_SetMainReady(); 638 [self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:0.0]; 639 640 return YES; 641} 642 643- (UIWindow *)window 644{ 645 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 646 if (_this) { 647 SDL_Window *window = NULL; 648 for (window = _this->windows; window != NULL; window = window->next) { 649 SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->internal; 650 if (data != nil) { 651 return data.uiwindow; 652 } 653 } 654 } 655 return nil; 656} 657 658- (void)setWindow:(UIWindow *)window 659{ 660 // Do nothing. 661} 662 663- (void)sendDropFileForURL:(NSURL *)url fromSourceApplication:(NSString *)sourceApplication 664{ 665 NSURL *fileURL = url.filePathURL; 666 const char *sourceApplicationCString = sourceApplication ? [sourceApplication UTF8String] : NULL; 667 if (fileURL != nil) { 668 SDL_SendDropFile(NULL, sourceApplicationCString, fileURL.path.UTF8String); 669 } else { 670 SDL_SendDropFile(NULL, sourceApplicationCString, url.absoluteString.UTF8String); 671 } 672 SDL_SendDropComplete(NULL); 673} 674 675- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options 676{ 677 // TODO: Handle options 678 [self sendDropFileForURL:url fromSourceApplication:NULL]; 679 return YES; 680} 681 682@end // SDLUIKitDelegate 683 684#endif // SDL_VIDEO_DRIVER_UIKIT 685
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.