btzy / nativefiledialog-extended

Cross platform (Windows, Mac, Linux) native file dialog library with C and C++ bindings, based on mlabbe/nativefiledialog.
zlib License
598 stars 89 forks source link

How does this project work? #103

Closed jcbhmr closed 1 year ago

jcbhmr commented 1 year ago

I'd be interested in learning more about how this project works. Some questions:

Why I'm curious: I'm interested in making a JavaScript wrapper around this API using https://napi.rs/ and https://github.com/btzy/nfde-rs and I was curious about some of the design decisions behind that Rust wrapper and that lead me to be curious about the design of the original library.

btzy commented 1 year ago

Hey,

That's a lot of questions.

What's the .m file? Beginner here. I googled and "An M file is a class implementation file used by programs written in Objective-C" Is this project written in .c or .cpp?

This project has a C interface. (This interface is nfd.h.) This means that after compiling this project into a static or shared library, you can use it with anything that knows how to call C code. C is the lingua franca of desktop programming, so almost any general-purpose programming language (including C++, Rust, Python, and JavaScript (NodeJS)) will have a way of calling C interfaces. For interpreted and garbage-collected languages like Python and JavaScript, this usually involves writing some boilerplate code (or autogenerating them using some tools) to marshal objects across languages.

This project is implemented in C++ (for Windows and Linux) and Objective-C (for MacOS). This means that to compile this project from source, you need to use a C++ or Objective-C compiler, depending that platform you are compiling for. (The nfd_cocoa.m file is the implementation for MacOS.) The required compilers are the standard compilers for each of the three operating systems, and can be downloaded easily for free from their official websites (or for Linux, it should come pre-installed). Once compiled into a static or shared library, however, its interface looks and behaves like a C library.

What's the high-level overview of what this project does? Is it basically a wrapper with #ifdef WINDOWS cascades for each platform? What's gtk?

I'm not sure what you're asking for here; the README should cover most high-level things. There are 3 .cpp files and 1 .m file in the src directory, and for each platform you will compile exactly one of those files. For Linux there are two implementations, GTK and Portal. Linux doesn't have a file dialog baked into the operating system, and most programs will use GTK (a GUI library) to show a file dialog. Portal is an interface on Linux that allows other GUI libraries (most notably KDE) to register themselves, so that applications can show their dialogs instead of GTK ones; this needs cooperation from applications because they need to open the file dialog through this interface, instead of directly calling GTK. The "Portal" implementation opens the file through this interface, and the "GTK" implementation calls GTK directly.

Why I'm curious: I'm interested in making a JavaScript wrapper around this API using https://napi.rs/ and https://github.com/btzy/nfde-rs and I was curious about some of the design decisions behind that Rust wrapper and that lead me to be curious about the design of the original library.

I would recommend trying to write/generate a JavaScript wrapper for this project directly, instead of trying to wrap nfde-rs. This is because nfde-rs is already a wrapper for this project, and having multiple wrapper layers add more dependencies (i.e. to build a JavaScript wrapper for nfde-rs, you will need a Rust compiler, on top of CMake and a C++/Objective-C compiler). I haven't checked this, but I would imagine that there are officially-supported ways to call a C library from NodeJS/Javascript, and so there is no need to go from JavaScript to Rust (which likely involves stepping through a C interface anyway).

jcbhmr commented 1 year ago

What's the high-level overview of what this project does? Is it basically a wrapper with #ifdef WINDOWS cascades for each platform?

I'm not sure what you're asking for here; the README should cover most high-level things.

I was kinda getting at "how do you magically make it use the right implementation on my system?" 😊 From university classes in C++, I've seen this kind of pattern:

int main() {
  #ifdef WINDOWS
    std::cout << "Windows!\n";
  #endif
  #ifdef MACOS
    std::cout << "macOS!\n";
  #endif
  #ifdef LINUX
    std::cout << "Linux!\n";
  #endif
}

I think that's all done in the CMakeLists.txt in this project's case?

https://github.com/btzy/nativefiledialog-extended/blob/dbd7139b4eb7372813cfd0d58d3fa1f355763f3d/src/CMakeLists.txt#L9-L11

https://github.com/btzy/nativefiledialog-extended/blob/dbd7139b4eb7372813cfd0d58d3fa1f355763f3d/src/CMakeLists.txt#L13

https://github.com/btzy/nativefiledialog-extended/blob/dbd7139b4eb7372813cfd0d58d3fa1f355763f3d/src/CMakeLists.txt#L90

For more context on my background: When I used "advanced C++" like terminal GUI libraries + HTTP stuff, etc, I used xmake since I found cmake too complicated 😂 https://xmake.io/#/getting_started

jcbhmr commented 1 year ago

I would recommend trying to write/generate a JavaScript wrapper for this project directly, instead of trying to wrap nfde-rs. This is because nfde-rs is already a wrapper for this project, and having multiple wrapper layers add more dependencies (i.e. to build a JavaScript wrapper for nfde-rs, you will need a Rust compiler, on top of CMake and a C++/Objective-C compiler). I haven't checked this, but I would imagine that there are officially-supported ways to call a C library from NodeJS/Javascript, and so there is no need to go from JavaScript to Rust (which likely involves stepping through a C interface anyway).

One of the reasons I gravitated to the Rust version was because https://napi.rs/ seems so easy to wrap stuff! 😱

image

vs

image

jcbhmr commented 1 year ago

unrelated question about CI: Does the circle ci config do anything, or is everything GitHub Actions now? Do you use CircleCI and GitHub actions together? I note that the GitHub actions workflow seems to be a good deal larger than circle ci.

guest271314 commented 1 year ago

If you want to work in C and JavaScipt you can use QuickJS which provides a means to import compiled shared object files intothe QuickJS environment.

btzy commented 1 year ago

What's the high-level overview of what this project does? Is it basically a wrapper with #ifdef WINDOWS cascades for each platform?

I'm not sure what you're asking for here; the README should cover most high-level things.

I was kinda getting at "how do you magically make it use the right implementation on my system?" 😊 From university classes in C++, I've seen this kind of pattern:

int main() {
  #ifdef WINDOWS
    std::cout << "Windows!\n";
  #endif
  #ifdef MACOS
    std::cout << "macOS!\n";
  #endif
  #ifdef LINUX
    std::cout << "Linux!\n";
  #endif
}

I think that's all done in the CMakeLists.txt in this project's case?

Yes that's right. There's no need to keep them in the same file when the four implementations are mostly different from each other. Also, it's impossible for macOS since it has to be in Objective-C instead of C++.

btzy commented 1 year ago

unrelated question about CI: Does the circle ci config do anything, or is everything GitHub Actions now? Do you use CircleCI and GitHub actions together? I note that the GitHub actions workflow seems to be a good deal larger than circle ci.

I added CircleCI at some point because GitHub Actions didn't support macOS 12, and I wanted to make sure it worked over there. Now it's redundant, since GitHub supports macOS 12.

jcbhmr commented 1 year ago

Thanks for your insight! The one thing about this project that seems to be a bit "nonstandard"-enough that might be worthy of putting in the wiki (judging from response in #106) is the part about how instead of #ifdef magic, you use CMake if(nfd_PLATFORM...) magic to compile one file from the src/ folder.

I'm closing this issue since you've answered my questions. Thanks for taking time out of your day to educate me! ❤️