diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/interface/interface_region_popup.c | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_windowmanager_types.h | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_types.h | 5 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm.c | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 77 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 3 |
7 files changed, 88 insertions, 4 deletions
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index c37d8ec7a2b..2f2556225b5 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -557,6 +557,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, #ifdef DEBUG wmEvent *event_back = window->eventstate; + wmEvent *event_last_back = window->event_last_handled; #endif /* create ui block */ @@ -740,6 +741,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, #ifdef DEBUG window->eventstate = event_back; + window->event_last_handled = event_last_back; #endif return block; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 42c94832a43..ade0fcdb13f 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -294,6 +294,8 @@ typedef struct wmWindow { /** Storage for event system. */ struct wmEvent *eventstate; + /** Keep the last handled event in `event_queue` here (owned and must be freed). */ + struct wmEvent *event_last_handled; /* Input Method Editor data - complex character input (especially for Asian character input) * Currently WIN32 and APPLE, runtime-only data. */ diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 8934f714c21..9edbafafdd3 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -610,6 +610,11 @@ typedef enum eWM_EventFlag { * See #KMI_REPEAT_IGNORE for details on how key-map handling uses this. */ WM_EVENT_IS_REPEAT = (1 << 1), + /** + * Mouse-move events may have this flag set to force creating a click-drag event + * even when the threshold has not been met. + */ + WM_EVENT_FORCE_DRAG_THRESHOLD = (1 << 2), } eWM_EventFlag; typedef struct wmTabletData { diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 487eafc736c..40d9b0b9a35 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -155,6 +155,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id) win->ghostwin = NULL; win->gpuctx = NULL; win->eventstate = NULL; + win->event_last_handled = NULL; win->cursor_keymap_status = NULL; #if defined(WIN32) || defined(__APPLE__) win->ime_data = NULL; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 47f1f36dceb..3fe8e6cd1b0 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -100,6 +100,7 @@ static int wm_operator_call_internal(bContext *C, wmEvent *event); static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot); +static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win); /* -------------------------------------------------------------------- */ /** \name Event Management @@ -200,6 +201,30 @@ void wm_event_free(wmEvent *event) MEM_freeN(event); } +/** A version of #wm_event_free that holds the last handled event. */ +static void wm_event_free_last_handled(wmWindow *win, wmEvent *event) +{ + /* Don't rely on this pointer being valid, + * callers should behave as if the memory has been freed. + * As this function should be interchangeable with #wm_event_free. */ +#ifndef NDEBUG + { + wmEvent *event_copy = MEM_dupallocN(event); + MEM_freeN(event); + event = event_copy; + } +#endif + + if (win->event_last_handled) { + wm_event_free(win->event_last_handled); + } + /* Don't store custom data in the last handled event as we don't have control how long this event + * will be stored and the referenced data may become invalid (also it's not needed currently). */ + wm_event_custom_free(event); + wm_event_custom_clear(event); + win->event_last_handled = event; +} + static void wm_event_free_last(wmWindow *win) { wmEvent *event = BLI_poptail(&win->event_queue); @@ -3176,7 +3201,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) * in `action` setting #WM_HANDLER_HANDLED, but not #WM_HANDLER_BREAK. */ if ((action & WM_HANDLER_BREAK) == 0 || wm_action_not_handled(action)) { if (win->event_queue_check_drag) { - if (WM_event_drag_test(event, event->prev_press_xy)) { + if ((event->flag & WM_EVENT_FORCE_DRAG_THRESHOLD) || + WM_event_drag_test(event, event->prev_press_xy)) { win->event_queue_check_drag_handled = true; const int direction = WM_event_drag_direction(event); @@ -3660,6 +3686,17 @@ void wm_event_do_handlers(bContext *C) while ((event = win->event_queue.first)) { int action = WM_HANDLER_CONTINUE; + /* Force handling drag if a key is pressed even if the drag threshold has not been met. + * Needed so tablet actions (which typically use a larger threshold) can click-drag + * then press keys - activating the drag action early. */ + if (win->event_queue_check_drag) { + if ((event->val == KM_PRESS) && ((event->flag & WM_EVENT_IS_REPEAT) == 0) && + ISKEYBOARD_OR_BUTTON(event->type)) { + event = wm_event_add_mousemove_to_head(win); + event->flag |= WM_EVENT_FORCE_DRAG_THRESHOLD; + } + } + /* Active screen might change during handlers, update pointer. */ screen = WM_window_get_active_screen(win); @@ -3675,7 +3712,7 @@ void wm_event_do_handlers(bContext *C) CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed"); } BLI_remlink(&win->event_queue, event); - wm_event_free(event); + wm_event_free_last_handled(win, event); continue; } @@ -3685,7 +3722,7 @@ void wm_event_do_handlers(bContext *C) if (event->type == EVT_XR_ACTION) { wm_event_handle_xrevent(C, wm, win, event); BLI_remlink(&win->event_queue, event); - wm_event_free(event); + wm_event_free_last_handled(win, event); /* Skip mouse event handling below, which is unnecessary for XR events. */ continue; } @@ -3823,7 +3860,7 @@ void wm_event_do_handlers(bContext *C) /* Un-link and free here, Blender-quit then frees all. */ BLI_remlink(&win->event_queue, event); - wm_event_free(event); + wm_event_free_last_handled(win, event); } /* Only add mouse-move when the event queue was read entirely. */ @@ -4752,6 +4789,38 @@ static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event) return event_new; } +static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win) +{ + /* Use the last handled event instead of `win->eventstate` because the state of the modifiers + * and previous values should be set based on the last state, not using values from the future. + * So this gives an accurate simulation of mouse motion before the next event is handled. */ + const wmEvent *event_last = win->event_last_handled; + + wmEvent tevent; + if (event_last) { + tevent = *event_last; + + tevent.flag = 0; + tevent.ascii = '\0'; + tevent.utf8_buf[0] = '\0'; + + wm_event_custom_clear(&tevent); + } + else { + memset(&tevent, 0x0, sizeof(tevent)); + } + + tevent.type = MOUSEMOVE; + copy_v2_v2_int(tevent.prev_xy, tevent.xy); + + wmEvent *event_new = wm_event_add(win, &tevent); + BLI_remlink(&win->event_queue, event_new); + BLI_addhead(&win->event_queue, event_new); + + copy_v2_v2_int(event_new->prev_xy, event_last->xy); + return event_new; +} + static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int deltax, int deltay) { /* Ignore in between track-pad events for performance, we only need high accuracy diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 5bf5780b93f..4ff96b82fd2 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -246,7 +246,9 @@ static void wm_window_substitute_old(wmWindowManager *oldwm, oldwin->gpuctx = NULL; win->eventstate = oldwin->eventstate; + win->event_last_handled = oldwin->event_last_handled; oldwin->eventstate = NULL; + oldwin->event_last_handled = NULL; /* Ensure proper screen re-scaling. */ win->sizex = oldwin->sizex; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 6c90e0603a5..d6f85e3795e 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -209,6 +209,9 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) if (win->eventstate) { MEM_freeN(win->eventstate); } + if (win->event_last_handled) { + MEM_freeN(win->event_last_handled); + } if (win->cursor_keymap_status) { MEM_freeN(win->cursor_keymap_status); |