Fix T103253: Infinite drag of number buttons is broken on WIN32

Recent reverting of changes to cursor grabbing intended to match
Blender 3.3 release. This is the case for 3.4x branch, however there is
an additional change to grabbing on WIN32 by Germano [0] which is a
significant improvement on old grabbing logic for Windows.
So instead of matching 3.3x behavior, restore logic that keeps
the cursor centered while grabbing & hidden.

This re-introduces T102792 issue displaying the paint-brush while
dragging buttons, this will have to be solved separately.

Re-apply [1] & [2], revert [3] & [4].

[4]: a3a9459050
[0]: 9fd6dae793
[1]: 4cac8025f0
[2]: 230744d6fd
[3]: 0240b89599
This commit is contained in:
Campbell Barton 2022-12-16 18:37:44 +11:00 committed by Hans Goudey
parent bb8cbf0c10
commit 5d1ed47d6c
4 changed files with 78 additions and 68 deletions

View File

@ -1075,17 +1075,46 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
int32_t x_new = x_screen;
int32_t y_new = y_screen;
int32_t x_accum, y_accum;
GHOST_Rect bounds;
/* Fallback to window bounds. */
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
window->getClientBounds(bounds);
/* Warp within bounds. */
{
GHOST_Rect bounds;
int32_t bounds_margin = 0;
GHOST_TAxisFlag bounds_axis = GHOST_kAxisNone;
if (window->getCursorGrabMode() == GHOST_kGrabHide) {
window->getClientBounds(bounds);
/* WARNING(@campbellbarton): The current warping logic fails to warp on every event,
* so the box needs to small enough not to let the cursor escape the window but large
* enough that the cursor isn't being warped every time.
* If this was not the case it would be less trouble to simply warp the cursor to the
* center of the screen on every motion, see: D16558 (alternative fix for T102346). */
const int32_t subregion_div = 4; /* One quarter of the region. */
const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()};
const int32_t center[2] = {(bounds.m_l + bounds.m_r) / 2, (bounds.m_t + bounds.m_b) / 2};
/* Shrink the box to prevent the cursor escaping. */
bounds.m_l = center[0] - (size[0] / (subregion_div * 2));
bounds.m_r = center[0] + (size[0] / (subregion_div * 2));
bounds.m_t = center[1] - (size[1] / (subregion_div * 2));
bounds.m_b = center[1] + (size[1] / (subregion_div * 2));
bounds_margin = 0;
bounds_axis = GHOST_TAxisFlag(GHOST_kAxisX | GHOST_kAxisY);
}
else {
/* Fallback to window bounds. */
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
window->getClientBounds(bounds);
}
bounds_margin = 2;
bounds_axis = window->getCursorGrabAxis();
}
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use inset in case the window is at screen bounds. */
bounds.wrapPoint(x_new, y_new, bounds_margin, bounds_axis);
}
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use inset in case the window is at screen bounds. */
bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis());
window->getCursorGrabAccum(x_accum, y_accum);
if (x_new != x_screen || y_new != y_screen) {
/* WORKAROUND: Store the current time so that we ignore outdated mousemove events. */

View File

@ -917,17 +917,48 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
int32_t x_new = xme.x_root;
int32_t y_new = xme.y_root;
int32_t x_accum, y_accum;
GHOST_Rect bounds;
/* fallback to window bounds */
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
window->getClientBounds(bounds);
/* Warp within bounds. */
{
GHOST_Rect bounds;
int32_t bounds_margin = 0;
GHOST_TAxisFlag bounds_axis = GHOST_kAxisNone;
if (window->getCursorGrabMode() == GHOST_kGrabHide) {
window->getClientBounds(bounds);
/* TODO(@campbellbarton): warp the cursor to `window->getCursorGrabInitPos`,
* on every motion event, see: D16557 (alternative fix for T102346). */
const int32_t subregion_div = 4; /* One quarter of the region. */
const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()};
const int32_t center[2] = {
(bounds.m_l + bounds.m_r) / 2,
(bounds.m_t + bounds.m_b) / 2,
};
/* Shrink the box to prevent the cursor escaping. */
bounds.m_l = center[0] - (size[0] / (subregion_div * 2));
bounds.m_r = center[0] + (size[0] / (subregion_div * 2));
bounds.m_t = center[1] - (size[1] / (subregion_div * 2));
bounds.m_b = center[1] + (size[1] / (subregion_div * 2));
bounds_margin = 0;
bounds_axis = GHOST_TAxisFlag(GHOST_kAxisX | GHOST_kAxisY);
}
else {
/* Fallback to window bounds. */
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
window->getClientBounds(bounds);
}
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use offset of 8 in case the window is at screen bounds. */
bounds_margin = 8;
bounds_axis = window->getCursorGrabAxis();
}
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use inset in case the window is at screen bounds. */
bounds.wrapPoint(x_new, y_new, bounds_margin, bounds_axis);
}
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use offset of 8 in case the window is at screen bounds. */
bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis());
window->getCursorGrabAccum(x_accum, y_accum);
if (x_new != xme.x_root || y_new != xme.y_root) {

View File

@ -55,14 +55,6 @@
#define USE_TABLET_SUPPORT
/**
* Use alternative behavior when cursor warp is supported
* to prevent the cursor escaping the window bounds, see: T102346.
*
* \note this is not needed if cursor positioning is not supported.
*/
#define USE_CURSOR_WARP_HACK
/* -------------------------------------------------------------------- */
/** \name Modal Key-map
* \{ */
@ -229,10 +221,6 @@ typedef struct WalkInfo {
bool need_rotation_keyframe;
bool need_translation_keyframe;
#ifdef USE_CURSOR_WARP_HACK
bool need_modal_cursor_warp_hack;
#endif
/** Previous 2D mouse values. */
int prev_mval[2];
/** Initial mouse location. */
@ -591,10 +579,6 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int
walk->need_rotation_keyframe = false;
walk->need_translation_keyframe = false;
#ifdef USE_CURSOR_WARP_HACK
walk->need_modal_cursor_warp_hack = false;
#endif
walk->time_lastdraw = PIL_check_seconds_timer();
walk->draw_handle_pixel = ED_region_draw_cb_activate(
@ -610,32 +594,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int
copy_v2_v2_int(walk->init_mval, mval);
copy_v2_v2_int(walk->prev_mval, mval);
#ifdef USE_CURSOR_WARP_HACK
if (WM_capabilities_flag() & WM_CAPABILITY_CURSOR_WARP) {
const rcti *winrct = &walk->region->winrct;
const int center[2] = {BLI_rcti_cent_x(winrct), BLI_rcti_cent_y(winrct)};
const int size[2] = {BLI_rcti_size_x(winrct), BLI_rcti_size_y(winrct)};
const int div = 4; /* Where 2 is the region size. */
const rcti wrap_region = {
.xmin = center[0] - (size[0] / div),
.xmax = center[0] + (size[0] / div),
.ymin = center[1] - (size[1] / div),
.ymax = center[1] + (size[1] / div),
};
WM_cursor_grab_enable(win, WM_CURSOR_WRAP_XY, &wrap_region, false);
/* Important to hide afterwards (not part of grabbing),
* since enabling cursor and hiding at the same time ignores bounds. */
WM_cursor_modal_set(win, WM_CURSOR_NONE);
walk->need_modal_cursor_warp_hack = true;
}
else
#endif /* USE_CURSOR_WARP_HACK */
{
WM_cursor_grab_enable(win, WM_CURSOR_WRAP_NONE, NULL, true);
}
WM_cursor_grab_enable(win, 0, NULL, true);
return 1;
}
@ -686,15 +645,6 @@ static int walkEnd(bContext *C, WalkInfo *walk)
WM_cursor_grab_disable(win, NULL);
#ifdef USE_CURSOR_WARP_HACK
if (walk->need_modal_cursor_warp_hack) {
WM_cursor_warp(win,
walk->region->winrct.xmin + walk->init_mval[0],
walk->region->winrct.ymin + walk->init_mval[1]);
WM_cursor_modal_restore(win);
}
#endif
if (walk->state == WALK_CONFIRM) {
MEM_freeN(walk);
return OPERATOR_FINISHED;

@ -1 +1 @@
Subproject commit dfa16042bf7149475ad318d29a8202d969982abb
Subproject commit fdfa2fcb9495d87571f2dfe2ae9fa0e032536600