Skip to content

Commit

Permalink
scene: add RAW_INPUT flag as a replacement for retain_pressed_state
Browse files Browse the repository at this point in the history
The retain_pressed_state mechanism was not enough, because it generates
fake button release events. Instead, we let grab nodes indicate that
they want to receive real events only.
  • Loading branch information
ammen99 committed Jun 1, 2023
1 parent b0b801e commit 3cca6c9
Show file tree
Hide file tree
Showing 21 changed files with 106 additions and 48 deletions.
25 changes: 22 additions & 3 deletions plugins/common/wayfire/plugins/common/input-grab.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 21,8 @@ class grab_node_t : public node_t
wf::output_t *output;
keyboard_interaction_t *keyboard = nullptr;
pointer_interaction_t *pointer = nullptr;
touch_interaction_t *touch = nullptr;
touch_interaction_t *touch = nullptr;
node_flags_bitmask_t m_flags = 0;

public:
grab_node_t(std::string name, wf::output_t *output,
Expand All @@ -32,6 33,16 @@ class grab_node_t : public node_t
keyboard(keyboard), pointer(pointer), touch(touch)
{}

node_flags_bitmask_t flags() const override
{
return node_t::flags() | m_flags;
}

void set_additional_flags(node_flags_bitmask_t add_flags)
{
this->m_flags = add_flags;
}

std::optional<input_node_t> find_node_at(const wf::pointf_t& at) override
{
if (output->get_layout_geometry() & at)
Expand Down Expand Up @@ -104,6 115,14 @@ class input_grab_t
grab_node = std::make_shared<scene::grab_node_t>(name, output, keyboard, pointer, touch);
}

/**
* Set/unset the RAW_INPUT flag on the grab node.
*/
void set_wants_raw_input(bool wants_raw)
{
grab_node->set_additional_flags(wants_raw ? (uint64_t)wf::scene::node_flags::RAW_INPUT : 0);
}

bool is_grabbed() const
{
return grab_node->parent() != nullptr;
Expand All @@ -112,7 131,7 @@ class input_grab_t
/**
* Grab input from all layers from background to @layer_below.
*/
void grab_input(wf::scene::layer layer_below, bool retain_pressed_state = false)
void grab_input(wf::scene::layer layer_below)
{
wf::dassert(grab_node->parent() == nullptr, "Trying to grab twice!");

Expand All @@ -126,7 145,7 @@ class input_grab_t
std::to_string((int)layer_below));
children.insert(idx, grab_node);
root->set_children_list(children);
wf::get_core().transfer_grab(grab_node, retain_pressed_state);
wf::get_core().transfer_grab(grab_node);
scene::update(root, scene::update_flag::CHILDREN_LIST);
output->refocus();
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/cube/cube.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 247,7 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer
void init() override
{
input_grab = std::make_unique<wf::input_grab_t>("cube", output, nullptr, this, nullptr);
input_grab->set_wants_raw_input(true);

animation.cube_animation.offset_y.set(0, 0);
animation.cube_animation.offset_z.set(0, 0);
Expand Down Expand Up @@ -523,6 524,7 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer
update_view_matrix();
output->render->schedule_redraw();

// Let the button go to the input grab
return false;
}

Expand Down
6 changes: 6 additions & 0 deletions plugins/scale/scale.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 533,9 @@ class wayfire_scale : public wf::per_output_plugin_instance_t,
opts.enable_snap_off = true;
opts.snap_off_threshold = 200;

// We want to receive raw inputs (e.g. no fake pointer releases) in case the view is moved to
// another output.
grab->set_wants_raw_input(true);
drag_helper->start_drag(last_selected_view, to, opts);
} else if (drag_helper->view)
{
Expand Down Expand Up @@ -1250,6 1253,7 @@ class wayfire_scale : public wf::per_output_plugin_instance_t,
{
if ((ev->focus_output == output) && can_handle_drag())
{
grab->set_wants_raw_input(true);
drag_helper->set_scale(1.0);
}
};
Expand All @@ -1273,6 1277,8 @@ class wayfire_scale : public wf::per_output_plugin_instance_t,

wf::move_drag::adjust_view_on_output(ev);
}

grab->set_wants_raw_input(false);
};

wf::signal::connection_t<wf::move_drag::snap_off_signal> on_drag_snap_off = [=] (auto)
Expand Down
3 changes: 3 additions & 0 deletions plugins/single_plugins/expo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 227,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
state.button_pressed = true;
auto [vw, vh] = output->wset()->get_workspace_grid_size();
drag_helper->set_scale(std::max(vw, vh));
input_grab->set_wants_raw_input(true);
}
};

Expand Down Expand Up @@ -271,6 272,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
move_started_ws = offscreen_point;
}

input_grab->set_wants_raw_input(false);
this->state.button_pressed = false;
};

Expand Down Expand Up @@ -414,6 416,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar
drag_helper->start_drag(view, grab output_offset,
wf::move_drag::find_relative_grab(bbox, ws_coords), opts);
move_started_ws = target_ws;
input_grab->set_wants_raw_input(true);
}

const wf::point_t offscreen_point = {-10, -10};
Expand Down
2 changes: 1 addition & 1 deletion plugins/single_plugins/fast-switcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 153,7 @@ class wayfire_fast_switcher : public wf::per_output_plugin_instance_t, public wf
set_view_alpha(view, inactive_alpha);
}

input_grab->grab_input(wf::scene::layer::OVERLAY, true);
input_grab->grab_input(wf::scene::layer::OVERLAY);
activating_modifiers = wf::get_core().seat->get_keyboard_modifiers();
switch_next(forward);

Expand Down
2 changes: 1 addition & 1 deletion plugins/single_plugins/move.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 256,7 @@ class wayfire_move : public wf::per_output_plugin_instance_t,
return false;
}

this->input_grab->grab_input(wf::scene::layer::OVERLAY, true);
this->input_grab->grab_input(wf::scene::layer::OVERLAY);

auto touch = wf::get_core().get_touch_state();
is_using_touch = !touch.fingers.empty();
Expand Down
4 changes: 3 additions & 1 deletion plugins/single_plugins/resize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 195,9 @@ class wayfire_resize : public wf::per_output_plugin_instance_t, public wf::point
return false;
}

input_grab->grab_input(wf::scene::layer::OVERLAY, true);
input_grab->set_wants_raw_input(true);
input_grab->grab_input(wf::scene::layer::OVERLAY);

grab_start = get_input_coords();
grabbed_geometry = view->get_wm_geometry();

Expand Down
2 changes: 1 addition & 1 deletion plugins/single_plugins/switcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 298,7 @@ class WayfireSwitcher : public wf::per_output_plugin_instance_t, public wf::keyb
if (!active)
{
active = true;
input_grab->grab_input(wf::scene::layer::OVERLAY, true);
input_grab->grab_input(wf::scene::layer::OVERLAY);

focus_next(dir);
arrange();
Expand Down
6 changes: 3 additions & 3 deletions plugins/tile/tile-plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 342,7 @@ class tile_output_plugin_t : public wf::pointer_interaction_t, public wf::custom
return;
}

input_grab->grab_input(wf::scene::layer::OVERLAY, true);
input_grab->grab_input(wf::scene::layer::OVERLAY);
controller = std::make_unique<Controller>(tile_workspace_set_data_t::get_current_root(output),
get_global_input_coordinates());
}
Expand Down Expand Up @@ -580,13 580,13 @@ class tile_output_plugin_t : public wf::pointer_interaction_t, public wf::custom
wf::button_callback on_move_view = [=] (auto)
{
start_controller<tile::move_view_controller_t>();
return false;
return false; // pass button to the grab node
};

wf::button_callback on_resize_view = [=] (auto)
{
start_controller<tile::resize_view_controller_t>();
return false;
return false; // pass button to the grab node
};

void handle_pointer_button(const wlr_pointer_button_event& event) override
Expand Down
11 changes: 6 additions & 5 deletions src/api/wayfire/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 170,15 @@ class compositor_core_t : public wf::object_base_t, public signal::provider_t
/**
* Break any grabs on pointer, touch and tablet input.
* Then, transfer input focus to the given node in a grab mode.
* Note that when transferring a grab, synthetic button release/etc. events are sent to the old pointer
* and touch focus nodes (except if they are not RAW_INPUT nodes).
*
* The grab node, if it is not RAW_INPUT, will also not receive button release events for buttons pressed
* before it grabbed the input, if it does not have the RAW_INPUT flag.
*
* @param node The node which should receive the grabbed input.
* @param retain_pressed_state Some plugins may be activated with a button/touch/etc. press (for example
* the move plugin). They want to receive the matching button_release event, even though they have not
* received the button press event. In these cases, they can use the @retain_pressed_state parameter to
* indicate to core their desire for receiving unmatched button release events.
*/
virtual void transfer_grab(wf::scene::node_ptr node, bool retain_pressed_state) = 0;
virtual void transfer_grab(wf::scene::node_ptr node) = 0;

/** no such coordinate will ever realistically be used for input */
static constexpr double invalid_coordinate =
Expand Down
8 changes: 4 additions & 4 deletions src/api/wayfire/scene-input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 135,10 @@ class pointer_interaction_t
/**
* Handle a button press or release event.
*
* When a node consumes a button event, core starts an *implicit grab* for it.
* This has the effect that all subsequent input events are forwarded to that
* node, until all buttons are released. Thus, a node is guaranteed to always
* receive matching press and release events.
* When a node consumes a button event, core starts an *implicit grab* for it. This has the effect that
* all subsequent input events are forwarded to that node, until all buttons are released. Thus, a node is
* guaranteed to always receive matching press and release events, except when it explicitly opts out via
* the RAW_INPUT node flag.
*
* @param pointer_position The position where the pointer is currently at.
* @param button The wlr event describing the event.
Expand Down
22 changes: 18 additions & 4 deletions src/api/wayfire/scene.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 84,16 @@ enum class node_flags : int
* Note that plugins might still force those nodes to receive input and be
* rendered by calling the corresponding methods directly.
*/
DISABLED = (1 << 0),
DISABLED = (1 << 0),
/**
* If set, the node indicates that it wishes to receive raw input events, that is, it may receive
* unmatched pointer press/release events, unmatched touch up/down events, etc.
*/
RAW_INPUT = (1 << 1),
};

using node_flags_bitmask_t = uint64_t;

/**
* Used as a result of an intersection of the scenegraph with the user input.
*/
Expand Down Expand Up @@ -165,10 172,9 @@ class node_t : public std::enable_shared_from_this<node_t>,
/**
* Get the current flags of the node.
*/
virtual int flags() const
virtual node_flags_bitmask_t flags() const
{
return enabled_counter > 0 ?
0 : (int)node_flags::DISABLED;
return enabled_counter > 0 ? 0 : (int)node_flags::DISABLED;
}

/**
Expand Down Expand Up @@ -266,6 272,14 @@ class node_t : public std::enable_shared_from_this<node_t>,
return !(flags() & (int)node_flags::DISABLED);
}

/**
* A helper function to get the status of the RAW_INPUT flag.
*/
inline bool wants_raw_input() const
{
return (flags() & (int)node_flags::RAW_INPUT);
}

/**
* Increase or decrease the enabled counter. A non-positive counter causes
* the DISABLED flag to be set.
Expand Down
2 changes: 1 addition & 1 deletion src/core/core-impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 54,7 @@ class compositor_core_impl_t : public compositor_core_t

wlr_seat *get_current_seat() override;
void warp_cursor(wf::pointf_t pos) override;
void transfer_grab(wf::scene::node_ptr node, bool retain_pressed_state) override;
void transfer_grab(wf::scene::node_ptr node) override;
void set_cursor(std::string name) override;
void unhide_cursor() override;
void hide_cursor() override;
Expand Down
8 changes: 4 additions & 4 deletions src/core/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 254,11 @@ void wf::compositor_core_impl_t::warp_cursor(wf::pointf_t pos)
seat->priv->cursor->warp_cursor(pos);
}

void wf::compositor_core_impl_t::transfer_grab(wf::scene::node_ptr node, bool retain_pressed_state)
void wf::compositor_core_impl_t::transfer_grab(wf::scene::node_ptr node)
{
seat->priv->transfer_grab(node, retain_pressed_state);
seat->priv->lpointer->transfer_grab(node, retain_pressed_state);
seat->priv->touch->transfer_grab(node, retain_pressed_state);
seat->priv->transfer_grab(node);
seat->priv->lpointer->transfer_grab(node);
seat->priv->touch->transfer_grab(node);

for (auto dev : this->get_input_devices())
{
Expand Down
5 changes: 5 additions & 0 deletions src/core/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 66,11 @@ std::string node_t::stringify_flags() const
fl = "d";
}

if (flags() & ((int)node_flags::RAW_INPUT))
{
fl = "R";
}

return "(" fl ")";
}

Expand Down
32 changes: 19 additions & 13 deletions src/core/seat/pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,22 96,25 @@ void wf::pointer_t::force_release_buttons()
{
if (cursor_focus)
{
for (auto button : this->currently_sent_buttons)
if (!cursor_focus->wants_raw_input())
{
LOGC(POINTER, "force-release button ", button);
wlr_pointer_button_event event;
event.pointer = NULL;
event.button = button;
event.state = WLR_BUTTON_RELEASED;
event.time_msec = wf::get_current_time();
cursor_focus->pointer_interaction().handle_pointer_button(event);
for (auto button : this->currently_sent_buttons)
{
LOGC(POINTER, "force-release button ", button);
wlr_pointer_button_event event;
event.pointer = NULL;
event.button = button;
event.state = WLR_BUTTON_RELEASED;
event.time_msec = wf::get_current_time();
cursor_focus->pointer_interaction().handle_pointer_button(event);
}
}

cursor_focus->pointer_interaction().handle_pointer_leave();
}
}

void wf::pointer_t::transfer_grab(scene::node_ptr node, bool retain_pressed_state)
void wf::pointer_t::transfer_grab(scene::node_ptr node)
{
if (node == cursor_focus)
{
Expand All @@ -130,7 133,7 @@ void wf::pointer_t::transfer_grab(scene::node_ptr node, bool retain_pressed_stat
auto local = get_node_local_coords(node.get(), gc);
node->pointer_interaction().handle_pointer_enter(local);

if (!retain_pressed_state)
if (!node->wants_raw_input())
{
currently_sent_buttons.clear();
}
Expand Down Expand Up @@ -267,11 270,14 @@ void wf::pointer_t::send_button(wlr_pointer_button_event *ev, bool has_binding)
this->currently_sent_buttons.insert(ev->button);
cursor_focus->pointer_interaction().handle_pointer_button(*ev);
} else if ((ev->state == WLR_BUTTON_RELEASED) &&
currently_sent_buttons.count(ev->button))
(currently_sent_buttons.count(ev->button) || cursor_focus->wants_raw_input()))
{
LOGC(POINTER, "normal button release ", ev->button);
this->currently_sent_buttons.erase(
currently_sent_buttons.find(ev->button));
if (currently_sent_buttons.count(ev->button))
{
this->currently_sent_buttons.erase(currently_sent_buttons.find(ev->button));
}

cursor_focus->pointer_interaction().handle_pointer_button(*ev);
} else
{
Expand Down
2 changes: 1 addition & 1 deletion src/core/seat/pointer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 87,7 @@ class pointer_t
/**
* Transfer focus and pressed buttons to the given grab.
*/
void transfer_grab(scene::node_ptr node, bool retain_pressed_state);
void transfer_grab(scene::node_ptr node);

private:
nonstd::observer_ptr<wf::input_manager_t> input;
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 @@ -54,7 54,7 @@ struct seat_t::impl
wf::scene::node_ptr keyboard_focus;
// Keys sent to the current keyboard focus
std::multiset<uint32_t> pressed_keys;
void transfer_grab(wf::scene::node_ptr new_focus, bool retain_pressed_state);
void transfer_grab(wf::scene::node_ptr new_focus);

/**
* Set the currently active keyboard on the seat.
Expand Down
2 changes: 1 addition & 1 deletion src/core/seat/seat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 272,7 @@ void wf::seat_t::impl::force_release_keys()
}
}

void wf::seat_t::impl::transfer_grab(wf::scene::node_ptr grab_node, bool retain_pressed_state)
void wf::seat_t::impl::transfer_grab(wf::scene::node_ptr grab_node)
{
if (this->keyboard_focus == grab_node)
{
Expand Down
Loading

0 comments on commit 3cca6c9

Please sign in to comment.