Merge branch 'master' into blender2.8
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
index dd6defaaf872c5f8054c0666275ff891b2db1dcb..3bde9d46df3f8ecefc5afa95f5eea5f728552727 100644 (file)
 #include "BKE_context.h"
 #include "BKE_idprop.h"
 #include "BKE_global.h"
+#include "BKE_layer.h"
 #include "BKE_main.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
 #include "BKE_screen.h"
+#include "BKE_workspace.h"
 
 #include "BKE_sound.h"
 
 
 #include "RNA_access.h"
 
-#include "GPU_debug.h"
-
 #include "UI_interface.h"
 
 #include "PIL_time.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
+#include "WM_message.h"
 #include "wm.h"
 #include "wm_window.h"
 #include "wm_event_system.h"
@@ -83,6 +84,8 @@
 
 #include "RNA_enum_types.h"
 
+#include "DEG_depsgraph.h"
+
 /* Motion in pixels allowed before we don't consider single/double click. */
 #define WM_EVENT_CLICK_WIGGLE_ROOM 2
 
@@ -247,6 +250,14 @@ void WM_main_remove_notifier_reference(const void *reference)
                                wm_notifier_clear(note);
                        }
                }
+
+               /* Remap instead. */
+#if 0
+               if (wm->message_bus) {
+                       WM_msg_id_remove(wm->message_bus, reference);
+               }
+#endif
+
        }
 }
 
@@ -266,6 +277,17 @@ void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
                        }
                }
        }
+
+       wmWindowManager *wm = bmain->wm.first;
+       if (wm && wm->message_bus) {
+               struct wmMsgBus *mbus = wm->message_bus;
+               if (new_id != NULL) {
+                       WM_msg_id_update(mbus, old_id, new_id);
+               }
+               else {
+                       WM_msg_id_remove(mbus, old_id);
+               }
+       }
 }
 
 static void wm_notifier_clear(wmNotifier *note)
@@ -285,15 +307,20 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
 
        /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
        for (wmWindow *win = wm->windows.first; win; win = win->next) {
-               win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
+               const Scene *scene = WM_window_get_active_scene(win);
+               const bScreen *screen = WM_window_get_active_screen(win);
+
+               win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
        }
 
        /* cached: editor refresh callbacks now, they get context */
        for (wmWindow *win = wm->windows.first; win; win = win->next) {
+               const bScreen *screen = WM_window_get_active_screen(win);
+               Scene *scene = WM_window_get_active_scene(win);
                ScrArea *sa;
 
                CTX_wm_window_set(C, win);
-               for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+               for (sa = screen->areabase.first; sa; sa = sa->next) {
                        if (sa->do_refresh) {
                                CTX_wm_area_set(C, sa);
                                ED_area_do_refresh(C, sa);
@@ -306,12 +333,16 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
                        Main *bmain = CTX_data_main(C);
 
                        /* copied to set's in scene_update_tagged_recursive() */
-                       win->screen->scene->customdata_mask = win_combine_v3d_datamask;
+                       scene->customdata_mask = win_combine_v3d_datamask;
 
                        /* XXX, hack so operators can enforce datamasks [#26482], gl render */
-                       win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
+                       scene->customdata_mask |= scene->customdata_mask_modal;
+
+                       WorkSpace *workspace = WM_window_get_active_workspace(win);
 
-                       BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
+                       BKE_workspace_update_object_mode(bmain->eval_ctx, workspace);
+
+                       BKE_workspace_update_tagged(bmain->eval_ctx, bmain, workspace, scene);
                }
        }
 
@@ -327,9 +358,12 @@ void wm_event_do_notifiers(bContext *C)
        
        if (wm == NULL)
                return;
-       
+
+       /* disable? - keep for now since its used for window level notifiers. */
+#if 1
        /* cache & catch WM level notifiers, such as frame change, scene/screen set */
        for (win = wm->windows.first; win; win = win->next) {
+               Scene *scene = WM_window_get_active_scene(win);
                bool do_anim = false;
                
                CTX_wm_window_set(C, win);
@@ -347,17 +381,31 @@ void wm_event_do_notifiers(bContext *C)
                        }
                        if (note->window == win) {
                                if (note->category == NC_SCREEN) {
-                                       if (note->data == ND_SCREENBROWSE) {
+                                       if (note->data == ND_WORKSPACE_SET) {
+                                               WorkSpace *ref_ws = note->reference;
+
+                                               UI_popup_handlers_remove_all(C, &win->modalhandlers);
+
+                                               ED_workspace_change(ref_ws, C, win);
+                                               if (G.debug & G_DEBUG_EVENTS)
+                                                       printf("%s: Workspace set %p\n", __func__, note->reference);
+                                       }
+                                       else if (note->data == ND_LAYOUTBROWSE) {
+                                               bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
+
                                                /* free popup handlers only [#35434] */
                                                UI_popup_handlers_remove_all(C, &win->modalhandlers);
 
 
-                                               ED_screen_set(C, note->reference);  // XXX hrms, think this over!
+                                               ED_screen_change(C, ref_screen);  /* XXX hrms, think this over! */
                                                if (G.debug & G_DEBUG_EVENTS)
                                                        printf("%s: screen set %p\n", __func__, note->reference);
                                        }
-                                       else if (note->data == ND_SCREENDELETE) {
-                                               ED_screen_delete(C, note->reference);   // XXX hrms, think this over!
+                                       else if (note->data == ND_LAYOUTDELETE) {
+                                               WorkSpace *workspace = WM_window_get_active_workspace(win);
+                                               WorkSpaceLayout *layout = note->reference;
+
+                                               ED_workspace_layout_delete(workspace, layout, C);   // XXX hrms, think this over!
                                                if (G.debug & G_DEBUG_EVENTS)
                                                        printf("%s: screen delete %p\n", __func__, note->reference);
                                        }
@@ -365,7 +413,7 @@ void wm_event_do_notifiers(bContext *C)
                        }
 
                        if (note->window == win ||
-                           (note->window == NULL && (note->reference == NULL || note->reference == win->screen->scene)))
+                           (note->window == NULL && (note->reference == NULL || note->reference == scene)))
                        {
                                if (note->category == NC_SCENE) {
                                        if (note->data == ND_FRAME)
@@ -373,19 +421,21 @@ void wm_event_do_notifiers(bContext *C)
                                }
                        }
                        if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
-                               ED_info_stats_clear(win->screen->scene);
+                               ViewLayer *view_layer = CTX_data_view_layer(C);
+                               ED_info_stats_clear(view_layer);
                                WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
                        }
                }
                if (do_anim) {
 
                        /* XXX, quick frame changes can cause a crash if framechange and rendering
-                        * collide (happens on slow scenes), BKE_scene_update_for_newframe can be called
+                        * collide (happens on slow scenes), BKE_scene_graph_update_for_newframe can be called
                         * twice which can depgraph update the same object at once */
                        if (G.is_rendering == false) {
-
                                /* depsgraph gets called, might send more notifiers */
-                               ED_update_for_newframe(CTX_data_main(C), win->screen->scene, 1);
+                               ViewLayer *view_layer = CTX_data_view_layer(C);
+                               Depsgraph *depsgraph = CTX_data_depsgraph(C);
+                               ED_update_for_newframe(CTX_data_main(C), scene, view_layer, depsgraph);
                        }
                }
        }
@@ -393,12 +443,20 @@ void wm_event_do_notifiers(bContext *C)
        /* the notifiers are sent without context, to keep it clean */
        while ((note = BLI_pophead(&wm->queue))) {
                for (win = wm->windows.first; win; win = win->next) {
-                       
+                       Scene *scene = WM_window_get_active_scene(win);
+                       bScreen *screen = WM_window_get_active_screen(win);
+                       WorkSpace *workspace = WM_window_get_active_workspace(win);
+
                        /* filter out notifiers */
-                       if (note->category == NC_SCREEN && note->reference && note->reference != win->screen) {
+                       if (note->category == NC_SCREEN &&
+                           note->reference &&
+                           note->reference != screen &&
+                           note->reference != workspace &&
+                           note->reference != WM_window_get_active_layout(win))
+                       {
                                /* pass */
                        }
-                       else if (note->category == NC_SCENE && note->reference && note->reference != win->screen->scene) {
+                       else if (note->category == NC_SCENE && note->reference && note->reference != scene) {
                                /* pass */
                        }
                        else {
@@ -411,14 +469,14 @@ void wm_event_do_notifiers(bContext *C)
                                /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name + 2, note->category); */
                                ED_screen_do_listen(C, note);
 
-                               for (ar = win->screen->regionbase.first; ar; ar = ar->next) {
-                                       ED_region_do_listen(win->screen, NULL, ar, note);
+                               for (ar = screen->regionbase.first; ar; ar = ar->next) {
+                                       ED_region_do_listen(screen, NULL, ar, note, scene);
                                }
                                
-                               for (sa = win->screen->areabase.first; sa; sa = sa->next) {
-                                       ED_area_do_listen(win->screen, sa, note);
+                               for (sa = screen->areabase.first; sa; sa = sa->next) {
+                                       ED_area_do_listen(screen, sa, note, scene, workspace);
                                        for (ar = sa->regionbase.first; ar; ar = ar->next) {
-                                               ED_region_do_listen(win->screen, sa, ar, note);
+                                               ED_region_do_listen(screen, sa, ar, note, scene);
                                        }
                                }
                        }
@@ -426,7 +484,17 @@ void wm_event_do_notifiers(bContext *C)
                
                MEM_freeN(note);
        }
-       
+#endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */
+
+       /* Handle message bus. */
+       {
+               for (win = wm->windows.first; win; win = win->next) {
+                       CTX_wm_window_set(C, win);
+                       WM_msgbus_handle(wm->message_bus, C);
+               }
+               CTX_wm_window_set(C, NULL);
+       }
+
        wm_event_do_refresh_wm_and_depsgraph(C);
 }
 
@@ -1597,6 +1665,36 @@ int WM_userdef_event_map(int kmitype)
        return kmitype;
 }
 
+/**
+ * Use so we can check if 'wmEvent.type' is released in modal operators.
+ *
+ * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
+ */
+int WM_userdef_event_type_from_keymap_type(int kmitype)
+{
+       switch (kmitype) {
+               case SELECTMOUSE:
+                       return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
+               case ACTIONMOUSE:
+                       return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
+               case EVT_TWEAK_S:
+                       return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
+               case EVT_TWEAK_A:
+                       return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
+               case EVT_TWEAK_L:
+                       return LEFTMOUSE;
+               case EVT_TWEAK_M:
+                       return MIDDLEMOUSE;
+               case EVT_TWEAK_R:
+                       return RIGHTMOUSE;
+               case WHEELOUTMOUSE:
+                       return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
+               case WHEELINMOUSE:
+                       return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
+       }
+
+       return kmitype;
+}
 
 static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
 {
@@ -1745,7 +1843,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        wm_handler_op_context(C, handler, event);
                        wm_region_mouse_co(C, event);
                        wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
-                       
+
                        if (ot->flag & OPTYPE_UNDO)
                                wm->op_undo_depth++;
 
@@ -1794,6 +1892,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                                        CTX_wm_region_set(C, NULL);
                                }
 
+                               /* update manipulators during modal handlers */
+                               wm_manipulatormaps_handled_modal_update(C, event, handler);
+
                                /* remove modal handler, operator itself should have been canceled and freed */
                                if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
                                        WM_cursor_grab_disable(CTX_wm_window(C), NULL);
@@ -2166,6 +2267,139 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
                                        }
                                }
                        }
+                       else if (handler->manipulator_map) {
+                               ScrArea *area = CTX_wm_area(C);
+                               ARegion *region = CTX_wm_region(C);
+                               wmManipulatorMap *mmap = handler->manipulator_map;
+                               wmManipulator *mpr = wm_manipulatormap_highlight_get(mmap);
+
+                               if (region->manipulator_map != handler->manipulator_map) {
+                                       WM_manipulatormap_tag_refresh(handler->manipulator_map);
+                               }
+
+                               wm_manipulatormap_handler_context(C, handler);
+                               wm_region_mouse_co(C, event);
+
+                               /* handle manipulator highlighting */
+                               if (event->type == MOUSEMOVE && !wm_manipulatormap_modal_get(mmap)) {
+                                       int part;
+                                       mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part);
+                                       wm_manipulatormap_highlight_set(mmap, C, mpr, part);
+                                       if (mpr != NULL) {
+                                               WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_manipulatormap_tooltip_init);
+                                       }
+                               }
+                               else {
+                                       /* Either we operate on a single highlighted item
+                                        * or groups attached to the selected manipulators.
+                                        * To simplify things both cases loop over an array of items. */
+                                       wmManipulatorGroup *mgroup_first;
+                                       bool is_mgroup_single;
+
+                                       if (ISMOUSE(event->type)) {
+                                               /* Keep mpr set as-is, just fake single selection. */
+                                               if (mpr) {
+                                                       mgroup_first = mpr->parent_mgroup;
+                                               }
+                                               else {
+                                                       mgroup_first = NULL;
+                                               }
+                                               is_mgroup_single = true;
+                                       }
+                                       else {
+                                               if (WM_manipulatormap_is_any_selected(mmap)) {
+                                                       const ListBase *groups = WM_manipulatormap_group_list(mmap);
+                                                       mgroup_first = groups->first;
+                                               }
+                                               else {
+                                                       mgroup_first = NULL;
+                                               }
+                                               is_mgroup_single = false;
+                                       }
+
+                                       /* Don't use from now on. */
+                                       mpr = NULL;
+
+                                       for (wmManipulatorGroup *mgroup = mgroup_first; mgroup; mgroup = mgroup->next) {
+                                               /* get user customized keymap from default one */
+
+                                               if ((is_mgroup_single == false) &&
+                                                   /* We might want to change the logic here and use some kind of manipulator edit-mode.
+                                                    * For now just use keymap when a selection exists. */
+                                                   wm_manipulatorgroup_is_any_selected(mgroup) == false)
+                                               {
+                                                       continue;
+                                               }
+
+                                               const wmKeyMap *keymap = WM_keymap_active(wm, mgroup->type->keymap);
+                                               wmKeyMapItem *kmi;
+
+                                               PRINT("%s:   checking '%s' ...", __func__, keymap->idname);
+
+                                               if (!keymap->poll || keymap->poll(C)) {
+                                                       PRINT("pass\n");
+                                                       for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+                                                               if (wm_eventmatch(event, kmi)) {
+                                                                       wmOperator *op = handler->op;
+
+                                                                       PRINT("%s:     item matched '%s'\n", __func__, kmi->idname);
+
+                                                                       /* weak, but allows interactive callback to not use rawkey */
+                                                                       event->keymap_idname = kmi->idname;
+
+                                                                       CTX_wm_manipulator_group_set(C, mgroup);
+
+                                                                       /* handler->op is called later, we want keymap op to be triggered here */
+                                                                       handler->op = NULL;
+                                                                       action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
+                                                                       handler->op = op;
+
+                                                                       CTX_wm_manipulator_group_set(C, NULL);
+
+                                                                       if (action & WM_HANDLER_BREAK) {
+                                                                               if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
+                                                                                       printf("%s:       handled - and pass on! '%s'\n",
+                                                                                              __func__, kmi->idname);
+                                                                               }
+                                                                               break;
+                                                                       }
+                                                                       else {
+                                                                               if (action & WM_HANDLER_HANDLED) {
+                                                                                       if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
+                                                                                               printf("%s:       handled - and pass on! '%s'\n",
+                                                                                                      __func__, kmi->idname);
+                                                                                       }
+                                                                               }
+                                                                               else {
+                                                                                       PRINT("%s:       un-handled '%s'\n",
+                                                                                             __func__, kmi->idname);
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               else {
+                                                       PRINT("fail\n");
+                                               }
+
+                                               if (action & WM_HANDLER_BREAK) {
+                                                       break;
+                                               }
+
+                                               if (is_mgroup_single) {
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               /* restore the area */
+                               CTX_wm_area_set(C, area);
+                               CTX_wm_region_set(C, region);
+
+                               if (handler->op) {
+                                       action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
+                               }
+                       }
                        else {
                                /* modal, swallows all */
                                action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
@@ -2346,17 +2580,19 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
 
 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
 {
+       bScreen *screen = WM_window_get_active_screen(win);
+
        if (BLI_listbase_is_empty(&wm->drags)) {
                return;
        }
        
        if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
-               win->screen->do_draw_drag = true;
+               screen->do_draw_drag = true;
        }
        else if (event->type == ESCKEY) {
                WM_drag_free_list(&wm->drags);
 
-               win->screen->do_draw_drag = true;
+               screen->do_draw_drag = true;
        }
        else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
                event->type = EVT_DROP;
@@ -2372,16 +2608,16 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
                event->customdatafree = 1;
                
                /* clear drop icon */
-               win->screen->do_draw_drag = true;
+               screen->do_draw_drag = true;
                
                /* restore cursor (disabled, see wm_dragdrop.c) */
                // WM_cursor_modal_restore(win);
        }
        
        /* overlap fails otherwise */
-       if (win->screen->do_draw_drag)
+       if (screen->do_draw_drag)
                if (win->drawmethod == USER_DRAW_OVERLAP)
-                       win->screen->do_draw = true;
+                       screen->do_draw = true;
        
 }
 
@@ -2411,22 +2647,28 @@ void wm_event_do_handlers(bContext *C)
 
        /* update key configuration before handling events */
        WM_keyconfig_update(wm);
+       WM_manipulatorconfig_update(CTX_data_main(C));
 
        for (win = wm->windows.first; win; win = win->next) {
+               bScreen *screen = WM_window_get_active_screen(win);
                wmEvent *event;
-               
-               if (win->screen == NULL)
+
+               /* some safty checks - these should always be set! */
+               BLI_assert(WM_window_get_active_scene(win));
+               BLI_assert(WM_window_get_active_screen(win));
+               BLI_assert(WM_window_get_active_workspace(win));
+
+               if (screen == NULL)
                        wm_event_free_all(win);
                else {
-                       Scene *scene = win->screen->scene;
-                       
+                       Scene *scene = WM_window_get_active_scene(win);
+
                        if (scene) {
-                               int is_playing_sound = BKE_sound_scene_playing(win->screen->scene);
+                               int is_playing_sound = BKE_sound_scene_playing(scene);
                                
                                if (is_playing_sound != -1) {
                                        bool is_playing_screen;
                                        CTX_wm_window_set(C, win);
-                                       CTX_wm_screen_set(C, win->screen);
                                        CTX_data_scene_set(C, scene);
                                        
                                        is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
@@ -2443,7 +2685,9 @@ void wm_event_do_handlers(bContext *C)
                                                        int ncfra = time * (float)FPS + 0.5f;
                                                        if (ncfra != scene->r.cfra) {
                                                                scene->r.cfra = ncfra;
-                                                               ED_update_for_newframe(CTX_data_main(C), scene, 1);
+                                                               ViewLayer *view_layer = CTX_data_view_layer(C);
+                                                               Depsgraph *depsgraph = CTX_data_depsgraph(C);
+                                                               ED_update_for_newframe(CTX_data_main(C), scene, view_layer, depsgraph);
                                                                WM_event_add_notifier(C, NC_WINDOW, NULL);
                                                        }
                                                }
@@ -2459,6 +2703,9 @@ void wm_event_do_handlers(bContext *C)
                while ( (event = win->queue.first) ) {
                        int action = WM_HANDLER_CONTINUE;
 
+                       /* active screen might change during handlers, update pointer */
+                       screen = WM_window_get_active_screen(win);
+
                        if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
                                printf("\n%s: Handling event\n", __func__);
                                WM_event_print(event);
@@ -2477,7 +2724,7 @@ void wm_event_do_handlers(bContext *C)
                        CTX_wm_window_set(C, win);
 
                        /* Clear tool-tip on mouse move. */
-                       if (win->screen->tool_tip && win->screen->tool_tip->exit_on_event) {
+                       if (screen->tool_tip && screen->tool_tip->exit_on_event) {
                                if (ISMOUSE(event->type)) {
                                        WM_tooltip_clear(C, win);
                                }
@@ -2501,8 +2748,7 @@ void wm_event_do_handlers(bContext *C)
                                return;
 
                        /* check for a tooltip */
-                       {
-                               bScreen *screen = CTX_wm_window(C)->screen;
+                       if (screen == WM_window_get_active_screen(win)) {
                                if (screen->tool_tip && screen->tool_tip->timer) {
                                        if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
                                                WM_tooltip_init(C, win);
@@ -2533,12 +2779,12 @@ void wm_event_do_handlers(bContext *C)
                                }
 #endif
 
-                               for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+                               for (sa = screen->areabase.first; sa; sa = sa->next) {
                                        /* after restoring a screen from SCREENMAXIMIZED we have to wait
                                         * with the screen handling till the region coordinates are updated */
-                                       if (win->screen->skip_handling == true) {
+                                       if (screen->skip_handling == true) {
                                                /* restore for the next iteration of wm_event_do_handlers */
-                                               win->screen->skip_handling = false;
+                                               screen->skip_handling = false;
                                                break;
                                        }
 
@@ -2565,9 +2811,48 @@ void wm_event_do_handlers(bContext *C)
                                                                                        wm_drags_check_ops(C, event);
                                                                                }
                                                                        }
-                                                                       
+
+#ifdef USE_WORKSPACE_TOOL
+                                                                       /* How to solve properly?
+                                                                        *
+                                                                        * Handlers are stored in each region,
+                                                                        * however the tool-system swaps keymaps often and isn't stored
+                                                                        * per region.
+                                                                        *
+                                                                        * Need to investigate how this could be done better.
+                                                                        * We might need to add a more dynamic handler type that uses a callback
+                                                                        * to fetch its current keymap.
+                                                                        */
+                                                                       wmEventHandler sneaky_handler = {NULL};
+                                                                       if (ar->regiontype == RGN_TYPE_WINDOW) {
+                                                                               WorkSpace *workspace = WM_window_get_active_workspace(win);
+                                                                               if (workspace->tool.keymap[0] &&
+                                                                                   workspace->tool.spacetype == sa->spacetype)
+                                                                               {
+                                                                                       wmKeyMap *km = WM_keymap_find_all(
+                                                                                               C, workspace->tool.keymap, sa->spacetype, RGN_TYPE_WINDOW);
+                                                                                       if (km != NULL) {
+                                                                                               sneaky_handler.keymap = km;
+                                                                                               /* Handle widgets first. */
+                                                                                               wmEventHandler *handler_last = ar->handlers.last;
+                                                                                               while (handler_last && handler_last->manipulator_map == NULL) {
+                                                                                                       handler_last = handler_last->prev;
+                                                                                               }
+                                                                                               /* Head of list or after last manipulator. */
+                                                                                               BLI_insertlinkafter(&ar->handlers, handler_last, &sneaky_handler);
+                                                                                       }
+                                                                               }
+                                                                       }
+#endif /* USE_WORKSPACE_TOOL */
+
                                                                        action |= wm_handlers_do(C, event, &ar->handlers);
 
+#ifdef USE_WORKSPACE_TOOL
+                                                                       if (sneaky_handler.keymap) {
+                                                                               BLI_remlink(&ar->handlers, &sneaky_handler);
+                                                                       }
+#endif /* USE_WORKSPACE_TOOL */
+
                                                                        /* fileread case (python), [#29489] */
                                                                        if (CTX_wm_window(C) == NULL)
                                                                                return;
@@ -2632,8 +2917,7 @@ void wm_event_do_handlers(bContext *C)
 
        /* update key configuration after handling events */
        WM_keyconfig_update(wm);
-
-       GPU_ASSERT_NO_GL_ERRORS("wm_event_do_handlers");
+       WM_manipulatorconfig_update(CTX_data_main(C));
 }
 
 /* ********** filesector handling ************ */
@@ -2746,6 +3030,34 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
        return handler;
 }
 
+/**
+ * Modal handlers store a pointer to an area which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_area.
+ */
+void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
+{
+       for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+               /* fileselect handler is quite special... it needs to keep old area stored in handler, so don't change it */
+               if ((handler->op_area == old_area) && (handler->type != WM_HANDLER_FILESELECT)) {
+                       handler->op_area = new_area;
+               }
+       }
+}
+
+/**
+ * Modal handlers store a pointer to a region which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_region.
+ */
+void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
+{
+       for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+               if (handler->op_region == old_region) {
+                       handler->op_region = new_region;
+                       handler->op_region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW;
+               }
+       }
+}
+
 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
 {
        wmEventHandler *handler;