diff --git a/src/include/server/mir/server.h b/src/include/server/mir/server.h index af588ea65c..fcd36d9dc2 100644 --- a/src/include/server/mir/server.h +++ b/src/include/server/mir/server.h @@ -23,6 +23,7 @@ #include #include +#include #include struct wl_display; @@ -473,6 +474,8 @@ class Server /// Get the name of the X11 display usable as a $DISPLAY value auto x11_display() const -> optional_value; + auto get_activation_token() const -> std::optional; + /// Overrides the standard set of Wayland extensions (mir::frontend::get_standard_extensions()) with a new list void set_enabled_wayland_extensions(std::vector const& extensions); /** @} */ diff --git a/src/miral/external_client.cpp b/src/miral/external_client.cpp index 792b96221b..75d54703b4 100644 --- a/src/miral/external_client.cpp +++ b/src/miral/external_client.cpp @@ -118,7 +118,7 @@ auto miral::ExternalClientLauncher::launch(std::vector const& comma auto const wayland_display = self->server->wayland_display(); auto const x11_display = self->server->x11_display(); - return launch_app_env(command_line, wayland_display, x11_display, self->env); + return launch_app_env(command_line, wayland_display, x11_display, self->server->get_activation_token(), self->env); } miral::ExternalClientLauncher::ExternalClientLauncher() : self{std::make_shared()} {} @@ -133,7 +133,8 @@ auto miral::ExternalClientLauncher::launch_using_x11(std::vector c if (auto const x11_display = self->server->x11_display()) { auto const wayland_display = self->server->wayland_display(); - return launch_app_env(command_line, wayland_display, x11_display, self->x11_env); + return launch_app_env( + command_line, wayland_display, x11_display, self->server->get_activation_token(), self->x11_env); } return -1; diff --git a/src/miral/launch_app.cpp b/src/miral/launch_app.cpp index 5d827df773..12f2e0a705 100644 --- a/src/miral/launch_app.cpp +++ b/src/miral/launch_app.cpp @@ -19,11 +19,11 @@ #include +#include #include #include #include -#include #include #include @@ -93,46 +93,21 @@ auto Environment::exec_env() const & -> std::vector result.push_back(nullptr); return result; } -} // namespace -auto miral::launch_app_env( - std::vector const& app, - mir::optional_value const& wayland_display, - mir::optional_value const& x11_display, - miral::AppEnvironment const& app_env) -> pid_t +void assign_or_unset(Environment& env, std::string const& key, auto optional_value) { - Environment application_environment; - - for (auto const& [key, value]: app_env) - { - if (value) - { - application_environment.setenv(key, value.value()); - } - else - { - application_environment.unsetenv(key); - } - } - - if (wayland_display) + if (optional_value) { - application_environment.setenv("WAYLAND_DISPLAY", wayland_display.value()); // configure Wayland socket + env.setenv(key, optional_value.value()); } else { - application_environment.unsetenv("WAYLAND_DISPLAY"); - } - - if (x11_display) - { - application_environment.setenv("DISPLAY", x11_display.value()); // configure X11 socket - } - else - { - application_environment.unsetenv("DISPLAY"); + env.unsetenv(key); } +} +auto execute_with_environment(std::vector const app, Environment& application_environment) -> pid_t +{ auto const exec_env = application_environment.exec_env(); std::vector exec_args; @@ -155,8 +130,9 @@ auto miral::launch_app_env( sigfillset(&all_signals); pthread_sigmask(SIG_UNBLOCK, &all_signals, nullptr); - // execvpe() isn't listed as being async-signal-safe, but the implementation looks fine and rewriting seems unnecessary - execvpe(exec_args[0], const_cast(exec_args.data()), const_cast(exec_env.data())); + // execvpe() isn't listed as being async-signal-safe, but the implementation looks fine and rewriting seems + // unnecessary + execvpe(exec_args[0], const_cast(exec_args.data()), const_cast(exec_env.data())); mir::log_warning("Failed to execute client (\"%s\") error: %s", exec_args[0], strerror(errno)); exit(EXIT_FAILURE); @@ -164,3 +140,40 @@ auto miral::launch_app_env( return pid; } +} // namespace + +auto miral::launch_app_env( + std::vector const& app, + mir::optional_value const& wayland_display, + mir::optional_value const& x11_display, + miral::AppEnvironment const& app_env) -> pid_t +{ + Environment application_environment; + + for (auto const& [key, value]: app_env) + assign_or_unset(application_environment, key, value); + + assign_or_unset(application_environment, "WAYLAND_DISPLAY", wayland_display); // configure Wayland socket + assign_or_unset(application_environment, "DISPLAY", x11_display); // configure X11 socket + + return execute_with_environment(app, application_environment); +} + +auto miral::launch_app_env( + std::vector const& app, + mir::optional_value const& wayland_display, + mir::optional_value const& x11_display, + std::optional const& xdg_activation_token, + miral::AppEnvironment const& app_env) -> pid_t +{ + Environment application_environment; + + for (auto const& [key, value]: app_env) + assign_or_unset(application_environment, key, value); + + assign_or_unset(application_environment, "WAYLAND_DISPLAY", wayland_display); // configure Wayland socket + assign_or_unset(application_environment, "DISPLAY", x11_display); // configure X11 socket + assign_or_unset(application_environment, "XDG_ACTIVATION_TOKEN", xdg_activation_token); + + return execute_with_environment(app, application_environment); +} diff --git a/src/miral/launch_app.h b/src/miral/launch_app.h index b3a9a36728..2eb82acf7f 100644 --- a/src/miral/launch_app.h +++ b/src/miral/launch_app.h @@ -35,6 +35,12 @@ auto launch_app_env(std::vector const& app, mir::optional_value const& wayland_display, mir::optional_value const& x11_display, AppEnvironment const& app_env) -> pid_t; + +auto launch_app_env(std::vector const& app, + mir::optional_value const& wayland_display, + mir::optional_value const& x11_display, + std::optional const& xdg_activation_token, + AppEnvironment const& app_env) -> pid_t; } #endif //MIRAL_LAUNCH_APP_H diff --git a/src/server/frontend_wayland/xdg_activation_v1.cpp b/src/server/frontend_wayland/xdg_activation_v1.cpp index dd77469d35..a859f49d10 100644 --- a/src/server/frontend_wayland/xdg_activation_v1.cpp +++ b/src/server/frontend_wayland/xdg_activation_v1.cpp @@ -26,7 +26,6 @@ #include "mir/shell/shell.h" #include "mir/wayland/protocol_error.h" #include "mir/log.h" -#include #include #include #include @@ -76,90 +75,6 @@ struct XdgActivationTokenData }; -class XdgActivationV1 : public wayland::XdgActivationV1::Global -{ -public: - XdgActivationV1( - struct wl_display* display, - std::shared_ptr const& shell, - std::shared_ptr const& session_coordinator, - std::shared_ptr const& main_loop, - std::shared_ptr> const& keyboard_observer_registrar, - Executor& wayland_executor); - ~XdgActivationV1(); - - std::shared_ptr const& create_token(std::shared_ptr const& session); - std::shared_ptr try_consume_token(std::string const& token); - void invalidate_all(); - void invalidate_if_not_from_session(std::shared_ptr const&); - -private: - class Instance : public wayland::XdgActivationV1 - { - public: - Instance( - struct wl_resource* resource, - mf::XdgActivationV1* xdg_activation_v1, - std::shared_ptr const& shell, - std::shared_ptr const& session_coordinator, - std::shared_ptr const& main_loop); - - private: - void get_activation_token(struct wl_resource* id) override; - - void activate(std::string const& token, struct wl_resource* surface) override; - - mf::XdgActivationV1* xdg_activation_v1; - std::shared_ptr shell; - std::shared_ptr const session_coordinator; - std::shared_ptr main_loop; - }; - - class KeyboardObserver: public input::KeyboardObserver - { - public: - KeyboardObserver(XdgActivationV1* xdg_activation_v1); - void keyboard_event(std::shared_ptr const& event) override; - void keyboard_focus_set(std::shared_ptr const& surface) override; - - private: - XdgActivationV1* xdg_activation_v1; - }; - - class SessionListener : public ms::SessionListener - { - public: - SessionListener(XdgActivationV1* xdg_activation_v1); - void starting(std::shared_ptr const&) override {} - void stopping(std::shared_ptr const&) override {} - void focused(std::shared_ptr const& session) override; - void unfocused() override {} - - void surface_created(ms::Session&, std::shared_ptr const&) override {} - void destroying_surface(ms::Session&, std::shared_ptr const&) override {} - - void buffer_stream_created( - ms::Session&, - std::shared_ptr const&) override {} - void buffer_stream_destroyed( - ms::Session&, - std::shared_ptr const&) override {} - - private: - XdgActivationV1* xdg_activation_v1; - }; - - void bind(wl_resource* resource) override; - - std::shared_ptr shell; - std::shared_ptr const session_coordinator; - std::shared_ptr main_loop; - std::shared_ptr> keyboard_observer_registrar; - std::shared_ptr keyboard_observer; - std::vector> pending_tokens; - std::mutex pending_tokens_mutex; -}; - class XdgActivationTokenV1 : public wayland::XdgActivationTokenV1 { public: @@ -231,6 +146,21 @@ std::shared_ptr const& mf::XdgActivationV1::create_t } } +std::string mf::XdgActivationV1::create_token_string() +{ + auto generated = generate_token(); + auto token = std::make_shared(generated, main_loop->create_alarm([this, generated]() + { + try_consume_token(generated); + }), nullptr); + + { + std::lock_guard guard(pending_tokens_mutex); + pending_tokens.emplace_back(std::move(token)); + return pending_tokens.back()->token; + } +} + std::shared_ptr mf::XdgActivationV1::try_consume_token(std::string const& token) { { diff --git a/src/server/frontend_wayland/xdg_activation_v1.h b/src/server/frontend_wayland/xdg_activation_v1.h index 388f9d1d19..f7af19f074 100644 --- a/src/server/frontend_wayland/xdg_activation_v1.h +++ b/src/server/frontend_wayland/xdg_activation_v1.h @@ -17,6 +17,8 @@ #ifndef MIR_FRONTEND_XDG_ACTIVATION_UNSTABLE_V1_H #define MIR_FRONTEND_XDG_ACTIVATION_UNSTABLE_V1_H +#include "mir/input/keyboard_observer.h" +#include "mir/scene/session_listener.h" #include "xdg-activation-v1_wrapper.h" #include "mir/observer_registrar.h" @@ -32,6 +34,7 @@ class Shell; namespace scene { class SessionCoordinator; +class Session; } namespace input { @@ -48,6 +51,93 @@ auto create_xdg_activation_v1( std::shared_ptr> const&, Executor& wayland_executor) -> std::shared_ptr; + +class XdgActivationTokenData; +class BufferStream; +class XdgActivationV1 : public wayland::XdgActivationV1::Global +{ +public: + XdgActivationV1( + struct wl_display* display, + std::shared_ptr const& shell, + std::shared_ptr const& session_coordinator, + std::shared_ptr const& main_loop, + std::shared_ptr> const& keyboard_observer_registrar, + Executor& wayland_executor); + ~XdgActivationV1(); + + std::shared_ptr const& create_token(std::shared_ptr const& session); + std::string create_token_string(); + std::shared_ptr try_consume_token(std::string const& token); + void invalidate_all(); + void invalidate_if_not_from_session(std::shared_ptr const&); + +private: + class Instance : public wayland::XdgActivationV1 + { + public: + Instance( + struct wl_resource* resource, + mir::frontend::XdgActivationV1* xdg_activation_v1, + std::shared_ptr const& shell, + std::shared_ptr const& session_coordinator, + std::shared_ptr const& main_loop); + + private: + void get_activation_token(struct wl_resource* id) override; + + void activate(std::string const& token, struct wl_resource* surface) override; + + mir::frontend::XdgActivationV1* xdg_activation_v1; + std::shared_ptr shell; + std::shared_ptr const session_coordinator; + std::shared_ptr main_loop; + }; + + class KeyboardObserver: public input::KeyboardObserver + { + public: + KeyboardObserver(mir::frontend::XdgActivationV1* xdg_activation_v1); + void keyboard_event(std::shared_ptr const& event) override; + void keyboard_focus_set(std::shared_ptr const& surface) override; + + private: + mir::frontend::XdgActivationV1* xdg_activation_v1; + }; + + class SessionListener : public mir::scene::SessionListener + { + public: + SessionListener(mir::frontend::XdgActivationV1* xdg_activation_v1); + void starting(std::shared_ptr const&) override {} + void stopping(std::shared_ptr const&) override {} + void focused(std::shared_ptr const& session) override; + void unfocused() override {} + + void surface_created(mir::scene::Session&, std::shared_ptr const&) override {} + void destroying_surface(mir::scene::Session&, std::shared_ptr const&) override {} + + void buffer_stream_created( + mir::scene::Session&, + std::shared_ptr const&) override {} + void buffer_stream_destroyed( + mir::scene::Session&, + std::shared_ptr const&) override {} + + private: + mir::frontend::XdgActivationV1* xdg_activation_v1; + }; + + void bind(wl_resource* resource) override; + + std::shared_ptr shell; + std::shared_ptr const session_coordinator; + std::shared_ptr main_loop; + std::shared_ptr> keyboard_observer_registrar; + std::shared_ptr keyboard_observer; + std::vector> pending_tokens; + std::mutex pending_tokens_mutex; +}; } } diff --git a/src/server/server.cpp b/src/server/server.cpp index 3126ca86b9..4b5a557a5d 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -16,6 +16,7 @@ #include "mir/server.h" +#include "frontend_wayland/xdg_activation_v1.h" #include "mir/emergency_cleanup.h" #include "mir/fd.h" #include "mir/frontend/connector.h" @@ -37,10 +38,7 @@ #include "mir/renderer/renderer_factory.h" #include "frontend_wayland/wayland_connector.h" - #include -#include - namespace mo = mir::options; namespace mi = mir::input; @@ -480,6 +478,22 @@ auto mir::Server::x11_display() const -> mir::optional_value BOOST_THROW_EXCEPTION(std::logic_error("Cannot open connection when not running")); } +auto mir::Server::get_activation_token() const -> std::optional +{ + if (auto const config = self->server_config) + { + auto const& connector = std::dynamic_pointer_cast(config->the_wayland_connector()); + auto xdg_activation_impl = std::static_pointer_cast(connector->get_extension("xdg_activation_v1")); + + if (!xdg_activation_impl) + return {}; + + return xdg_activation_impl->create_token_string(); + } + + BOOST_THROW_EXCEPTION(std::logic_error("Cannot open connection when not running")); +} + void mir::Server::run_on_wayland_display(std::function const& functor) { if (auto const config = self->server_config) diff --git a/src/server/symbols.map b/src/server/symbols.map index b80c832125..c295fdcaa3 100644 --- a/src/server/symbols.map +++ b/src/server/symbols.map @@ -1404,3 +1404,10 @@ global: local: *; }; +MIR_SERVER_INTERNAL_2.18 { +global: + extern "C++" { + mir::Server::get_activation_token*; + }; +} MIR_SERVER_INTERNAL_2.19; +