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.

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