diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 57a4aea93bd..b824bc4fde0 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -120,7 +120,7 @@ Displays OS native dialog for selecting files or directories in the file system. Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int[/code]. - [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature, i.e. Linux (X11), Windows, and macOS. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include Linux (X11 and Wayland), Windows, and macOS. [b]Note:[/b] [param current_directory] might be ignored. [b]Note:[/b] On Linux, [param show_hidden] is ignored. [b]Note:[/b] On macOS, native file dialogs have no title. @@ -145,7 +145,7 @@ - [code]"values"[/code] - [PackedStringArray] of values. If empty, boolean option (check box) is used. - [code]"default"[/code] - default selected option index ([int]) or default boolean value ([bool]). Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int, selected_option: Dictionary[/code]. - [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature, i.e. Linux, Windows, and macOS. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include Linux (X11 and Wayland), Windows, and macOS. [b]Note:[/b] [param current_directory] might be ignored. [b]Note:[/b] On Linux (X11), [param show_hidden] is ignored. [b]Note:[/b] On macOS, native file dialogs have no title. diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub index dbb3c026906..d2b000ff660 100644 --- a/platform/linuxbsd/wayland/SCsub +++ b/platform/linuxbsd/wayland/SCsub @@ -151,11 +151,22 @@ env.WAYLAND_API_CODE( source="#thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml", ) +env.WAYLAND_API_HEADER( + target="protocol/xdg_foreign.gen.h", + source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/xdg_foreign.gen.c", + source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml", +) + source_files = [ "protocol/wayland.gen.c", "protocol/viewporter.gen.c", "protocol/fractional_scale.gen.c", "protocol/xdg_shell.gen.c", + "protocol/xdg_foreign.gen.c", "protocol/xdg_decoration.gen.c", "protocol/xdg_activation.gen.c", "protocol/relative_pointer.gen.c", diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index e22eddd08e5..2076840f073 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -196,6 +196,9 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const { case FEATURE_SWAP_BUFFERS: case FEATURE_KEEP_SCREEN_ON: case FEATURE_CLIPBOARD_PRIMARY: +#ifdef DBUS_ENABLED + case FEATURE_NATIVE_DIALOG: +#endif case FEATURE_HIDPI: { return true; } break; @@ -269,6 +272,22 @@ bool DisplayServerWayland::is_dark_mode() const { } } +Error DisplayServerWayland::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector &p_filters, const Callable &p_callback) { + WindowID window_id = MAIN_WINDOW_ID; + // TODO: Use window IDs for multiwindow support. + + WaylandThread::WindowState *ws = wayland_thread.wl_surface_get_window_state(wayland_thread.window_get_wl_surface(window_id)); + return portal_desktop->file_dialog_show(window_id, (ws ? ws->exported_handle : String()), p_title, p_current_directory, String(), p_filename, p_mode, p_filters, TypedArray(), p_callback, false); +} + +Error DisplayServerWayland::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector &p_filters, const TypedArray &p_options, const Callable &p_callback) { + WindowID window_id = MAIN_WINDOW_ID; + // TODO: Use window IDs for multiwindow support. + + WaylandThread::WindowState *ws = wayland_thread.wl_surface_get_window_state(wayland_thread.window_get_wl_surface(window_id)); + return portal_desktop->file_dialog_show(window_id, (ws ? ws->exported_handle : String()), p_title, p_current_directory, p_root, p_filename, p_mode, p_filters, p_options, p_callback, true); +} + #endif void DisplayServerWayland::mouse_set_mode(MouseMode p_mode) { @@ -1192,10 +1211,11 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win if (context_rd) { if (context_rd->initialize() != OK) { + ERR_PRINT(vformat("Could not initialize %s", context_rd->get_api_name())); memdelete(context_rd); context_rd = nullptr; r_error = ERR_CANT_CREATE; - ERR_FAIL_MSG(vformat("Could not initialize %s", context_rd->get_api_name())); + return; } } #endif diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index f0aabb8c52d..c1cf937ae37 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -171,6 +171,9 @@ public: #ifdef DBUS_ENABLED virtual bool is_dark_mode_supported() const override; virtual bool is_dark_mode() const override; + + virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector &p_filters, const Callable &p_callback) override; + virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector &p_filters, const TypedArray &p_options, const Callable &p_callback) override; #endif virtual void mouse_set_mode(MouseMode p_mode) override; diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index 9410e4653d6..7e96f2dd759 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -370,6 +370,12 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re return; } + if (strcmp(interface, zxdg_exporter_v1_interface.name) == 0) { + registry->wl_exporter = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1); + registry->wl_exporter_name = name; + return; + } + if (strcmp(interface, wl_compositor_interface.name) == 0) { registry->wl_compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4); registry->wl_compositor_name = name; @@ -570,6 +576,17 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry return; } + if (name == registry->wl_exporter_name) { + if (registry->wl_exporter) { + zxdg_exporter_v1_destroy(registry->wl_exporter); + registry->wl_exporter = nullptr; + } + + registry->wl_exporter_name = 0; + + return; + } + if (name == registry->wl_compositor_name) { if (registry->wl_compositor) { wl_compositor_destroy(registry->wl_compositor); @@ -1107,6 +1124,13 @@ void WaylandThread::_xdg_toplevel_on_wm_capabilities(void *data, struct xdg_topl } } +void WaylandThread::_xdg_exported_on_exported(void *data, zxdg_exported_v1 *exported, const char *handle) { + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + ws->exported_handle = vformat("wayland:%s", String::utf8(handle)); +} + void WaylandThread::_xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode) { if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) { #ifdef LIBDECOR_ENABLED @@ -2975,6 +2999,11 @@ void WaylandThread::window_create(DisplayServer::WindowID p_window_id, int p_wid // "loop". wl_surface_commit(ws.wl_surface); + if (registry.wl_exporter) { + ws.xdg_exported = zxdg_exporter_v1_export(registry.wl_exporter, ws.wl_surface); + zxdg_exported_v1_add_listener(ws.xdg_exported, &xdg_exported_listener, &ws); + } + // Wait for the surface to be configured before continuing. wl_display_roundtrip(wl_display); } @@ -3980,6 +4009,10 @@ void WaylandThread::destroy() { xdg_wm_base_destroy(registry.xdg_wm_base); } + if (registry.wl_exporter) { + zxdg_exporter_v1_destroy(registry.wl_exporter); + } + if (registry.wl_shm) { wl_shm_destroy(registry.wl_shm); } diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h index 8591db43065..43c562aaded 100644 --- a/platform/linuxbsd/wayland/wayland_thread.h +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -63,6 +63,7 @@ #include "wayland/protocol/wayland.gen.h" #include "wayland/protocol/xdg_activation.gen.h" #include "wayland/protocol/xdg_decoration.gen.h" +#include "wayland/protocol/xdg_foreign.gen.h" #include "wayland/protocol/xdg_shell.gen.h" #ifdef LIBDECOR_ENABLED @@ -132,6 +133,9 @@ public: struct xdg_wm_base *xdg_wm_base = nullptr; uint32_t xdg_wm_base_name = 0; + struct zxdg_exporter_v1 *wl_exporter = nullptr; + uint32_t wl_exporter_name = 0; + // wayland-protocols globals. struct wp_viewporter *wp_viewporter = nullptr; @@ -197,6 +201,9 @@ public: struct wp_viewport *wp_viewport = nullptr; struct wp_fractional_scale_v1 *wp_fractional_scale = nullptr; + struct zxdg_exported_v1 *xdg_exported = nullptr; + + String exported_handle; // Currently applied buffer scale. int buffer_scale = 1; @@ -599,6 +606,8 @@ private: static void _xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode); + static void _xdg_exported_on_exported(void *data, zxdg_exported_v1 *exported, const char *handle); + static void _xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token); // Core Wayland event listeners. @@ -753,6 +762,10 @@ private: .frame = _wp_tablet_tool_on_frame, }; + static constexpr struct zxdg_exported_v1_listener xdg_exported_listener = { + .handle = _xdg_exported_on_exported + }; + static constexpr struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = { .configure = _xdg_toplevel_decoration_on_configure, }; diff --git a/thirdparty/README.md b/thirdparty/README.md index 5507fa96000..19887443406 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -971,6 +971,8 @@ Files extracted from upstream source: - `unstable/tablet/tablet-unstable-v2.xml` - `unstable/xdg-decoration/README` - `unstable/xdg-decoration/xdg-decoration-unstable-v1.xml` +- `unstable/xdg-foreign/README` +- `unstable/xdg-foreign/xdg-foreign-unstable-v1.xml` - `COPYING` diff --git a/thirdparty/wayland-protocols/unstable/xdg-foreign/README b/thirdparty/wayland-protocols/unstable/xdg-foreign/README new file mode 100644 index 00000000000..f5bcb838f34 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/xdg-foreign/README @@ -0,0 +1,4 @@ +xdg foreign protocol + +Maintainers: +Jonas Ådahl diff --git a/thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml b/thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml new file mode 100644 index 00000000000..913963aa524 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml @@ -0,0 +1,182 @@ + + + + + Copyright © 2015-2016 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a way for making it possible to reference a surface + of a different client. With such a reference, a client can, by using the + interfaces provided by this protocol, manipulate the relationship between + its own surfaces and the surface of some other client. For example, stack + some of its own surface above the other clients surface. + + In order for a client A to get a reference of a surface of client B, client + B must first export its surface using xdg_exporter.export. Upon doing this, + client B will receive a handle (a unique string) that it may share with + client A in some way (for example D-Bus). After client A has received the + handle from client B, it may use xdg_importer.import to create a reference + to the surface client B just exported. See the corresponding requests for + details. + + A possible use case for this is out-of-process dialogs. For example when a + sandboxed client without file system access needs the user to select a file + on the file system, given sandbox environment support, it can export its + surface, passing the exported surface handle to an unsandboxed process that + can show a file browser dialog and stack it above the sandboxed client's + surface. + + Warning! The protocol described in this file is experimental and backward + incompatible changes may be made. Backward compatible changes may be added + together with the corresponding interface version bump. Backward + incompatible changes are done by bumping the version number in the protocol + and interface names and resetting the interface version. Once the protocol + is to be declared stable, the 'z' prefix and the version number in the + protocol and interface names are removed and the interface version number is + reset. + + + + + A global interface used for exporting surfaces that can later be imported + using xdg_importer. + + + + + Notify the compositor that the xdg_exporter object will no longer be + used. + + + + + + The export request exports the passed surface so that it can later be + imported via xdg_importer. When called, a new xdg_exported object will + be created and xdg_exported.handle will be sent immediately. See the + corresponding interface and event for details. + + A surface may be exported multiple times, and each exported handle may + be used to create an xdg_imported multiple times. Only xdg_surface + surfaces may be exported. + + + + + + + + + A global interface used for importing surfaces exported by xdg_exporter. + With this interface, a client can create a reference to a surface of + another client. + + + + + Notify the compositor that the xdg_importer object will no longer be + used. + + + + + + The import request imports a surface from any client given a handle + retrieved by exporting said surface using xdg_exporter.export. When + called, a new xdg_imported object will be created. This new object + represents the imported surface, and the importing client can + manipulate its relationship using it. See xdg_imported for details. + + + + + + + + + An xdg_exported object represents an exported reference to a surface. The + exported surface may be referenced as long as the xdg_exported object not + destroyed. Destroying the xdg_exported invalidates any relationship the + importer may have established using xdg_imported. + + + + + Revoke the previously exported surface. This invalidates any + relationship the importer may have set up using the xdg_imported created + given the handle sent via xdg_exported.handle. + + + + + + The handle event contains the unique handle of this exported surface + reference. It may be shared with any client, which then can use it to + import the surface by calling xdg_importer.import. A handle may be + used to import the surface multiple times. + + + + + + + + An xdg_imported object represents an imported reference to surface exported + by some client. A client can use this interface to manipulate + relationships between its own surfaces and the imported surface. + + + + + Notify the compositor that it will no longer use the xdg_imported + object. Any relationship that may have been set up will at this point + be invalidated. + + + + + + Set the imported surface as the parent of some surface of the client. + The passed surface must be a toplevel xdg_surface. Calling this function + sets up a surface to surface relation with the same stacking and positioning + semantics as xdg_surface.set_parent. + + + + + + + The imported surface handle has been destroyed and any relationship set + up has been invalidated. This may happen for various reasons, for + example if the exported surface or the exported surface handle has been + destroyed, if the handle used for importing was invalid. + + + + +