Skip to content

Commit f8fe46f

Browse files
committed
xdg-activation: generate activation tokens and pass them to commands run by Wayfire
This is required for them to activate if focusing newly mapped views by default is disabled.
1 parent b811724 commit f8fe46f

1 file changed

Lines changed: 72 additions & 8 deletions

File tree

plugins/protocols/xdg-activation.cpp

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <wayfire/nonstd/wlroots-full.hpp>
99
#include <wayfire/window-manager.hpp>
1010
#include <wayfire/util.hpp>
11+
#include <wayfire/seat.hpp>
1112
#include "config.h"
1213

1314
class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
@@ -28,13 +29,15 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
2829

2930
xdg_activation_request_activate.connect(&xdg_activation->events.request_activate);
3031
xdg_activation_new_token.connect(&xdg_activation->events.new_token);
32+
wf::get_core().connect(&on_run_command);
3133
}
3234

3335
void fini() override
3436
{
3537
xdg_activation_request_activate.disconnect();
3638
xdg_activation_new_token.disconnect();
3739
xdg_activation_token_destroy.disconnect();
40+
xdg_activation_token_self_destroy.disconnect();
3841
on_view_mapped.disconnect();
3942
last_token = nullptr;
4043
if (last_view)
@@ -43,6 +46,8 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
4346
last_view->disconnect(&on_view_deactivated);
4447
last_view = nullptr;
4548
}
49+
50+
wf::get_core().disconnect(&on_run_command);
4651
}
4752

4853
bool is_unloadable() override
@@ -57,19 +62,23 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
5762
{
5863
auto event = static_cast<const struct wlr_xdg_activation_v1_request_activate_event*>(data);
5964

60-
if (!event->token->seat)
65+
if (event->token != last_self_token)
6166
{
62-
LOGI("Denying focus request, token was rejected at creation");
63-
return;
64-
}
67+
if (!event->token->seat)
68+
{
69+
LOGI("Denying focus request, token was rejected at creation");
70+
return;
71+
}
6572

66-
if (only_last_token && (event->token != last_token))
67-
{
68-
LOGI("Denying focus request, token is expired");
69-
return;
73+
if (only_last_token && (event->token != last_token))
74+
{
75+
LOGI("Denying focus request, token is expired");
76+
return;
77+
}
7078
}
7179

7280
last_token = nullptr; // avoid reusing the same token
81+
last_self_token = nullptr;
7382

7483
if (prevent_focus_stealing && !last_view)
7584
{
@@ -167,6 +176,13 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
167176
xdg_activation_token_destroy.disconnect();
168177
});
169178

179+
xdg_activation_token_self_destroy.set_callback([this] (void *data)
180+
{
181+
last_self_token = nullptr;
182+
183+
xdg_activation_token_self_destroy.disconnect();
184+
});
185+
170186
timeout.set_callback(timeout_changed);
171187
}
172188

@@ -226,11 +242,59 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
226242
wf::get_core().default_wm->focus_request(signal->view);
227243
};
228244

245+
wf::signal::connection_t<wf::command_run_signal> on_run_command = [this] (auto signal)
246+
{
247+
if (wf::get_core().default_wm->focus_on_map)
248+
{
249+
// no need to do anything if views are focused anyway
250+
return;
251+
}
252+
253+
if (last_self_token)
254+
{
255+
// TODO: invalidate our last token !
256+
last_self_token = nullptr;
257+
}
258+
259+
auto active_view = wf::get_core().seat->get_active_view();
260+
if (active_view && (active_view->role == wf::VIEW_ROLE_DESKTOP_ENVIRONMENT))
261+
{
262+
active_view = nullptr;
263+
}
264+
265+
auto active_toplevel = active_view ? wf::toplevel_cast(active_view) : nullptr;
266+
267+
if (!active_toplevel)
268+
{
269+
// if there is no active view, we don't need a token
270+
return;
271+
}
272+
273+
if (last_view)
274+
{
275+
// TODO: we need a separate last_view actually !
276+
last_view->disconnect(&on_view_unmapped);
277+
last_view->disconnect(&on_view_deactivated);
278+
}
279+
280+
last_view = active_toplevel;
281+
last_view->connect(&on_view_unmapped);
282+
last_view->connect(&on_view_deactivated);
283+
last_self_token = wlr_xdg_activation_token_v1_create(xdg_activation);
284+
xdg_activation_token_self_destroy.disconnect();
285+
xdg_activation_token_self_destroy.connect(&last_self_token->events.destroy);
286+
const char *token_id = wlr_xdg_activation_token_v1_get_name(last_self_token);
287+
signal->env.emplace_back("XDG_ACTIVATION_TOKEN", token_id);
288+
signal->env.emplace_back("DESKTOP_STARTUP_ID", token_id);
289+
};
290+
229291
struct wlr_xdg_activation_v1 *xdg_activation;
230292
wf::wl_listener_wrapper xdg_activation_request_activate;
231293
wf::wl_listener_wrapper xdg_activation_new_token;
232294
wf::wl_listener_wrapper xdg_activation_token_destroy;
295+
wf::wl_listener_wrapper xdg_activation_token_self_destroy;
233296
struct wlr_xdg_activation_token_v1 *last_token = nullptr;
297+
struct wlr_xdg_activation_token_v1 *last_self_token = nullptr;
234298
wayfire_toplevel_view last_view = nullptr; // view that created the token
235299

236300
wf::option_wrapper_t<bool> check_surface{"xdg-activation/check_surface"};

0 commit comments

Comments
 (0)