fix(wayland): stop EiScreen cursor from following transient shape churn

updateShape() unconditionally recentered the cursor and notified the
server on every call, even mid-churn when no device reports a region
yet. Only touch tracked state once a real region is found, and only
notify the server when the shape actually changed.
This commit is contained in:
ElCruncharino 2026-07-15 13:09:00 -04:00 committed by Nick Bolton
parent e8e9d1c193
commit 89a6c7f2ed
2 changed files with 36 additions and 12 deletions

View file

@ -481,26 +481,49 @@ bool EiScreen::isPrimary() const
void EiScreen::updateShape() void EiScreen::updateShape()
{ {
m_w = 1; std::uint32_t newW = 1;
m_h = 1; std::uint32_t newH = 1;
m_x = std::numeric_limits<uint32_t>::max(); std::uint32_t newX = std::numeric_limits<uint32_t>::max();
m_y = std::numeric_limits<uint32_t>::max(); std::uint32_t newY = std::numeric_limits<uint32_t>::max();
bool foundRegion = false;
for (auto it = m_eiDevices.begin(); it != m_eiDevices.end(); it++) { for (auto it = m_eiDevices.begin(); it != m_eiDevices.end(); it++) {
auto idx = 0; auto idx = 0;
struct ei_region *r; struct ei_region *r;
while ((r = ei_device_get_region(*it, idx++)) != nullptr) { while ((r = ei_device_get_region(*it, idx++)) != nullptr) {
m_x = std::min(ei_region_get_x(r), m_x); foundRegion = true;
m_y = std::min(ei_region_get_y(r), m_y); newX = std::min(ei_region_get_x(r), newX);
m_w = std::max(ei_region_get_x(r) + ei_region_get_width(r), m_w); newY = std::min(ei_region_get_y(r), newY);
m_h = std::max(ei_region_get_y(r) + ei_region_get_height(r), m_h); newW = std::max(ei_region_get_x(r) + ei_region_get_width(r), newW);
newH = std::max(ei_region_get_y(r) + ei_region_get_height(r), newH);
} }
} }
LOG_DEBUG("logical output size: %dx%d@%d.%d", m_w, m_h, m_x, m_y); if (!foundRegion) {
m_cursorX = m_x + m_w / 2; LOG_DEBUG("logical output size: unchanged (no region-reporting device present)");
m_cursorY = m_y + m_h / 2; return;
}
LOG_DEBUG("logical output size: %dx%d@%d.%d", newW, newH, newX, newY);
const bool changed = newX != m_x || newY != m_y || newW != m_w || newH != m_h;
if (!m_isShapeInitialized) {
m_cursorX = newX + newW / 2;
m_cursorY = newY + newH / 2;
m_isShapeInitialized = true;
} else if (changed) {
m_cursorX = std::clamp(m_cursorX, static_cast<int32_t>(newX), static_cast<int32_t>(newX + newW - 1));
m_cursorY = std::clamp(m_cursorY, static_cast<int32_t>(newY), static_cast<int32_t>(newY + newH - 1));
}
m_x = newX;
m_y = newY;
m_w = newW;
m_h = newH;
if (changed) {
sendEvent(EventTypes::ScreenShapeChanged, nullptr); sendEvent(EventTypes::ScreenShapeChanged, nullptr);
}
} }
void EiScreen::addDevice(struct ei_device *device) void EiScreen::addDevice(struct ei_device *device)

View file

@ -158,6 +158,7 @@ private:
std::uint32_t m_y = 0; std::uint32_t m_y = 0;
std::uint32_t m_w = 0; std::uint32_t m_w = 0;
std::uint32_t m_h = 0; std::uint32_t m_h = 0;
bool m_isShapeInitialized = false;
// true if mouse has entered the screen // true if mouse has entered the screen
bool m_isOnScreen; bool m_isOnScreen;