fix(wayland): guard null focusedWindow in pointer handlers
Sway delivers pointer events in surprising orders around input-device hot-plug — observed: a second wl_pointer.leave after focus was already cleared, which crashed in PointerListenerHandleLeave (null deref), and motion/button would crash the same way if an enter never matched one of our surfaces. Early-return instead. Found while end-to-end-testing the scroll chain for #32 with a zwlr_virtual_pointer_v1 injector. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
419730f46b
commit
2402f35e6c
1 changed files with 14 additions and 2 deletions
|
|
@ -223,6 +223,11 @@ void Device::handle_global_remove(void* data, wl_registry* registry, uint32_t na
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state) {
|
void Device::pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state) {
|
||||||
|
// Defensive: compositors can deliver pointer events without (or after)
|
||||||
|
// a matching enter — observed on sway during input-device hot-plug.
|
||||||
|
if (focusedWindow == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (button == BTN_LEFT) {
|
if (button == BTN_LEFT) {
|
||||||
if(state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
if(state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
Device::focusedWindow->mouseLeftHeld = true;
|
Device::focusedWindow->mouseLeftHeld = true;
|
||||||
|
|
@ -243,6 +248,9 @@ void Device::pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, std::uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
void Device::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, std::uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||||
|
if (focusedWindow == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Vector<float, 2> pos(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
|
Vector<float, 2> pos(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
|
||||||
//Device::focusedWindow->lastMousePos = Device::focusedWindow->currentMousePos;
|
//Device::focusedWindow->lastMousePos = Device::focusedWindow->currentMousePos;
|
||||||
Device::focusedWindow->currentMousePos = pos * Device::focusedWindow->scale;
|
Device::focusedWindow->currentMousePos = pos * Device::focusedWindow->scale;
|
||||||
|
|
@ -267,8 +275,12 @@ void Device::PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, std:
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::PointerListenerHandleLeave(void* data, wl_pointer*, std::uint32_t, wl_surface*) {
|
void Device::PointerListenerHandleLeave(void* data, wl_pointer*, std::uint32_t, wl_surface*) {
|
||||||
Device::focusedWindow->onMouseLeave.Invoke();
|
// Sway has been observed to send a second leave after focus is already
|
||||||
focusedWindow = nullptr;
|
// gone (input-device hot-plug) — don't crash on it.
|
||||||
|
if (focusedWindow != nullptr) {
|
||||||
|
focusedWindow->onMouseLeave.Invoke();
|
||||||
|
focusedWindow = nullptr;
|
||||||
|
}
|
||||||
// Drop any sub-detent scroll remainder so it can't leak into whatever
|
// Drop any sub-detent scroll remainder so it can't leak into whatever
|
||||||
// window the pointer enters next.
|
// window the pointer enters next.
|
||||||
scrollDetentRemainder = 0.0;
|
scrollDetentRemainder = 0.0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue