From a336c85dc425a498b1edc6b7438c73f5f7f0a947 Mon Sep 17 00:00:00 2001 From: Campbell Jones Date: Sat, 28 Oct 2023 14:36:16 -0400 Subject: [PATCH] Implement constraints --- src/input/constraint.cpp | 7 ++++-- src/input/cursor.cpp | 43 +++++++++++++++++++++++++++++------ src/input/cursor.hpp | 2 ++ src/input/seat.cpp | 42 +++++++++++++++++++++++++++++++--- src/input/seat.hpp | 4 +++- src/server.cpp | 1 + src/server.hpp | 3 ++- src/surface/xdg_view.cpp | 4 ++++ src/surface/xwayland_view.cpp | 4 ++++ 9 files changed, 96 insertions(+), 14 deletions(-) diff --git a/src/input/constraint.cpp b/src/input/constraint.cpp index 0730892e8..73a8ce736 100644 --- a/src/input/constraint.cpp +++ b/src/input/constraint.cpp @@ -24,9 +24,13 @@ static void constraint_destroy_notify(wl_listener* listener, void* data) { (void) data; auto& current_constraint = constraint.seat.current_constraint; - if (current_constraint.has_value() && current_constraint.value().wlr == constraint.wlr) { + if (current_constraint.has_value() && current_constraint.value().get().wlr == constraint.wlr) { + constraint.seat.cursor.warp_to_constraint(current_constraint.value()); + constraint.deactivate(); current_constraint.reset(); } + + delete &constraint; } PointerConstraint::PointerConstraint(Seat& seat, wlr_pointer_constraint_v1* constraint) noexcept @@ -40,7 +44,6 @@ PointerConstraint::PointerConstraint(Seat& seat, wlr_pointer_constraint_v1* cons } PointerConstraint::~PointerConstraint() noexcept { - deactivate(); wl_list_remove(&listeners.set_region.link); wl_list_remove(&listeners.surface_commit.link); wl_list_remove(&listeners.destroy.link); diff --git a/src/input/cursor.cpp b/src/input/cursor.cpp index 2a3dc8b3c..ca9063f6f 100644 --- a/src/input/cursor.cpp +++ b/src/input/cursor.cpp @@ -1,5 +1,6 @@ #include "cursor.hpp" +#include "input/constraint.hpp" #include "seat.hpp" #include "server.hpp" #include "surface/surface.hpp" @@ -120,7 +121,13 @@ static void cursor_motion_absolute_notify(wl_listener* listener, void* data) { wlr_relative_pointer_manager_v1_send_relative_motion( cursor.relative_pointer_mgr, cursor.seat.seat, (uint64_t) event->time_msec * 1000, dx, dy, dx, dy); - wlr_cursor_warp_absolute(cursor.cursor, &event->pointer->base, event->x, event->y); + if (cursor.seat.is_pointer_locked(event->pointer)) { + return; + } + + cursor.seat.apply_constraint(event->pointer, &dx, &dy); + + wlr_cursor_move(cursor.cursor, &event->pointer->base, dx, dy); cursor.process_motion(event->time_msec); } @@ -158,12 +165,15 @@ static void cursor_motion_notify(wl_listener* listener, void* data) { wlr_relative_pointer_manager_v1_send_relative_motion(cursor.relative_pointer_mgr, cursor.seat.seat, (uint64_t) event->time_msec * 1000, event->delta_x, event->delta_y, event->unaccel_dx, event->unaccel_dy); - /* The cursor doesn't move unless we tell it to. The cursor automatically - * handles constraining the motion to the output layout, as well as any - * special configuration applied for the specific input device which - * generated the event. You can pass NULL for the device if you want to move - * the cursor around without any input. */ - wlr_cursor_move(cursor.cursor, &event->pointer->base, event->delta_x, event->delta_y); + if (cursor.seat.is_pointer_locked(event->pointer)) { + return; + } + + double dx = event->delta_x; + double dy = event->delta_y; + cursor.seat.apply_constraint(event->pointer, &dx, &dy); + + wlr_cursor_move(cursor.cursor, &event->pointer->base, dx, dy); cursor.process_motion(event->time_msec); } @@ -339,3 +349,22 @@ void Cursor::reset_mode() { mode = MAGPIE_CURSOR_PASSTHROUGH; seat.server.grabbed_view = NULL; } + +void Cursor::warp_to_constraint(PointerConstraint& constraint) { + if (seat.server.focused_view->surface != constraint.wlr->surface) { + return; + } + + if (seat.server.focused_view == nullptr) { + // only warp to constraints tied to views... + return; + } + + if (constraint.wlr->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { + double x = constraint.wlr->current.cursor_hint.x; + double y = constraint.wlr->current.cursor_hint.y; + + wlr_cursor_warp(cursor, nullptr, seat.server.focused_view->current.x + x, seat.server.focused_view->current.y + y); + wlr_seat_pointer_warp(seat.seat, x, y); + } +} diff --git a/src/input/cursor.hpp b/src/input/cursor.hpp index fb557cca0..ed97db539 100644 --- a/src/input/cursor.hpp +++ b/src/input/cursor.hpp @@ -1,6 +1,7 @@ #ifndef MAGPIE_CURSOR_HPP #define MAGPIE_CURSOR_HPP +#include "input/constraint.hpp" #include "types.hpp" #include @@ -54,6 +55,7 @@ class Cursor { void attach_input_device(wlr_input_device* device); void process_motion(uint32_t time); void reset_mode(); + void warp_to_constraint(PointerConstraint& constraint); }; #endif diff --git a/src/input/seat.cpp b/src/input/seat.cpp index 49a94b2a9..664485a00 100644 --- a/src/input/seat.cpp +++ b/src/input/seat.cpp @@ -3,6 +3,7 @@ #include "cursor.hpp" #include "keyboard.hpp" #include "server.hpp" +#include "surface/view.hpp" #include "types.hpp" #include @@ -13,6 +14,7 @@ #include #include #include +#include #include "wlr-wrap-end.hpp" static void new_input_notify(wl_listener* listener, void* data) { @@ -124,17 +126,51 @@ void Seat::new_input_device(wlr_input_device* device) { } void Seat::set_constraint(wlr_pointer_constraint_v1* wlr_constraint) { + printf("Setting constraint %p\n", (void*) wlr_constraint); + if (current_constraint.has_value()) { - if (current_constraint.value().wlr == wlr_constraint) { + if (current_constraint.value().get().wlr == wlr_constraint) { // we already have this constraint marked as the current constraint return; } + cursor.warp_to_constraint(current_constraint.value()); current_constraint.reset(); } if (wlr_constraint != nullptr) { - current_constraint.emplace(PointerConstraint(*this, wlr_constraint)); - current_constraint.value().activate(); + current_constraint = *(new PointerConstraint(*this, wlr_constraint)); + current_constraint.value().get().activate(); + } +} + +void Seat::apply_constraint(const wlr_pointer* pointer, double* dx, double* dy) const { + if (!current_constraint.has_value() || pointer->base.type != WLR_INPUT_DEVICE_POINTER) { + return; } + + if (server.focused_view == nullptr) { + return; + } + + double x = cursor.cursor->x; + double y = cursor.cursor->y; + + x -= server.focused_view->current.x; + y -= server.focused_view->current.y; + + double confined_x = 0; + double confined_y = 0; + if (!wlr_region_confine(¤t_constraint->get().wlr->region, x, y, x + *dx, y + *dy, &confined_x, &confined_y)) { + printf("Couldn't confine\n"); + return; + } + + *dx = confined_x - x; + *dy = confined_y - y; +} + +bool Seat::is_pointer_locked(const wlr_pointer* pointer) const { + return current_constraint.has_value() && pointer->base.type == WLR_INPUT_DEVICE_POINTER && + current_constraint->get().wlr->type == WLR_POINTER_CONSTRAINT_V1_LOCKED; } diff --git a/src/input/seat.hpp b/src/input/seat.hpp index 20ac183b4..5a89ee968 100644 --- a/src/input/seat.hpp +++ b/src/input/seat.hpp @@ -39,13 +39,15 @@ class Seat { wlr_virtual_pointer_manager_v1* virtual_pointer_mgr; wlr_virtual_keyboard_manager_v1* virtual_keyboard_mgr; wlr_pointer_constraints_v1* pointer_constraints; - std::optional current_constraint = {}; + std::optional> current_constraint = {}; Seat(Server& server) noexcept; ~Seat() noexcept; void new_input_device(wlr_input_device* device); void set_constraint(wlr_pointer_constraint_v1* wlr_constraint); + void apply_constraint(const wlr_pointer* pointer, double* dx, double* dy) const; + bool is_pointer_locked(const wlr_pointer* pointer) const; }; #endif diff --git a/src/server.cpp b/src/server.cpp index 767891442..5e5f04904 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -60,6 +60,7 @@ void Server::focus_view(View& view, wlr_surface* surface) { /* Activate the new surface */ server.views.insert(server.views.begin(), &view); view.set_activated(true); + focused_view = &view; /* * Tell the seat to have the keyboard enter this surface. wlroots will keep diff --git a/src/server.hpp b/src/server.hpp index 3191e2f03..bdab00ae6 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -69,7 +69,8 @@ class Server { Seat* seat; std::list views; - View* grabbed_view; + View* focused_view = nullptr; + View* grabbed_view = nullptr; double grab_x, grab_y; wlr_box grab_geobox; uint32_t resize_edges; diff --git a/src/surface/xdg_view.cpp b/src/surface/xdg_view.cpp index 08799adfb..db8c12e13 100644 --- a/src/surface/xdg_view.cpp +++ b/src/surface/xdg_view.cpp @@ -224,6 +224,10 @@ void XdgView::unmap() { if (this == server.grabbed_view) { server.seat->cursor.reset_mode(); } + + if (this == server.focused_view) { + server.focused_view = nullptr; + } } void XdgView::impl_set_position(const int new_x, const int new_y) { diff --git a/src/surface/xwayland_view.cpp b/src/surface/xwayland_view.cpp index dcef6c6a3..001c88923 100644 --- a/src/surface/xwayland_view.cpp +++ b/src/surface/xwayland_view.cpp @@ -221,6 +221,10 @@ void XWaylandView::unmap() { cursor.reset_mode(); } + if (this == server.focused_view) { + server.focused_view = nullptr; + } + if (server.seat->seat->keyboard_state.focused_surface == surface) { server.seat->seat->keyboard_state.focused_surface = NULL; }