Question

I'm trying to build a basic dynamic library for OS X that simply displays a dialog for opening files. My code looks something like this:

NSOpenPanel * dlg = [NSOpenPanel openPanel];
...//setting title and other properties for dlg

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_main_queue(), ^
{
    resButton = [dlg runModal];
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
if (resButton == NSFileHandlingPanelOKButton)//resButton is global
{...}

Now while this basically works, everything is a little bit off:

-The dialog never quite initializes twice the same way (different initial directories, layout mode...).

-Sometimes the initial directory is shown as being empty until I select another one and the first one again.

-"right click" menu won't show.

-Scrolling bounce back effect doesn't work (!!!). I can scroll downwards indefinitely until everything disappears.

-In column mode, previews do not work (the loading icon turns forever) although when viewing in large icon mode, images have their proper preview.

It's like there is a whole update thread that's not running. It's probably linked to the weird context in which the lib is called: from a java program using JNA. But I'm hoping maybe someone knows of a little trick that could fix things, like "just call [system startUpdateTask]" or something :)

Thanks for any help

Was it helpful?

Solution

(After comment response:)

Something for you to try (I can't test your scenario). NSOpenPanel/NSSavePanel are very delicate classes since the introduction of sandbox and need to be handled with care.

All UI operations need to be performed on the main thread, as you have discovered. However instead of using the dispatch_* functions try using a synchronous performSelectorOnMainThread:

NSOpenPanel * dlg = [NSOpenPanel openPanel];
... //setting title and other properties for dlg

resButton = [dlg performSelectorOnMainThread:@selector(runModal)
                                  withObject:nil
                               waitUntilDone:YES];

if (resButton == NSFileHandlingPanelOKButton) //resButton is global
{...}

That may solve your issue, or not...

Addendum

My bad, as you correctly point out performSelectorOnMainThread doesn't return a value. You can instead:

Add resButton as an instance variable to your class.

Add the method:

- (void) myRunModal:(NSOpenPanel *)dlg
{
   resButton = [dlg runModal];
}

Change the code to:

[self performSelectorOnMainThread:@selector(myRunModal:)
                       withObject:dlg
                    waitUntilDone:YES];

Or something similar.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top