1/*
2  ==============================================================================
3
4   This file is part of the JUCE library.
5   Copyright (c) 2020 - Raw Material Software Limited
6
7   JUCE is an open source library subject to commercial or open-source
8   licensing.
9
10   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12
13   End User License Agreement: www.juce.com/juce-6-licence
14   Privacy Policy: www.juce.com/juce-privacy-policy
15
16   Or: You may also use this code under the terms of the GPL v3 (see
17   www.gnu.org/licenses).
18
19   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21   DISCLAIMED.
22
23  ==============================================================================
24*/
25
26namespace juce
27{
28    extern bool isIOSAppActive;
29
30    struct AppInactivityCallback // NB: careful, this declaration is duplicated in other modules
31    {
32        virtual ~AppInactivityCallback() = default;
33        virtual void appBecomingInactive() = 0;
34    };
35
36    // This is an internal list of callbacks (but currently used between modules)
37    Array<AppInactivityCallback*> appBecomingInactiveCallbacks;
38}
39
40#if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
41@interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate, UNUserNotificationCenterDelegate>
42#else
43@interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate>
44#endif
45{
46    UIBackgroundTaskIdentifier appSuspendTask;
47}
48
49@property (strong, nonatomic) UIWindow *window;
50- (id) init;
51- (void) dealloc;
52- (void) applicationDidFinishLaunching: (UIApplication*) application;
53- (void) applicationWillTerminate: (UIApplication*) application;
54- (void) applicationDidEnterBackground: (UIApplication*) application;
55- (void) applicationWillEnterForeground: (UIApplication*) application;
56- (void) applicationDidBecomeActive: (UIApplication*) application;
57- (void) applicationWillResignActive: (UIApplication*) application;
58- (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*) identifier
59   completionHandler: (void (^)(void)) completionHandler;
60- (void) applicationDidReceiveMemoryWarning: (UIApplication *) application;
61#if JUCE_PUSH_NOTIFICATIONS
62- (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings;
63- (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken;
64- (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error;
65- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo;
66- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
67  fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler;
68- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
69  forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
70   completionHandler: (void(^)()) completionHandler;
71- (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification;
72- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
73  forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler;
74- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
75  forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
76   completionHandler: (void(^)()) completionHandler;
77#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
78- (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
79          withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler;
80- (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
81          withCompletionHandler: (void(^)())completionHandler;
82#endif
83#endif
84
85@end
86
87@implementation JuceAppStartupDelegate
88
89    NSObject* _pushNotificationsDelegate;
90
91- (id) init
92{
93    self = [super init];
94    appSuspendTask = UIBackgroundTaskInvalid;
95
96   #if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
97    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
98   #endif
99
100    return self;
101}
102
103- (void) dealloc
104{
105    [super dealloc];
106}
107
108- (void) applicationDidFinishLaunching: (UIApplication*) application
109{
110    ignoreUnused (application);
111    initialiseJuce_GUI();
112
113    if (auto* app = JUCEApplicationBase::createInstance())
114    {
115        if (! app->initialiseApp())
116            exit (app->shutdownApp());
117    }
118    else
119    {
120        jassertfalse; // you must supply an application object for an iOS app!
121    }
122}
123
124- (void) applicationWillTerminate: (UIApplication*) application
125{
126    ignoreUnused (application);
127    JUCEApplicationBase::appWillTerminateByForce();
128}
129
130- (void) applicationDidEnterBackground: (UIApplication*) application
131{
132    if (auto* app = JUCEApplicationBase::getInstance())
133    {
134       #if JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK
135        appSuspendTask = [application beginBackgroundTaskWithName:@"JUCE Suspend Task" expirationHandler:^{
136            if (appSuspendTask != UIBackgroundTaskInvalid)
137            {
138                [application endBackgroundTask:appSuspendTask];
139                appSuspendTask = UIBackgroundTaskInvalid;
140            }
141        }];
142
143        MessageManager::callAsync ([app] { app->suspended(); });
144       #else
145        ignoreUnused (application);
146        app->suspended();
147       #endif
148    }
149}
150
151- (void) applicationWillEnterForeground: (UIApplication*) application
152{
153    ignoreUnused (application);
154
155    if (auto* app = JUCEApplicationBase::getInstance())
156        app->resumed();
157}
158
159- (void) applicationDidBecomeActive: (UIApplication*) application
160{
161    application.applicationIconBadgeNumber = 0;
162
163    isIOSAppActive = true;
164}
165
166- (void) applicationWillResignActive: (UIApplication*) application
167{
168    ignoreUnused (application);
169    isIOSAppActive = false;
170
171    for (int i = appBecomingInactiveCallbacks.size(); --i >= 0;)
172        appBecomingInactiveCallbacks.getReference(i)->appBecomingInactive();
173}
174
175- (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*)identifier
176   completionHandler: (void (^)(void))completionHandler
177{
178    ignoreUnused (application);
179    URL::DownloadTask::juce_iosURLSessionNotify (nsStringToJuce (identifier));
180    completionHandler();
181}
182
183- (void) applicationDidReceiveMemoryWarning: (UIApplication*) application
184{
185    ignoreUnused (application);
186
187    if (auto* app = JUCEApplicationBase::getInstance())
188        app->memoryWarningReceived();
189}
190
191- (void) setPushNotificationsDelegateToUse: (NSObject*) delegate
192{
193    _pushNotificationsDelegate = delegate;
194}
195
196#if JUCE_PUSH_NOTIFICATIONS
197- (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings
198{
199    ignoreUnused (application);
200
201    SEL selector = NSSelectorFromString (@"application:didRegisterUserNotificationSettings:");
202
203    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
204    {
205        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
206        [invocation setSelector: selector];
207        [invocation setTarget: _pushNotificationsDelegate];
208        [invocation setArgument: &application          atIndex:2];
209        [invocation setArgument: &notificationSettings atIndex:3];
210
211        [invocation invoke];
212    }
213}
214
215- (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken
216{
217    ignoreUnused (application);
218
219    SEL selector = NSSelectorFromString (@"application:didRegisterForRemoteNotificationsWithDeviceToken:");
220
221    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
222    {
223        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
224        [invocation setSelector: selector];
225        [invocation setTarget: _pushNotificationsDelegate];
226        [invocation setArgument: &application atIndex:2];
227        [invocation setArgument: &deviceToken atIndex:3];
228
229        [invocation invoke];
230    }
231}
232
233- (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error
234{
235    ignoreUnused (application);
236
237    SEL selector = NSSelectorFromString (@"application:didFailToRegisterForRemoteNotificationsWithError:");
238
239    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
240    {
241        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
242        [invocation setSelector: selector];
243        [invocation setTarget: _pushNotificationsDelegate];
244        [invocation setArgument: &application atIndex:2];
245        [invocation setArgument: &error       atIndex:3];
246
247        [invocation invoke];
248    }
249}
250
251- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
252{
253    ignoreUnused (application);
254
255    SEL selector = NSSelectorFromString (@"application:didReceiveRemoteNotification:");
256
257    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
258    {
259        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
260        [invocation setSelector: selector];
261        [invocation setTarget: _pushNotificationsDelegate];
262        [invocation setArgument: &application atIndex:2];
263        [invocation setArgument: &userInfo    atIndex:3];
264
265        [invocation invoke];
266    }
267}
268
269- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
270  fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler
271{
272    ignoreUnused (application);
273
274    SEL selector = NSSelectorFromString (@"application:didReceiveRemoteNotification:fetchCompletionHandler:");
275
276    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
277    {
278        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
279        [invocation setSelector: selector];
280        [invocation setTarget: _pushNotificationsDelegate];
281        [invocation setArgument: &application       atIndex:2];
282        [invocation setArgument: &userInfo          atIndex:3];
283        [invocation setArgument: &completionHandler atIndex:4];
284
285        [invocation invoke];
286    }
287}
288
289- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
290  forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
291  completionHandler: (void(^)()) completionHandler
292{
293    ignoreUnused (application);
294
295    SEL selector = NSSelectorFromString (@"application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:");
296
297    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
298    {
299        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
300        [invocation setSelector: selector];
301        [invocation setTarget: _pushNotificationsDelegate];
302        [invocation setArgument: &application       atIndex:2];
303        [invocation setArgument: &identifier        atIndex:3];
304        [invocation setArgument: &userInfo          atIndex:4];
305        [invocation setArgument: &responseInfo      atIndex:5];
306        [invocation setArgument: &completionHandler atIndex:6];
307
308        [invocation invoke];
309    }
310}
311
312- (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification
313{
314    ignoreUnused (application);
315
316    SEL selector = NSSelectorFromString (@"application:didReceiveLocalNotification:");
317
318    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
319    {
320        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
321        [invocation setSelector: selector];
322        [invocation setTarget: _pushNotificationsDelegate];
323        [invocation setArgument: &application  atIndex:2];
324        [invocation setArgument: &notification atIndex:3];
325
326        [invocation invoke];
327    }
328}
329
330- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
331  forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler
332{
333    ignoreUnused (application);
334
335    SEL selector = NSSelectorFromString (@"application:handleActionWithIdentifier:forLocalNotification:completionHandler:");
336
337    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
338    {
339        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
340        [invocation setSelector: selector];
341        [invocation setTarget: _pushNotificationsDelegate];
342        [invocation setArgument: &application       atIndex:2];
343        [invocation setArgument: &identifier        atIndex:3];
344        [invocation setArgument: &notification      atIndex:4];
345        [invocation setArgument: &completionHandler atIndex:5];
346
347        [invocation invoke];
348    }
349}
350
351- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
352  forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
353  completionHandler: (void(^)()) completionHandler
354{
355    ignoreUnused (application);
356
357    SEL selector = NSSelectorFromString (@"application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:");
358
359    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
360    {
361        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
362        [invocation setSelector: selector];
363        [invocation setTarget: _pushNotificationsDelegate];
364        [invocation setArgument: &application       atIndex:2];
365        [invocation setArgument: &identifier        atIndex:3];
366        [invocation setArgument: &notification      atIndex:4];
367        [invocation setArgument: &responseInfo      atIndex:5];
368        [invocation setArgument: &completionHandler atIndex:6];
369
370        [invocation invoke];
371    }
372}
373
374#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
375- (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
376         withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler
377{
378    ignoreUnused (center);
379
380    SEL selector = NSSelectorFromString (@"userNotificationCenter:willPresentNotification:withCompletionHandler:");
381
382    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
383    {
384        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
385        [invocation setSelector: selector];
386        [invocation setTarget: _pushNotificationsDelegate];
387        [invocation setArgument: &center            atIndex:2];
388        [invocation setArgument: &notification      atIndex:3];
389        [invocation setArgument: &completionHandler atIndex:4];
390
391        [invocation invoke];
392    }
393}
394
395- (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
396         withCompletionHandler: (void(^)()) completionHandler
397{
398    ignoreUnused (center);
399
400    SEL selector = NSSelectorFromString (@"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:");
401
402    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
403    {
404        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
405        [invocation setSelector: selector];
406        [invocation setTarget: _pushNotificationsDelegate];
407        [invocation setArgument: &center            atIndex:2];
408        [invocation setArgument: &response          atIndex:3];
409        [invocation setArgument: &completionHandler atIndex:4];
410
411        [invocation invoke];
412    }
413}
414#endif
415#endif
416
417@end
418
419namespace juce
420{
421
422int juce_iOSMain (int argc, const char* argv[], void* customDelegatePtr);
423int juce_iOSMain (int argc, const char* argv[], void* customDelegatePtr)
424{
425    Class delegateClass = (customDelegatePtr != nullptr ? reinterpret_cast<Class> (customDelegatePtr) : [JuceAppStartupDelegate class]);
426
427    return UIApplicationMain (argc, const_cast<char**> (argv), nil, NSStringFromClass (delegateClass));
428}
429
430//==============================================================================
431void LookAndFeel::playAlertSound()
432{
433    // TODO
434}
435
436//==============================================================================
437class iOSMessageBox
438{
439public:
440    iOSMessageBox (const String& title, const String& message,
441                   NSString* button1, NSString* button2, NSString* button3,
442                   ModalComponentManager::Callback* cb, const bool async)
443        : result (0), resultReceived (false), callback (cb), isAsync (async)
444    {
445        if (currentlyFocusedPeer != nullptr)
446        {
447            UIAlertController* alert = [UIAlertController alertControllerWithTitle: juceStringToNS (title)
448                                                                           message: juceStringToNS (message)
449                                                                    preferredStyle: UIAlertControllerStyleAlert];
450            addButton (alert, button1, 0);
451            addButton (alert, button2, 1);
452            addButton (alert, button3, 2);
453
454            [currentlyFocusedPeer->controller presentViewController: alert
455                                                           animated: YES
456                                                         completion: nil];
457        }
458        else
459        {
460            // Since iOS8, alert windows need to be associated with a window, so you need to
461            // have at least one window on screen when you use this
462            jassertfalse;
463        }
464    }
465
466    int getResult()
467    {
468        jassert (callback == nullptr);
469
470        JUCE_AUTORELEASEPOOL
471        {
472            while (! resultReceived)
473                [[NSRunLoop mainRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
474        }
475
476        return result;
477    }
478
479    void buttonClicked (const int buttonIndex) noexcept
480    {
481        result = buttonIndex;
482        resultReceived = true;
483
484        if (callback != nullptr)
485            callback->modalStateFinished (result);
486
487        if (isAsync)
488            delete this;
489    }
490
491private:
492    int result;
493    bool resultReceived;
494    std::unique_ptr<ModalComponentManager::Callback> callback;
495    const bool isAsync;
496
497    void addButton (UIAlertController* alert, NSString* text, int index)
498    {
499        if (text != nil)
500            [alert addAction: [UIAlertAction actionWithTitle: text
501                                                       style: UIAlertActionStyleDefault
502                                                     handler: ^(UIAlertAction*) { this->buttonClicked (index); }]];
503    }
504
505    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox)
506};
507
508//==============================================================================
509#if JUCE_MODAL_LOOPS_PERMITTED
510void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType /*iconType*/,
511                                                     const String& title, const String& message,
512                                                     Component* /*associatedComponent*/)
513{
514    JUCE_AUTORELEASEPOOL
515    {
516        iOSMessageBox mb (title, message, @"OK", nil, nil, nullptr, false);
517        ignoreUnused (mb.getResult());
518    }
519}
520#endif
521
522void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
523                                                          const String& title, const String& message,
524                                                          Component* /*associatedComponent*/,
525                                                          ModalComponentManager::Callback* callback)
526{
527    new iOSMessageBox (title, message, @"OK", nil, nil, callback, true);
528}
529
530bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
531                                                      const String& title, const String& message,
532                                                      Component* /*associatedComponent*/,
533                                                      ModalComponentManager::Callback* callback)
534{
535    std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"OK",
536                                                          nil, callback, callback != nullptr));
537
538    if (callback == nullptr)
539        return mb->getResult() == 1;
540
541    mb.release();
542    return false;
543}
544
545int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
546                                                        const String& title, const String& message,
547                                                        Component* /*associatedComponent*/,
548                                                        ModalComponentManager::Callback* callback)
549{
550    std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"Cancel", @"Yes", @"No", callback, callback != nullptr));
551
552    if (callback == nullptr)
553        return mb->getResult();
554
555    mb.release();
556    return 0;
557}
558
559int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/,
560                                                  const String& title, const String& message,
561                                                  Component* /*associatedComponent*/,
562                                                  ModalComponentManager::Callback* callback)
563{
564    std::unique_ptr<iOSMessageBox> mb (new iOSMessageBox (title, message, @"No", @"Yes", nil, callback, callback != nullptr));
565
566    if (callback == nullptr)
567        return mb->getResult();
568
569    mb.release();
570    return 0;
571}
572
573//==============================================================================
574bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray&, bool, Component*, std::function<void()>)
575{
576    jassertfalse;    // no such thing on iOS!
577    return false;
578}
579
580bool DragAndDropContainer::performExternalDragDropOfText (const String&, Component*, std::function<void()>)
581{
582    jassertfalse;    // no such thing on iOS!
583    return false;
584}
585
586//==============================================================================
587void Desktop::setScreenSaverEnabled (const bool isEnabled)
588{
589    if (! SystemStats::isRunningInAppExtensionSandbox())
590        [[UIApplication sharedApplication] setIdleTimerDisabled: ! isEnabled];
591}
592
593bool Desktop::isScreenSaverEnabled()
594{
595    if (SystemStats::isRunningInAppExtensionSandbox())
596        return true;
597
598    return ! [[UIApplication sharedApplication] isIdleTimerDisabled];
599}
600
601//==============================================================================
602bool juce_areThereAnyAlwaysOnTopWindows()
603{
604    return false;
605}
606
607//==============================================================================
608Image juce_createIconForFile (const File&)
609{
610    return Image();
611}
612
613//==============================================================================
614void SystemClipboard::copyTextToClipboard (const String& text)
615{
616    [[UIPasteboard generalPasteboard] setValue: juceStringToNS (text)
617                             forPasteboardType: @"public.text"];
618}
619
620String SystemClipboard::getTextFromClipboard()
621{
622    return nsStringToJuce ([[UIPasteboard generalPasteboard] valueForPasteboardType: @"public.text"]);
623}
624
625//==============================================================================
626bool MouseInputSource::SourceList::addSource()
627{
628    addSource (sources.size(), MouseInputSource::InputSourceType::touch);
629    return true;
630}
631
632bool MouseInputSource::SourceList::canUseTouch()
633{
634    return true;
635}
636
637bool Desktop::canUseSemiTransparentWindows() noexcept
638{
639    return true;
640}
641
642Point<float> MouseInputSource::getCurrentRawMousePosition()
643{
644    return juce_lastMousePos;
645}
646
647void MouseInputSource::setRawMousePosition (Point<float>)
648{
649}
650
651double Desktop::getDefaultMasterScale()
652{
653    return 1.0;
654}
655
656Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
657{
658    UIInterfaceOrientation orientation = SystemStats::isRunningInAppExtensionSandbox() ? UIInterfaceOrientationPortrait
659                                                                                       : getWindowOrientation();
660
661    return Orientations::convertToJuce (orientation);
662}
663
664void Displays::findDisplays (float masterScale)
665{
666    JUCE_AUTORELEASEPOOL
667    {
668        UIScreen* s = [UIScreen mainScreen];
669
670        Display d;
671        d.userArea = d.totalArea = convertToRectInt ([s bounds]) / masterScale;
672        d.isMain = true;
673        d.scale = masterScale * s.scale;
674        d.dpi = 160 * d.scale;
675
676        displays.add (d);
677    }
678}
679
680} // namespace juce
681