Skip to content

Commit

Permalink
Pass XDG_ACTIVATION_TOKEN to apps launched via launch_app_env
Browse files Browse the repository at this point in the history
  • Loading branch information
tarek-y-ismail committed Dec 18, 2024
1 parent 40c93fe commit aef6758
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 125 deletions.
3 changes: 3 additions & 0 deletions src/include/server/mir/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <functional>
#include <memory>
#include <optional>
#include <vector>

struct wl_display;
Expand Down Expand Up @@ -473,6 +474,8 @@ class Server
/// Get the name of the X11 display usable as a $DISPLAY value
auto x11_display() const -> optional_value<std::string>;

auto get_activation_token() const -> std::optional<std::string>;

/// Overrides the standard set of Wayland extensions (mir::frontend::get_standard_extensions()) with a new list
void set_enabled_wayland_extensions(std::vector<std::string> const& extensions);
/** @} */
Expand Down
5 changes: 3 additions & 2 deletions src/miral/external_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ auto miral::ExternalClientLauncher::launch(std::vector<std::string> 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<Self>()} {}
Expand All @@ -133,7 +133,8 @@ auto miral::ExternalClientLauncher::launch_using_x11(std::vector<std::string> 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;
Expand Down
83 changes: 48 additions & 35 deletions src/miral/launch_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@

#include <boost/throw_exception.hpp>

#include <string>
#include <unistd.h>
#include <signal.h>

#include <cstring>
#include <stdexcept>
#include <system_error>
#include <vector>

Expand Down Expand Up @@ -93,46 +93,21 @@ auto Environment::exec_env() const & -> std::vector<char const*>
result.push_back(nullptr);
return result;
}
} // namespace

auto miral::launch_app_env(
std::vector<std::string> const& app,
mir::optional_value<std::string> const& wayland_display,
mir::optional_value<std::string> 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<std::string> const app, Environment& application_environment) -> pid_t
{
auto const exec_env = application_environment.exec_env();

std::vector<char const*> exec_args;
Expand All @@ -155,12 +130,50 @@ 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<char*const*>(exec_args.data()), const_cast<char*const*>(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<char* const*>(exec_args.data()), const_cast<char* const*>(exec_env.data()));

mir::log_warning("Failed to execute client (\"%s\") error: %s", exec_args[0], strerror(errno));
exit(EXIT_FAILURE);
}

return pid;
}
} // namespace

auto miral::launch_app_env(
std::vector<std::string> const& app,
mir::optional_value<std::string> const& wayland_display,
mir::optional_value<std::string> 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<std::string> const& app,
mir::optional_value<std::string> const& wayland_display,
mir::optional_value<std::string> const& x11_display,
std::optional<std::string> 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);
}
6 changes: 6 additions & 0 deletions src/miral/launch_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ auto launch_app_env(std::vector<std::string> const& app,
mir::optional_value<std::string> const& wayland_display,
mir::optional_value<std::string> const& x11_display,
AppEnvironment const& app_env) -> pid_t;

auto launch_app_env(std::vector<std::string> const& app,
mir::optional_value<std::string> const& wayland_display,
mir::optional_value<std::string> const& x11_display,
std::optional<std::string> const& xdg_activation_token,
AppEnvironment const& app_env) -> pid_t;
}

#endif //MIRAL_LAUNCH_APP_H
100 changes: 15 additions & 85 deletions src/server/frontend_wayland/xdg_activation_v1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include "mir/shell/shell.h"
#include "mir/wayland/protocol_error.h"
#include "mir/log.h"
#include <random>
#include <chrono>
#include <uuid.h>
#include <mir/events/keyboard_event.h>
Expand Down Expand Up @@ -76,90 +75,6 @@ struct XdgActivationTokenData
};


class XdgActivationV1 : public wayland::XdgActivationV1::Global
{
public:
XdgActivationV1(
struct wl_display* display,
std::shared_ptr<msh::Shell> const& shell,
std::shared_ptr<ms::SessionCoordinator> const& session_coordinator,
std::shared_ptr<MainLoop> const& main_loop,
std::shared_ptr<ObserverRegistrar<input::KeyboardObserver>> const& keyboard_observer_registrar,
Executor& wayland_executor);
~XdgActivationV1();

std::shared_ptr<XdgActivationTokenData> const& create_token(std::shared_ptr<ms::Session> const& session);
std::shared_ptr<XdgActivationTokenData> try_consume_token(std::string const& token);
void invalidate_all();
void invalidate_if_not_from_session(std::shared_ptr<ms::Session> const&);

private:
class Instance : public wayland::XdgActivationV1
{
public:
Instance(
struct wl_resource* resource,
mf::XdgActivationV1* xdg_activation_v1,
std::shared_ptr<msh::Shell> const& shell,
std::shared_ptr<ms::SessionCoordinator> const& session_coordinator,
std::shared_ptr<MainLoop> 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<msh::Shell> shell;
std::shared_ptr<ms::SessionCoordinator> const session_coordinator;
std::shared_ptr<MainLoop> main_loop;
};

class KeyboardObserver: public input::KeyboardObserver
{
public:
KeyboardObserver(XdgActivationV1* xdg_activation_v1);
void keyboard_event(std::shared_ptr<MirEvent const> const& event) override;
void keyboard_focus_set(std::shared_ptr<mi::Surface> const& surface) override;

private:
XdgActivationV1* xdg_activation_v1;
};

class SessionListener : public ms::SessionListener
{
public:
SessionListener(XdgActivationV1* xdg_activation_v1);
void starting(std::shared_ptr<ms::Session> const&) override {}
void stopping(std::shared_ptr<ms::Session> const&) override {}
void focused(std::shared_ptr<ms::Session> const& session) override;
void unfocused() override {}

void surface_created(ms::Session&, std::shared_ptr<ms::Surface> const&) override {}
void destroying_surface(ms::Session&, std::shared_ptr<ms::Surface> const&) override {}

void buffer_stream_created(
ms::Session&,
std::shared_ptr<mf::BufferStream> const&) override {}
void buffer_stream_destroyed(
ms::Session&,
std::shared_ptr<mf::BufferStream> const&) override {}

private:
XdgActivationV1* xdg_activation_v1;
};

void bind(wl_resource* resource) override;

std::shared_ptr<msh::Shell> shell;
std::shared_ptr<ms::SessionCoordinator> const session_coordinator;
std::shared_ptr<MainLoop> main_loop;
std::shared_ptr<ObserverRegistrar<input::KeyboardObserver>> keyboard_observer_registrar;
std::shared_ptr<KeyboardObserver> keyboard_observer;
std::vector<std::shared_ptr<XdgActivationTokenData>> pending_tokens;
std::mutex pending_tokens_mutex;
};

class XdgActivationTokenV1 : public wayland::XdgActivationTokenV1
{
public:
Expand Down Expand Up @@ -231,6 +146,21 @@ std::shared_ptr<mf::XdgActivationTokenData> const& mf::XdgActivationV1::create_t
}
}

std::string mf::XdgActivationV1::create_token_string()
{
auto generated = generate_token();
auto token = std::make_shared<XdgActivationTokenData>(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::XdgActivationTokenData> mf::XdgActivationV1::try_consume_token(std::string const& token)
{
{
Expand Down
Loading

0 comments on commit aef6758

Please sign in to comment.