Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager/intern/wm_event_system.cc')
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc241
1 files changed, 165 insertions, 76 deletions
diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc
index 102441f1b4d..181ec89cabd 100644
--- a/source/blender/windowmanager/intern/wm_event_system.cc
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -27,6 +27,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_timer.h"
#include "BLI_utildefines.h"
@@ -55,6 +56,8 @@
#include "ED_util.h"
#include "ED_view3d.h"
+#include "GPU_context.h"
+
#include "RNA_access.h"
#include "UI_interface.h"
@@ -90,6 +93,7 @@
#define USE_GIZMO_MOUSE_PRIORITY_HACK
static void wm_notifier_clear(wmNotifier *note);
+static bool wm_notifier_is_clear(const wmNotifier *note);
static int wm_operator_call_internal(bContext *C,
wmOperatorType *ot,
@@ -252,36 +256,67 @@ void wm_event_init_from_window(wmWindow *win, wmEvent *event)
/** \name Notifiers & Listeners
* \{ */
-static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference)
+/**
+ * Hash for #wmWindowManager.notifier_queue_set, ignores `window`.
+ */
+static uint note_hash_for_queue_fn(const void *ptr)
{
- LISTBASE_FOREACH (wmNotifier *, note, &wm->notifier_queue) {
- if ((note->category | note->data | note->subtype | note->action) == type &&
- note->reference == reference) {
- return true;
- }
- }
+ const wmNotifier *note = static_cast<const wmNotifier *>(ptr);
+ return (BLI_ghashutil_ptrhash(note->reference) ^
+ (note->category | note->data | note->subtype | note->action));
+}
- return false;
+/**
+ * Comparison for #wmWindowManager.notifier_queue_set
+ *
+ * \note This is not an exact equality function as the `window` is ignored.
+ */
+static bool note_cmp_for_queue_fn(const void *a, const void *b)
+{
+ const wmNotifier *note_a = static_cast<const wmNotifier *>(a);
+ const wmNotifier *note_b = static_cast<const wmNotifier *>(b);
+ return !(((note_a->category | note_a->data | note_a->subtype | note_a->action) ==
+ (note_b->category | note_b->data | note_b->subtype | note_b->action)) &&
+ (note_a->reference == note_b->reference));
}
void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
{
- if (wm_test_duplicate_notifier(wm, type, reference)) {
+ if (wm == nullptr) {
+ /* There may be some cases where e.g. `G_MAIN` is not actually the real current main, but some
+ * other temporary one (e.g. during liboverride processing over linked data), leading to null
+ * window manager.
+ *
+ * This is fairly bad and weak, but unfortunately RNA does not have any way to operate over
+ * another main than G_MAIN currently. */
return;
}
- wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
+ wmNotifier note_test = {nullptr};
- BLI_addtail(&wm->notifier_queue, note);
+ note_test.window = win;
+
+ note_test.category = type & NOTE_CATEGORY;
+ note_test.data = type & NOTE_DATA;
+ note_test.subtype = type & NOTE_SUBTYPE;
+ note_test.action = type & NOTE_ACTION;
+ note_test.reference = reference;
- note->window = win;
+ BLI_assert(!wm_notifier_is_clear(&note_test));
- note->category = type & NOTE_CATEGORY;
- note->data = type & NOTE_DATA;
- note->subtype = type & NOTE_SUBTYPE;
- note->action = type & NOTE_ACTION;
+ if (wm->notifier_queue_set == nullptr) {
+ wm->notifier_queue_set = BLI_gset_new_ex(
+ note_hash_for_queue_fn, note_cmp_for_queue_fn, __func__, 1024);
+ }
- note->reference = reference;
+ void **note_p;
+ if (BLI_gset_ensure_p_ex(wm->notifier_queue_set, &note_test, &note_p)) {
+ return;
+ }
+ wmNotifier *note = MEM_new<wmNotifier>(__func__);
+ *note = note_test;
+ *note_p = note;
+ BLI_addtail(&wm->notifier_queue, note);
}
/* XXX: in future, which notifiers to send to other windows? */
@@ -290,25 +325,12 @@ void WM_event_add_notifier(const bContext *C, uint type, void *reference)
WM_event_add_notifier_ex(CTX_wm_manager(C), CTX_wm_window(C), type, reference);
}
-void WM_main_add_notifier(unsigned int type, void *reference)
+void WM_main_add_notifier(uint type, void *reference)
{
Main *bmain = G_MAIN;
wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
- if (!wm || wm_test_duplicate_notifier(wm, type, reference)) {
- return;
- }
-
- wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
-
- BLI_addtail(&wm->notifier_queue, note);
-
- note->category = type & NOTE_CATEGORY;
- note->data = type & NOTE_DATA;
- note->subtype = type & NOTE_SUBTYPE;
- note->action = type & NOTE_ACTION;
-
- note->reference = reference;
+ WM_event_add_notifier_ex(wm, nullptr, type, reference);
}
void WM_main_remove_notifier_reference(const void *reference)
@@ -319,6 +341,9 @@ void WM_main_remove_notifier_reference(const void *reference)
if (wm) {
LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
if (note->reference == reference) {
+ const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr);
+ BLI_assert(removed);
+ UNUSED_VARS_NDEBUG(removed);
/* Don't remove because this causes problems for #wm_event_do_notifiers
* which may be looping on the data (deleting screens). */
wm_notifier_clear(note);
@@ -334,7 +359,7 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
-static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_data))
+static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void * /*user_data*/)
{
ED_assetlist_storage_id_remap(old_id, new_id);
}
@@ -374,6 +399,12 @@ static void wm_notifier_clear(wmNotifier *note)
{
/* nullptr the entire notifier, only leaving (`next`, `prev`) members intact. */
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
+ note->category = NOTE_CATEGORY_TAG_CLEARED;
+}
+
+static bool wm_notifier_is_clear(const wmNotifier *note)
+{
+ return note->category == NOTE_CATEGORY_TAG_CLEARED;
}
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
@@ -455,11 +486,15 @@ static void wm_event_execute_timers(bContext *C)
void wm_event_do_notifiers(bContext *C)
{
+ /* Ensure inside render boundary. */
+ GPU_render_begin();
+
/* Run the timer before assigning `wm` in the unlikely case a timer loads a file, see T80028. */
wm_event_execute_timers(C);
wmWindowManager *wm = CTX_wm_manager(C);
if (wm == nullptr) {
+ GPU_render_end();
return;
}
@@ -473,7 +508,7 @@ void wm_event_do_notifiers(bContext *C)
CTX_wm_window_set(C, win);
- LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
+ LISTBASE_FOREACH_MUTABLE (const wmNotifier *, note, &wm->notifier_queue) {
if (note->category == NC_WM) {
if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
wm->file_saved = 1;
@@ -532,7 +567,7 @@ void wm_event_do_notifiers(bContext *C)
}
if (note->window == win ||
- (note->window == nullptr && (ELEM(note->reference, nullptr, scene)))) {
+ (note->window == nullptr && ELEM(note->reference, nullptr, scene))) {
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME) {
do_anim = true;
@@ -565,8 +600,15 @@ void wm_event_do_notifiers(bContext *C)
}
/* The notifiers are sent without context, to keep it clean. */
- wmNotifier *note;
- while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) {
+ const wmNotifier *note;
+ while ((note = static_cast<const wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) {
+ if (wm_notifier_is_clear(note)) {
+ MEM_freeN((void *)note);
+ continue;
+ }
+ const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr);
+ BLI_assert(removed);
+ UNUSED_VARS_NDEBUG(removed);
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
Scene *scene = WM_window_get_active_scene(win);
bScreen *screen = WM_window_get_active_screen(win);
@@ -590,6 +632,7 @@ void wm_event_do_notifiers(bContext *C)
win->screen->id.name + 2,
note->category);
# endif
+ ED_workspace_do_listen(C, note);
ED_screen_do_listen(C, note);
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
@@ -630,7 +673,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
- MEM_freeN(note);
+ MEM_freeN((void *)note);
}
#endif /* If 1 (postpone disabling for in favor of message-bus), eventually. */
@@ -655,9 +698,11 @@ void wm_event_do_notifiers(bContext *C)
/* Auto-run warning. */
wm_test_autorun_warning(C);
+
+ GPU_render_end();
}
-static int wm_event_always_pass(const wmEvent *event)
+static bool wm_event_always_pass(const wmEvent *event)
{
/* Some events we always pass on, to ensure proper communication. */
return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
@@ -667,14 +712,23 @@ static int wm_event_always_pass(const wmEvent *event)
* Debug only sanity check for the return value of event handlers. Checks that "always pass" events
* don't cause non-passing handler return values, and thus actually pass.
*
- * Can't be executed if the handler just loaded a file (typically identified by `CTX_wm_window(C)`
- * returning `nullptr`), because the event will have been freed then.
+ * \param C: Pass in the context to check if it's "window" was cleared.
+ * The event check can't be executed if the handler just loaded a file or closed the window.
+ * (typically identified by `CTX_wm_window(C)` returning null),
+ * because the event will have been freed then.
+ * When null, always check the event (assume the caller knows the event was not freed).
*/
-BLI_INLINE void wm_event_handler_return_value_check(const wmEvent *event, const int action)
+BLI_INLINE void wm_event_handler_return_value_check(const bContext *C,
+ const wmEvent *event,
+ const int action)
{
- BLI_assert_msg(!wm_event_always_pass(event) || (action != WM_HANDLER_BREAK),
- "Return value for events that should always pass should never be BREAK.");
- UNUSED_VARS_NDEBUG(event, action);
+#ifndef NDEBUG
+ if (C == nullptr || CTX_wm_window(C)) {
+ BLI_assert_msg(!wm_event_always_pass(event) || (action != WM_HANDLER_BREAK),
+ "Return value for events that should always pass should never be BREAK.");
+ }
+#endif
+ UNUSED_VARS_NDEBUG(C, event, action);
}
/** \} */
@@ -1172,7 +1226,7 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op)
op->flag &= ~op_flag;
return ret;
}
-bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
+bool WM_operator_repeat_check(const bContext * /*C*/, wmOperator *op)
{
if (op->type->exec != nullptr) {
return true;
@@ -1546,6 +1600,7 @@ static int wm_operator_call_internal(bContext *C,
case WM_OP_EXEC_AREA:
case WM_OP_EXEC_SCREEN:
event = nullptr;
+ break;
default:
break;
}
@@ -2131,26 +2186,26 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
/* Account for rare case of when these keys are used as the 'type' not as modifiers. */
if (kmi->shift != KM_ANY) {
const bool shift = (winevent->modifier & KM_SHIFT) != 0;
- if ((shift != (bool)kmi->shift) &&
+ if ((shift != bool(kmi->shift)) &&
!ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
return false;
}
}
if (kmi->ctrl != KM_ANY) {
const bool ctrl = (winevent->modifier & KM_CTRL) != 0;
- if (ctrl != (bool)kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ if (ctrl != bool(kmi->ctrl) && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
return false;
}
}
if (kmi->alt != KM_ANY) {
const bool alt = (winevent->modifier & KM_ALT) != 0;
- if (alt != (bool)kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
+ if (alt != bool(kmi->alt) && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
return false;
}
}
if (kmi->oskey != KM_ANY) {
const bool oskey = (winevent->modifier & KM_OSKEY) != 0;
- if ((oskey != (bool)kmi->oskey) && (winevent->type != EVT_OSKEY)) {
+ if ((oskey != bool(kmi->oskey)) && (winevent->type != EVT_OSKEY)) {
return false;
}
}
@@ -2175,7 +2230,7 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
/* Should already be handled by #wm_user_modal_keymap_set_items. */
BLI_assert(kmi->propvalue_str[0] == '\0');
if (wm_eventmatch(event, kmi)) {
- if ((keymap->poll_modal_item == nullptr) || (keymap->poll_modal_item(op, kmi->propvalue))) {
+ if ((keymap->poll_modal_item == nullptr) || keymap->poll_modal_item(op, kmi->propvalue)) {
return kmi;
}
}
@@ -2333,7 +2388,7 @@ static int wm_handler_operator_call(bContext *C,
/* When the window changes the modal modifier may have loaded a new blend file
* (the `system_demo_mode` add-on does this), so we have to assume the event,
* operator, area, region etc have all been freed. */
- if ((CTX_wm_window(C) == win)) {
+ if (CTX_wm_window(C) == win) {
wm_event_modalkeymap_end(event, &event_backup);
@@ -2731,7 +2786,7 @@ static int wm_handler_fileselect_call(bContext *C,
return wm_handler_fileselect_do(C, handlers, handler, event->val);
}
-static int wm_action_not_handled(int action)
+static bool wm_action_not_handled(int action)
{
return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL);
}
@@ -3101,7 +3156,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
int action = WM_HANDLER_CONTINUE;
if (handlers == nullptr) {
- wm_event_handler_return_value_check(event, action);
+ wm_event_handler_return_value_check(C, event, action);
return action;
}
@@ -3267,9 +3322,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
}
/* Do some extra sanity checking before returning the action. */
- if (CTX_wm_window(C) != nullptr) {
- wm_event_handler_return_value_check(event, action);
- }
+ wm_event_handler_return_value_check(C, event, action);
return action;
}
@@ -3440,7 +3493,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
}
}
- wm_event_handler_return_value_check(event, action);
+ wm_event_handler_return_value_check(C, event, action);
return action;
}
@@ -3568,7 +3621,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
/* Clear drop icon. */
screen->do_draw_drag = true;
- /* Restore cursor (disabled, see `wm_dragdrop.c`) */
+ /* Restore cursor (disabled, see `wm_dragdrop.cc`) */
// WM_cursor_modal_restore(win);
}
}
@@ -3717,7 +3770,7 @@ static int wm_event_do_handlers_area_regions(bContext *C, wmEvent *event, ScrAre
action |= wm_event_do_region_handlers(C, event, region);
}
- wm_event_handler_return_value_check(event, action);
+ wm_event_handler_return_value_check(C, event, action);
return action;
}
@@ -4038,9 +4091,9 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
* An appropriate window is either of the following:
* * A parent window that does not yet contain a modal File Browser. This is determined using
* #ED_fileselect_handler_area_find_any_with_op().
- * * A parent window containing a modal File Browser, but in a maximized/fullscreen state. Users
+ * * A parent window containing a modal File Browser, but in a maximized/full-screen state. Users
* shouldn't be able to put a temporary screen like the modal File Browser into
- * maximized/fullscreen state themselves. So this setup indicates that the File Browser was
+ * maximized/full-screen state themselves. So this setup indicates that the File Browser was
* opened using #USER_TEMP_SPACE_DISPLAY_FULLSCREEN.
*
* If no appropriate parent window can be found from the context window, return the first
@@ -4223,7 +4276,7 @@ void WM_event_modal_handler_region_replace(wmWindow *win,
* it needs to keep old region stored in handler, so don't change it. */
if ((handler->context.region == old_region) && (handler->is_fileselect == false)) {
handler->context.region = new_region;
- handler->context.region_type = new_region ? new_region->regiontype : (int)RGN_TYPE_WINDOW;
+ handler->context.region_type = new_region ? new_region->regiontype : int(RGN_TYPE_WINDOW);
}
}
}
@@ -4404,7 +4457,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
wmKeyMap *keymap,
- int UNUSED(priority))
+ int /*priority*/)
{
WM_event_remove_keymap_handler(handlers, keymap);
@@ -4626,16 +4679,16 @@ void WM_event_add_mousemove(wmWindow *win)
static int convert_key(GHOST_TKey key)
{
if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) {
- return (EVT_AKEY + ((int)key - GHOST_kKeyA));
+ return (EVT_AKEY + (int(key) - GHOST_kKeyA));
}
if (key >= GHOST_kKey0 && key <= GHOST_kKey9) {
- return (EVT_ZEROKEY + ((int)key - GHOST_kKey0));
+ return (EVT_ZEROKEY + (int(key) - GHOST_kKey0));
}
if (key >= GHOST_kKeyNumpad0 && key <= GHOST_kKeyNumpad9) {
- return (EVT_PAD0 + ((int)key - GHOST_kKeyNumpad0));
+ return (EVT_PAD0 + (int(key) - GHOST_kKeyNumpad0));
}
if (key >= GHOST_kKeyF1 && key <= GHOST_kKeyF24) {
- return (EVT_F1KEY + ((int)key - GHOST_kKeyF1));
+ return (EVT_F1KEY + (int(key) - GHOST_kKeyF1));
}
switch (key) {
@@ -4689,7 +4742,8 @@ static int convert_key(GHOST_TKey key)
return EVT_LEFTCTRLKEY;
case GHOST_kKeyRightControl:
return EVT_RIGHTCTRLKEY;
- case GHOST_kKeyOS:
+ case GHOST_kKeyLeftOS:
+ case GHOST_kKeyRightOS:
return EVT_OSKEY;
case GHOST_kKeyLeftAlt:
return EVT_LEFTALTKEY;
@@ -4777,7 +4831,7 @@ static int convert_key(GHOST_TKey key)
#endif
}
- CLOG_WARN(WM_LOG_EVENTS, "unknown event type %d from ghost", (int)key);
+ CLOG_WARN(WM_LOG_EVENTS, "unknown event type %d from ghost", int(key));
return EVENT_NONE;
}
@@ -4890,7 +4944,7 @@ void WM_event_tablet_data_default_set(wmTabletData *tablet_data)
void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
if ((tablet_data != nullptr) && tablet_data->Active != GHOST_kTabletModeNone) {
- wmtab->active = (int)tablet_data->Active;
+ wmtab->active = int(tablet_data->Active);
wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
wmtab->x_tilt = tablet_data->Xtilt;
wmtab->y_tilt = tablet_data->Ytilt;
@@ -5174,7 +5228,7 @@ static bool wm_event_is_ignorable_key_press(const wmWindow *win, const wmEvent &
return false;
}
- const wmEvent &last_event = *reinterpret_cast<const wmEvent *>(win->event_queue.last);
+ const wmEvent &last_event = *static_cast<const wmEvent *>(win->event_queue.last);
return wm_event_is_same_key_press(last_event, event);
}
@@ -5214,6 +5268,13 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
event.prev_type = event.type;
event.prev_val = event.val;
+ /* Always use modifiers from the active window since
+ * changes to modifiers aren't sent to inactive windows, see: T66088. */
+ if ((wm->winactive != win) && (wm->winactive && wm->winactive->eventstate)) {
+ event.modifier = wm->winactive->eventstate->modifier;
+ event.keymodifier = wm->winactive->eventstate->keymodifier;
+ }
+
/* Ensure the event state is correct, any deviation from this may cause bugs.
*
* NOTE: #EVENT_NONE is set when unknown keys are pressed,
@@ -5256,6 +5317,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
if (win_other) {
wmEvent event_other = *win_other->eventstate;
+ /* Use the modifier state of this window. */
+ event_other.modifier = event.modifier;
+ event_other.keymodifier = event.keymodifier;
+
/* See comment for this operation on `event` for details. */
event_other.prev_type = event_other.type;
event_other.prev_val = event_other.val;
@@ -5345,6 +5410,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
if (win_other) {
wmEvent event_other = *win_other->eventstate;
+ /* Use the modifier state of this window. */
+ event_other.modifier = event.modifier;
+ event_other.keymodifier = event.keymodifier;
+
/* See comment for this operation on `event` for details. */
event_other.prev_type = event_other.type;
event_other.prev_val = event_other.val;
@@ -5402,7 +5471,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
* special handling of Latin1 when building without UTF8 support.
* Avoid regressions by adding this conversions, it should eventually be removed. */
if ((event.utf8_buf[0] >= 0x80) && (event.utf8_buf[1] == '\0')) {
- const uint c = (uint)event.utf8_buf[0];
+ const uint c = uint(event.utf8_buf[0]);
int utf8_buf_len = BLI_str_utf8_from_unicode(c, event.utf8_buf, sizeof(event.utf8_buf));
CLOG_ERROR(WM_LOG_EVENTS,
"ghost detected non-ASCII single byte character '%u', converting to utf8 "
@@ -5416,11 +5485,30 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
if (BLI_str_utf8_size(event.utf8_buf) == -1) {
CLOG_ERROR(WM_LOG_EVENTS,
"ghost detected an invalid unicode character '%d'",
- (int)(unsigned char)event.utf8_buf[0]);
+ int(uchar(event.utf8_buf[0])));
event.utf8_buf[0] = '\0';
}
}
+ /* NOTE(@campbellbarton): Setting the modifier state based on press/release
+ * is technically incorrect.
+ *
+ * - The user might hold both left/right modifier keys, then only release one.
+ *
+ * This could be solved by storing a separate flag for the left/right modifiers,
+ * and combine them into `event.modifiers`.
+ *
+ * - The user might have multiple keyboards (or keyboard + NDOF device)
+ * where it's possible to press the same modifier key multiple times.
+ *
+ * This could be solved by tracking the number of held modifier keys,
+ * (this is in fact what LIBXKB does), however doing this relies on all GHOST
+ * back-ends properly reporting every press/release as any mismatch could result
+ * in modifier keys being stuck (which is very bad!).
+ *
+ * To my knowledge users never reported a bug relating to these limitations so
+ * it seems reasonable to keep the current logic. */
+
switch (event.type) {
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY: {
@@ -5532,7 +5620,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventNDOFButton: {
GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata);
- event.type = NDOF_BUTTON_NONE + e->button;
+ event.type = NDOF_BUTTON_INDEX_AS_EVENT(e->button);
switch (e->action) {
case GHOST_kPress:
@@ -5870,11 +5958,12 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
bToolRef *tref = nullptr;
if ((region->regiontype == RGN_TYPE_WINDOW) &&
((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
+ const Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
WorkSpace *workspace = WM_window_get_active_workspace(win);
bToolKey tkey{};
tkey.space_type = area->spacetype;
- tkey.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
+ tkey.mode = WM_toolsystem_mode_from_spacetype(scene, view_layer, area, area->spacetype);
tref = WM_toolsystem_ref_find(workspace, &tkey);
}
wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);