Fullscreen on Mobile, windowed on Desktop

I’ve had a real struggle configuring a 7-year-old JUCE app to handle this.

Even creating a fresh Projucer project I had to fiddle a lot.

Shouldn’t this be the out-of-the-box / hello-world / default? Seems the most natural/expected behaviour to me.

Sharing my solution mainly as it doesn’t feel comfortable yet, so if I’m missing something obvious, please do say!

So what I did first was “update” my boilerplate code by creating a fresh project from the ProJucer and ripping code from Main.cpp and MainComponent.{cpp/h}.

NOTE: One thing I realized was that simultaneously having open iOS and macOS XCode windows (opened from the Projucer exporters) was messing with flags like JUCE_IOS – A #if JUCE_IOS block was mis-colouring (and mis-executing). To fix, I needed to close all XCode windows and re-export the target-of-interest.

Ok so here’s the working code:

    class MainWindow : public juce::DocumentWindow
    {
    public:
        MainWindow(juce::String name)
            : DocumentWindow(
                name,
                juce::Desktop::getInstance().getDefaultLookAndFeel().findColour(
                    juce::ResizableWindow::backgroundColourId
                ),
                DocumentWindow::allButtons
            )  // above here is all boilerplate
        {
            setUsingNativeTitleBar (true);
           #if JUCE_IOS || JUCE_ANDROID
            bool resizeToFitWhenContentChangesSize = false;
           #else
            bool resizeToFitWhenContentChangesSize = true;
           #endif
            setContentOwned (new MainContentComponent(), resizeToFitWhenContentChangesSize );

           #if JUCE_IOS || JUCE_ANDROID
            setFullScreen (true);
           #else
            setResizable (true, true);
//            setSize(1024, 768);
            centreWithSize (getWidth(), getHeight());
           #endif

            setVisible (true);
        }

Shouldn’t something like this be in the boilerplate that gets auto-generated by the Projucer?

Also to make it work for desktop, I have to add a setSize to the END of my MainComponent’s c’tor:

class MainContentComponent : public Component
                            ,private Button::Listener
                            ,private MidiInputCallback
                            ,public ActionListener
{
private:
    SharedResourcePointer<AudioSettings> sharedAudioSettings;
    TextButton btnInput, btnOutput;

    std::unique_ptr<PiSynthPlayer> pSynthPlayer;
    std::unique_ptr<Wheel> pWheel;
    std::unique_ptr<GameLogic> pGameLogic;

public:
    MainContentComponent()
    {
//        setSize (800, 600);

        addAndMakeVisible(&btnInput);
        btnInput.setButtonText("Input");
        btnInput.addListener(this);
        btnInput.setColour(TextButton::buttonColourId, Colours::red);

        addAndMakeVisible(&btnOutput);
        btnOutput.setButtonText("Output");
        btnOutput.addListener(this);
        btnOutput.setColour(TextButton::buttonColourId, Colours::green);

        // - - - - - - -
        pWheel = std::make_unique<Wheel>();
        addAndMakeVisible(pWheel.get());
        pWheel->addActionListener(this);
        pWheel->setVisible(true);
        pWheel->toFront(true);

        // - - - - - - -
        pSynthPlayer = std::make_unique<PiSynthPlayer>(sharedAudioSettings->getOutputDeviceManager());

        sharedAudioSettings->getInputDeviceManager().setMidiInputDeviceEnabled(MidiInput::getAvailableDevices()[0].name, true);
        sharedAudioSettings->getInputDeviceManager().addMidiInputDeviceCallback(String(""), this);

        // - - - - - - -
        pGameLogic = std::make_unique<GameLogic>(pWheel.get(), pSynthPlayer.get());
        addAndMakeVisible(pGameLogic.get());

        //setWantsKeyboardFocus(true); // also see paint()
#if JUCE_MAC
        setSize(1024, 768);
#endif
    }

The only relevant line in that last block is the setSize. But it needs to go at the end of the c’tor. If it goes at the start, I get an assertion error:

    inline ValueType getWidth() const noexcept                      { return w; }
// line 133 of juce_Rectangle.h, EXC_BAD_ACCESS

I cannot figure out what’s the difference in putting it at the start/end of that c’tor.
Everything else seems to be components I’m adding in, and I don’t see how any of them could be affecting this crash.

Also it seems I have to setSize in the MainComponent.
If I try to do it in Main.cpp, like this:

           #if JUCE_IOS || JUCE_ANDROID
            setFullScreen (true);
           #else
            setResizable (true, true);
            setSize(1024, 768);
            centreWithSize (getWidth(), getHeight());
           #endif

… I now get an assert fail in juce_ResizableWindow.cpp line 244:

void ResizableWindow::childBoundsChanged (Component* child)
{
    if ((child == contentComponent) && (child != nullptr) && resizeToFitContent)
    {
        // not going to look very good if this component has a zero size..
        jassert (child->getWidth() > 0);

Can anyone help me to tidy up my code? I would like for the skeleton of the app to be as clean as I can get it.

PS It might be useful to have IS_MOBILE and IS_DESKTOP #define-s which are guaranteed to exist as either 0 or 1. This would allow a more compact x = IS_MOBILE ? foo : bar syntax.

1 Like

Can you use the same approach as we do in the DemoRunner?

1 Like