diff options
| author | Vaxry <vaxry@vaxry.net> | 2024-05-10 18:27:57 +0100 |
|---|---|---|
| committer | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2024-05-14 23:02:24 +0100 |
| commit | 121d3a72137d4780602cf245704615f63357ea22 (patch) | |
| tree | b25c8a3ee7b239006281f0e00110d1c324b8cedc /src/protocols/core/Seat.cpp | |
| parent | 4cdddcfe466cb21db81af0ac39e51cc15f574da9 (diff) | |
wl_seat: move to hyprland impl
Diffstat (limited to 'src/protocols/core/Seat.cpp')
| -rw-r--r-- | src/protocols/core/Seat.cpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp new file mode 100644 index 00000000..489fced7 --- /dev/null +++ b/src/protocols/core/Seat.cpp @@ -0,0 +1,437 @@ +#include "Seat.hpp" +#include "../../devices/IKeyboard.hpp" +#include "../../managers/SeatManager.hpp" +#include "../../config/ConfigValue.hpp" +#include <algorithm> + +#include <fcntl.h> + +#define LOGM PROTO::seat->protoLog + +CWLTouchResource::CWLTouchResource(SP<CWlTouch> resource_, SP<CWLSeatResource> owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](CWlTouch* r) { PROTO::seat->destroyResource(this); }); + resource->setOnDestroy([this](CWlTouch* r) { PROTO::seat->destroyResource(this); }); +} + +bool CWLTouchResource::good() { + return resource->resource(); +} + +void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local) { + if (!owner) + return; + + if (currentSurface) { + LOGM(WARN, "requested CWLTouchResource::sendDown without sendUp first."); + sendUp(timeMs, id); + } + + ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + + currentSurface = surface; + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, [this, id, timeMs](void* owner, void* data) { sendUp(timeMs + 10 /* hack */, id); }, this, "CWLTouchResource"); + + // FIXME: + // fix this once we get our own wlr_surface, this is horrible + resource->sendDownRaw(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->resource, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { + if (!owner || !currentSurface) + return; + + resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id); + currentSurface = nullptr; + hyprListener_surfaceDestroy.removeCallback(); +} + +void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { + if (!owner || !currentSurface) + return; + + resource->sendMotion(timeMs, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLTouchResource::sendFrame() { + if (!owner || !currentSurface) + return; + + resource->sendFrame(); +} + +void CWLTouchResource::sendCancel() { + if (!owner || !currentSurface) + return; + + resource->sendCancel(); +} + +void CWLTouchResource::sendShape(int32_t id, const Vector2D& shape) { + if (!owner || !currentSurface || resource->version() < 6) + return; + + resource->sendShape(id, wl_fixed_from_double(shape.x), wl_fixed_from_double(shape.y)); +} + +void CWLTouchResource::sendOrientation(int32_t id, double angle) { + if (!owner || !currentSurface || resource->version() < 6) + return; + + resource->sendOrientation(id, wl_fixed_from_double(angle)); +} + +CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResource> owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](CWlPointer* r) { PROTO::seat->destroyResource(this); }); + resource->setOnDestroy([this](CWlPointer* r) { PROTO::seat->destroyResource(this); }); + + resource->setSetCursor([this](CWlPointer* r, uint32_t serial, wl_resource* surf, int32_t hotX, int32_t hotY) { + if (!owner) { + LOGM(ERR, "Client bug: setCursor when seatClient is already dead"); + return; + } + + g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? wlr_surface_from_resource(surf) : nullptr, {hotX, hotY}); + }); +} + +bool CWLPointerResource::good() { + return resource->resource(); +} + +void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local) { + if (!owner || currentSurface == surface) + return; + + if (currentSurface) { + LOGM(WARN, "requested CWLPointerResource::sendEnter without sendLeave first."); + sendLeave(); + } + + ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + + currentSurface = surface; + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLPointerResource"); + + resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLPointerResource::sendLeave() { + if (!owner || !currentSurface) + return; + + resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); + currentSurface = nullptr; + hyprListener_surfaceDestroy.removeCallback(); +} + +void CWLPointerResource::sendMotion(uint32_t timeMs, const Vector2D& local) { + if (!owner || !currentSurface) + return; + + resource->sendMotion(timeMs, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLPointerResource::sendButton(uint32_t timeMs, uint32_t button, wl_pointer_button_state state) { + if (!owner || !currentSurface) + return; + + resource->sendButton(g_pSeatManager->nextSerial(owner.lock()), timeMs, button, state); +} + +void CWLPointerResource::sendAxis(uint32_t timeMs, wl_pointer_axis axis, double value) { + if (!owner || !currentSurface) + return; + + resource->sendAxis(timeMs, axis, wl_fixed_from_double(value)); +} + +void CWLPointerResource::sendFrame() { + if (!owner || resource->version() < 5) + return; + + resource->sendFrame(); +} + +void CWLPointerResource::sendAxisSource(wl_pointer_axis_source source) { + if (!owner || !currentSurface || resource->version() < 5) + return; + + resource->sendAxisSource(source); +} + +void CWLPointerResource::sendAxisStop(uint32_t timeMs, wl_pointer_axis axis) { + if (!owner || !currentSurface || resource->version() < 5) + return; + + resource->sendAxisStop(timeMs, axis); +} + +void CWLPointerResource::sendAxisDiscrete(wl_pointer_axis axis, int32_t discrete) { + if (!owner || !currentSurface || resource->version() < 5) + return; + + resource->sendAxisDiscrete(axis, discrete); +} + +void CWLPointerResource::sendAxisValue120(wl_pointer_axis axis, int32_t value120) { + if (!owner || !currentSurface || resource->version() < 8) + return; + + resource->sendAxisValue120(axis, value120); +} + +void CWLPointerResource::sendAxisRelativeDirection(wl_pointer_axis axis, wl_pointer_axis_relative_direction direction) { + if (!owner || !currentSurface || resource->version() < 9) + return; + + resource->sendAxisRelativeDirection(axis, direction); +} + +CWLKeyboardResource::CWLKeyboardResource(SP<CWlKeyboard> resource_, SP<CWLSeatResource> owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); + resource->setOnDestroy([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); + + static auto REPEAT = CConfigValue<Hyprlang::INT>("input:repeat_rate"); + static auto DELAY = CConfigValue<Hyprlang::INT>("input:repeat_delay"); + sendKeymap(g_pSeatManager->keyboard.lock()); + repeatInfo(*REPEAT, *DELAY); +} + +bool CWLKeyboardResource::good() { + return resource->resource(); +} + +void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) { + wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; + int fd; + uint32_t size; + if (keyboard) { + fd = keyboard->wlr()->keymap_fd; + size = keyboard->wlr()->keymap_size; + } else { + fd = open("/dev/null", O_RDONLY | O_CLOEXEC); + if (fd < 0) { + LOGM(ERR, "Failed to open /dev/null"); + return; + } + size = 0; + } + + resource->sendKeymap(format, fd, size); + + if (!keyboard) + close(fd); +} + +void CWLKeyboardResource::sendEnter(wlr_surface* surface) { + if (!owner || currentSurface == surface) + return; + + if (currentSurface) { + LOGM(WARN, "requested CWLKeyboardResource::sendEnter without sendLeave first."); + sendLeave(); + } + + ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + + currentSurface = surface; + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLKeyboardResource"); + + wl_array arr; + wl_array_init(&arr); + + resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, &arr); + + wl_array_release(&arr); +} + +void CWLKeyboardResource::sendLeave() { + if (!owner || !currentSurface) + return; + + resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); + currentSurface = nullptr; + hyprListener_surfaceDestroy.removeCallback(); +} + +void CWLKeyboardResource::sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) { + if (!owner || !currentSurface) + return; + + resource->sendKey(g_pSeatManager->nextSerial(owner.lock()), timeMs, key, state); +} + +void CWLKeyboardResource::sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { + if (!owner || !currentSurface) + return; + + resource->sendModifiers(g_pSeatManager->nextSerial(owner.lock()), depressed, latched, locked, group); +} + +void CWLKeyboardResource::repeatInfo(uint32_t rate, uint32_t delayMs) { + if (!owner || resource->version() < 4) + return; + + resource->sendRepeatInfo(rate, delayMs); +} + +CWLSeatResource::CWLSeatResource(SP<CWlSeat> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSeat* r) { + events.destroy.emit(); + PROTO::seat->destroyResource(this); + }); + resource->setRelease([this](CWlSeat* r) { + events.destroy.emit(); + PROTO::seat->destroyResource(this); + }); + + pClient = resource->client(); + + resource->setGetKeyboard([this](CWlSeat* r, uint32_t id) { + const auto RESOURCE = PROTO::seat->m_vKeyboards.emplace_back(makeShared<CWLKeyboardResource>(makeShared<CWlKeyboard>(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::seat->m_vKeyboards.pop_back(); + return; + } + + keyboards.push_back(RESOURCE); + }); + + resource->setGetPointer([this](CWlSeat* r, uint32_t id) { + const auto RESOURCE = PROTO::seat->m_vPointers.emplace_back(makeShared<CWLPointerResource>(makeShared<CWlPointer>(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::seat->m_vPointers.pop_back(); + return; + } + + pointers.push_back(RESOURCE); + }); + + resource->setGetTouch([this](CWlSeat* r, uint32_t id) { + const auto RESOURCE = PROTO::seat->m_vTouches.emplace_back(makeShared<CWLTouchResource>(makeShared<CWlTouch>(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::seat->m_vTouches.pop_back(); + return; + } + + touches.push_back(RESOURCE); + }); + + if (resource->version() >= 2) + resource->sendName(HL_SEAT_NAME); + + sendCapabilities(PROTO::seat->currentCaps); +} + +CWLSeatResource::~CWLSeatResource() { + events.destroy.emit(); +} + +void CWLSeatResource::sendCapabilities(uint32_t caps) { + uint32_t wlCaps = 0; + if (caps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD) + wlCaps |= WL_SEAT_CAPABILITY_KEYBOARD; + if (caps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER) + wlCaps |= WL_SEAT_CAPABILITY_POINTER; + if (caps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH) + wlCaps |= WL_SEAT_CAPABILITY_TOUCH; + + resource->sendCapabilities((wl_seat_capability)wlCaps); +} + +bool CWLSeatResource::good() { + return resource->resource(); +} + +wl_client* CWLSeatResource::client() { + return pClient; +} + +CWLSeatProtocol::CWLSeatProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLSeatProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vSeatResources.emplace_back(makeShared<CWLSeatResource>(makeShared<CWlSeat>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vSeatResources.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New seat resource bound at {:x}", (uintptr_t)RESOURCE.get()); + + events.newSeatResource.emit(RESOURCE); +} + +void CWLSeatProtocol::destroyResource(CWLSeatResource* seat) { + std::erase_if(m_vSeatResources, [&](const auto& other) { return other.get() == seat; }); +} + +void CWLSeatProtocol::destroyResource(CWLKeyboardResource* resource) { + std::erase_if(m_vKeyboards, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSeatProtocol::destroyResource(CWLPointerResource* resource) { + std::erase_if(m_vPointers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSeatProtocol::destroyResource(CWLTouchResource* resource) { + std::erase_if(m_vTouches, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSeatProtocol::updateCapabilities(uint32_t caps) { + if (caps == currentCaps) + return; + + currentCaps = caps; + + for (auto& s : m_vSeatResources) { + s->sendCapabilities(caps); + } +} + +void CWLSeatProtocol::updateKeymap() { + for (auto& k : m_vKeyboards) { + k->sendKeymap(g_pSeatManager->keyboard.lock()); + } +} + +void CWLSeatProtocol::updateRepeatInfo(uint32_t rate, uint32_t delayMs) { + for (auto& k : m_vKeyboards) { + k->repeatInfo(rate, delayMs); + } +} + +SP<CWLSeatResource> CWLSeatProtocol::seatResourceForClient(wl_client* client) { + for (auto& r : m_vSeatResources) { + if (r->client() == client) + return r; + } + + return nullptr; +} |
