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.

1 Like

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

Hi Folks, I’ve just started to look at transitioning the Wotja code base from JUCE 5 to JUCE 6.

I’ve put this off for a long time, as I’ve had to make a lot of fixes to JUCE over the past few years.

Anyhow, the most complex set of change is related to this issue. I see it still isn’t implemented in JUCE 6?

To verify this for yourself, is really really simple to prove.

  1. in the .plist file: set UIRequiresFullScreen to NO
  2. build and run your iPad app
  3. Try using multi-tasking / split screen. Here is what I do (on Simulator)

a) where nothing yet running i.e. your app starts first

  • start your iPad app running
  • drag-up enough to show the Task Bar
  • start-up
  • select the Safari or Reminders app icon (both these apps support split screen) 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.

b) where another app is running, and you want to see if your pre-deployed app starts-up properly in split screen mode:

  • start-up Safari (as that supports split screen mode) or Reminders app (ditto)
  • drag-up enough to show the Task Bar
  • select your app’s 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.

I have had to change both juce_ios_UIViewComponentPeer.mm and juce_ios_Windowing.mm extensively to fix this again in JUCE6, but it is working well again! Do please contact me if you want my code, so you can patch it back in.

Best wishes as always,

Pete

I’ve just pushed a fix which should enable support for iOS multitasking:

As before, you’ll need to make the following changes to your project to enable multitasking:

  • Set UIRequiresFullScreen to false in the app’s plist
  • Ensure that all screen orientations are enabled for the app

This patch seems to work well in the DemoRunner and AudioPluginHost - hopefully it will work well for your use-case too. Let us know if not, and I’ll take another look.

Hi - thanks for this!

I’ve just been pushing-out a new Wotja release, but will hopefully try out your code and report back sometime later today; failing that, in just a day or two; merging-in changes from the main Juce distribution is always a bit tough, as I’ve had to patch Juce pretty heavily to work well cross platform!

Best wishes,

Pete