exitModalState not working?


#1

has something changed recently with the exitModalState function? It has worked fine for me on Mac and Windows, but after an update to the tip last night it seems that it doesn’t work anymore on Mac. Windows has no problems.

I just put a Component in a modal state and have some thread try to get it out of the modal state with exitModalState after it has finished.


#2

update:

setprogress with a ThreadWithProgressWindow also stopped working for me on a Mac, it doesn’t update. However, the Juce demo works perfect, so it must be something that I have to change because of a change in Juce?


#3

Can’t think of anything I’ve changed recently that might have affected that…?


#4

it puzzles me too, must be something stupid I have forgot…

I’ll roll back and see what happens.


#5

I did some research and found the following, also true for your demo:

when I run a ThreadWithProgress Window from a menu perform function, it doesn’t get updated. Running the same code from for example the buttonclicked method works fine. This is only the case for Mac, Windows is ok here. I don’t know if my original exitModalState problem has something to do with this, but it seems that there is something going on with threading in Mac? It used to run fine here.


#6

But in the demo, the threadwithprogress demo is triggered from a menu, and it works fine here on my mac…?


#7

in the version I have of your demo it is invoked in the buttonClicked method, line 1305 in the WidgetsDemo file.


#8

anyway, if you add:

[code]//==============================================================================
class DemoBackgroundThread : public ThreadWithProgressWindow
{
public:
DemoBackgroundThread()
: ThreadWithProgressWindow (T(“busy doing some important things…”),
true,
true)
{
setStatusMessage (T(“Getting ready…”));
}

~DemoBackgroundThread()
{
}

void run()
{
    setProgress (-1.0); // setting a value beyond the range 0 -> 1 will show a spinning bar..
    setStatusMessage (T("Preparing to do some stuff..."));
    wait (2000);

    const int thingsToDo = 10;

    for (int i = 0; i < thingsToDo; ++i)
    {
        // must check this as often as possible, because this is
        // how we know if the user's pressed 'cancel'
        if (threadShouldExit())
            return;

        // this will update the progress bar on the dialog box
        setProgress (i / (double) thingsToDo);

        setStatusMessage (String (thingsToDo - i) + T(" things left to do..."));

        wait (500);
    }

    setProgress (-1.0); // setting a value beyond the range 0 -> 1 will show a spinning bar..
    setStatusMessage (T("Finishing off the last few bits and pieces!"));
    wait (2000);
}

};
[/code]
to the MainDemoWindow.cpp file and add:

[code] DemoBackgroundThread demoThread;

                if (demoThread.runThread())
                {
                    // thread finished normally..
                    AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                                 T("Progress window"),
                                                 T("Thread finished ok!"));
                }
                else
                {
                    // user pressed the cancel button..
                    AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                                 T("Progress window"),
                                                 T("You pressed cancel!"));
                }

[/code]

to one of the functions in the perform method, it fails to run properly on my Intel and G4 Macs, but runs fine on Windows


#9

Agh… Yes, you’ve found a nasty one there! This is because I changed the way the mac messages get delivered, but it looks like OSX is refusing to let you dispatch any UI events inside a CFTimer callback.

Unfortunately, this will involve some serious re-writing of mac messaging to fix. I’ll do it right away, but not sure when I’ll be able to check in a fix.


#10

in the meantime, can you point me to a version just before this was changed? I need to release real soon…


#11

Ok, I’ve got a nice fix now. Try replacing this class in juce_mac_MessageManager.mm:

[code]class AppDelegateRedirector
{
public:
AppDelegateRedirector()
{
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
runLoop = CFRunLoopGetMain();
#else
runLoop = CFRunLoopGetCurrent();
#endif
CFRunLoopSourceContext sourceContext;
zerostruct (sourceContext);
sourceContext.info = this;
sourceContext.perform = runLoopSourceCallback;
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
}

virtual ~AppDelegateRedirector()
{
    CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
    CFRunLoopSourceInvalidate (runLoopSource);
    CFRelease (runLoopSource);

    while (messages.size() > 0)
        delete ((Message*) messages.remove(0));
}

virtual NSApplicationTerminateReply shouldTerminate()
{
    if (JUCEApplication::getInstance() != 0)
    {
        JUCEApplication::getInstance()->systemRequestedQuit();
        return NSTerminateCancel;
    }

    return NSTerminateNow;
}

virtual BOOL openFile (const NSString* filename)
{
    if (JUCEApplication::getInstance() != 0)
    {
        JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename));
        return YES;
    }

    return NO;
}

virtual void openFiles (NSArray* filenames)
{
    StringArray files;
    for (unsigned int i = 0; i < [filenames count]; ++i)
    {
        String filename (nsStringToJuce ((NSString*) [filenames objectAtIndex: i]));
        if (filename.containsChar (T(' ')))
            filename = filename.quoted('"');

        files.add (filename);
    }

    if (files.size() > 0 && JUCEApplication::getInstance() != 0)
    {
        JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" ")));
    }
}

virtual void focusChanged()
{
    juce_HandleProcessFocusChange();
}

virtual void performCallback (CallbackMessagePayload* pl)
{
    pl->result = (*pl->function) (pl->parameter);
    pl->hasBeenExecuted = true;
}

virtual void deleteSelf()
{
    delete this;
}

void postMessage (void* m) throw()
{
    messages.add (m);
    CFRunLoopSourceSignal (runLoopSource);
    CFRunLoopWakeUp (runLoop);
}

private:
CFRunLoopRef runLoop;
CFRunLoopSourceRef runLoopSource;
Array <void*, CriticalSection> messages;

void runLoopCallback() throw()
{
    int numDispatched = 0;

    do
    {
        void* const nextMessage = messages.remove (0);

        if (nextMessage == 0)
            return;

        const ScopedAutoReleasePool pool;
        MessageManager::getInstance()->deliverMessage (nextMessage);

    } while (++numDispatched <= 4);

    CFRunLoopSourceSignal (runLoopSource);
    CFRunLoopWakeUp (runLoop);
}

static void runLoopSourceCallback (void* info)
{
    ((AppDelegateRedirector*) info)->runLoopCallback();
}

};[/code]


#12

you have saved my day! works perfectly, you can check that in

thank you very much!

Pieter Stenekes


#13

It’s actually a bit more efficient than the old messaging code too.


#14