Skip to content

Commit

Permalink
core: add a reason hint for keyboard focus change
Browse files Browse the repository at this point in the history
This is useful for example when we want to close popups on actual
focus change (user alt-tabbed, clicked outside of the view, etc.) but
not for 'mundane' reasons like a refocus if the popup does not have a
grab.
  • Loading branch information
ammen99 committed Jun 18, 2024
1 parent 1123ecd commit 74c8f5e
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/api/wayfire/plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class plugin_interface_t
using wayfire_plugin_load_func = wf::plugin_interface_t * (*)();

/** The version of Wayfire's API/ABI */
constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2024'04'16;
constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2024'06'18;

/**
* Each plugin must also provide a function which returns the Wayfire API/ABI
Expand Down
11 changes: 10 additions & 1 deletion src/api/wayfire/seat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

namespace wf
{
enum class keyboard_focus_reason
{
USER,
GRAB,
REFOCUS,
UNKNOWN,
};

/**
* A seat represents a group of input devices (mouse, keyboard, etc.) which logically belong together.
* Each seat has its own keyboard, touch, pointer and tablet focus.
Expand Down Expand Up @@ -52,7 +60,8 @@ class seat_t
*
* The new_focus' last focus timestamp will be updated.
*/
void set_active_node(wf::scene::node_ptr node);
void set_active_node(wf::scene::node_ptr node,
wf::keyboard_focus_reason reason = keyboard_focus_reason::UNKNOWN);

/**
* Get the node which has current keyboard focus.
Expand Down
2 changes: 2 additions & 0 deletions src/api/wayfire/signal-definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "wayfire/view.hpp"
#include "wayfire/output.hpp"
#include "wayfire/seat.hpp"

/**
* Documentation of signals emitted from core components.
Expand Down Expand Up @@ -201,6 +202,7 @@ struct reload_config_signal
struct keyboard_focus_changed_signal
{
wf::scene::node_ptr new_focus;
keyboard_focus_reason reason = keyboard_focus_reason::UNKNOWN;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/core/seat/seat-impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ struct seat_t::impl
uint32_t get_modifiers();
void break_mod_bindings();

void set_keyboard_focus(wf::scene::node_ptr keyboard_focus);
void set_keyboard_focus(wf::scene::node_ptr keyboard_focus, wf::keyboard_focus_reason reason);
wf::scene::node_ptr keyboard_focus;
// Keys sent to the current keyboard focus
std::multiset<uint32_t> pressed_keys;
Expand Down
12 changes: 7 additions & 5 deletions src/core/seat/seat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "wayfire/view.hpp"

wf::seat_t::~seat_t() = default;
void wf::seat_t::set_active_node(wf::scene::node_ptr node)
void wf::seat_t::set_active_node(wf::scene::node_ptr node, wf::keyboard_focus_reason reason)
{
if (node)
{
Expand All @@ -36,7 +36,7 @@ void wf::seat_t::set_active_node(wf::scene::node_ptr node)
}

auto focus = wf::get_core().scene()->keyboard_refocus(priv->active_output);
priv->set_keyboard_focus(focus.node ? focus.node->shared_from_this() : nullptr);
priv->set_keyboard_focus(focus.node ? focus.node->shared_from_this() : nullptr, reason);
}

wf::scene::node_ptr wf::seat_t::get_active_node()
Expand Down Expand Up @@ -166,7 +166,7 @@ void wf::seat_t::focus_view(wayfire_view v)

const auto& give_input_focus = [this] (wayfire_view view)
{
set_active_node(view ? view->get_surface_root_node() : nullptr);
set_active_node(view ? view->get_surface_root_node() : nullptr, keyboard_focus_reason::USER);
};

v = select_focus_view(v);
Expand Down Expand Up @@ -198,7 +198,7 @@ void wf::seat_t::refocus()
priv->update_active_view(focus_sptr);
}

priv->set_keyboard_focus(focus_sptr);
priv->set_keyboard_focus(focus_sptr, keyboard_focus_reason::REFOCUS);
}

uint32_t wf::seat_t::get_keyboard_modifiers()
Expand Down Expand Up @@ -504,10 +504,11 @@ void wf::seat_t::impl::transfer_grab(wf::scene::node_ptr grab_node)

wf::keyboard_focus_changed_signal data;
data.new_focus = grab_node;
data.reason = keyboard_focus_reason::GRAB;
wf::get_core().emit(&data);
}

void wf::seat_t::impl::set_keyboard_focus(wf::scene::node_ptr new_focus)
void wf::seat_t::impl::set_keyboard_focus(wf::scene::node_ptr new_focus, keyboard_focus_reason reason)
{
if (this->keyboard_focus == new_focus)
{
Expand All @@ -528,6 +529,7 @@ void wf::seat_t::impl::set_keyboard_focus(wf::scene::node_ptr new_focus)

wf::keyboard_focus_changed_signal data;
data.new_focus = new_focus;
data.reason = reason;
wf::get_core().emit(&data);
}

Expand Down
50 changes: 43 additions & 7 deletions src/view/xdg-shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,37 @@ class wayfire_xdg_popup_node : public wf::scene::translation_node_t
std::unique_ptr<wf::wlr_view_keyboard_interaction_t> kb_interaction;
};

bool wayfire_xdg_popup::should_close_on_focus_change(wf::keyboard_focus_changed_signal *ev)
{
if (!is_mapped())
{
return false;
}

auto view = wf::node_to_view(ev->new_focus);
const bool focus_client_changes = view && (view->get_client() != this->get_client());
const bool has_grab = this->popup->seat != nullptr;

if (has_grab)
{
return !view || focus_client_changes;
} else
{
if ((ev->reason == wf::keyboard_focus_reason::UNKNOWN) ||
(ev->reason == wf::keyboard_focus_reason::REFOCUS))
{
return false;
}

if ((ev->new_focus && !view) || focus_client_changes)
{
return true;
}
}

return false;
}

wayfire_xdg_popup::wayfire_xdg_popup(wlr_xdg_popup *popup) : wf::view_interface_t()
{
this->popup_parent = wf::wl_surface_to_wayfire_view(popup->parent->resource).get();
Expand All @@ -81,11 +112,9 @@ wayfire_xdg_popup::wayfire_xdg_popup(wlr_xdg_popup *popup) : wf::view_interface_
// Note: we shouldn't close nested popups manually, since the parent popups will destroy them as well.
this->on_keyboard_focus_changed = [=] (wf::keyboard_focus_changed_signal *ev)
{
auto view = wf::node_to_view(ev->new_focus);
if (!view || (view->get_client() != this->get_client()))
if (should_close_on_focus_change(ev))
{
this->close();
return;
}
};
}
Expand All @@ -97,7 +126,6 @@ wayfire_xdg_popup::wayfire_xdg_popup(wlr_xdg_popup *popup) : wf::view_interface_

on_map.set_callback([&] (void*) { map(); });
on_unmap.set_callback([&] (void*) { unmap(); });
on_destroy.set_callback([&] (void*) { destroy(); });
on_new_popup.set_callback([&] (void *data)
{
create_xdg_popup((wlr_xdg_popup*)data);
Expand All @@ -113,7 +141,6 @@ wayfire_xdg_popup::wayfire_xdg_popup(wlr_xdg_popup *popup) : wf::view_interface_

on_map.connect(&popup->base->surface->events.map);
on_unmap.connect(&popup->base->surface->events.unmap);
on_destroy.connect(&popup->base->events.destroy);
on_new_popup.connect(&popup->base->events.new_popup);
on_ping_timeout.connect(&popup->base->events.ping_timeout);
on_reposition.connect(&popup->events.reposition);
Expand Down Expand Up @@ -152,6 +179,7 @@ std::shared_ptr<wayfire_xdg_popup> wayfire_xdg_popup::create(wlr_xdg_popup *popu

void wayfire_xdg_popup::map()
{
LOGC(VIEWS, "Trying to map xdg-popup ", self());
if (!get_output())
{
close();
Expand Down Expand Up @@ -189,9 +217,12 @@ void wayfire_xdg_popup::unmap()
{
if (!is_mapped())
{
LOGC(VIEWS, "Denying unmap of unmapped xdg-popup ", self());
return;
}

auto _self_ref = shared_from_this();
LOGC(VIEWS, "Unmapping xdg-popup ", self());
on_keyboard_focus_changed.disconnect();
damage();
emit_view_pre_unmap();
Expand Down Expand Up @@ -266,7 +297,6 @@ void wayfire_xdg_popup::destroy()
{
on_map.disconnect();
on_unmap.disconnect();
on_destroy.disconnect();
on_new_popup.disconnect();
on_ping_timeout.disconnect();
on_reposition.disconnect();
Expand All @@ -275,8 +305,10 @@ void wayfire_xdg_popup::destroy()

void wayfire_xdg_popup::close()
{
LOGC(VIEWS, "Closing xdg-popup ", self(), " ", is_mapped());
if (is_mapped())
{
wf::print_trace(true);
wlr_xdg_popup_destroy(popup);
}
}
Expand Down Expand Up @@ -372,7 +404,11 @@ class xdg_popup_controller_t
public:
xdg_popup_controller_t(wlr_xdg_popup *popup)
{
on_destroy.set_callback([=] (auto) { delete this; });
on_destroy.set_callback([=] (auto)
{
view->destroy();
delete this;
});
on_destroy.connect(&popup->base->events.destroy);
view = wayfire_xdg_popup::create(popup);
}
Expand Down
5 changes: 3 additions & 2 deletions src/view/xdg-shell.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ class wayfire_xdg_popup_node;
class wayfire_xdg_popup : public wf::view_interface_t
{
protected:
wf::wl_listener_wrapper on_destroy, on_new_popup,
on_map, on_unmap, on_ping_timeout, on_reposition;
wf::wl_listener_wrapper on_new_popup, on_map, on_unmap, on_ping_timeout, on_reposition;

wf::signal::connection_t<wf::view_geometry_changed_signal> parent_geometry_changed;
wf::signal::connection_t<wf::view_title_changed_signal> parent_title_changed;
Expand Down Expand Up @@ -74,6 +73,8 @@ class wayfire_xdg_popup : public wf::view_interface_t
void handle_app_id_changed(std::string new_app_id);
void handle_title_changed(std::string new_title);
void update_size();

bool should_close_on_focus_change(wf::keyboard_focus_changed_signal *ev);
};

void create_xdg_popup(wlr_xdg_popup *popup);
Expand Down

0 comments on commit 74c8f5e

Please sign in to comment.