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.

428 lines
13KB

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