[Wayland] Add support for native file dialogs.
This commit is contained in:
parent
313f623b9d
commit
edb21e0573
9 changed files with 271 additions and 3 deletions
|
@ -120,7 +120,7 @@
|
|||
<description>
|
||||
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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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<String> &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<Dictionary>(), 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<String> &p_filters, const TypedArray<Dictionary> &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
|
||||
|
|
|
@ -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<String> &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<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
|
||||
#endif
|
||||
|
||||
virtual void mouse_set_mode(MouseMode p_mode) override;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
2
thirdparty/README.md
vendored
2
thirdparty/README.md
vendored
|
@ -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`
|
||||
|
||||
|
||||
|
|
4
thirdparty/wayland-protocols/unstable/xdg-foreign/README
vendored
Normal file
4
thirdparty/wayland-protocols/unstable/xdg-foreign/README
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
xdg foreign protocol
|
||||
|
||||
Maintainers:
|
||||
Jonas Ådahl <jadahl@gmail.com>
|
182
thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml
vendored
Normal file
182
thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="xdg_foreign_unstable_v1">
|
||||
|
||||
<copyright>
|
||||
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.
|
||||
</copyright>
|
||||
|
||||
<description summary="Protocol for exporting xdg surface handles">
|
||||
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.
|
||||
</description>
|
||||
|
||||
<interface name="zxdg_exporter_v1" version="1">
|
||||
<description summary="interface for exporting surfaces">
|
||||
A global interface used for exporting surfaces that can later be imported
|
||||
using xdg_importer.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the xdg_exporter object">
|
||||
Notify the compositor that the xdg_exporter object will no longer be
|
||||
used.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="export">
|
||||
<description summary="export a surface">
|
||||
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.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zxdg_exported_v1"
|
||||
summary="the new xdg_exported object"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"
|
||||
summary="the surface to export"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zxdg_importer_v1" version="1">
|
||||
<description summary="interface for importing surfaces">
|
||||
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.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the xdg_importer object">
|
||||
Notify the compositor that the xdg_importer object will no longer be
|
||||
used.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="import">
|
||||
<description summary="import a surface">
|
||||
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.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zxdg_imported_v1"
|
||||
summary="the new xdg_imported object"/>
|
||||
<arg name="handle" type="string"
|
||||
summary="the exported surface handle"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zxdg_exported_v1" version="1">
|
||||
<description summary="an exported surface handle">
|
||||
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.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unexport the exported surface">
|
||||
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.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="handle">
|
||||
<description summary="the exported surface 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.
|
||||
</description>
|
||||
<arg name="handle" type="string" summary="the exported surface handle"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zxdg_imported_v1" version="1">
|
||||
<description summary="an imported surface handle">
|
||||
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.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the xdg_imported object">
|
||||
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.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_parent_of">
|
||||
<description summary="set as the parent of some surface">
|
||||
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.
|
||||
</description>
|
||||
<arg name="surface" type="object" interface="wl_surface"
|
||||
summary="the child surface"/>
|
||||
</request>
|
||||
|
||||
<event name="destroyed">
|
||||
<description summary="the imported surface handle has been destroyed">
|
||||
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.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
Loading…
Reference in a new issue