diff options
Diffstat (limited to 'platform/linuxbsd/freedesktop_portal_desktop.cpp')
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.cpp | 216 |
1 files changed, 127 insertions, 89 deletions
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index a3633e72b7..e65404a531 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -367,6 +367,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo } ERR_FAIL_INDEX_V(int(p_mode), DisplayServer::FILE_DIALOG_MODE_SAVE_MAX, FAILED); + ERR_FAIL_NULL_V(monitor_connection, FAILED); Vector<String> filter_names; Vector<String> filter_exts; @@ -406,24 +407,16 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo Error rng_err = rng.get_random_bytes(uuid, 64); ERR_FAIL_COND_V_MSG(rng_err, rng_err, "Failed to generate unique token."); - fd.connection = dbus_bus_get(DBUS_BUS_SESSION, &err); - if (dbus_error_is_set(&err)) { - ERR_PRINT(vformat("Failed to open DBus connection: %s", err.message)); - dbus_error_free(&err); - unsupported = true; - return FAILED; - } - - String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(fd.connection)); + String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(monitor_connection)); String token = String::hex_encode_buffer(uuid, 64); String path = vformat("/org/freedesktop/portal/desktop/request/%s/%s", dbus_unique_name.replace(".", "_").replace(":", ""), token); - fd.path = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name); - dbus_bus_add_match(fd.connection, fd.path.utf8().get_data(), &err); + fd.path = path; + fd.filter = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name); + dbus_bus_add_match(monitor_connection, fd.filter.utf8().get_data(), &err); if (dbus_error_is_set(&err)) { ERR_PRINT(vformat("Failed to add DBus match: %s", err.message)); dbus_error_free(&err); - dbus_connection_unref(fd.connection); return FAILED; } @@ -460,14 +453,13 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo dbus_message_iter_close_container(&iter, &arr_iter); } - DBusMessage *reply = dbus_connection_send_with_reply_and_block(fd.connection, message, DBUS_TIMEOUT_INFINITE, &err); + DBusMessage *reply = dbus_connection_send_with_reply_and_block(monitor_connection, message, DBUS_TIMEOUT_INFINITE, &err); dbus_message_unref(message); if (!reply || dbus_error_is_set(&err)) { ERR_PRINT(vformat("Failed to send DBus message: %s", err.message)); dbus_error_free(&err); - dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err); - dbus_connection_unref(fd.connection); + dbus_bus_remove_match(monitor_connection, fd.filter.utf8().get_data(), &err); return FAILED; } @@ -479,19 +471,17 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo const char *new_path = nullptr; dbus_message_iter_get_basic(&iter, &new_path); if (String::utf8(new_path) != path) { - dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err); + dbus_bus_remove_match(monitor_connection, fd.filter.utf8().get_data(), &err); if (dbus_error_is_set(&err)) { ERR_PRINT(vformat("Failed to remove DBus match: %s", err.message)); dbus_error_free(&err); - dbus_connection_unref(fd.connection); return FAILED; } - fd.path = String::utf8(new_path); - dbus_bus_add_match(fd.connection, fd.path.utf8().get_data(), &err); + fd.filter = String::utf8(new_path); + dbus_bus_add_match(monitor_connection, fd.filter.utf8().get_data(), &err); if (dbus_error_is_set(&err)) { ERR_PRINT(vformat("Failed to add DBus match: %s", err.message)); dbus_error_free(&err); - dbus_connection_unref(fd.connection); return FAILED; } } @@ -506,83 +496,111 @@ 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))); + } } } } -void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) { +void FreeDesktopPortalDesktop::_thread_monitor(void *p_ud) { FreeDesktopPortalDesktop *portal = (FreeDesktopPortalDesktop *)p_ud; - while (!portal->file_dialog_thread_abort.is_set()) { - { - MutexLock lock(portal->file_dialog_mutex); - for (int i = portal->file_dialogs.size() - 1; i >= 0; i--) { - bool remove = false; - { - FreeDesktopPortalDesktop::FileDialogData &fd = portal->file_dialogs.write[i]; - if (fd.connection) { - while (true) { - DBusMessage *msg = dbus_connection_pop_message(fd.connection); - if (!msg) { - break; - } else if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) { - DBusMessageIter iter; - if (dbus_message_iter_init(msg, &iter)) { - bool cancel = false; - Vector<String> uris; - Dictionary options; - int index = 0; - 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); - } - if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) { - callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus); - } + while (!portal->monitor_thread_abort.is_set()) { + if (portal->monitor_connection) { + while (true) { + DBusMessage *msg = dbus_connection_pop_message(portal->monitor_connection); + if (!msg) { + break; + } else if (dbus_message_is_signal(msg, "org.freedesktop.portal.Settings", "SettingChanged")) { + DBusMessageIter iter; + if (dbus_message_iter_init(msg, &iter)) { + const char *value; + dbus_message_iter_get_basic(&iter, &value); + String name_space = String::utf8(value); + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &value); + String key = String::utf8(value); + + if (name_space == "org.freedesktop.appearance" && key == "color-scheme") { + callable_mp(portal, &FreeDesktopPortalDesktop::_system_theme_changed_callback).call_deferred(); + } + } + } else if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) { + String path = String::utf8(dbus_message_get_path(msg)); + MutexLock lock(portal->file_dialog_mutex); + for (int i = 0; i < portal->file_dialogs.size(); i++) { + FreeDesktopPortalDesktop::FileDialogData &fd = portal->file_dialogs.write[i]; + if (fd.path == path) { + DBusMessageIter iter; + if (dbus_message_iter_init(msg, &iter)) { + bool cancel = false; + Vector<String> uris; + Dictionary options; + int index = 0; + file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index, options); + + if (fd.callback.is_valid()) { + 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); } - dbus_message_unref(msg); - - DBusError err; - dbus_error_init(&err); - dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err); - dbus_error_free(&err); - dbus_connection_unref(fd.connection); - remove = true; - break; } - dbus_message_unref(msg); + + DBusError err; + dbus_error_init(&err); + dbus_bus_remove_match(portal->monitor_connection, fd.filter.utf8().get_data(), &err); + dbus_error_free(&err); + + portal->file_dialogs.remove_at(i); + break; } - dbus_connection_read_write(fd.connection, 0); } } - if (remove) { - portal->file_dialogs.remove_at(i); - } + dbus_message_unref(msg); } + dbus_connection_read_write(portal->monitor_connection, 0); } + usleep(50000); } } +void FreeDesktopPortalDesktop::_system_theme_changed_callback() { + if (system_theme_changed.is_valid()) { + system_theme_changed.call(); + } +} + FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() { #ifdef SOWRAP_ENABLED #ifdef DEBUG_ENABLED @@ -611,25 +629,45 @@ FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() { unsupported = true; } + DBusError err; + dbus_error_init(&err); + monitor_connection = dbus_bus_get(DBUS_BUS_SESSION, &err); + if (dbus_error_is_set(&err)) { + dbus_error_free(&err); + } else { + theme_path = "type='signal',sender='org.freedesktop.portal.Desktop',interface='org.freedesktop.portal.Settings',member='SettingChanged'"; + dbus_bus_add_match(monitor_connection, theme_path.utf8().get_data(), &err); + if (dbus_error_is_set(&err)) { + dbus_error_free(&err); + dbus_connection_unref(monitor_connection); + monitor_connection = nullptr; + } + dbus_connection_read_write(monitor_connection, 0); + } + if (!unsupported) { - file_dialog_thread_abort.clear(); - file_dialog_thread.start(FreeDesktopPortalDesktop::_thread_file_dialog_monitor, this); + monitor_thread_abort.clear(); + monitor_thread.start(FreeDesktopPortalDesktop::_thread_monitor, this); } } FreeDesktopPortalDesktop::~FreeDesktopPortalDesktop() { - file_dialog_thread_abort.set(); - if (file_dialog_thread.is_started()) { - file_dialog_thread.wait_to_finish(); + monitor_thread_abort.set(); + if (monitor_thread.is_started()) { + monitor_thread.wait_to_finish(); } - for (FreeDesktopPortalDesktop::FileDialogData &fd : file_dialogs) { - if (fd.connection) { - DBusError err; + + if (monitor_connection) { + DBusError err; + for (FreeDesktopPortalDesktop::FileDialogData &fd : file_dialogs) { dbus_error_init(&err); - dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err); + dbus_bus_remove_match(monitor_connection, fd.filter.utf8().get_data(), &err); dbus_error_free(&err); - dbus_connection_unref(fd.connection); } + dbus_error_init(&err); + dbus_bus_remove_match(monitor_connection, theme_path.utf8().get_data(), &err); + dbus_error_free(&err); + dbus_connection_unref(monitor_connection); } } |