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.

juce_ios_Windowing.mm 13KB

9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
10 years ago
10 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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. //xxx
  92. //AudioServicesPlaySystemSound ();
  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. [[UIApplication sharedApplication] setIdleTimerDisabled: ! isEnabled];
  269. }
  270. bool Desktop::isScreenSaverEnabled()
  271. {
  272. return ! [[UIApplication sharedApplication] isIdleTimerDisabled];
  273. }
  274. //==============================================================================
  275. bool juce_areThereAnyAlwaysOnTopWindows()
  276. {
  277. return false;
  278. }
  279. //==============================================================================
  280. Image juce_createIconForFile (const File&)
  281. {
  282. return Image::null;
  283. }
  284. //==============================================================================
  285. void SystemClipboard::copyTextToClipboard (const String& text)
  286. {
  287. [[UIPasteboard generalPasteboard] setValue: juceStringToNS (text)
  288. forPasteboardType: @"public.text"];
  289. }
  290. String SystemClipboard::getTextFromClipboard()
  291. {
  292. return nsStringToJuce ([[UIPasteboard generalPasteboard] valueForPasteboardType: @"public.text"]);
  293. }
  294. //==============================================================================
  295. bool MouseInputSource::SourceList::addSource()
  296. {
  297. addSource (sources.size(), false);
  298. return true;
  299. }
  300. bool Desktop::canUseSemiTransparentWindows() noexcept
  301. {
  302. return true;
  303. }
  304. Point<float> MouseInputSource::getCurrentRawMousePosition()
  305. {
  306. return juce_lastMousePos;
  307. }
  308. void MouseInputSource::setRawMousePosition (Point<float>)
  309. {
  310. }
  311. double Desktop::getDefaultMasterScale()
  312. {
  313. return 1.0;
  314. }
  315. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  316. {
  317. return Orientations::convertToJuce ([[UIApplication sharedApplication] statusBarOrientation]);
  318. }
  319. void Desktop::Displays::findDisplays (float masterScale)
  320. {
  321. JUCE_AUTORELEASEPOOL
  322. {
  323. UIScreen* s = [UIScreen mainScreen];
  324. Display d;
  325. d.userArea = d.totalArea = UIViewComponentPeer::realScreenPosToRotated (convertToRectInt ([s bounds])) / masterScale;
  326. d.isMain = true;
  327. d.scale = masterScale;
  328. if ([s respondsToSelector: @selector (scale)])
  329. d.scale *= s.scale;
  330. d.dpi = 160 * d.scale;
  331. displays.add (d);
  332. }
  333. }