Hyprland/src/protocols/core/Seat.cpp

582 lines
18 KiB
C++
Raw Normal View History

2024-05-10 18:27:57 +01:00
#include "Seat.hpp"
#include "Compositor.hpp"
#include "DataDevice.hpp"
2024-05-10 18:27:57 +01:00
#include "../../devices/IKeyboard.hpp"
#include "../../devices/IHID.hpp"
2024-05-10 18:27:57 +01:00
#include "../../managers/SeatManager.hpp"
#include "../../config/ConfigValue.hpp"
#include <algorithm>
#include <fcntl.h>
CWLTouchResource::CWLTouchResource(SP<CWlTouch> resource_, SP<CWLSeatResource> owner_) : owner(owner_), resource(resource_) {
if UNLIKELY (!good())
2024-05-10 18:27:57 +01:00
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(SP<CWLSurfaceResource> surface, uint32_t timeMs, int32_t id, const Vector2D& local) {
2024-05-10 18:27:57 +01:00
if (!owner)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
return;
ASSERT(surface->client() == owner->client());
2024-05-10 18:27:57 +01:00
currentSurface = surface;
listeners.destroySurface = surface->events.destroy.registerListener([this, timeMs, id](std::any d) { sendUp(timeMs + 10 /* hack */, id); });
2024-05-10 18:27:57 +01:00
resource->sendDown(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->getResource().get(), id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
fingers++;
2024-05-10 18:27:57 +01:00
}
void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) {
if (!owner)
2024-05-10 18:27:57 +01:00
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
return;
2024-05-10 18:27:57 +01:00
resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id);
fingers--;
if (fingers <= 0) {
currentSurface.reset();
listeners.destroySurface.reset();
fingers = 0;
}
2024-05-10 18:27:57 +01:00
}
void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) {
if (!owner)
2024-05-10 18:27:57 +01:00
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
return;
2024-05-10 18:27:57 +01:00
resource->sendMotion(timeMs, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
}
void CWLTouchResource::sendFrame() {
if (!owner)
2024-05-10 18:27:57 +01:00
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
return;
2024-05-10 18:27:57 +01:00
resource->sendFrame();
}
void CWLTouchResource::sendCancel() {
if (!owner || !currentSurface)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
return;
2024-05-10 18:27:57 +01:00
resource->sendCancel();
}
void CWLTouchResource::sendShape(int32_t id, const Vector2D& shape) {
if (!owner || !currentSurface || resource->version() < 6)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
return;
2024-05-10 18:27:57 +01:00
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;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
return;
2024-05-10 18:27:57 +01:00
resource->sendOrientation(id, wl_fixed_from_double(angle));
}
CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResource> owner_) : owner(owner_), resource(resource_) {
if UNLIKELY (!good())
2024-05-10 18:27:57 +01:00
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;
}
auto surfResource = surf ? CWLSurfaceResource::fromResource(surf) : nullptr;
if (surfResource && surfResource->role->role() != SURFACE_ROLE_CURSOR && surfResource->role->role() != SURFACE_ROLE_UNASSIGNED) {
r->error(-1, "Cursor surface already has a different role");
return;
}
if (surfResource) {
surfResource->role = makeShared<CCursorSurfaceRole>();
surfResource->updateCursorShm();
}
g_pSeatManager->onSetCursor(owner.lock(), serial, surfResource, {hotX, hotY});
2024-05-10 18:27:57 +01:00
});
if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client())
sendEnter(g_pSeatManager->state.pointerFocus.lock(), {-1, -1} /* Coords don't really matter that much, they will be updated next move */);
2024-05-10 18:27:57 +01:00
}
int CWLPointerResource::version() {
return resource->version();
}
2024-05-10 18:27:57 +01:00
bool CWLPointerResource::good() {
return resource->resource();
}
void CWLPointerResource::sendEnter(SP<CWLSurfaceResource> surface, const Vector2D& local) {
2024-05-10 18:27:57 +01:00
if (!owner || currentSurface == surface)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
if (currentSurface) {
LOGM(WARN, "requested CWLPointerResource::sendEnter without sendLeave first.");
sendLeave();
}
ASSERT(surface->client() == owner->client());
2024-05-10 18:27:57 +01:00
currentSurface = surface;
listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); });
2024-05-10 18:27:57 +01:00
resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
2024-05-10 18:27:57 +01:00
}
void CWLPointerResource::sendLeave() {
if (!owner || !currentSurface)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
// release all buttons unless we have a dnd going on in which case
// the events shall be lost.
if (!PROTO::data->dndActive()) {
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
for (auto const& b : pressedButtons) {
sendButton(now.tv_sec * 1000 + now.tv_nsec / 1000000, b, WL_POINTER_BUTTON_STATE_RELEASED);
}
}
pressedButtons.clear();
resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get());
currentSurface.reset();
listeners.destroySurface.reset();
2024-05-10 18:27:57 +01:00
}
void CWLPointerResource::sendMotion(uint32_t timeMs, const Vector2D& local) {
if (!owner || !currentSurface)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
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;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
if (state == WL_POINTER_BUTTON_STATE_RELEASED && std::find(pressedButtons.begin(), pressedButtons.end(), button) == pressedButtons.end()) {
LOGM(ERR, "sendButton release on a non-pressed button");
return;
} else if (state == WL_POINTER_BUTTON_STATE_PRESSED && std::find(pressedButtons.begin(), pressedButtons.end(), button) != pressedButtons.end()) {
LOGM(ERR, "sendButton press on a non-pressed button");
return;
}
if (state == WL_POINTER_BUTTON_STATE_RELEASED)
std::erase(pressedButtons, button);
else if (state == WL_POINTER_BUTTON_STATE_PRESSED)
pressedButtons.emplace_back(button);
2024-05-10 18:27:57 +01:00
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;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
resource->sendAxis(timeMs, axis, wl_fixed_from_double(value));
}
void CWLPointerResource::sendFrame() {
if (!owner || resource->version() < 5)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
resource->sendFrame();
}
void CWLPointerResource::sendAxisSource(wl_pointer_axis_source source) {
if (!owner || !currentSurface || resource->version() < 5)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
resource->sendAxisSource(source);
}
void CWLPointerResource::sendAxisStop(uint32_t timeMs, wl_pointer_axis axis) {
if (!owner || !currentSurface || resource->version() < 5)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
resource->sendAxisStop(timeMs, axis);
}
void CWLPointerResource::sendAxisDiscrete(wl_pointer_axis axis, int32_t discrete) {
if (!owner || !currentSurface || resource->version() < 5)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
resource->sendAxisDiscrete(axis, discrete);
}
void CWLPointerResource::sendAxisValue120(wl_pointer_axis axis, int32_t value120) {
if (!owner || !currentSurface || resource->version() < 8)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
resource->sendAxisValue120(axis, value120);
}
void CWLPointerResource::sendAxisRelativeDirection(wl_pointer_axis axis, wl_pointer_axis_relative_direction direction) {
if (!owner || !currentSurface || resource->version() < 9)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
return;
2024-05-10 18:27:57 +01:00
resource->sendAxisRelativeDirection(axis, direction);
}
CWLKeyboardResource::CWLKeyboardResource(SP<CWlKeyboard> resource_, SP<CWLSeatResource> owner_) : owner(owner_), resource(resource_) {
if UNLIKELY (!good())
2024-05-10 18:27:57 +01:00
return;
resource->setRelease([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); });
resource->setOnDestroy([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); });
if (!g_pSeatManager->keyboard) {
LOGM(ERR, "No keyboard on bound wl_keyboard??");
return;
}
2024-05-10 18:27:57 +01:00
sendKeymap(g_pSeatManager->keyboard.lock());
repeatInfo(g_pSeatManager->keyboard->repeatRate, g_pSeatManager->keyboard->repeatDelay);
if (g_pSeatManager->state.keyboardFocus && g_pSeatManager->state.keyboardFocus->client() == resource->client())
sendEnter(g_pSeatManager->state.keyboardFocus.lock());
2024-05-10 18:27:57 +01:00
}
bool CWLKeyboardResource::good() {
return resource->resource();
}
void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) {
if (!keyboard)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
return;
seat: avoid sending pointless 'keymap' and 'repeat_info' events (#8276) #### Describe your PR, what does it fix/add? Fix lag spikes when pressing more than 6 keys at the same time. #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) Debugging process: <details> This is triggered by typing some applications, like CopyQ or XWayland. Typing in Firefox doesn't lead to lag, however it itself does lag handling these events. Profiling CopyQ shows that paths leading to `QtWaylandClient::QWaylandInputDevice::Keyboard::keyboard` take over 80% of processing time of an otherwise idle program. Looking at output of 'wev' even when it's not focused shows same events received over and over again. ``` [14: wl_keyboard] repeat_info: rate: 25 keys/sec; delay: 300 ms [14: wl_keyboard] keymap: format: 1 (xkb v1), size: 64754 ``` Looking at what passes through CInputManager::onKeyboardKey() -> CSeatManager::setKeyboard() shows Hyprland 'switching' between endpoints of the same keyboard, one of them being named like the other but with '-1' suffix. </details> Tested changing layouts in Fcitx5 and with following config. ``` input:kb_layout = us,cz input:kb_variant = ,qwerty input:kb_options = grp:alt_shift_toggle ``` Also tested changing 'input:repeat_delay' while running. Curiously, now these events appear in the output of 'wev' only once. Changing layouts still seems to work fine though. #### Is it ready for merging, or does it need work? Ready for merging.
2024-10-28 22:25:27 +03:00
std::string_view keymap;
int fd;
uint32_t size;
2024-05-10 18:27:57 +01:00
if (keyboard) {
seat: avoid sending pointless 'keymap' and 'repeat_info' events (#8276) #### Describe your PR, what does it fix/add? Fix lag spikes when pressing more than 6 keys at the same time. #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) Debugging process: <details> This is triggered by typing some applications, like CopyQ or XWayland. Typing in Firefox doesn't lead to lag, however it itself does lag handling these events. Profiling CopyQ shows that paths leading to `QtWaylandClient::QWaylandInputDevice::Keyboard::keyboard` take over 80% of processing time of an otherwise idle program. Looking at output of 'wev' even when it's not focused shows same events received over and over again. ``` [14: wl_keyboard] repeat_info: rate: 25 keys/sec; delay: 300 ms [14: wl_keyboard] keymap: format: 1 (xkb v1), size: 64754 ``` Looking at what passes through CInputManager::onKeyboardKey() -> CSeatManager::setKeyboard() shows Hyprland 'switching' between endpoints of the same keyboard, one of them being named like the other but with '-1' suffix. </details> Tested changing layouts in Fcitx5 and with following config. ``` input:kb_layout = us,cz input:kb_variant = ,qwerty input:kb_options = grp:alt_shift_toggle ``` Also tested changing 'input:repeat_delay' while running. Curiously, now these events appear in the output of 'wev' only once. Changing layouts still seems to work fine though. #### Is it ready for merging, or does it need work? Ready for merging.
2024-10-28 22:25:27 +03:00
keymap = keyboard->xkbKeymapString;
fd = keyboard->xkbKeymapFD;
size = keyboard->xkbKeymapString.length() + 1;
2024-05-10 18:27:57 +01:00
} else {
fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
LOGM(ERR, "Failed to open /dev/null");
return;
}
size = 0;
}
seat: avoid sending pointless 'keymap' and 'repeat_info' events (#8276) #### Describe your PR, what does it fix/add? Fix lag spikes when pressing more than 6 keys at the same time. #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) Debugging process: <details> This is triggered by typing some applications, like CopyQ or XWayland. Typing in Firefox doesn't lead to lag, however it itself does lag handling these events. Profiling CopyQ shows that paths leading to `QtWaylandClient::QWaylandInputDevice::Keyboard::keyboard` take over 80% of processing time of an otherwise idle program. Looking at output of 'wev' even when it's not focused shows same events received over and over again. ``` [14: wl_keyboard] repeat_info: rate: 25 keys/sec; delay: 300 ms [14: wl_keyboard] keymap: format: 1 (xkb v1), size: 64754 ``` Looking at what passes through CInputManager::onKeyboardKey() -> CSeatManager::setKeyboard() shows Hyprland 'switching' between endpoints of the same keyboard, one of them being named like the other but with '-1' suffix. </details> Tested changing layouts in Fcitx5 and with following config. ``` input:kb_layout = us,cz input:kb_variant = ,qwerty input:kb_options = grp:alt_shift_toggle ``` Also tested changing 'input:repeat_delay' while running. Curiously, now these events appear in the output of 'wev' only once. Changing layouts still seems to work fine though. #### Is it ready for merging, or does it need work? Ready for merging.
2024-10-28 22:25:27 +03:00
if (keymap == lastKeymap) {
if (!keyboard)
close(fd);
return;
}
lastKeymap = keymap;
const wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP;
2024-05-10 18:27:57 +01:00
resource->sendKeymap(format, fd, size);
if (!keyboard)
close(fd);
}
void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface) {
2024-05-10 18:27:57 +01:00
if (!owner || currentSurface == surface)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
return;
2024-05-10 18:27:57 +01:00
if (currentSurface) {
LOGM(WARN, "requested CWLKeyboardResource::sendEnter without sendLeave first.");
sendLeave();
}
ASSERT(surface->client() == owner->client());
2024-05-10 18:27:57 +01:00
currentSurface = surface;
listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); });
2024-05-10 18:27:57 +01:00
wl_array arr;
wl_array_init(&arr);
resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), &arr);
2024-05-10 18:27:57 +01:00
wl_array_release(&arr);
}
void CWLKeyboardResource::sendLeave() {
if (!owner || !currentSurface)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
return;
resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get());
currentSurface.reset();
listeners.destroySurface.reset();
2024-05-10 18:27:57 +01:00
}
void CWLKeyboardResource::sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) {
if (!owner || !currentSurface)
return;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
return;
2024-05-10 18:27:57 +01:00
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;
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
return;
2024-05-10 18:27:57 +01:00
resource->sendModifiers(g_pSeatManager->nextSerial(owner.lock()), depressed, latched, locked, group);
}
void CWLKeyboardResource::repeatInfo(uint32_t rate, uint32_t delayMs) {
seat: avoid sending pointless 'keymap' and 'repeat_info' events (#8276) #### Describe your PR, what does it fix/add? Fix lag spikes when pressing more than 6 keys at the same time. #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) Debugging process: <details> This is triggered by typing some applications, like CopyQ or XWayland. Typing in Firefox doesn't lead to lag, however it itself does lag handling these events. Profiling CopyQ shows that paths leading to `QtWaylandClient::QWaylandInputDevice::Keyboard::keyboard` take over 80% of processing time of an otherwise idle program. Looking at output of 'wev' even when it's not focused shows same events received over and over again. ``` [14: wl_keyboard] repeat_info: rate: 25 keys/sec; delay: 300 ms [14: wl_keyboard] keymap: format: 1 (xkb v1), size: 64754 ``` Looking at what passes through CInputManager::onKeyboardKey() -> CSeatManager::setKeyboard() shows Hyprland 'switching' between endpoints of the same keyboard, one of them being named like the other but with '-1' suffix. </details> Tested changing layouts in Fcitx5 and with following config. ``` input:kb_layout = us,cz input:kb_variant = ,qwerty input:kb_options = grp:alt_shift_toggle ``` Also tested changing 'input:repeat_delay' while running. Curiously, now these events appear in the output of 'wev' only once. Changing layouts still seems to work fine though. #### Is it ready for merging, or does it need work? Ready for merging.
2024-10-28 22:25:27 +03:00
if (!owner || resource->version() < 4 || (rate == lastRate && delayMs == lastDelayMs))
2024-05-10 18:27:57 +01:00
return;
seat: avoid sending pointless 'keymap' and 'repeat_info' events (#8276) #### Describe your PR, what does it fix/add? Fix lag spikes when pressing more than 6 keys at the same time. #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) Debugging process: <details> This is triggered by typing some applications, like CopyQ or XWayland. Typing in Firefox doesn't lead to lag, however it itself does lag handling these events. Profiling CopyQ shows that paths leading to `QtWaylandClient::QWaylandInputDevice::Keyboard::keyboard` take over 80% of processing time of an otherwise idle program. Looking at output of 'wev' even when it's not focused shows same events received over and over again. ``` [14: wl_keyboard] repeat_info: rate: 25 keys/sec; delay: 300 ms [14: wl_keyboard] keymap: format: 1 (xkb v1), size: 64754 ``` Looking at what passes through CInputManager::onKeyboardKey() -> CSeatManager::setKeyboard() shows Hyprland 'switching' between endpoints of the same keyboard, one of them being named like the other but with '-1' suffix. </details> Tested changing layouts in Fcitx5 and with following config. ``` input:kb_layout = us,cz input:kb_variant = ,qwerty input:kb_options = grp:alt_shift_toggle ``` Also tested changing 'input:repeat_delay' while running. Curiously, now these events appear in the output of 'wev' only once. Changing layouts still seems to work fine though. #### Is it ready for merging, or does it need work? Ready for merging.
2024-10-28 22:25:27 +03:00
lastRate = rate;
lastDelayMs = delayMs;
2024-05-10 18:27:57 +01:00
resource->sendRepeatInfo(rate, delayMs);
}
CWLSeatResource::CWLSeatResource(SP<CWlSeat> resource_) : resource(resource_) {
if UNLIKELY (!good())
2024-05-10 18:27:57 +01:00
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 UNLIKELY (!RESOURCE->good()) {
2024-05-10 18:27:57 +01:00
r->noMemory();
PROTO::seat->m_vKeyboards.pop_back();
return;
}
keyboards.emplace_back(RESOURCE);
2024-05-10 18:27:57 +01:00
});
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 UNLIKELY (!RESOURCE->good()) {
2024-05-10 18:27:57 +01:00
r->noMemory();
PROTO::seat->m_vPointers.pop_back();
return;
}
pointers.emplace_back(RESOURCE);
2024-05-10 18:27:57 +01:00
});
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 UNLIKELY (!RESOURCE->good()) {
2024-05-10 18:27:57 +01:00
r->noMemory();
PROTO::seat->m_vTouches.pop_back();
return;
}
touches.emplace_back(RESOURCE);
2024-05-10 18:27:57 +01:00
});
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 UNLIKELY (!RESOURCE->good()) {
2024-05-10 18:27:57 +01:00
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 const& s : m_vSeatResources) {
2024-05-10 18:27:57 +01:00
s->sendCapabilities(caps);
}
}
void CWLSeatProtocol::updateKeymap() {
if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
return;
for (auto const& k : m_vKeyboards) {
2024-05-10 18:27:57 +01:00
k->sendKeymap(g_pSeatManager->keyboard.lock());
}
}
void CWLSeatProtocol::updateRepeatInfo(uint32_t rate, uint32_t delayMs) {
if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
return;
for (auto const& k : m_vKeyboards) {
2024-05-10 18:27:57 +01:00
k->repeatInfo(rate, delayMs);
}
}
SP<CWLSeatResource> CWLSeatProtocol::seatResourceForClient(wl_client* client) {
for (auto const& r : m_vSeatResources) {
2024-05-10 18:27:57 +01:00
if (r->client() == client)
return r;
}
return nullptr;
}
std::vector<uint8_t>& CCursorSurfaceRole::cursorPixelData(SP<CWLSurfaceResource> surface) {
RASSERT(surface->role->role() == SURFACE_ROLE_CURSOR, "cursorPixelData called on a non-cursor surface");
auto role = (CCursorSurfaceRole*)surface->role.get();
return role->cursorShmPixelData;
}