diff options
author | Campbell Barton <campbell@blender.org> | 2022-06-14 08:54:17 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-06-14 09:59:33 +0300 |
commit | 827fa8176737f822b7f8d2354b05e59976c7101a (patch) | |
tree | f4bab251385f9c84e638c8dce5b05ee31a1bab3f | |
parent | f001c857722a8d7ebfc647be54f1a9cb3b2972c4 (diff) |
Fix cursor coordinates being quantized to the window scale in Wayland
- Apply the scale before converting cursor coordinates to int.
- Store sub-pixel cursor coordinates internally since
this is what Wayland uses.
- Use `wl_fixed_t xy[2]` for storing coordinates as it simplifies
assigning/passing x/y coordinates to an argument / variable.
- Also fix drag-and-drop coordinates which ignored scale.
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWayland.cpp | 155 |
1 files changed, 102 insertions, 53 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index dceff4ef2b4..9e683ceb437 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -107,7 +107,8 @@ struct data_offer_t { struct wl_data_offer *id; std::atomic<bool> in_use; struct { - int x, y; + /** Compatible with #input_t.xy coordinates. */ + wl_fixed_t xy[2]; } dnd; }; @@ -137,7 +138,23 @@ struct input_t { uint32_t pointer_serial; uint32_t tablet_serial; - int x, y; + + /** Use to check if the last cursor input was tablet or pointer. */ + uint32_t cursor_serial; + + /** + * High precision mouse coordinates (pointer or tablet). + * + * The following example converts these values to screen coordinates. + * \code{.cc} + * const wl_fixed_t scale = win->scale(); + * const int event_xy[2] = { + * wl_fixed_to_int(scale * input->xy[0]), + * wl_fixed_to_int(scale * input->xy[1]), + * }; + * \endocde + */ + wl_fixed_t xy[2]; GHOST_Buttons buttons; struct cursor_t cursor; @@ -544,18 +561,19 @@ static void relative_pointer_relative_motion( wl_fixed_t /*dy_unaccel*/) { input_t *input = static_cast<input_t *>(data); - - input->x += wl_fixed_to_int(dx); - input->y += wl_fixed_to_int(dy); - - GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( - wl_surface_get_user_data(input->focus_pointer)); + GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_pointer)); + if (win == nullptr) { + return; + } + const wl_fixed_t scale = win->scale(); + input->xy[0] += dx / scale; + input->xy[1] += dy / scale; input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), GHOST_kEventCursorMove, win, - input->x, - input->y, + wl_fixed_to_int(scale * input->xy[0]), + wl_fixed_to_int(scale * input->xy[1]), GHOST_TABLET_DATA_NONE)); } @@ -573,16 +591,20 @@ static void dnd_events(const input_t *const input, const GHOST_TEventType event) { /* NOTE: `input->data_offer_dnd_mutex` must already be locked. */ const uint64_t time = input->system->getMilliSeconds(); - GHOST_IWindow *const window = static_cast<GHOST_WindowWayland *>( + GHOST_WindowWayland *const win = static_cast<GHOST_WindowWayland *>( wl_surface_get_user_data(input->focus_dnd)); + if (!win) { + return; + } + const wl_fixed_t scale = win->scale(); + const int event_xy[2] = { + wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[0]), + wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[1]), + }; + for (const std::string &type : mime_preference_order) { - input->system->pushEvent(new GHOST_EventDragnDrop(time, - event, - mime_dnd.at(type), - window, - input->data_offer_dnd->dnd.x, - input->data_offer_dnd->dnd.y, - nullptr)); + input->system->pushEvent(new GHOST_EventDragnDrop( + time, event, mime_dnd.at(type), win, event_xy[0], event_xy[1], nullptr)); } } @@ -759,8 +781,8 @@ static void data_device_enter(void *data, data_offer_t *data_offer = input->data_offer_dnd; data_offer->in_use.store(true); - data_offer->dnd.x = wl_fixed_to_int(x); - data_offer->dnd.y = wl_fixed_to_int(y); + data_offer->dnd.xy[0] = x; + data_offer->dnd.xy[1] = y; wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | @@ -799,8 +821,9 @@ static void data_device_motion(void *data, input_t *input = static_cast<input_t *>(data); std::lock_guard lock{input->data_offer_dnd_mutex}; - input->data_offer_dnd->dnd.x = wl_fixed_to_int(x); - input->data_offer_dnd->dnd.y = wl_fixed_to_int(y); + input->data_offer_dnd->dnd.xy[0] = x; + input->data_offer_dnd->dnd.xy[1] = y; + dnd_events(input, GHOST_kEventDraggingUpdated); } @@ -820,8 +843,7 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic data_offer_t *data_offer, wl_surface *surface, const std::string mime_receive) { - const int x = data_offer->dnd.x; - const int y = data_offer->dnd.y; + const wl_fixed_t *xy = data_offer->dnd.xy; const std::string data = read_pipe(data_offer, mime_receive, nullptr); @@ -863,12 +885,14 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic flist->strings[i] = static_cast<uint8_t *>(malloc((uris[i].size() + 1) * sizeof(uint8_t))); memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1); } + + const wl_fixed_t scale = win->scale(); system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(), GHOST_kEventDraggingDropDone, GHOST_kDragnDropTypeFilenames, win, - x, - y, + wl_fixed_to_int(scale * xy[0]), + wl_fixed_to_int(scale * xy[1]), flist)); } else if (mime_receive == mime_text_plain || mime_receive == mime_text_utf8) { @@ -1052,17 +1076,19 @@ static void pointer_enter(void *data, input_t *input = static_cast<input_t *>(data); input->pointer_serial = serial; - input->x = win->scale() * wl_fixed_to_int(surface_x); - input->y = win->scale() * wl_fixed_to_int(surface_y); + input->cursor_serial = serial; + input->xy[0] = surface_x; + input->xy[1] = surface_y; input->focus_pointer = surface; win->setCursorShape(win->getCursorShape()); + const wl_fixed_t scale = win->scale(); input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), GHOST_kEventCursorMove, static_cast<GHOST_WindowWayland *>(win), - input->x, - input->y, + wl_fixed_to_int(scale * input->xy[0]), + wl_fixed_to_int(scale * input->xy[1]), GHOST_TABLET_DATA_NONE)); } @@ -1095,14 +1121,15 @@ static void pointer_motion(void *data, return; } - input->x = win->scale() * wl_fixed_to_int(surface_x); - input->y = win->scale() * wl_fixed_to_int(surface_y); + input->xy[0] = surface_x; + input->xy[1] = surface_y; + const wl_fixed_t scale = win->scale(); input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), GHOST_kEventCursorMove, win, - input->x, - input->y, + wl_fixed_to_int(scale * input->xy[0]), + wl_fixed_to_int(scale * input->xy[1]), GHOST_TABLET_DATA_NONE)); } @@ -1253,6 +1280,8 @@ static void tablet_tool_proximity_in(void *data, input->focus_tablet = surface; input->tablet_serial = serial; + input->cursor_serial = serial; + input->data_source_serial = serial; /* Update #GHOST_TabletData. */ @@ -1333,14 +1362,15 @@ static void tablet_tool_motion(void *data, return; } - input->x = win->scale() * wl_fixed_to_int(x); - input->y = win->scale() * wl_fixed_to_int(y); + input->xy[0] = x; + input->xy[1] = y; + const wl_fixed_t scale = win->scale(); input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), GHOST_kEventCursorMove, win, - input->x, - input->y, + wl_fixed_to_int(scale * input->xy[0]), + wl_fixed_to_int(scale * input->xy[1]), tool_input->data)); } @@ -2116,13 +2146,26 @@ uint8_t GHOST_SystemWayland::getNumDisplays() const GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const { - if (d->inputs.empty() || - (d->inputs[0]->focus_pointer == nullptr && d->inputs[0]->focus_tablet == nullptr)) { + if (d->inputs.empty()) { + return GHOST_kFailure; + } + + input_t *input = d->inputs[0]; + struct wl_surface *surface = nullptr; + if (input->pointer_serial == input->cursor_serial) { + surface = input->focus_pointer; + } + else if (input->tablet_serial == input->cursor_serial) { + surface = input->focus_tablet; + } + if (!surface) { return GHOST_kFailure; } - x = d->inputs[0]->x; - y = d->inputs[0]->y; + GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface)); + const wl_fixed_t scale = win->scale(); + x = wl_fixed_to_int(scale * input->xy[0]); + y = wl_fixed_to_int(scale * input->xy[1]); return GHOST_kSuccess; } @@ -2556,30 +2599,36 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo if (mode_current == GHOST_kGrabWrap) { GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface)); GHOST_Rect bounds; - int x_new = input->x, y_new = input->y; + int32_t xy_new[2] = {input->xy[0], input->xy[1]}; /* Fallback to window bounds. */ if (win->getCursorGrabBounds(bounds) == GHOST_kFailure) { win->getClientBounds(bounds); } - bounds.wrapPoint(x_new, y_new, 0, win->getCursorGrabAxis()); + + const int scale = win->scale(); + + bounds.m_l = wl_fixed_from_int(bounds.m_l) / scale; + bounds.m_t = wl_fixed_from_int(bounds.m_t) / scale; + bounds.m_r = wl_fixed_from_int(bounds.m_r) / scale; + bounds.m_b = wl_fixed_from_int(bounds.m_b) / scale; + + bounds.wrapPoint(xy_new[0], xy_new[1], 0, win->getCursorGrabAxis()); /* Push an event so the new location is registered. */ - if ((x_new != input->x) || (y_new != input->y)) { + if ((xy_new[0] != input->xy[0]) || (xy_new[1] != input->xy[1])) { input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), GHOST_kEventCursorMove, win, - x_new, - y_new, + wl_fixed_to_int(scale * xy_new[0]), + wl_fixed_to_int(scale * xy_new[1]), GHOST_TABLET_DATA_NONE)); } - input->x = x_new; - input->y = y_new; + input->xy[0] = xy_new[0]; + input->xy[1] = xy_new[1]; - const int scale = win->scale(); - zwp_locked_pointer_v1_set_cursor_position_hint(input->locked_pointer, - wl_fixed_from_int(x_new) / scale, - wl_fixed_from_int(y_new) / scale); + zwp_locked_pointer_v1_set_cursor_position_hint( + input->locked_pointer, xy_new[0], xy_new[1]); wl_surface_commit(surface); } |