iOS Multitasking

Hi,

I am trying to implement Multitasking for iPads in iOS (two Apps side by side). To achieve this e.g. with the JUCE DemoRunner I just enabled all device orientations for iPad and unselected “Requires full screen”.

Now I am struggling with resizing my window to the space available. It seems Juce keeps setting the window to be the complete screen size of the device instead of just the part that is available for my app. This leads to a part of my app being concealed by the second app. Please see screenshot attached.

Digging into the iOS implementation it seems that
JuceUIViewController::viewWillTransitionToSize: (CGSize) size withTransitionCoordinator: (id) coordinator is not always called when I adjust the size of my window (but always when I change device orientation). And if it is called the size argument is ignored by Juce which instead uses Desktop::getInstance().getDisplays().getMainDisplay().userArea which in turn seems to hold the complete screen and not the portion that is available to my app.

Any ideas on how to fix this?

All the best,
Roman

PNG

2 Likes

Hi Roman, funnily enough I’m facing the same problem, and would love to have a solution.

Jules, any chance you can resolve this for us?

Pete

I’ve been able to get this working for both cases:
a) when my app starts full screen, and another app is dragged-in via the task bar
b) where another app starts first and my app is dragged-up via the task bar.

My solution thus far is pretty simple:

  1. in the .plist file:
    UIRequiresFullScreen

  2. in juce_ios_UIViewComponentPeer.mm:

// Declare two statics (yes, ugly, I know!)

CGSize GUseWindowSize;
static bool GbGotUseWindowSize = false;

//...

// Modify method:
- (void) viewWillTransitionToSize: (CGSize) size withTransitionCoordinator: (id<UIViewControllerTransitionCoordinator>) coordinator
{
    GUseWindowSize = size;
    GbGotUseWindowSize = true;

//...
// Modify constructor UIViewComponentPeer::UIViewComponentPeer
//...
{
    CGRect r = convertToCGRect (component.getBounds());

    if (GbGotUseWindowSize) {
        r.size = GUseWindowSize;
    }

//...
// Modify UIWindow constructor:
//...

        //window = [[JuceUIWindow alloc] initWithFrame: r];
        window = [[JuceUIWindow alloc] init]; // Multitasking change
        if (GbGotUseWindowSize == false) {
            GbGotUseWindowSize = true;
            GUseWindowSize = window.bounds.size;
            view.bounds.size = GUseWindowSize;
        }

// Disable flag setting:
        //window.autoresizesSubviews = NO;
  1. Modify juce_ios_Windowing.mm
extern CGSize GUseWindowSize;
extern bool GbGotUseWindowSize;

void Desktop::Displays::findDisplays (float masterScale)
{
    JUCE_AUTORELEASEPOOL
    {
        UIScreen* s = [UIScreen mainScreen];

        auto theBounds = [s bounds];
        if (GbGotUseWindowSize) {
            theBounds.size = GUseWindowSize;
        }

        Display d;
        d.userArea = d.totalArea = UIViewComponentPeer::realScreenPosToRotated (convertToRectInt (theBounds)) / masterScale;

Of course, this is just a hack, maybe not all the changes are correct, and will no doubt need to be finessed.

That said: Jules & team - is there any chance you could merge-in a tidied-up version of the above into the code base?

Testing notes: to use multi-tasking on iPad, in case this helps!

  • start your app
  • drag-up enough to show the Task Bar
  • select icon in task bar, and drag to left/right of the current app; it’ll show a window where you app will appear
  • you can then drag the central splitter left/right to resize, or if you drag fully left/right both apps become full screen mode.
  • only some apps work of course - including the built-in Reminders app (very useful for testing on Simulator!) and Safari.

Thanks,

Pete

Thanks for looking into this and posting your solution. I’ll add this to our backlog and hopefully we’ll get around to looking at it soon.

Thanks. Just tidied-up the code formatting a bit to make it clearer for you. As you can see, the changes are pretty simple! Pete