Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions metadata/xdg-activation.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
<_long>Whether to reject activation requests if a newer request has arrived since their creation.</_long>
<default>false</default>
</option>
<option name="focus_stealing_prevention" type="bool">
<_short>Prevent stealing focus by an activation request</_short>
<_long>Whether to reject an activation request if the user interacted with a different view since its creation.</_long>
<default>true</default>
</option>
<option name="timeout" type="int">
<_short>Timeout for activation (in seconds)</_short>
<_long>Focus requests will be ignored if at least this amount of time has elapsed between creating and using it.</_long>
Expand Down
66 changes: 66 additions & 0 deletions plugins/protocols/xdg-activation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
xdg_activation_new_token.disconnect();
xdg_activation_token_destroy.disconnect();
last_token = nullptr;
if (last_view)
{
last_view->disconnect(&on_view_unmapped);
last_view->disconnect(&on_view_deactivated);
last_view = nullptr;
}
}

bool is_unloadable() override
Expand Down Expand Up @@ -64,6 +70,17 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t

last_token = nullptr; // avoid reusing the same token

if (last_view)
{
last_view->disconnect(&on_view_unmapped);
last_view->disconnect(&on_view_deactivated);
last_view = nullptr;
} else if (prevent_focus_stealing)
{
LOGI("Denying focus request, requesting view has been deactivated");
return;
}

wayfire_view view = wf::wl_surface_to_wayfire_view(event->surface->resource);
if (!view)
{
Expand Down Expand Up @@ -100,6 +117,26 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
return;
}

// unset any previously saved view
if (last_view)
{
last_view->disconnect(&on_view_unmapped);
last_view->disconnect(&on_view_deactivated);
last_view = nullptr;
}

wayfire_view view = token->surface ? wf::wl_surface_to_wayfire_view(
token->surface->resource) : nullptr;
if (view)
{
last_view = wf::toplevel_cast(view); // might return nullptr
if (last_view)
{
last_view->connect(&on_view_unmapped);
last_view->connect(&on_view_deactivated);
}
}

// update our token and connect its destroy signal
last_token = token;
xdg_activation_token_destroy.disconnect();
Expand All @@ -125,14 +162,43 @@ class wayfire_xdg_activation_protocol_impl : public wf::plugin_interface_t
}
};

wf::signal::connection_t<wf::view_unmapped_signal> on_view_unmapped = [this] (auto)
{
last_view->disconnect(&on_view_unmapped);
last_view->disconnect(&on_view_deactivated);
// handle the case when last_view was a dialog that is closed by user interaction
last_view = last_view->parent;
if (last_view)
{
last_view->connect(&on_view_unmapped);
last_view->connect(&on_view_deactivated);
}
};

wf::signal::connection_t<wf::view_activated_state_signal> on_view_deactivated = [this] (auto)
{
if (last_view->activated)
{
// could be a spurious event, e.g. activating the parent
// view after closing a dialog
return;
}

last_view->disconnect(&on_view_unmapped);
last_view->disconnect(&on_view_deactivated);
last_view = nullptr;
};

struct wlr_xdg_activation_v1 *xdg_activation;
wf::wl_listener_wrapper xdg_activation_request_activate;
wf::wl_listener_wrapper xdg_activation_new_token;
wf::wl_listener_wrapper xdg_activation_token_destroy;
struct wlr_xdg_activation_token_v1 *last_token = nullptr;
wayfire_toplevel_view last_view = nullptr; // view that created the token

wf::option_wrapper_t<bool> check_surface{"xdg-activation/check_surface"};
wf::option_wrapper_t<bool> only_last_token{"xdg-activation/only_last_request"};
wf::option_wrapper_t<bool> prevent_focus_stealing{"xdg-activation/focus_stealing_prevention"};
wf::option_wrapper_t<int> timeout{"xdg-activation/timeout"};
};

Expand Down