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.

426 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[]);
  85. int juce_iOSMain (int argc, const char* argv[])
  86. {
  87. return UIApplicationMain (argc, const_cast<char**> (argv), nil, @"JuceAppStartupDelegate");
  88. }
  89. //==============================================================================
  90. void LookAndFeel::playAlertSound()
  91. {
  92. // TODO
  93. }
  94. //==============================================================================
  95. class iOSMessageBox;
  96. #if defined (__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
  97. #define JUCE_USE_NEW_IOS_ALERTWINDOW 1
  98. #endif
  99. #if ! JUCE_USE_NEW_IOS_ALERTWINDOW
  100. } // (juce namespace)
  101. @interface JuceAlertBoxDelegate : NSObject <UIAlertViewDelegate>
  102. {
  103. @public
  104. iOSMessageBox* owner;
  105. }
  106. - (void) alertView: (UIAlertView*) alertView clickedButtonAtIndex: (NSInteger) buttonIndex;
  107. @end
  108. namespace juce
  109. {
  110. #endif
  111. class iOSMessageBox
  112. {
  113. public:
  114. iOSMessageBox (const String& title, const String& message,
  115. NSString* button1, NSString* button2, NSString* button3,
  116. ModalComponentManager::Callback* cb, const bool async)
  117. : result (0), resultReceived (false), callback (cb), isAsync (async)
  118. {
  119. #if JUCE_USE_NEW_IOS_ALERTWINDOW
  120. if (currentlyFocusedPeer != nullptr)
  121. {
  122. UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (title)
  123. message: juceStringToNS (message)
  124. preferredStyle: UIAlertControllerStyleAlert];
  125. addButton (alert, button1, 0);
  126. addButton (alert, button2, 1);
  127. addButton (alert, button3, 2);
  128. [currentlyFocusedPeer->controller presentViewController: alert
  129. animated: YES
  130. completion: nil];
  131. }
  132. else
  133. {
  134. // Since iOS8, alert windows need to be associated with a window, so you need to
  135. // have at least one window on screen when you use this
  136. jassertfalse;
  137. }
  138. #else
  139. delegate = [[JuceAlertBoxDelegate alloc] init];
  140. delegate->owner = this;
  141. alert = [[UIAlertView alloc] initWithTitle: juceStringToNS (title)
  142. message: juceStringToNS (message)
  143. delegate: delegate
  144. cancelButtonTitle: button1
  145. otherButtonTitles: button2, button3, nil];
  146. [alert retain];
  147. [alert show];
  148. #endif
  149. }
  150. ~iOSMessageBox()
  151. {
  152. #if ! JUCE_USE_NEW_IOS_ALERTWINDOW
  153. [alert release];
  154. [delegate release];
  155. #endif
  156. }
  157. int getResult()
  158. {
  159. jassert (callback == nullptr);
  160. JUCE_AUTORELEASEPOOL
  161. {
  162. #if JUCE_USE_NEW_IOS_ALERTWINDOW
  163. while (! resultReceived)
  164. #else
  165. while (! (alert.hidden || resultReceived))
  166. #endif
  167. [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
  168. }
  169. return result;
  170. }
  171. void buttonClicked (const int buttonIndex) noexcept
  172. {
  173. result = buttonIndex;
  174. resultReceived = true;
  175. if (callback != nullptr)
  176. callback->modalStateFinished (result);
  177. if (isAsync)
  178. delete this;
  179. }
  180. private:
  181. int result;
  182. bool resultReceived;
  183. ScopedPointer<ModalComponentManager::Callback> callback;
  184. const bool isAsync;
  185. #if JUCE_USE_NEW_IOS_ALERTWINDOW
  186. void addButton (UIAlertController* alert, NSString* text, int index)
  187. {
  188. if (text != nil)
  189. [alert addAction: [UIAlertAction actionWithTitle: text
  190. style: UIAlertActionStyleDefault
  191. handler: ^(UIAlertAction*) { this->buttonClicked (index); }]];
  192. }
  193. #else
  194. UIAlertView* alert;
  195. JuceAlertBoxDelegate* delegate;
  196. #endif
  197. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox)
  198. };
  199. #if ! JUCE_USE_NEW_IOS_ALERTWINDOW
  200. } // (juce namespace)
  201. @implementation JuceAlertBoxDelegate
  202. - (void) alertView: (UIAlertView*) alertView clickedButtonAtIndex: (NSInteger) buttonIndex
  203. {
  204. owner->buttonClicked ((int) buttonIndex);
  205. alertView.hidden = true;
  206. }
  207. @end
  208. namespace juce
  209. {
  210. #endif
  211. //==============================================================================
  212. #if JUCE_MODAL_LOOPS_PERMITTED
  213. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType /*iconType*/,
  214. const String& title, const String& message,
  215. Component* /*associatedComponent*/)
  216. {
  217. JUCE_AUTORELEASEPOOL
  218. {
  219. iOSMessageBox mb (title, message, @"OK", nil, nil, nullptr, false);
  220. ignoreUnused (mb.getResult());
  221. }
  222. }
  223. #endif
  224. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
  225. const String& title, const String& message,
  226. Component* /*associatedComponent*/,
  227. ModalComponentManager::Callback* callback)
  228. {
  229. new iOSMessageBox (title, message, @"OK", nil, nil, callback, true);
  230. }
  231. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
  232. const String& title, const String& message,
  233. Component* /*associatedComponent*/,
  234. ModalComponentManager::Callback* callback)
  235. {
  236. ScopedPointer<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"OK",
  237. nil, callback, callback != nullptr));
  238. if (callback == nullptr)
  239. return mb->getResult() == 1;
  240. mb.release();
  241. return false;
  242. }
  243. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
  244. const String& title, const String& message,
  245. Component* /*associatedComponent*/,
  246. ModalComponentManager::Callback* callback)
  247. {
  248. ScopedPointer<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"Yes", @"No", callback, callback != nullptr));
  249. if (callback == nullptr)
  250. return mb->getResult();
  251. mb.release();
  252. return 0;
  253. }
  254. //==============================================================================
  255. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray&, bool)
  256. {
  257. jassertfalse; // no such thing on iOS!
  258. return false;
  259. }
  260. bool DragAndDropContainer::performExternalDragDropOfText (const String&)
  261. {
  262. jassertfalse; // no such thing on iOS!
  263. return false;
  264. }
  265. //==============================================================================
  266. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  267. {
  268. if (! SystemStats::isRunningInAppExtensionSandbox())
  269. [[UIApplication sharedApplication] setIdleTimerDisabled: ! isEnabled];
  270. }
  271. bool Desktop::isScreenSaverEnabled()
  272. {
  273. if (SystemStats::isRunningInAppExtensionSandbox())
  274. return true;
  275. return ! [[UIApplication sharedApplication] isIdleTimerDisabled];
  276. }
  277. //==============================================================================
  278. bool juce_areThereAnyAlwaysOnTopWindows()
  279. {
  280. return false;
  281. }
  282. //==============================================================================
  283. Image juce_createIconForFile (const File&)
  284. {
  285. return Image();
  286. }
  287. //==============================================================================
  288. void SystemClipboard::copyTextToClipboard (const String& text)
  289. {
  290. [[UIPasteboard generalPasteboard] setValue: juceStringToNS (text)
  291. forPasteboardType: @"public.text"];
  292. }
  293. String SystemClipboard::getTextFromClipboard()
  294. {
  295. return nsStringToJuce ([[UIPasteboard generalPasteboard] valueForPasteboardType: @"public.text"]);
  296. }
  297. //==============================================================================
  298. bool MouseInputSource::SourceList::addSource()
  299. {
  300. addSource (sources.size(), false);
  301. return true;
  302. }
  303. bool Desktop::canUseSemiTransparentWindows() noexcept
  304. {
  305. return true;
  306. }
  307. Point<float> MouseInputSource::getCurrentRawMousePosition()
  308. {
  309. return juce_lastMousePos;
  310. }
  311. void MouseInputSource::setRawMousePosition (Point<float>)
  312. {
  313. }
  314. double Desktop::getDefaultMasterScale()
  315. {
  316. return 1.0;
  317. }
  318. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  319. {
  320. UIInterfaceOrientation orientation = SystemStats::isRunningInAppExtensionSandbox() ? UIInterfaceOrientationPortrait
  321. : [[UIApplication sharedApplication] statusBarOrientation];
  322. return Orientations::convertToJuce (orientation);
  323. }
  324. void Desktop::Displays::findDisplays (float masterScale)
  325. {
  326. JUCE_AUTORELEASEPOOL
  327. {
  328. UIScreen* s = [UIScreen mainScreen];
  329. Display d;
  330. d.userArea = d.totalArea = UIViewComponentPeer::realScreenPosToRotated (convertToRectInt ([s bounds])) / masterScale;
  331. d.isMain = true;
  332. d.scale = masterScale;
  333. if ([s respondsToSelector: @selector (scale)])
  334. d.scale *= s.scale;
  335. d.dpi = 160 * d.scale;
  336. displays.add (d);
  337. }
  338. }