The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

757 lines
30KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. extern bool isIOSAppActive;
  21. struct AppInactivityCallback // NB: careful, this declaration is duplicated in other modules
  22. {
  23. virtual ~AppInactivityCallback() = default;
  24. virtual void appBecomingInactive() = 0;
  25. };
  26. // This is an internal list of callbacks (but currently used between modules)
  27. Array<AppInactivityCallback*> appBecomingInactiveCallbacks;
  28. }
  29. #if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  30. @interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate, UNUserNotificationCenterDelegate>
  31. #else
  32. @interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate>
  33. #endif
  34. {
  35. UIBackgroundTaskIdentifier appSuspendTask;
  36. }
  37. @property (strong, nonatomic) UIWindow *window;
  38. - (id) init;
  39. - (void) dealloc;
  40. - (void) applicationDidFinishLaunching: (UIApplication*) application;
  41. - (void) applicationWillTerminate: (UIApplication*) application;
  42. - (void) applicationDidEnterBackground: (UIApplication*) application;
  43. - (void) applicationWillEnterForeground: (UIApplication*) application;
  44. - (void) applicationDidBecomeActive: (UIApplication*) application;
  45. - (void) applicationWillResignActive: (UIApplication*) application;
  46. - (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*) identifier
  47. completionHandler: (void (^)(void)) completionHandler;
  48. - (void) applicationDidReceiveMemoryWarning: (UIApplication *) application;
  49. #if JUCE_PUSH_NOTIFICATIONS
  50. - (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings;
  51. - (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken;
  52. - (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error;
  53. - (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo;
  54. - (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
  55. fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler;
  56. - (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
  57. forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
  58. completionHandler: (void(^)()) completionHandler;
  59. - (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification;
  60. - (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
  61. forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler;
  62. - (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
  63. forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
  64. completionHandler: (void(^)()) completionHandler;
  65. #if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  66. - (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
  67. withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler;
  68. - (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
  69. withCompletionHandler: (void(^)())completionHandler;
  70. #endif
  71. #endif
  72. @end
  73. @implementation JuceAppStartupDelegate
  74. NSObject* _pushNotificationsDelegate;
  75. - (id) init
  76. {
  77. self = [super init];
  78. appSuspendTask = UIBackgroundTaskInvalid;
  79. #if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  80. [UNUserNotificationCenter currentNotificationCenter].delegate = self;
  81. #endif
  82. return self;
  83. }
  84. - (void) dealloc
  85. {
  86. [super dealloc];
  87. }
  88. - (void) applicationDidFinishLaunching: (UIApplication*) application
  89. {
  90. ignoreUnused (application);
  91. initialiseJuce_GUI();
  92. if (auto* app = JUCEApplicationBase::createInstance())
  93. {
  94. if (! app->initialiseApp())
  95. exit (app->shutdownApp());
  96. }
  97. else
  98. {
  99. jassertfalse; // you must supply an application object for an iOS app!
  100. }
  101. }
  102. - (void) applicationWillTerminate: (UIApplication*) application
  103. {
  104. ignoreUnused (application);
  105. JUCEApplicationBase::appWillTerminateByForce();
  106. }
  107. - (void) applicationDidEnterBackground: (UIApplication*) application
  108. {
  109. if (auto* app = JUCEApplicationBase::getInstance())
  110. {
  111. #if JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK
  112. appSuspendTask = [application beginBackgroundTaskWithName:@"JUCE Suspend Task" expirationHandler:^{
  113. if (appSuspendTask != UIBackgroundTaskInvalid)
  114. {
  115. [application endBackgroundTask:appSuspendTask];
  116. appSuspendTask = UIBackgroundTaskInvalid;
  117. }
  118. }];
  119. MessageManager::callAsync ([app] { app->suspended(); });
  120. #else
  121. ignoreUnused (application);
  122. app->suspended();
  123. #endif
  124. }
  125. }
  126. - (void) applicationWillEnterForeground: (UIApplication*) application
  127. {
  128. ignoreUnused (application);
  129. if (auto* app = JUCEApplicationBase::getInstance())
  130. app->resumed();
  131. }
  132. - (void) applicationDidBecomeActive: (UIApplication*) application
  133. {
  134. application.applicationIconBadgeNumber = 0;
  135. isIOSAppActive = true;
  136. }
  137. - (void) applicationWillResignActive: (UIApplication*) application
  138. {
  139. ignoreUnused (application);
  140. isIOSAppActive = false;
  141. for (int i = appBecomingInactiveCallbacks.size(); --i >= 0;)
  142. appBecomingInactiveCallbacks.getReference(i)->appBecomingInactive();
  143. }
  144. - (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*)identifier
  145. completionHandler: (void (^)(void))completionHandler
  146. {
  147. ignoreUnused (application);
  148. URL::DownloadTask::juce_iosURLSessionNotify (nsStringToJuce (identifier));
  149. completionHandler();
  150. }
  151. - (void) applicationDidReceiveMemoryWarning: (UIApplication*) application
  152. {
  153. ignoreUnused (application);
  154. if (auto* app = JUCEApplicationBase::getInstance())
  155. app->memoryWarningReceived();
  156. }
  157. - (void) setPushNotificationsDelegateToUse: (NSObject*) delegate
  158. {
  159. _pushNotificationsDelegate = delegate;
  160. }
  161. #if JUCE_PUSH_NOTIFICATIONS
  162. - (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings
  163. {
  164. ignoreUnused (application);
  165. SEL selector = @selector (application:didRegisterUserNotificationSettings:);
  166. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  167. {
  168. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  169. [invocation setSelector: selector];
  170. [invocation setTarget: _pushNotificationsDelegate];
  171. [invocation setArgument: &application atIndex:2];
  172. [invocation setArgument: &notificationSettings atIndex:3];
  173. [invocation invoke];
  174. }
  175. }
  176. - (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken
  177. {
  178. ignoreUnused (application);
  179. SEL selector = @selector (application:didRegisterForRemoteNotificationsWithDeviceToken:);
  180. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  181. {
  182. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  183. [invocation setSelector: selector];
  184. [invocation setTarget: _pushNotificationsDelegate];
  185. [invocation setArgument: &application atIndex:2];
  186. [invocation setArgument: &deviceToken atIndex:3];
  187. [invocation invoke];
  188. }
  189. }
  190. - (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error
  191. {
  192. ignoreUnused (application);
  193. SEL selector = @selector (application:didFailToRegisterForRemoteNotificationsWithError:);
  194. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  195. {
  196. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  197. [invocation setSelector: selector];
  198. [invocation setTarget: _pushNotificationsDelegate];
  199. [invocation setArgument: &application atIndex:2];
  200. [invocation setArgument: &error atIndex:3];
  201. [invocation invoke];
  202. }
  203. }
  204. - (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
  205. {
  206. ignoreUnused (application);
  207. SEL selector = @selector (application:didReceiveRemoteNotification:);
  208. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  209. {
  210. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  211. [invocation setSelector: selector];
  212. [invocation setTarget: _pushNotificationsDelegate];
  213. [invocation setArgument: &application atIndex:2];
  214. [invocation setArgument: &userInfo atIndex:3];
  215. [invocation invoke];
  216. }
  217. }
  218. - (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
  219. fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler
  220. {
  221. ignoreUnused (application);
  222. SEL selector = @selector (application:didReceiveRemoteNotification:fetchCompletionHandler:);
  223. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  224. {
  225. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  226. [invocation setSelector: selector];
  227. [invocation setTarget: _pushNotificationsDelegate];
  228. [invocation setArgument: &application atIndex:2];
  229. [invocation setArgument: &userInfo atIndex:3];
  230. [invocation setArgument: &completionHandler atIndex:4];
  231. [invocation invoke];
  232. }
  233. }
  234. - (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
  235. forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
  236. completionHandler: (void(^)()) completionHandler
  237. {
  238. ignoreUnused (application);
  239. SEL selector = @selector (application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:);
  240. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  241. {
  242. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  243. [invocation setSelector: selector];
  244. [invocation setTarget: _pushNotificationsDelegate];
  245. [invocation setArgument: &application atIndex:2];
  246. [invocation setArgument: &identifier atIndex:3];
  247. [invocation setArgument: &userInfo atIndex:4];
  248. [invocation setArgument: &responseInfo atIndex:5];
  249. [invocation setArgument: &completionHandler atIndex:6];
  250. [invocation invoke];
  251. }
  252. }
  253. - (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification
  254. {
  255. ignoreUnused (application);
  256. SEL selector = @selector (application:didReceiveLocalNotification:);
  257. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  258. {
  259. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  260. [invocation setSelector: selector];
  261. [invocation setTarget: _pushNotificationsDelegate];
  262. [invocation setArgument: &application atIndex:2];
  263. [invocation setArgument: &notification atIndex:3];
  264. [invocation invoke];
  265. }
  266. }
  267. - (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
  268. forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler
  269. {
  270. ignoreUnused (application);
  271. SEL selector = @selector (application:handleActionWithIdentifier:forLocalNotification:completionHandler:);
  272. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  273. {
  274. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  275. [invocation setSelector: selector];
  276. [invocation setTarget: _pushNotificationsDelegate];
  277. [invocation setArgument: &application atIndex:2];
  278. [invocation setArgument: &identifier atIndex:3];
  279. [invocation setArgument: &notification atIndex:4];
  280. [invocation setArgument: &completionHandler atIndex:5];
  281. [invocation invoke];
  282. }
  283. }
  284. - (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
  285. forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
  286. completionHandler: (void(^)()) completionHandler
  287. {
  288. ignoreUnused (application);
  289. SEL selector = @selector (application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:);
  290. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  291. {
  292. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  293. [invocation setSelector: selector];
  294. [invocation setTarget: _pushNotificationsDelegate];
  295. [invocation setArgument: &application atIndex:2];
  296. [invocation setArgument: &identifier atIndex:3];
  297. [invocation setArgument: &notification atIndex:4];
  298. [invocation setArgument: &responseInfo atIndex:5];
  299. [invocation setArgument: &completionHandler atIndex:6];
  300. [invocation invoke];
  301. }
  302. }
  303. #if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  304. - (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
  305. withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler
  306. {
  307. ignoreUnused (center);
  308. SEL selector = @selector (userNotificationCenter:willPresentNotification:withCompletionHandler:);
  309. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  310. {
  311. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  312. [invocation setSelector: selector];
  313. [invocation setTarget: _pushNotificationsDelegate];
  314. [invocation setArgument: &center atIndex:2];
  315. [invocation setArgument: &notification atIndex:3];
  316. [invocation setArgument: &completionHandler atIndex:4];
  317. [invocation invoke];
  318. }
  319. }
  320. - (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
  321. withCompletionHandler: (void(^)()) completionHandler
  322. {
  323. ignoreUnused (center);
  324. SEL selector = @selector (userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:);
  325. if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
  326. {
  327. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
  328. [invocation setSelector: selector];
  329. [invocation setTarget: _pushNotificationsDelegate];
  330. [invocation setArgument: &center atIndex:2];
  331. [invocation setArgument: &response atIndex:3];
  332. [invocation setArgument: &completionHandler atIndex:4];
  333. [invocation invoke];
  334. }
  335. }
  336. #endif
  337. #endif
  338. @end
  339. namespace juce
  340. {
  341. int juce_iOSMain (int argc, const char* argv[], void* customDelegatePtr);
  342. int juce_iOSMain (int argc, const char* argv[], void* customDelegatePtr)
  343. {
  344. Class delegateClass = (customDelegatePtr != nullptr ? reinterpret_cast<Class> (customDelegatePtr) : [JuceAppStartupDelegate class]);
  345. return UIApplicationMain (argc, const_cast<char**> (argv), nil, NSStringFromClass (delegateClass));
  346. }
  347. //==============================================================================
  348. void LookAndFeel::playAlertSound()
  349. {
  350. // TODO
  351. }
  352. //==============================================================================
  353. class iOSMessageBox
  354. {
  355. public:
  356. iOSMessageBox (const MessageBoxOptions& opts, std::unique_ptr<ModalComponentManager::Callback>&& cb)
  357. : callback (std::move (cb))
  358. {
  359. if (currentlyFocusedPeer != nullptr)
  360. {
  361. UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (opts.getTitle())
  362. message: juceStringToNS (opts.getMessage())
  363. preferredStyle: UIAlertControllerStyleAlert];
  364. addButton (alert, opts.getButtonText (0));
  365. addButton (alert, opts.getButtonText (1));
  366. addButton (alert, opts.getButtonText (2));
  367. [currentlyFocusedPeer->controller presentViewController: alert
  368. animated: YES
  369. completion: nil];
  370. }
  371. else
  372. {
  373. // Since iOS8, alert windows need to be associated with a window, so you need to
  374. // have at least one window on screen when you use this
  375. jassertfalse;
  376. }
  377. }
  378. int getResult()
  379. {
  380. jassert (callback == nullptr);
  381. JUCE_AUTORELEASEPOOL
  382. {
  383. while (result < 0)
  384. [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
  385. }
  386. return result;
  387. }
  388. void buttonClicked (int buttonIndex) noexcept
  389. {
  390. result = buttonIndex;
  391. if (callback != nullptr)
  392. {
  393. callback->modalStateFinished (result);
  394. delete this;
  395. }
  396. }
  397. private:
  398. void addButton (UIAlertController* alert, const String& text)
  399. {
  400. if (! text.isEmpty())
  401. {
  402. const auto index = [[alert actions] count];
  403. [alert addAction: [UIAlertAction actionWithTitle: juceStringToNS (text)
  404. style: UIAlertActionStyleDefault
  405. handler: ^(UIAlertAction*) { this->buttonClicked ((int) index); }]];
  406. }
  407. }
  408. int result = -1;
  409. std::unique_ptr<ModalComponentManager::Callback> callback;
  410. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox)
  411. };
  412. //==============================================================================
  413. static int showDialog (const MessageBoxOptions& options,
  414. std::unique_ptr<ModalComponentManager::Callback> callback,
  415. Async async)
  416. {
  417. #if JUCE_MODAL_LOOPS_PERMITTED
  418. if (async == Async::no)
  419. {
  420. JUCE_AUTORELEASEPOOL
  421. {
  422. iOSMessageBox messageBox (options, std::move (callback));
  423. return messageBox.getResult();
  424. }
  425. }
  426. #endif
  427. ignoreUnused (async);
  428. new iOSMessageBox (options, std::move (callback));
  429. return 0;
  430. }
  431. #if JUCE_MODAL_LOOPS_PERMITTED
  432. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType /*iconType*/,
  433. const String& title, const String& message,
  434. Component* /*associatedComponent*/)
  435. {
  436. showDialog (MessageBoxOptions()
  437. .withTitle (title)
  438. .withMessage (message)
  439. .withButton (TRANS("OK")),
  440. nullptr, Async::no);
  441. }
  442. int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
  443. {
  444. return showDialog (options, nullptr, Async::no);
  445. }
  446. #endif
  447. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType /*iconType*/,
  448. const String& title, const String& message,
  449. Component* /*associatedComponent*/,
  450. ModalComponentManager::Callback* callback)
  451. {
  452. showDialog (MessageBoxOptions()
  453. .withTitle (title)
  454. .withMessage (message)
  455. .withButton (TRANS("OK")),
  456. rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::messageBox)),
  457. Async::yes);
  458. }
  459. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType /*iconType*/,
  460. const String& title, const String& message,
  461. Component* /*associatedComponent*/,
  462. ModalComponentManager::Callback* callback)
  463. {
  464. return showDialog (MessageBoxOptions()
  465. .withTitle (title)
  466. .withMessage (message)
  467. .withButton (TRANS("OK"))
  468. .withButton (TRANS("Cancel")),
  469. rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
  470. callback != nullptr ? Async::yes : Async::no) == 1;
  471. }
  472. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType /*iconType*/,
  473. const String& title, const String& message,
  474. Component* /*associatedComponent*/,
  475. ModalComponentManager::Callback* callback)
  476. {
  477. return showDialog (MessageBoxOptions()
  478. .withTitle (title)
  479. .withMessage (message)
  480. .withButton (TRANS("Yes"))
  481. .withButton (TRANS("No"))
  482. .withButton (TRANS("Cancel")),
  483. rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::yesNoCancel)),
  484. callback != nullptr ? Async::yes : Async::no);
  485. }
  486. int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType /*iconType*/,
  487. const String& title, const String& message,
  488. Component* /*associatedComponent*/,
  489. ModalComponentManager::Callback* callback)
  490. {
  491. return showDialog (MessageBoxOptions()
  492. .withTitle (title)
  493. .withMessage (message)
  494. .withButton (TRANS("Yes"))
  495. .withButton (TRANS("No")),
  496. rawToUniquePtr (AlertWindowMappings::getWrappedCallback (callback, AlertWindowMappings::okCancel)),
  497. callback != nullptr ? Async::yes : Async::no);
  498. }
  499. void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
  500. ModalComponentManager::Callback* callback)
  501. {
  502. showDialog (options, rawToUniquePtr (callback), Async::yes);
  503. }
  504. void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
  505. std::function<void (int)> callback)
  506. {
  507. showAsync (options, ModalCallbackFunction::create (callback));
  508. }
  509. //==============================================================================
  510. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray&, bool, Component*, std::function<void()>)
  511. {
  512. jassertfalse; // no such thing on iOS!
  513. return false;
  514. }
  515. bool DragAndDropContainer::performExternalDragDropOfText (const String&, Component*, std::function<void()>)
  516. {
  517. jassertfalse; // no such thing on iOS!
  518. return false;
  519. }
  520. //==============================================================================
  521. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  522. {
  523. if (! SystemStats::isRunningInAppExtensionSandbox())
  524. [[UIApplication sharedApplication] setIdleTimerDisabled: ! isEnabled];
  525. }
  526. bool Desktop::isScreenSaverEnabled()
  527. {
  528. if (SystemStats::isRunningInAppExtensionSandbox())
  529. return true;
  530. return ! [[UIApplication sharedApplication] isIdleTimerDisabled];
  531. }
  532. //==============================================================================
  533. bool juce_areThereAnyAlwaysOnTopWindows()
  534. {
  535. return false;
  536. }
  537. //==============================================================================
  538. Image juce_createIconForFile (const File&)
  539. {
  540. return Image();
  541. }
  542. //==============================================================================
  543. void SystemClipboard::copyTextToClipboard (const String& text)
  544. {
  545. [[UIPasteboard generalPasteboard] setValue: juceStringToNS (text)
  546. forPasteboardType: @"public.text"];
  547. }
  548. String SystemClipboard::getTextFromClipboard()
  549. {
  550. return nsStringToJuce ([[UIPasteboard generalPasteboard] valueForPasteboardType: @"public.text"]);
  551. }
  552. //==============================================================================
  553. bool MouseInputSource::SourceList::addSource()
  554. {
  555. addSource (sources.size(), MouseInputSource::InputSourceType::touch);
  556. return true;
  557. }
  558. bool MouseInputSource::SourceList::canUseTouch()
  559. {
  560. return true;
  561. }
  562. bool Desktop::canUseSemiTransparentWindows() noexcept
  563. {
  564. return true;
  565. }
  566. Point<float> MouseInputSource::getCurrentRawMousePosition()
  567. {
  568. return juce_lastMousePos;
  569. }
  570. void MouseInputSource::setRawMousePosition (Point<float>)
  571. {
  572. }
  573. double Desktop::getDefaultMasterScale()
  574. {
  575. return 1.0;
  576. }
  577. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  578. {
  579. UIInterfaceOrientation orientation = SystemStats::isRunningInAppExtensionSandbox() ? UIInterfaceOrientationPortrait
  580. : getWindowOrientation();
  581. return Orientations::convertToJuce (orientation);
  582. }
  583. // The most straightforward way of retrieving the screen area available to an iOS app
  584. // seems to be to create a new window (which will take up all available space) and to
  585. // query its frame.
  586. struct TemporaryWindow
  587. {
  588. UIWindow* window = [[UIWindow alloc] init];
  589. ~TemporaryWindow() noexcept { [window release]; }
  590. };
  591. static Rectangle<int> getRecommendedWindowBounds()
  592. {
  593. return convertToRectInt (TemporaryWindow().window.frame);
  594. }
  595. static BorderSize<int> getSafeAreaInsets (float masterScale)
  596. {
  597. #if defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_11_0
  598. UIEdgeInsets safeInsets = TemporaryWindow().window.safeAreaInsets;
  599. auto getInset = [&] (CGFloat original) { return roundToInt (original / masterScale); };
  600. return { getInset (safeInsets.top), getInset (safeInsets.left),
  601. getInset (safeInsets.bottom), getInset (safeInsets.right) };
  602. #else
  603. auto statusBarSize = [UIApplication sharedApplication].statusBarFrame.size;
  604. auto statusBarHeight = jmin (statusBarSize.width, statusBarSize.height);
  605. return { roundToInt (statusBarHeight / masterScale), 0, 0, 0 };
  606. #endif
  607. }
  608. void Displays::findDisplays (float masterScale)
  609. {
  610. JUCE_AUTORELEASEPOOL
  611. {
  612. UIScreen* s = [UIScreen mainScreen];
  613. Display d;
  614. d.totalArea = convertToRectInt ([s bounds]) / masterScale;
  615. d.userArea = getRecommendedWindowBounds() / masterScale;
  616. d.safeAreaInsets = getSafeAreaInsets (masterScale);
  617. d.isMain = true;
  618. d.scale = masterScale * s.scale;
  619. d.dpi = 160 * d.scale;
  620. displays.add (d);
  621. }
  622. }
  623. } // namespace juce