From 8faa7eece01e494b097b49158a647c12813bd8e2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:46:57 +0000 Subject: [PATCH] Implement xdg-dialog-v1 Wayland protocol Co-authored-by: AlanGriffiths <9048879+AlanGriffiths@users.noreply.github.com> Agent-Logs-Url: https://github.com/canonical/mir/sessions/57869bba-f1af-4bf3-b578-8b9ba38da6fa --- src/server/frontend_wayland/CMakeLists.txt | 1 + .../wayland_default_configuration.cpp | 6 + src/server/frontend_wayland/xdg_dialog_v1.cpp | 154 ++++++++++++++++++ src/server/frontend_wayland/xdg_dialog_v1.h | 32 ++++ src/wayland/CMakeLists.txt | 1 + wayland-protocols/xdg-dialog-v1.xml | 104 ++++++++++++ 6 files changed, 298 insertions(+) create mode 100644 src/server/frontend_wayland/xdg_dialog_v1.cpp create mode 100644 src/server/frontend_wayland/xdg_dialog_v1.h create mode 100644 wayland-protocols/xdg-dialog-v1.xml diff --git a/src/server/frontend_wayland/CMakeLists.txt b/src/server/frontend_wayland/CMakeLists.txt index 5ad341bcd1b..e7a82d2c96e 100644 --- a/src/server/frontend_wayland/CMakeLists.txt +++ b/src/server/frontend_wayland/CMakeLists.txt @@ -57,6 +57,7 @@ set( primary_selection_v1.cpp primary_selection_v1.h session_lock_v1.cpp session_lock_v1.h xdg_decoration_unstable_v1.cpp xdg_decoration_unstable_v1.h + xdg_dialog_v1.cpp xdg_dialog_v1.h ${PROJECT_SOURCE_DIR}/src/include/server/mir/frontend/wayland.h ${CMAKE_CURRENT_BINARY_DIR}/wayland_frontend.tp.c ${CMAKE_CURRENT_BINARY_DIR}/wayland_frontend.tp.h diff --git a/src/server/frontend_wayland/wayland_default_configuration.cpp b/src/server/frontend_wayland/wayland_default_configuration.cpp index d4347626513..fc5f3533ea9 100644 --- a/src/server/frontend_wayland/wayland_default_configuration.cpp +++ b/src/server/frontend_wayland/wayland_default_configuration.cpp @@ -51,6 +51,7 @@ #include "xdg_activation_v1.h" #include "xdg-decoration-unstable-v1_wrapper.h" #include "xdg_decoration_unstable_v1.h" +#include "xdg_dialog_v1.h" #include "xdg_output_v1.h" #include "xdg_shell_stable.h" #include "xdg_shell_v6.h" @@ -261,6 +262,10 @@ std::vector const internal_extension_builders = { { return mf::create_xdg_decoration_unstable_v1(ctx.display, ctx.decoration_strategy); }), + make_extension_builder([](auto const& ctx) + { + return mf::create_xdg_dialog_v1(ctx.display); + }), make_extension_builder([](auto const& ctx) { return mf::create_fractional_scale_v1(ctx.display); @@ -399,6 +404,7 @@ auto mf::get_standard_extensions() -> std::vector mw::TextInputManagerV3::interface_name, mw::MirShellV1::interface_name, mw::XdgDecorationManagerV1::interface_name, + mw::XdgWmDialogV1::interface_name, mw::XdgActivationV1::interface_name, mw::FractionalScaleManagerV1::interface_name}; } diff --git a/src/server/frontend_wayland/xdg_dialog_v1.cpp b/src/server/frontend_wayland/xdg_dialog_v1.cpp new file mode 100644 index 00000000000..51222e17cea --- /dev/null +++ b/src/server/frontend_wayland/xdg_dialog_v1.cpp @@ -0,0 +1,154 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xdg_dialog_v1.h" + +#include + +#include "xdg-dialog-v1_wrapper.h" +#include "xdg_shell_stable.h" + +#include +#include + +namespace mir +{ +namespace frontend +{ +class ToplevelsWithDialogs +{ +public: + ToplevelsWithDialogs() = default; + ToplevelsWithDialogs(ToplevelsWithDialogs const&) = delete; + ToplevelsWithDialogs& operator=(ToplevelsWithDialogs const&) = delete; + + /// \return true if no duplicates existed before insertion, false otherwise. + bool register_toplevel(wl_resource* toplevel) + { + auto [_, inserted] = toplevels_with_dialogs.insert(toplevel); + return inserted; + } + + /// \return true if the toplevel was still registered, false otherwise. + bool unregister_toplevel(wl_resource* toplevel) + { + return toplevels_with_dialogs.erase(toplevel) > 0; + } + +private: + std::unordered_set toplevels_with_dialogs; +}; + +class XdgDialogV1 : public wayland::XdgDialogV1 +{ +public: + explicit XdgDialogV1(wl_resource* id); + + void set_modal() override; + void unset_modal() override; +}; + +class XdgWmDialogV1 : public wayland::XdgWmDialogV1 +{ +public: + XdgWmDialogV1(wl_resource* resource); + + class Global : public wayland::XdgWmDialogV1::Global + { + public: + Global(wl_display* display); + + private: + void bind(wl_resource* new_xdg_wm_dialog_v1) override; + }; + +private: + void get_xdg_dialog(wl_resource* id, wl_resource* toplevel) override; + + std::shared_ptr const toplevels_with_dialogs; +}; +} // namespace frontend +} // namespace mir + +auto mir::frontend::create_xdg_dialog_v1(wl_display* display) + -> std::shared_ptr +{ + return std::make_shared(display); +} + +mir::frontend::XdgWmDialogV1::Global::Global(wl_display* display) : + wayland::XdgWmDialogV1::Global::Global{display, Version<1>{}} +{ +} + +void mir::frontend::XdgWmDialogV1::Global::bind(wl_resource* new_xdg_wm_dialog_v1) +{ + new XdgWmDialogV1{new_xdg_wm_dialog_v1}; +} + +mir::frontend::XdgWmDialogV1::XdgWmDialogV1(wl_resource* resource) : + wayland::XdgWmDialogV1{resource, Version<1>{}}, + toplevels_with_dialogs{std::make_shared()} +{ +} + +void mir::frontend::XdgWmDialogV1::get_xdg_dialog(wl_resource* id, wl_resource* toplevel) +{ + auto* tl = XdgToplevelStable::from(toplevel); + if (!tl) + { + BOOST_THROW_EXCEPTION(std::runtime_error( + "Failed to obtain XdgToplevelStable from xdg_toplevel resource")); + } + + if (!toplevels_with_dialogs->register_toplevel(toplevel)) + { + BOOST_THROW_EXCEPTION(mir::wayland::ProtocolError( + resource, Error::already_used, "xdg_dialog_v1 already created for this toplevel")); + } + + auto* dialog = new XdgDialogV1{id}; + dialog->add_destroy_listener( + [toplevels_with_dialogs = this->toplevels_with_dialogs, toplevel]() + { + toplevels_with_dialogs->unregister_toplevel(toplevel); + }); + + tl->add_destroy_listener( + [toplevels_with_dialogs = this->toplevels_with_dialogs, toplevel]() + { + toplevels_with_dialogs->unregister_toplevel(toplevel); + }); + + tl->set_type(mir_window_type_dialog); +} + +mir::frontend::XdgDialogV1::XdgDialogV1(wl_resource* id) : + wayland::XdgDialogV1{id, Version<1>{}} +{ +} + +void mir::frontend::XdgDialogV1::set_modal() +{ + // In Mir, mir_window_type_dialog already represents a modal dialog. + // No additional state change is needed. +} + +void mir::frontend::XdgDialogV1::unset_modal() +{ + // Mir does not distinguish between modal and non-modal dialogs at the + // window type level; the toplevel remains a dialog regardless. +} diff --git a/src/server/frontend_wayland/xdg_dialog_v1.h b/src/server/frontend_wayland/xdg_dialog_v1.h new file mode 100644 index 00000000000..ea17267b295 --- /dev/null +++ b/src/server/frontend_wayland/xdg_dialog_v1.h @@ -0,0 +1,32 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MIR_FRONTEND_XDG_DIALOG_V1_H +#define MIR_FRONTEND_XDG_DIALOG_V1_H + +#include "xdg-dialog-v1_wrapper.h" + +struct wl_display; + +namespace mir +{ +namespace frontend +{ +auto create_xdg_dialog_v1(struct wl_display* display) -> std::shared_ptr; +} +} + +#endif // MIR_FRONTEND_XDG_DIALOG_V1_H diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 5ad3bc6cd67..25d821232f8 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -40,6 +40,7 @@ mir_generate_protocol_wrapper(mirwayland "z" xdg-decoration-unstable-v1.xml) mir_generate_protocol_wrapper(mirwayland "wp_" viewporter.xml) mir_generate_protocol_wrapper(mirwayland "wp_" fractional-scale-v1.xml) mir_generate_protocol_wrapper(mirwayland "z" xdg-activation-v1.xml) +mir_generate_protocol_wrapper(mirwayland "" xdg-dialog-v1.xml) mir_generate_protocol_wrapper(mirwayland "wp_" linux-drm-syncobj-v1.xml) mir_generate_protocol_wrapper(mirwayland "ext_" ext-data-control-v1.xml) # We don't strip the "ext_" prefix here, because it would conflict diff --git a/wayland-protocols/xdg-dialog-v1.xml b/wayland-protocols/xdg-dialog-v1.xml new file mode 100644 index 00000000000..f3129bd1c76 --- /dev/null +++ b/wayland-protocols/xdg-dialog-v1.xml @@ -0,0 +1,104 @@ + + + + + Copyright © 2023 Carlos Garnacho + + 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. + + + + + The xdg_wm_dialog_v1 interface is exposed as a global object allowing + to create xdg_dialog_v1 objects. These objects can be used to + coordinate the creation of dialogs relative to another toplevel. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + + + + + + Destroys the xdg_wm_dialog_v1 object. This does not affect + the xdg_dialog_v1 objects created from it. + + + + + + Create a new dialog object associated with the given toplevel, to + allow managing dialogs. + + Only one xdg_dialog_v1 may exist for each xdg_toplevel. If an + xdg_dialog_v1 already exists for the given xdg_toplevel, the + already_used error is raised. + + + + + + + + + A dialog object is associated to a xdg_toplevel. It allows the + compositor to treat the toplevel as a dialog and apply dialog-specific + policies. + + Compositors may treat dialogs differently from regular windows in many + ways, e.g. refusing to iconify or maximize them. The user can usually + dismiss a dialog by pressing a dedicated key (e.g. Escape). + + + + + Destroys the xdg_dialog_v1 object. This does not affect + the dialog state on the associated xdg_toplevel. + + + + + + Hint that the dialog has modal behavior. See the description of + xdg_dialog_v1 for more details about what is expected from + modal dialogs. + + This request does not take effect for an unmapped toplevel. + + + + + + Hint that the dialog does not have modal behavior. See the description + of xdg_dialog_v1 for more details. + + This request does not take effect for an unmapped toplevel. + + + + +