Audio plugin host https://kx.studio/carla
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.

481 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. extern bool isIOSAppActive;
  20. struct AppInactivityCallback // NB: careful, this declaration is duplicated in other modules
  21. {
  22. virtual ~AppInactivityCallback() {}
  23. virtual void appBecomingInactive() = 0;
  24. };
  25. // This is an internal list of callbacks (but currently used between modules)
  26. Array<AppInactivityCallback*> appBecomingInactiveCallbacks;
  27. } // (juce namespace)
  28. @interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate>
  29. {
  30. UIBackgroundTaskIdentifier appSuspendTask;
  31. }
  32. @property (strong, nonatomic) UIWindow *window;
  33. - (id)init;
  34. - (void) applicationDidFinishLaunching: (UIApplication*) application;
  35. - (void) applicationWillTerminate: (UIApplication*) application;
  36. - (void) applicationDidEnterBackground: (UIApplication*) application;
  37. - (void) applicationWillEnterForeground: (UIApplication*) application;
  38. - (void) applicationDidBecomeActive: (UIApplication*) application;
  39. - (void) applicationWillResignActive: (UIApplication*) application;
  40. - (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*)identifier
  41. completionHandler: (void (^)(void))completionHandler;
  42. @end
  43. @implementation JuceAppStartupDelegate
  44. - (id)init
  45. {
  46. self = [super init];
  47. appSuspendTask = UIBackgroundTaskInvalid;
  48. return self;
  49. }
  50. - (void) applicationDidFinishLaunching: (UIApplication*) application
  51. {
  52. ignoreUnused (application);
  53. initialiseJuce_GUI();
  54. if (JUCEApplicationBase* app = JUCEApplicationBase::createInstance())
  55. {
  56. if (! app->initialiseApp())
  57. exit (app->shutdownApp());
  58. }
  59. else
  60. {
  61. jassertfalse; // you must supply an application object for an iOS app!
  62. }
  63. }
  64. - (void) applicationWillTerminate: (UIApplication*) application
  65. {
  66. ignoreUnused (application);
  67. JUCEApplicationBase::appWillTerminateByForce();
  68. }
  69. - (void) applicationDidEnterBackground: (UIApplication*) application
  70. {
  71. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  72. {
  73. #if JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK
  74. appSuspendTask = [application beginBackgroundTaskWithName:@"JUCE Suspend Task" expirationHandler:^{
  75. if (appSuspendTask != UIBackgroundTaskInvalid)
  76. {
  77. [application endBackgroundTask:appSuspendTask];
  78. appSuspendTask = UIBackgroundTaskInvalid;
  79. }
  80. }];
  81. MessageManager::callAsync ([self,application,app] () { app->suspended(); });
  82. #else
  83. ignoreUnused (application);
  84. app->suspended();
  85. #endif
  86. }
  87. }
  88. - (void) applicationWillEnterForeground: (UIApplication*) application
  89. {
  90. ignoreUnused (application);
  91. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  92. app->resumed();
  93. }
  94. - (void) applicationDidBecomeActive: (UIApplication*) application
  95. {
  96. ignoreUnused (application);
  97. isIOSAppActive = true;
  98. }
  99. - (void) applicationWillResignActive: (UIApplication*) application
  100. {
  101. ignoreUnused (application);
  102. isIOSAppActive = false;
  103. for (int i = appBecomingInactiveCallbacks.size(); --i >= 0;)
  104. appBecomingInactiveCallbacks.getReference(i)->appBecomingInactive();
  105. }
  106. - (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*)identifier
  107. completionHandler: (void (^)(void))completionHandler
  108. {
  109. ignoreUnused (application);
  110. URL::DownloadTask::juce_iosURLSessionNotify (nsStringToJuce (identifier));
  111. completionHandler();
  112. }
  113. @end
  114. namespace juce
  115. {
  116. int juce_iOSMain (int argc, const char* argv[], void* customDelgatePtr);
  117. int juce_iOSMain (int argc, const char* argv[], void* customDelagetPtr)
  118. {
  119. Class delegateClass = (customDelagetPtr != nullptr ? reinterpret_cast<Class> (customDelagetPtr) : [JuceAppStartupDelegate class]);
  120. return UIApplicationMain (argc, const_cast<char**> (argv), nil, NSStringFromClass (delegateClass));
  121. }
  122. //==============================================================================
  123. void LookAndFeel::playAlertSound()
  124. {
  125. // TODO
  126. }
  127. //==============================================================================
  128. class iOSMessageBox;
  129. #if defined (__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
  130. #define JUCE_USE_NEW_IOS_ALERTWINDOW 1
  131. #endif
  132. #if ! JUCE_USE_NEW_IOS_ALERTWINDOW
  133. } // (juce namespace)
  134. @interface JuceAlertBoxDelegate : NSObject <UIAlertViewDelegate>
  135. {
  136. @public
  137. iOSMessageBox* owner;
  138. }
  139. - (void) alertView: (UIAlertView*) alertView clickedButtonAtIndex: (NSInteger) buttonIndex;
  140. @end
  141. namespace juce
  142. {
  143. #endif
  144. class iOSMessageBox
  145. {
  146. public:
  147. iOSMessageBox (const String& title, const String& message,
  148. NSString* button1, NSString* button2, NSString* button3,
  149. ModalComponentManager::Callback* cb, const bool async)
  150. : result (0), resultReceived (false), callback (cb), isAsync (async)
  151. {
  152. #if JUCE_USE_NEW_IOS_ALERTWINDOW
  153. if (currentlyFocusedPeer != nullptr)
  154. {
  155. UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (title)
  156. message: juceStringToNS (message)
  157. preferredStyle: UIAlertControllerStyleAlert];
  158. addButton (alert, button1, 0);
  159. addButton (alert, button2, 1);
  160. addButton (alert, button3, 2);
  161. [currentlyFocusedPeer->controller presentViewController: alert
  162. animated: YES
  163. completion: nil];
  164. }
  165. else
  166. {
  167. // Since iOS8, alert windows need to be associated with a window, so you need to
  168. // have at least one window on screen when you use this
  169. jassertfalse;
  170. }
  171. #else
  172. delegate = [[JuceAlertBoxDelegate alloc] init];
  173. delegate->owner = this;
  174. alert = [[UIAlertView alloc] initWithTitle: juceStringToNS (title)
  175. message: juceStringToNS (message)
  176. delegate: delegate
  177. cancelButtonTitle: button1
  178. otherButtonTitles: button2, button3, nil];
  179. [alert retain];
  180. [alert show];
  181. #endif
  182. }
  183. ~iOSMessageBox()
  184. {
  185. #if ! JUCE_USE_NEW_IOS_ALERTWINDOW
  186. [alert release];
  187. [delegate release];
  188. #endif
  189. }
  190. int getResult()
  191. {
  192. jassert (callback == nullptr);
  193. JUCE_AUTORELEASEPOOL
  194. {
  195. #if JUCE_USE_NEW_IOS_ALERTWINDOW
  196. while (! resultReceived)
  197. #else
  198. while (! (alert.hidden || resultReceived))
  199. #endif
  200. [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
  201. }
  202. return result;
  203. }
  204. void buttonClicked (const int buttonIndex) noexcept
  205. {
  206. result = buttonIndex;
  207. resultReceived = true;
  208. if (callback != nullptr)
  209. callback->modalStateFinished (result);
  210. if (isAsync)
  211. delete this;
  212. }
  213. private:
  214. int result;
  215. bool resultReceived;
  216. ScopedPointer<ModalComponentManager::Callback> callback;
  217. const bool isAsync;
  218. #if JUCE_USE_NEW_IOS_ALERTWINDOW
  219. void addButton (UIAlertController* alert, NSString* text, int index)
  220. {
  221. if (text != nil)
  222. [alert addAction: [UIAlertAction actionWithTitle: text
  223. style: UIAlertActionStyleDefault
  224. handler: ^(UIAlertAction*) { this->buttonClicked (index); }]];
  225. }
  226. #else
  227. UIAlertView* alert;
  228. JuceAlertBoxDelegate* delegate;
  229. #endif
  230. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox)
  231. };
  232. #if ! JUCE_USE_NEW_IOS_ALERTWINDOW
  233. } // (juce namespace)
  234. @implementation JuceAlertBoxDelegate
  235. - (void) alertView: (UIAlertView*) alertView clickedButtonAtIndex: (NSInteger) buttonIndex
  236. {
  237. owner->buttonClicked ((int) buttonIndex);
  238. alertView.hidden = true;
  239. }
  240. @end
  241. namespace juce
  242. {
  243. #endif
  244. //==============================================================================
  245. #if JUCE_MODAL_LOOPS_PERMITTED
  246. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType /*iconType*/,
  247. const String& title, const String& message,
  248. Component* /*associatedComponent*/)
  249. {
  250. JUCE_AUTORELEASEPOOL
  251. {
  252. iOSMessageBox mb (title, message, @"OK", nil, nil, nullptr, false);
  253. ignoreUnused (mb.getResult());
  254. }
  255. }
  256. #endif
  257. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
  258. const String& title, const String& message,
  259. Component* /*associatedComponent*/,
  260. ModalComponentManager::Callback* callback)
  261. {
  262. new iOSMessageBox (title, message, @"OK", nil, nil, callback, true);
  263. }
  264. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
  265. const String& title, const String& message,
  266. Component* /*associatedComponent*/,
  267. ModalComponentManager::Callback* callback)
  268. {
  269. ScopedPointer<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"OK",
  270. nil, callback, callback != nullptr));
  271. if (callback == nullptr)
  272. return mb->getResult() == 1;
  273. mb.release();
  274. return false;
  275. }
  276. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
  277. const String& title, const String& message,
  278. Component* /*associatedComponent*/,
  279. ModalComponentManager::Callback* callback)
  280. {
  281. ScopedPointer<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"Yes", @"No", callback, callback != nullptr));
  282. if (callback == nullptr)
  283. return mb->getResult();
  284. mb.release();
  285. return 0;
  286. }
  287. int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/,
  288. const String& title, const String& message,
  289. Component* /*associatedComponent*/,
  290. ModalComponentManager::Callback* callback)
  291. {
  292. ScopedPointer<iOSMessageBox> mb (new iOSMessageBox (title, message, @"No", @"Yes", nil, callback, callback != nullptr));
  293. if (callback == nullptr)
  294. return mb->getResult();
  295. mb.release();
  296. return 0;
  297. }
  298. //==============================================================================
  299. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray&, bool, Component*)
  300. {
  301. jassertfalse; // no such thing on iOS!
  302. return false;
  303. }
  304. bool DragAndDropContainer::performExternalDragDropOfText (const String&, Component*)
  305. {
  306. jassertfalse; // no such thing on iOS!
  307. return false;
  308. }
  309. //==============================================================================
  310. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  311. {
  312. if (! SystemStats::isRunningInAppExtensionSandbox())
  313. [[UIApplication sharedApplication] setIdleTimerDisabled: ! isEnabled];
  314. }
  315. bool Desktop::isScreenSaverEnabled()
  316. {
  317. if (SystemStats::isRunningInAppExtensionSandbox())
  318. return true;
  319. return ! [[UIApplication sharedApplication] isIdleTimerDisabled];
  320. }
  321. //==============================================================================
  322. bool juce_areThereAnyAlwaysOnTopWindows()
  323. {
  324. return false;
  325. }
  326. //==============================================================================
  327. Image juce_createIconForFile (const File&)
  328. {
  329. return Image();
  330. }
  331. //==============================================================================
  332. void SystemClipboard::copyTextToClipboard (const String& text)
  333. {
  334. [[UIPasteboard generalPasteboard] setValue: juceStringToNS (text)
  335. forPasteboardType: @"public.text"];
  336. }
  337. String SystemClipboard::getTextFromClipboard()
  338. {
  339. return nsStringToJuce ([[UIPasteboard generalPasteboard] valueForPasteboardType: @"public.text"]);
  340. }
  341. //==============================================================================
  342. bool MouseInputSource::SourceList::addSource()
  343. {
  344. addSource (sources.size(), MouseInputSource::InputSourceType::touch);
  345. return true;
  346. }
  347. bool MouseInputSource::SourceList::canUseTouch()
  348. {
  349. return true;
  350. }
  351. bool Desktop::canUseSemiTransparentWindows() noexcept
  352. {
  353. return true;
  354. }
  355. Point<float> MouseInputSource::getCurrentRawMousePosition()
  356. {
  357. return juce_lastMousePos;
  358. }
  359. void MouseInputSource::setRawMousePosition (Point<float>)
  360. {
  361. }
  362. double Desktop::getDefaultMasterScale()
  363. {
  364. return 1.0;
  365. }
  366. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  367. {
  368. UIInterfaceOrientation orientation = SystemStats::isRunningInAppExtensionSandbox() ? UIInterfaceOrientationPortrait
  369. : [[UIApplication sharedApplication] statusBarOrientation];
  370. return Orientations::convertToJuce (orientation);
  371. }
  372. void Desktop::Displays::findDisplays (float masterScale)
  373. {
  374. JUCE_AUTORELEASEPOOL
  375. {
  376. UIScreen* s = [UIScreen mainScreen];
  377. Display d;
  378. d.userArea = d.totalArea = UIViewComponentPeer::realScreenPosToRotated (convertToRectInt ([s bounds])) / masterScale;
  379. d.isMain = true;
  380. d.scale = masterScale;
  381. if ([s respondsToSelector: @selector (scale)])
  382. d.scale *= s.scale;
  383. d.dpi = 160 * d.scale;
  384. displays.add (d);
  385. }
  386. }