From 27552976705e416ce481ca74d377578bcbc134e0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 3 May 2024 01:27:59 +0100 Subject: [PATCH] virtual-pointer: move to new impl --- CMakeLists.txt | 1 + protocols/meson.build | 1 + protocols/wlr-virtual-pointer-unstable-v1.xml | 152 ++++++++++++++++ src/Compositor.cpp | 4 - src/Compositor.hpp | 1 - src/events/Devices.cpp | 8 - src/helpers/WLClasses.hpp | 15 +- src/includes.hpp | 2 +- src/managers/ProtocolManager.cpp | 2 + src/managers/input/InputManager.cpp | 36 +++- src/managers/input/InputManager.hpp | 5 +- src/protocols/VirtualPointer.cpp | 165 ++++++++++++++++++ src/protocols/VirtualPointer.hpp | 57 ++++++ 13 files changed, 428 insertions(+), 21 deletions(-) create mode 100644 protocols/wlr-virtual-pointer-unstable-v1.xml create mode 100644 src/protocols/VirtualPointer.cpp create mode 100644 src/protocols/VirtualPointer.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d485977c..f2939040 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,6 +262,7 @@ protocolNew("protocols/wlr-gamma-control-unstable-v1.xml" "wlr-gamma-control-uns protocolNew("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreign-toplevel-management-unstable-v1" true) protocolNew("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true) protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unstable-v1" true) +protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer-unstable-v1" true) protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) diff --git a/protocols/meson.build b/protocols/meson.build index 57bca3d1..38b973af 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -40,6 +40,7 @@ new_protocols = [ ['wlr-output-power-management-unstable-v1.xml'], ['input-method-unstable-v2.xml'], ['virtual-keyboard-unstable-v1.xml'], + ['wlr-virtual-pointer-unstable-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], diff --git a/protocols/wlr-virtual-pointer-unstable-v1.xml b/protocols/wlr-virtual-pointer-unstable-v1.xml new file mode 100644 index 00000000..ea243e7c --- /dev/null +++ b/protocols/wlr-virtual-pointer-unstable-v1.xml @@ -0,0 +1,152 @@ + + + + Copyright © 2019 Josef Gajdusek + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + This protocol allows clients to emulate a physical pointer device. The + requests are mostly mirror opposites of those specified in wl_pointer. + + + + + + + + + + The pointer has moved by a relative amount to the previous request. + + Values are in the global compositor space. + + + + + + + + + The pointer has moved in an absolute coordinate frame. + + Value of x can range from 0 to x_extent, value of y can range from 0 + to y_extent. + + + + + + + + + + + A button was pressed or released. + + + + + + + + + Scroll and other axis requests. + + + + + + + + + Indicates the set of events that logically belong together. + + + + + + Source information for scroll and other axis. + + + + + + + Stop notification for scroll and other axes. + + + + + + + + Discrete step information for scroll and other axes. + + This event allows the client to extend data normally sent using the axis + event with discrete value. + + + + + + + + + + + + + + + This object allows clients to create individual virtual pointer objects. + + + + + Creates a new virtual pointer. The optional seat is a suggestion to the + compositor. + + + + + + + + + + + + + Creates a new virtual pointer. The seat and the output arguments are + optional. If the seat argument is set, the compositor should assign the + input device to the requested seat. If the output argument is set, the + compositor should map the input device to the requested output. + + + + + + + diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 80e61a25..3f53f6c3 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -245,8 +245,6 @@ void CCompositor::initServer() { m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay); - m_sWLRVirtPtrMgr = wlr_virtual_pointer_manager_v1_create(m_sWLDisplay); - m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend); if (!m_sWRLDRMLeaseMgr) { Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager"); @@ -305,7 +303,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLROutputLayout->events.change, &Events::listen_change, m_sWLROutputLayout, "OutputLayout"); addWLSignal(&m_sWLROutputMgr->events.apply, &Events::listen_outputMgrApply, m_sWLROutputMgr, "OutputMgr"); addWLSignal(&m_sWLROutputMgr->events.test, &Events::listen_outputMgrTest, m_sWLROutputMgr, "OutputMgr"); - addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); if (m_sWRLDRMLeaseMgr) @@ -346,7 +343,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_change); removeWLSignal(&Events::listen_outputMgrApply); removeWLSignal(&Events::listen_outputMgrTest); - removeWLSignal(&Events::listen_newVirtPtr); removeWLSignal(&Events::listen_RendererDestroy); if (m_sWRLDRMLeaseMgr) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 175688c7..02fd6311 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -60,7 +60,6 @@ class CCompositor { wlr_egl* m_sWLREGL; int m_iDRMFD; wlr_server_decoration_manager* m_sWLRServerDecoMgr; - wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; wlr_tablet_manager_v2* m_sWLRTabletManager; wlr_xdg_foreign_registry* m_sWLRForeignRegistry; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index bf72d89f..ec0b14c4 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -93,14 +93,6 @@ void Events::listener_newInput(wl_listener* listener, void* data) { g_pInputManager->updateCapabilities(); } -void Events::listener_newVirtPtr(wl_listener* listener, void* data) { - const auto EV = (wlr_virtual_pointer_v1_new_pointer_event*)data; - const auto POINTER = EV->new_pointer; - const auto DEVICE = &POINTER->pointer.base; - - g_pInputManager->newMouse(DEVICE, true); -} - void Events::listener_destroyMouse(void* owner, void* data) { const auto PMOUSE = (SMouse*)owner; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 6b155e83..7eaebead 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -12,6 +12,7 @@ class CMonitor; class CVirtualKeyboard; +class CVirtualPointer; struct SRenderData { CMonitor* pMonitor; @@ -104,13 +105,19 @@ struct SKeyboard { }; struct SMouse { - wlr_input_device* mouse = nullptr; + wlr_input_device* mouse = nullptr; - std::string name = ""; + std::string name = ""; - bool virt = false; + bool virt = false; - bool connected = false; // means connected to the cursor + bool connected = false; // means connected to the cursor + + WP virtualPointer; + + struct { + CHyprSignalListener destroyMouse; + } listeners; DYNLISTENER(destroyMouse); diff --git a/src/includes.hpp b/src/includes.hpp index 052c973e..73611fb2 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -67,7 +67,6 @@ extern "C" { #include #include #include -#include #include #include #include @@ -79,6 +78,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 122e2ff1..8ec2a35f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -21,6 +21,7 @@ #include "../protocols/SessionLock.hpp" #include "../protocols/InputMethodV2.hpp" #include "../protocols/VirtualKeyboard.hpp" +#include "../protocols/VirtualPointer.hpp" CProtocolManager::CProtocolManager() { @@ -45,6 +46,7 @@ CProtocolManager::CProtocolManager() { PROTO::sessionLock = std::make_unique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); PROTO::ime = std::make_unique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); PROTO::virtualKeyboard = std::make_unique(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); + PROTO::virtualPointer = std::make_unique(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index e3c1b463..58b5caa3 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -12,6 +12,7 @@ #include "../../protocols/SessionLock.hpp" #include "../../protocols/InputMethodV2.hpp" #include "../../protocols/VirtualKeyboard.hpp" +#include "../../protocols/VirtualPointer.hpp" CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { @@ -40,6 +41,8 @@ CInputManager::CInputManager() { m_sListeners.newIdleInhibitor = PROTO::idleInhibit->events.newIdleInhibitor.registerListener([this](std::any data) { this->newIdleInhibitor(data); }); m_sListeners.newVirtualKeyboard = PROTO::virtualKeyboard->events.newKeyboard.registerListener([this](std::any data) { this->newVirtualKeyboard(std::any_cast>(data)); }); + m_sListeners.newVirtualMouse = + PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) { this->newVirtualMouse(std::any_cast>(data)); }); } CInputManager::~CInputManager() { @@ -968,12 +971,41 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { pKeyboard->keyboard->name); } -void CInputManager::newMouse(wlr_input_device* mouse, bool virt) { +void CInputManager::newVirtualMouse(SP mouse) { + const auto PMOUSE = &m_lMice.emplace_back(); + + PMOUSE->mouse = &mouse->wlr()->base; + PMOUSE->virtualPointer = mouse; + PMOUSE->virt = true; + try { + PMOUSE->name = getNameForNewDevice(mouse->wlr()->base.name); + } catch (std::exception& e) { + Debug::log(ERR, "Mouse had no name???"); // logic error + } + + wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, &mouse->wlr()->base); + + PMOUSE->connected = true; + + setPointerConfigs(); + + PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->wlr()->base.events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse"); + + // TODO: this pointer pass sucks. + PMOUSE->listeners.destroyMouse = mouse->events.destroy.registerListener([this, PMOUSE](std::any data) { destroyMouse(PMOUSE->mouse); }); + + g_pCompositor->m_sSeat.mouse = PMOUSE; + + m_tmrLastCursorMovement.reset(); + + Debug::log(LOG, "New virtual mouse created, pointer WLR: {:x}", (uintptr_t)mouse->wlr()); +} + +void CInputManager::newMouse(wlr_input_device* mouse) { m_lMice.emplace_back(); const auto PMOUSE = &m_lMice.back(); PMOUSE->mouse = mouse; - PMOUSE->virt = virt; try { PMOUSE->name = getNameForNewDevice(mouse->name); } catch (std::exception& e) { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 27551249..6a338088 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -12,6 +12,7 @@ class CPointerConstraint; class CWindow; class CIdleInhibitor; class CVirtualKeyboard; +class CVirtualPointer; enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, @@ -79,7 +80,8 @@ class CInputManager { void newKeyboard(wlr_input_device*); void newVirtualKeyboard(SP); - void newMouse(wlr_input_device*, bool virt = false); + void newMouse(wlr_input_device*); + void newVirtualMouse(SP); void newTouchDevice(wlr_input_device*); void newSwitch(wlr_input_device*); void destroyTouchDevice(STouchDevice*); @@ -201,6 +203,7 @@ class CInputManager { CHyprSignalListener setCursorShape; CHyprSignalListener newIdleInhibitor; CHyprSignalListener newVirtualKeyboard; + CHyprSignalListener newVirtualMouse; } m_sListeners; bool m_bCursorImageOverridden = false; diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp new file mode 100644 index 00000000..287e7bad --- /dev/null +++ b/src/protocols/VirtualPointer.cpp @@ -0,0 +1,165 @@ +#include "VirtualPointer.hpp" + +#define LOGM PROTO::virtualPointer->protoLog + +static const wlr_pointer_impl pointerImpl = { + .name = "virtual-pointer-v1", +}; + +CVirtualPointer::CVirtualPointer(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwlrVirtualPointerV1* r) { + events.destroy.emit(); + PROTO::virtualPointer->destroyResource(this); + }); + resource->setOnDestroy([this](CZwlrVirtualPointerV1* r) { + events.destroy.emit(); + PROTO::virtualPointer->destroyResource(this); + }); + + wlr_pointer_init(&pointer, &pointerImpl, "CVirtualPointer"); + + resource->setMotion([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, wl_fixed_t dx, wl_fixed_t dy) { + wlr_pointer_motion_event event = { + .pointer = &pointer, + .time_msec = timeMs, + .delta_x = wl_fixed_to_double(dx), + .delta_y = wl_fixed_to_double(dy), + .unaccel_dx = wl_fixed_to_double(dx), + .unaccel_dy = wl_fixed_to_double(dy), + }; + wl_signal_emit_mutable(&pointer.events.motion, &event); + }); + + resource->setMotionAbsolute([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t x, uint32_t y, uint32_t xExtent, uint32_t yExtent) { + if (!xExtent || !yExtent) + return; + + wlr_pointer_motion_absolute_event event = { + .pointer = &pointer, + .time_msec = timeMs, + .x = (double)x / xExtent, + .y = (double)y / yExtent, + }; + wl_signal_emit_mutable(&pointer.events.motion_absolute, &event); + }); + + resource->setButton([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t button, uint32_t state) { + struct wlr_pointer_button_event event = { + .pointer = &pointer, + .time_msec = timeMs, + .button = button, + .state = (wl_pointer_button_state)state, + }; + wl_signal_emit_mutable(&pointer.events.button, &event); + }); + + resource->setAxis([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value) { + if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + r->error(ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, "Invalid axis"); + return; + } + + axis = axis_; + axisEvents[axis] = wlr_pointer_axis_event{.pointer = &pointer, .time_msec = timeMs, .orientation = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)}; + }); + + resource->setFrame([this](CZwlrVirtualPointerV1* r) { + for (auto& e : axisEvents) { + if (!e.pointer) + continue; + wl_signal_emit_mutable(&pointer.events.axis, &e); + e.pointer = nullptr; + } + + wl_signal_emit_mutable(&pointer.events.frame, &pointer); + }); + + resource->setAxisSource([this](CZwlrVirtualPointerV1* r, uint32_t source) { axisEvents[axis].source = (wl_pointer_axis_source)source; }); + + resource->setAxisStop([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_) { + if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + r->error(ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, "Invalid axis"); + return; + } + + axis = axis_; + axisEvents[axis].pointer = &pointer; + axisEvents[axis].time_msec = timeMs; + axisEvents[axis].orientation = (wl_pointer_axis)axis; + axisEvents[axis].delta = 0; + axisEvents[axis].delta_discrete = 0; + }); + + resource->setAxisDiscrete([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value, int32_t discrete) { + if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + r->error(ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, "Invalid axis"); + return; + } + + axis = axis_; + axisEvents[axis].pointer = &pointer; + axisEvents[axis].time_msec = timeMs; + axisEvents[axis].orientation = (wl_pointer_axis)axis; + axisEvents[axis].delta = wl_fixed_to_double(value); + axisEvents[axis].delta_discrete = discrete * 120; + }); +} + +CVirtualPointer::~CVirtualPointer() { + wlr_pointer_finish(&pointer); + events.destroy.emit(); +} + +bool CVirtualPointer::good() { + return resource->resource(); +} + +wlr_pointer* CVirtualPointer::wlr() { + return &pointer; +} + +wl_client* CVirtualPointer::client() { + return resource->client(); +} + +CVirtualPointerProtocol::CVirtualPointerProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CVirtualPointerProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); + RESOURCE->setDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setCreateVirtualPointer([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { this->onCreatePointer(pMgr, seat, id); }); + RESOURCE->setCreateVirtualPointerWithOutput([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, wl_resource* output, uint32_t id) { + LOGM(WARN, "TODO: CreateWithOutput is not supported yet. Ignoring for now."); + this->onCreatePointer(pMgr, seat, id); + }); +} + +void CVirtualPointerProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CVirtualPointerProtocol::destroyResource(CVirtualPointer* pointer) { + std::erase_if(m_vPointers, [&](const auto& other) { return other.get() == pointer; }); +} + +void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { + + const auto RESOURCE = m_vPointers.emplace_back(std::make_shared(std::make_shared(pMgr->client(), pMgr->version(), id))); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vPointers.pop_back(); + return; + } + + LOGM(LOG, "New VPointer at id {}", id); + + events.newPointer.emit(RESOURCE); +} \ No newline at end of file diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp new file mode 100644 index 00000000..4528b491 --- /dev/null +++ b/src/protocols/VirtualPointer.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "wlr-virtual-pointer-unstable-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CVirtualPointer { + public: + CVirtualPointer(SP resource_); + ~CVirtualPointer(); + + struct { + CSignal destroy; + } events; + + bool good(); + wlr_pointer* wlr(); + wl_client* client(); + + private: + SP resource; + wlr_pointer pointer; + + uint32_t axis = 0; + + std::array axisEvents; +}; + +class CVirtualPointerProtocol : public IWaylandProtocol { + public: + CVirtualPointerProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + struct { + CSignal newPointer; // SP + } events; + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CVirtualPointer* pointer); + void onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id); + + // + std::vector> m_vManagers; + std::vector> m_vPointers; + + friend class CVirtualPointer; +}; + +namespace PROTO { + inline UP virtualPointer; +};