From 67d6be30a005cce39a51894cadda55268341178c Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:33:33 +0300 Subject: [PATCH] [DBus] Process file dialog callback in the main event loop instead of using deferred call. --- .../linuxbsd/freedesktop_portal_desktop.cpp | 49 ++++++++++++------- .../linuxbsd/freedesktop_portal_desktop.h | 13 ++++- .../wayland/display_server_wayland.cpp | 6 +++ platform/linuxbsd/x11/display_server_x11.cpp | 6 +++ 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index 214725832f22..e65404a53138 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -496,24 +496,30 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo return OK; } -void FreeDesktopPortalDesktop::_file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index, const Variant &p_options, bool p_opt_in_cb) { - if (p_opt_in_cb) { - Variant ret; - Callable::CallError ce; - const Variant *args[4] = { &p_status, &p_list, &p_index, &p_options }; - - p_callable.callp(args, 4, ret, ce); - if (ce.error != Callable::CallError::CALL_OK) { - ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callable, args, 4, ce))); - } - } else { - Variant ret; - Callable::CallError ce; - const Variant *args[3] = { &p_status, &p_list, &p_index }; +void FreeDesktopPortalDesktop::process_file_dialog_callbacks() { + MutexLock lock(file_dialog_mutex); + while (!pending_cbs.is_empty()) { + FileDialogCallback cb = pending_cbs.front()->get(); + pending_cbs.pop_front(); + + if (cb.opt_in_cb) { + Variant ret; + Callable::CallError ce; + const Variant *args[4] = { &cb.status, &cb.files, &cb.index, &cb.options }; + + cb.callback.callp(args, 4, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 4, ce))); + } + } else { + Variant ret; + Callable::CallError ce; + const Variant *args[3] = { &cb.status, &cb.files, &cb.index }; - p_callable.callp(args, 3, ret, ce); - if (ce.error != Callable::CallError::CALL_OK) { - ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callable, args, 3, ce))); + cb.callback.callp(args, 3, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 3, ce))); + } } } } @@ -556,7 +562,14 @@ void FreeDesktopPortalDesktop::_thread_monitor(void *p_ud) { file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index, options); if (fd.callback.is_valid()) { - callable_mp(portal, &FreeDesktopPortalDesktop::_file_dialog_callback).call_deferred(fd.callback, !cancel, uris, index, options, fd.opt_in_cb); + FileDialogCallback cb; + cb.callback = fd.callback; + cb.status = !cancel; + cb.files = uris; + cb.index = index; + cb.options = options; + cb.opt_in_cb = fd.opt_in_cb; + portal->pending_cbs.push_back(cb); } if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) { callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus); diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h index ba9c352e62f7..96c38de2c282 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.h +++ b/platform/linuxbsd/freedesktop_portal_desktop.h @@ -56,8 +56,6 @@ class FreeDesktopPortalDesktop : public Object { static void append_dbus_dict_bool(DBusMessageIter *p_iter, const String &p_key, bool p_value); static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector &p_names, bool &r_cancel, Vector &r_urls, int &r_index, Dictionary &r_options); - void _file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index, const Variant &p_options, bool p_opt_in_cb); - struct FileDialogData { Vector filter_names; DisplayServer::WindowID prev_focus = DisplayServer::INVALID_WINDOW_ID; @@ -67,6 +65,16 @@ class FreeDesktopPortalDesktop : public Object { bool opt_in_cb = false; }; + struct FileDialogCallback { + Callable callback; + Variant status; + Variant files; + Variant index; + Variant options; + bool opt_in_cb = false; + }; + List pending_cbs; + Mutex file_dialog_mutex; Vector file_dialogs; Thread monitor_thread; @@ -86,6 +94,7 @@ class FreeDesktopPortalDesktop : public Object { bool is_supported() { return !unsupported; } Error file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector &p_filters, const TypedArray &p_options, const Callable &p_callback, bool p_options_in_cb); + void process_file_dialog_callbacks(); // Retrieve the system's preferred color scheme. // 0: No preference or unknown. diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index a815db1c05eb..da70dae4ff3f 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -1161,6 +1161,12 @@ void DisplayServerWayland::process_events() { } } +#ifdef DBUS_ENABLED + if (portal_desktop) { + portal_desktop->process_file_dialog_callbacks(); + } +#endif + wayland_thread.mutex.unlock(); Input::get_singleton()->flush_buffered_events(); diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 4c7dfbb107c3..0041b4c7f347 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -5097,6 +5097,12 @@ void DisplayServerX11::process_events() { */ } +#ifdef DBUS_ENABLED + if (portal_desktop) { + portal_desktop->process_file_dialog_callbacks(); + } +#endif + _THREAD_SAFE_UNLOCK_ Input::get_singleton()->flush_buffered_events();