Git Product home page Git Product logo

Comments (10)

tsl0922 avatar tsl0922 commented on June 28, 2024 1

I'm OK with a callback api. It's not hard to implement the check api myself on top of callback.

from nativefiledialog-extended.

btzy avatar btzy commented on June 28, 2024

Hi,

I think it isn't possible on macOS to have the file dialog run on a non-main thread. There's this StackOverflow question about it, which seems to also say that it isn't possible. #46 seems to assume that it's impossible to open the file dialog from a non-main thread, maybe you can try asking them about it.

Actually, I'm not sure if what you're doing is guaranteed to work on Windows and Linux. For Windows, it seems to be possible to create windows in threads, but it seems like there's some additional setup that needs to be done for that to work.

from nativefiledialog-extended.

tsl0922 avatar tsl0922 commented on June 28, 2024

Hi, I've managed to make async call work on macOS, will you accept a PR for it? @btzy

Sample code to make NFD_OpenDialogN can be called from none main thread:

nfdresult_t NFD_OpenDialogN() {
    __block nfdresult_t result = NFD_CANCEL;

    if ([NSThread isMainThread]) {
        NSOpenPanel* dialog = [NSOpenPanel openPanel];
        NSModalResponse resp = [dialog runModal];
        // result = ...
    } else {
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        dispatch_async(dispatch_get_main_queue(), ^{
            NSOpenPanel* dialog = [NSOpenPanel openPanel];
            [dialog beginWithCompletionHandler:^(NSModalResponse resp) {
                // result = ...
                dispatch_semaphore_signal(semaphore);
            }];
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }

    return result
}

The idea is from Rusty File Dialog, which supports async on both windows / Linux / macOS.

from nativefiledialog-extended.

btzy avatar btzy commented on June 28, 2024

I think there're two separate things in the code above:

  1. The code is async in the sense that it does not block the main thread. This is because beginWithCompletionHandler returns immediately without waiting for the dialog to complete. When the dialog is complete (i.e. the user pressed "OK" or "Cancel"), we will get a callback via the completion handler, and it will be called on an arbitrary thread. This allows the main thread to do other things, and is usually what we mean when we talk about async file dialogs.
  2. The dialog can be invoked from threads other than the main thread. This is because the code does dispatch_async(dispatch_get_main_queue(), ...). This will only work if the main thread is running a regular macOS event loop, but won't work if it is some console program which doesn't use the regular event loop (since there main thread won't poll the queue in that case).

I find your proposed solution kind of hacky for what the OP wants to do: They want to open a file dialog asynchronously, but instead the program performs a delicate dance between threads, by spawning a new thread which then invokes the main thread again to start the task (which will only start if they are using a regular macOS event loop). We should just have the main thread call beginWithCompletionHandler directly without spawning the secondary thread.

I think we can design a more proper async API at some point - something like OpenDialogAsync(..., void (*handler)(void*, nfdresult_t, char*), void* context) (exact API up to discussion). But we should properly understand how opening a non-model dialog works on Windows and on Linux first. For Linux I believe it is possible to not have the callback be invoked on a separate thread at all (using some kind of epoll-ish mechanism, where we have an fd that will trigger when the dialog is complete), so there's a question of whether we want to support that in some way too (I think probably not though, since such mechanisms are quite OS-specific).

from nativefiledialog-extended.

tsl0922 avatar tsl0922 commented on June 28, 2024

I find your proposed solution kind of hacky
I think we can design a more proper async API at some point

I agree, will you consider implementing an async API?

a OpenDialogAsync API may not be enough, it's better to provide a boo wait(int timeout) API that allow the caller to check if the dialog is finish and return control to the caller (similay to the approch used by portable-file-dialogs).

In fact, I'm going to make a wrapper like that in my application.

from nativefiledialog-extended.

btzy avatar btzy commented on June 28, 2024

Can you explain why a bool wait(int timeout) API is preferable? It seems worse than an OpenDialogAsync API to me for at least three reasons:

  • Calling that function freezes up your application for however long you specify to wait for.
  • The only way to properly wait for the dialog to be completed is to keep calling wait() in a tight loop, which takes up CPU cycles.
  • It is easy to implement your wait API on top of OpenDialogAsync, but the other way around can only be done with busy waiting.

The wait API seems to me to be like an inferior attempt at coroutines.

from nativefiledialog-extended.

tsl0922 avatar tsl0922 commented on June 28, 2024

I'm using it in an imgui app (glfw+opengl3), which will run my code in every frame (event loop).

To check async result in a loop without blocking the loop forever, the try+wait API maybe useful.

from nativefiledialog-extended.

btzy avatar btzy commented on June 28, 2024

I'm using it in an imgui app (glfw+opengl3), which will run my code in every frame (event loop).

In this case, aren't you going to pass a timeout of zero (i.e. it becomes more like a poll() API)?

from nativefiledialog-extended.

tsl0922 avatar tsl0922 commented on June 28, 2024

Yes, will pass it with 0.

The wait+timeout api is more like what a c++ future provides, it's more flexible for general use case.

from nativefiledialog-extended.

btzy avatar btzy commented on June 28, 2024

I'm still not really convinced that wait+timeout will be useful for file dialogs, and I'm more of the opinion that those who want async file dialogs will mostly use the callback API. I think this design decision will also be affected by how the platform-specific APIs work - if most OSes provide a wait+timeout API, then I would be more inclined to implement it in NFD; however if most of them provide a callback API, then I would gravitate toward something like OpenDialogAsync.

from nativefiledialog-extended.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.