godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Add supported file type configuration to exported projects and method to open files sent from OS #10195

Open lostminds opened 2 months ago

lostminds commented 2 months ago

Describe the project you are working on

A non-game editor application with both a custom file format and support for importing multiple standard image file formats

Describe the problem or limitation you are having in your project

Currently there are three main methods for the user to get files from the OS into a Godot application:

However, it does not seem to be possible to catch files sent to the application from the OS by the user dragging the file onto the application icon (in dock/taskbar) or double clicking it in the file system with the application associated as the application to open the file type with. So several of the natural ways of opening files with an application available in OSs aren't then possible to use in exported Godot projects, limiting non-game Godot projects that deal with files.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Primarily I'd like to have a new feature to catch files passed from the OS in these cases. When the user using the OS file system tells the OS to open a file with the application (that is already running). For example it could be implemented as a new signal OS.files_opened similar to the Window files_dropped signal.

The second part of this proposal is a little more involved, and revolves around associating the supported file types with the exported Godot application. Basically I'd like to be able to set up a list of supported/exported file types for the project, with file type name, file extension, UTI, mime-type, icon etc. And have these then be registered appropriately for each platform in the exported project.

When the file types are correctly associated it will allow the app to set a custom icon for the file type, open double-clicked files, allow the user to drag and drop files of supported types onto the application, select the application to open this file type etc.

This type association is currently possible to do (I think), but involves a lot of work and is quite complicated. But as long as there is no method of catching the files sent from the OS it's pointless since it'll just open/activate the application without actually then allowing you to open the files.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

A new signal OS.files_opened added similar to the Window.files_dropped signal, emitted when the OS tells the application to open files. For consistency this files_opened signal could also be emitted at launch if OS.get_cmdline_args() contains a file path, so projects interested in files can consistently use files_opened to get files from the OS.

A new universal section added in Project Settings for supported file types, for example below Application/Config. There an array can be set up with the supported file types, with all their associated properties. Like name for the format, file extension, UTI, mime-type, data formats, icon file etc.

On export platform-appropriate methods will be used to translate this list of supported file types into the needed format on the platform you export to. For macOS adding the needed info.plist keys (like CFBundleDocumentTypes and UTExportedTypeDeclarations) for Windows code to set the appropriate registry entries and on linux code to generate and install a suitable .desktop file with the information.

To support custom file type icons the icon files for custom format icons also need to be included ans files in the export bundle so these can be referenced and accessed by the system when associating the file type. However, being able to set these custom icons might be considered "nice to have" and may be skipped as the other functionality is in my mind much more important.

If this enhancement will not be used often, can it be worked around with a few lines of script?

The file type association can possibly be done, at least on windows and macOS, but not then catching the event when the files are sent from the OS. Custom file type icons can be included in a custom export template on macOS at least, but this then requires creating and maintaining one of these just to include the document icon file.

Is there a reason why this should be core and not an add-on in the asset library?

OS interaction like this feels like a core feature to me. If supported it will make all exported projects feel more integrated with the OS, allowing properly associating for example custom map file formats or other game files with an exported game. And of course bringing great benefits for non-game applications made in Godot.

This functionality could also be used for the Godot editor itself to associate its' files types with Godot on all platforms. For the editor this currently only seems to be partially implemented on macOS.

Calinou commented 2 months ago

However, it does not seem to be possible to catch files sent to the application from the OS by the user dragging the file onto the application icon (in dock/taskbar) or double clicking it in the file system with the application associated as the application to open the file type with. So several of the natural ways of opening files with an application available in OSs aren't then possible to use in exported Godot projects, limiting non-game Godot projects that deal with files.

This is already possible by reading OS.get_cmdline_args()' first positional argument. If multiple files are passed, read each argument individually using a for loop. Note that OS.get_cmdline_user_args() will not work here, as the file name is passed before the -- separator (which is not used here).

This is standard behavior on all platforms, not just Windows.

Basically I'd like to be able to set up a list of supported/exported file types for the project, with file type name, file extension, UTI, mime-type, icon etc. And have these then be registered appropriately for each platform in the exported project.

Creating file associations can only be done the first time the exported project is launched. It's done by setting registry keys, so you can also have an installer that creates registry keys or instruct users to double-click a .reg file distributed with the project.

lostminds commented 2 months ago

This is already possible by reading OS.get_cmdline_args()' first positional argument.

I was under the impression that this only returned launch arguments for the process, in other words whatever files were passed to the application when it was launched. This I'm aware of as mentioned above. What I'm missing is files passed from the OS while the application is running, not at launch. Are you saying the cmdline_args can change post launch to contain new file paths if additional files are received from the OS? And if so, is there a way to be notified when this happens (like the files_opened signal proposed above)?

lostminds commented 2 months ago

There seems to another potentially serious issue with associating file types. If you do this manually and then as the OS to open the file with the exported Godot application while it's running, instead of this just activating as I expected a duplicate new process is started, as reported here: https://github.com/godotengine/godot/issues/94344#issuecomment-2227371607 and perhaps related to the process duplication issue reported there.

So you can end up with multiple copies of the application running, which it is not supposed to support. For example you can use this issue to open multiple instances of the Godot editor editing the same project.

Calinou commented 2 months ago

So you can end up with multiple copies of the application running, which it is not supposed to support. For example you can use this issue to open multiple instances of the Godot editor editing the same project.

Single-instance enforcement is a separate topic which deserves its own proposal. On Linux, it's typically handled via dbus.

lostminds commented 2 months ago

Single-instance enforcement is a separate topic which deserves its own proposal.

I see. I assumed at least exported Godot projects were already intended to be single-instance, but I guess this is not the case then. I will make such a proposal if there isn't one already.

If there currently is no way to prevent new instances of the game process to be launched I guess this explains the lack of a files_opened type signal as I proposed above, since a new process will just be started for each open request from the OS instead.

lostminds commented 1 month ago

There's now a pull request (draft) for adding a signal for files opened from the OS (at least on sandboxed macOS exports): https://github.com/godotengine/godot/pull/94909 that will be a step in this direction.