Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Thu, 7 Jun 2018 15:08:55 +0000 (17:08 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 7 Jun 2018 15:08:55 +0000 (17:08 +0200)
1  2 
source/blender/editors/interface/interface_region_menu_pie.c
source/blender/makesrna/intern/rna_wm.c
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c

@@@ -76,7 -76,7 +76,7 @@@ static uiBlock *ui_block_func_PIE(bCont
        uiPieMenu *pie = arg_pie;
        int minwidth, width, height;
  
 -      minwidth = 50;
 +      minwidth = UI_MENU_WIDTH_MIN;
        block = pie->block_radial;
  
        /* in some cases we create the block before the region,
@@@ -150,8 -150,16 +150,16 @@@ uiPieMenu *UI_pie_menu_begin(struct bCo
        }
  
        pie->layout = UI_block_layout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
-       pie->mx = event->x;
-       pie->my = event->y;
+       /* Open from where we started dragging. */
+       if (event->val == KM_CLICK_DRAG) {
+               pie->mx = event->prevclickx;
+               pie->my = event->prevclicky;
+       }
+       else {
+               pie->mx = event->x;
+               pie->my = event->y;
+       }
  
        /* create title button */
        if (title[0]) {
@@@ -194,6 -202,7 +202,6 @@@ void UI_pie_menu_end(bContext *C, uiPie
                menu, WM_HANDLER_ACCEPT_DBL_CLICK);
        WM_event_add_mousemove(C);
  
 -      menu->can_refresh = false;
        MEM_freeN(pie);
  }
  
@@@ -36,8 -36,6 +36,8 @@@
  
  #include "BLT_translation.h"
  
 +#include "BKE_workspace.h"
 +
  #include "RNA_access.h"
  #include "RNA_define.h"
  #include "RNA_enum_types.h"
@@@ -53,6 -51,7 +53,7 @@@ static const EnumPropertyItem event_key
        {KM_RELEASE, "RELEASE", 0, "Release", ""},
        {KM_CLICK, "CLICK", 0, "Click", ""},
        {KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""},
+       {KM_CLICK_DRAG, "CLICK_DRAG", 0, "Click Drag", ""},
        {0, NULL, 0, NULL, NULL}
  };
  
@@@ -391,6 -390,7 +392,7 @@@ const EnumPropertyItem rna_enum_event_v
        {KM_RELEASE, "RELEASE", 0, "Release", ""},
        {KM_CLICK, "CLICK", 0, "Click", ""},
        {KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""},
+       {KM_CLICK_DRAG, "CLICK_DRAG", 0, "Click Drag", ""},
        {EVT_GESTURE_N, "NORTH", 0, "North", ""},
        {EVT_GESTURE_NE, "NORTH_EAST", 0, "North-East", ""},
        {EVT_GESTURE_E, "EAST", 0, "East", ""},
@@@ -444,11 -444,6 +446,11 @@@ const EnumPropertyItem rna_enum_operato
        {0, NULL, 0, NULL, NULL}
  };
  
 +const EnumPropertyItem rna_enum_operator_property_tags[] = {
 +      {OP_PROP_TAG_ADVANCED, "ADVANCED", 0, "Advanced", "The property is advanced so UI is suggested to hide it"},
 +      {0, NULL, 0, NULL, NULL}
 +};
 +
  /* flag/enum */
  const EnumPropertyItem rna_enum_wm_report_items[] = {
        {RPT_DEBUG, "DEBUG", 0, "Debug", ""},
  
  #include "WM_api.h"
  
 +#include "DNA_object_types.h"
 +#include "DNA_workspace_types.h"
 +
 +#include "ED_screen.h"
 +
  #include "UI_interface.h"
  
 +#include "BKE_global.h"
  #include "BKE_idprop.h"
  
  #include "MEM_guardedalloc.h"
  
 +#ifdef WITH_PYTHON
 +#  include "BPY_extern.h"
 +#endif
 +
 +
  static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr)
  {
        wmWindowManager *wm = ptr->id.data;
@@@ -629,17 -613,6 +631,17 @@@ static PointerRNA rna_PopupMenu_layout_
        return rptr;
  }
  
 +static PointerRNA rna_PopoverMenu_layout_get(PointerRNA *ptr)
 +{
 +      struct uiPopover *pup = ptr->data;
 +      uiLayout *layout = UI_popover_layout(pup);
 +
 +      PointerRNA rptr;
 +      RNA_pointer_create(ptr->id.data, &RNA_UILayout, layout, &rptr);
 +
 +      return rptr;
 +}
 +
  static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr)
  {
        struct uiPieMenu *pie = ptr->data;
        return rptr;
  }
  
 -static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
 +static void rna_Window_scene_set(PointerRNA *ptr, PointerRNA value)
 +{
 +      wmWindow *win = ptr->data;
 +
 +      if (value.data == NULL) {
 +              return;
 +      }
 +
 +      win->new_scene = value.data;
 +}
 +
 +static void rna_Window_scene_update(bContext *C, PointerRNA *ptr)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      wmWindow *win = ptr->data;
 +
 +      /* exception: must use context so notifier gets to the right window  */
 +      if (win->new_scene) {
 +#ifdef WITH_PYTHON
 +              BPy_BEGIN_ALLOW_THREADS;
 +#endif
 +
 +              WM_window_change_active_scene(bmain, C, win, win->new_scene);
 +
 +#ifdef WITH_PYTHON
 +              BPy_END_ALLOW_THREADS;
 +#endif
 +
 +              WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, win->new_scene);
 +
 +              if (G.debug & G_DEBUG)
 +                      printf("scene set %p\n", win->new_scene);
 +
 +              win->new_scene = NULL;
 +      }
 +}
 +
 +static PointerRNA rna_Window_workspace_get(PointerRNA *ptr)
 +{
 +      wmWindow *win = ptr->data;
 +      return rna_pointer_inherit_refine(ptr, &RNA_WorkSpace, BKE_workspace_active_get(win->workspace_hook));
 +}
 +
 +static void rna_Window_workspace_set(PointerRNA *ptr, PointerRNA value)
  {
        wmWindow *win = (wmWindow *)ptr->data;
  
        /* disallow ID-browsing away from temp screens */
 -      if (win->screen->temp) {
 +      if (WM_window_is_temp_screen(win)) {
                return;
        }
 +      if (value.data == NULL) {
 +              return;
 +      }
 +
 +      /* exception: can't set workspaces inside of area/region handlers */
 +      win->workspace_hook->temp_workspace_store = value.data;
 +}
 +
 +static void rna_Window_workspace_update(bContext *C, PointerRNA *ptr)
 +{
 +      wmWindow *win = ptr->data;
 +      WorkSpace *new_workspace = win->workspace_hook->temp_workspace_store;
 +
 +      /* exception: can't set screens inside of area/region handlers,
 +       * and must use context so notifier gets to the right window */
 +      if (new_workspace) {
 +              WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, new_workspace);
 +              win->workspace_hook->temp_workspace_store = NULL;
 +      }
 +}
  
 -      if (value.data == NULL)
 +PointerRNA rna_Window_screen_get(PointerRNA *ptr)
 +{
 +      wmWindow *win = ptr->data;
 +      return rna_pointer_inherit_refine(ptr, &RNA_Screen, BKE_workspace_active_screen_get(win->workspace_hook));
 +}
 +
 +static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
 +{
 +      wmWindow *win = ptr->data;
 +      WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
 +      WorkSpaceLayout *layout_new;
 +      const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
 +
 +      /* disallow ID-browsing away from temp screens */
 +      if (screen->temp) {
 +              return;
 +      }
 +      if (value.data == NULL) {
                return;
 +      }
  
        /* exception: can't set screens inside of area/region handlers */
 -      win->newscreen = value.data;
 +      layout_new = BKE_workspace_layout_find(workspace, value.data);
 +      win->workspace_hook->temp_layout_store = layout_new;
  }
  
  static int rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
  {
 -      bScreen *screen = (bScreen *)value.id.data;
 -
 +      bScreen *screen = value.id.data;
        return !screen->temp;
  }
  
 -
 -static void rna_Window_screen_update(bContext *C, PointerRNA *ptr)
 +static void rna_workspace_screen_update(bContext *C, PointerRNA *ptr)
  {
 -      wmWindow *win = (wmWindow *)ptr->data;
 +      wmWindow *win = ptr->data;
 +      WorkSpaceLayout *layout_new = win->workspace_hook->temp_layout_store;
  
        /* exception: can't set screens inside of area/region handlers,
         * and must use context so notifier gets to the right window */
 -      if (win->newscreen) {
 -              WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, win->newscreen);
 -              win->newscreen = NULL;
 +      if (layout_new) {
 +              WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
 +              win->workspace_hook->temp_layout_store = NULL;
        }
  }
  
 +static PointerRNA rna_Window_view_layer_get(PointerRNA *ptr)
 +{
 +      wmWindow *win = ptr->data;
 +      Scene *scene;
 +      ViewLayer *view_layer = WM_window_get_active_view_layer_ex(win, &scene);
 +      PointerRNA scene_ptr;
 +
 +      RNA_id_pointer_create(&scene->id, &scene_ptr);
 +      return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer);
 +}
 +
 +static void rna_Window_view_layer_set(PointerRNA *ptr, PointerRNA value)
 +{
 +      wmWindow *win = ptr->data;
 +      Scene *scene = WM_window_get_active_scene(win);
 +      WorkSpace *workspace = WM_window_get_active_workspace(win);
 +
 +      BKE_workspace_view_layer_set(workspace, value.data, scene);
 +}
 +
  static PointerRNA rna_KeyMapItem_properties_get(PointerRNA *ptr)
  {
        wmKeyMapItem *kmi = ptr->data;
@@@ -1323,7 -1195,6 +1325,7 @@@ static StructRNA *rna_Operator_register
        /* create a new operator type */
        dummyot.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
        RNA_def_struct_flag(dummyot.ext.srna, STRUCT_NO_IDPROPERTIES); /* operator properties are registered separately */
 +      RNA_def_struct_property_tags(dummyot.ext.srna, rna_enum_operator_property_tags);
        RNA_def_struct_translation_context(dummyot.ext.srna, dummyot.translation_context);
        dummyot.ext.data = data;
        dummyot.ext.call = call;
@@@ -1683,7 -1554,6 +1685,7 @@@ static void rna_def_operator(BlenderRN
        RNA_def_struct_ui_text(srna, "Operator Properties", "Input properties of an Operator");
        RNA_def_struct_refine_func(srna, "rna_OperatorProperties_refine");
        RNA_def_struct_idprops_func(srna, "rna_OperatorProperties_idprops");
 +      RNA_def_struct_property_tags(srna, rna_enum_operator_property_tags);
        RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
  }
  
@@@ -1989,11 -1859,6 +1991,11 @@@ static void rna_def_popupmenu(BlenderRN
        rna_def_popup_menu_wrapper(brna, "UIPopupMenu", "uiPopupMenu", "rna_PopupMenu_layout_get");
  }
  
 +static void rna_def_popovermenu(BlenderRNA *brna)
 +{
 +      rna_def_popup_menu_wrapper(brna, "UIPopover", "uiPopover", "rna_PopoverMenu_layout_get");
 +}
 +
  static void rna_def_piemenu(BlenderRNA *brna)
  {
        rna_def_popup_menu_wrapper(brna, "UIPieMenu", "uiPieMenu", "rna_PieMenu_layout_get");
@@@ -2041,35 -1906,14 +2043,35 @@@ static void rna_def_window(BlenderRNA *
  
        rna_def_window_stereo3d(brna);
  
 -      prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
 +      prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
 +      RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
 +      RNA_def_property_pointer_funcs(prop, NULL, "rna_Window_scene_set", NULL, NULL);
 +      RNA_def_property_ui_text(prop, "Scene", "Active scene to be edited in the window");
 +      RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
 +      RNA_def_property_update(prop, 0, "rna_Window_scene_update");
 +
 +      prop = RNA_def_property(srna, "workspace", PROP_POINTER, PROP_NONE);
        RNA_def_property_flag(prop, PROP_NEVER_NULL);
 +      RNA_def_property_struct_type(prop, "WorkSpace");
 +      RNA_def_property_ui_text(prop, "Workspace", "Active workspace showing in the window");
 +      RNA_def_property_pointer_funcs(prop, "rna_Window_workspace_get", "rna_Window_workspace_set", NULL, NULL);
 +      RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
 +      RNA_def_property_update(prop, 0, "rna_Window_workspace_update");
 +
 +      prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
        RNA_def_property_struct_type(prop, "Screen");
 -      RNA_def_property_ui_text(prop, "Screen", "Active screen showing in the window");
 -      RNA_def_property_flag(prop, PROP_EDITABLE);
 -      RNA_def_property_pointer_funcs(prop, NULL, "rna_Window_screen_set", NULL, "rna_Window_screen_assign_poll");
 -      RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
 -      RNA_def_property_update(prop, 0, "rna_Window_screen_update");
 +      RNA_def_property_ui_text(prop, "Screen", "Active workspace screen showing in the window");
 +      RNA_def_property_pointer_funcs(prop, "rna_Window_screen_get", "rna_Window_screen_set", NULL,
 +                                     "rna_Window_screen_assign_poll");
 +      RNA_def_property_flag(prop, PROP_NEVER_NULL | PROP_EDITABLE | PROP_CONTEXT_UPDATE);
 +      RNA_def_property_update(prop, 0, "rna_workspace_screen_update");
 +
 +      prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
 +      RNA_def_property_struct_type(prop, "ViewLayer");
 +      RNA_def_property_pointer_funcs(prop, "rna_Window_view_layer_get", "rna_Window_view_layer_set", NULL, NULL);
 +      RNA_def_property_ui_text(prop, "Active View Layer", "The active workspace view layer showing in the window");
 +      RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
 +      RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL);
  
        prop = RNA_def_property(srna, "x", PROP_INT, PROP_NONE);
        RNA_def_property_int_sdna(prop, NULL, "posx");
@@@ -2244,10 -2088,6 +2246,10 @@@ static void rna_def_keyconfig(BlenderRN
        RNA_def_property_ui_text(prop, "Name", "Name of the key map");
        RNA_def_struct_name_property(srna, prop);
  
 +      prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
 +      RNA_def_property_string_sdna(prop, NULL, "owner_id");
 +      RNA_def_property_ui_text(prop, "Owner", "Internal owner");
 +
        prop = RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "spaceid");
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@@ -2431,7 -2271,6 +2433,7 @@@ void RNA_def_wm(BlenderRNA *brna
        rna_def_event(brna);
        rna_def_timer(brna);
        rna_def_popupmenu(brna);
 +      rna_def_popovermenu(brna);
        rna_def_piemenu(brna);
        rna_def_window(brna);
        rna_def_windowmanager(brna);
@@@ -109,22 -109,16 +109,22 @@@ extern "C" 
  struct bContext;
  struct wmEvent;
  struct wmWindowManager;
 +struct wmMsgBus;
  struct wmOperator;
  struct ImBuf;
  
  #include "RNA_types.h"
  #include "DNA_listBase.h"
 +#include "DNA_vec_types.h"
  #include "BLI_compiler_attrs.h"
  
  /* exported types for WM */
  #include "wm_cursors.h"
  #include "wm_event_types.h"
 +#include "manipulators/WM_manipulator_types.h"
 +
 +/* Include external manipulator API's */
 +#include "manipulators/WM_manipulator_api.h"
  
  /* ************** wmOperatorType ************************ */
  
@@@ -166,12 -160,6 +166,12 @@@ enum 
        WM_OP_EXEC_SCREEN
  };
  
 +/* property tags for RNA_OperatorProperties */
 +typedef enum eOperatorPropTags {
 +      OP_PROP_TAG_ADVANCED = (1 << 0),
 +} eOperatorPropTags;
 +#define OP_PROP_TAG_ADVANCED ((eOperatorPropTags)OP_PROP_TAG_ADVANCED)
 +
  /* ************** wmKeyMap ************************ */
  
  /* modifier */
  #define KM_RELEASE    2
  #define KM_CLICK      3
  #define KM_DBL_CLICK  4
+ #define KM_CLICK_DRAG 5
  
  
  /* ************** UI Handler ***************** */
@@@ -215,6 -204,7 +216,6 @@@ typedef struct wmNotifier 
        struct wmWindowManager *wm;
        struct wmWindow *window;
  
 -      int swinid;                     /* can't rely on this, notifiers can be added without context, swinid of 0 */
        unsigned int category, data, subtype, action;
  
        void *reference;
  #define NOTE_CATEGORY         0xFF000000
  #define       NC_WM                           (1<<24)
  #define       NC_WINDOW                       (2<<24)
 -#define       NC_SCREEN                       (3<<24)
 +#define NC_SCREEN                     (3<<24)
  #define       NC_SCENE                        (4<<24)
  #define       NC_OBJECT                       (5<<24)
  #define       NC_MATERIAL                     (6<<24)
  #define ND_JOB                                (5<<16)
  #define ND_UNDO                               (6<<16)
  
 -      /* NC_SCREEN screen */
 -#define ND_SCREENBROWSE               (1<<16)
 -#define ND_SCREENDELETE               (2<<16)
 +      /* NC_SCREEN */
 +#define ND_LAYOUTBROWSE               (1<<16)
 +#define ND_LAYOUTDELETE               (2<<16)
  #define ND_SCREENCAST         (3<<16)
  #define ND_ANIMPLAY                   (4<<16)
  #define ND_GPENCIL                    (5<<16)
  #define ND_EDITOR_CHANGED     (6<<16) /*sent to new editors after switching to them*/
 -#define ND_SCREENSET          (7<<16)
 +#define ND_LAYOUTSET          (7<<16)
  #define ND_SKETCH                     (8<<16)
 +#define ND_WORKSPACE_SET      (9<<16)
 +#define ND_WORKSPACE_DELETE (10<<16)
  
        /* NC_SCENE Scene */
  #define ND_SCENEBROWSE                (1<<16)
@@@ -423,7 -411,7 +424,7 @@@ typedef struct wmGesture 
        struct wmGesture *next, *prev;
        int event_type; /* event->type */
        int type;               /* gesture type define */
 -      int swinid;             /* initial subwindow id where it started */
 +      rcti winrct;    /* bounds of region to draw gesture within */
        int points;             /* optional, amount of points stored */
        int points_alloc;       /* optional, maximum amount of points stored */
        int modal_state;
@@@ -475,6 -463,7 +476,7 @@@ typedef struct wmEvent 
  
        /* set in case a KM_PRESS went by unhandled */
        char check_click;
+       char check_drag;
        char is_motion_absolute;
  
        /* keymap item, set by handler (weak?) */
@@@ -719,9 -708,6 +721,9 @@@ extern struct CLG_LogRef *WM_LOG_OPERAT
  extern struct CLG_LogRef *WM_LOG_HANDLERS;
  extern struct CLG_LogRef *WM_LOG_EVENTS;
  extern struct CLG_LogRef *WM_LOG_KEYMAPS;
 +extern struct CLG_LogRef *WM_LOG_TOOLS;
 +extern struct CLG_LogRef *WM_LOG_MSGBUS_PUB;
 +extern struct CLG_LogRef *WM_LOG_MSGBUS_SUB;
  
  
  #ifdef __cplusplus
  #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_toolsystem.h"
 +
  #include "wm.h"
  #include "wm_window.h"
  #include "wm_event_system.h"
@@@ -89,8 -86,6 +89,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
  
@@@ -187,6 -182,7 +187,6 @@@ static bool wm_test_duplicate_notifier(
  /* XXX: in future, which notifiers to send to other windows? */
  void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
  {
 -      ARegion *ar;
        wmWindowManager *wm = CTX_wm_manager(C);
        wmNotifier *note;
  
  
        note->window = CTX_wm_window(C);
  
 -      ar = CTX_wm_region(C);
 -      if (ar)
 -              note->swinid = ar->swinid;
 -
        note->category = type & NOTE_CATEGORY;
        note->data = type & NOTE_DATA;
        note->subtype = type & NOTE_SUBTYPE;
@@@ -250,14 -250,6 +250,14 @@@ void WM_main_remove_notifier_reference(
                                wm_notifier_clear(note);
                        }
                }
 +
 +              /* Remap instead. */
 +#if 0
 +              if (wm->message_bus) {
 +                      WM_msg_id_remove(wm->message_bus, reference);
 +              }
 +#endif
 +
        }
  }
  
@@@ -277,17 -269,6 +277,17 @@@ void WM_main_remap_editor_id_reference(
                        }
                }
        }
 +
 +      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)
@@@ -307,20 -288,15 +307,20 @@@ void wm_event_do_refresh_wm_and_depsgra
  
        /* 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);
                        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_tagged(bmain, workspace, scene);
                }
        }
  
@@@ -357,11 -331,8 +357,11 @@@ 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);
                        }
                        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, wm, win);
 +                                              if (G.debug & G_DEBUG_EVENTS)
 +                                                      printf("%s: Workspace set %p\n", __func__, note->reference);
 +                                      }
 +                                      else if (note->data == ND_WORKSPACE_DELETE) {
 +                                              WorkSpace *workspace = note->reference;
 +
 +                                              ED_workspace_delete(workspace, CTX_data_main(C), C, wm);   // XXX hrms, think this over!
 +                                              if (G.debug & G_DEBUG_EVENTS)
 +                                                      printf("%s: Workspace delete %p\n", __func__, workspace);
 +                                      }
 +                                      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!
 -                                              CLOG_INFO(WM_LOG_EVENTS, 1, "screen set %p", note->reference);
 +                                              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!
 -                                              CLOG_INFO(WM_LOG_EVENTS, 1, "screen delete %p", note->reference);
 +                                      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);
                                        }
                                }
                        }
  
                        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)
                                }
                        }
                        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);
 +                              Depsgraph *depsgraph = CTX_data_depsgraph(C);
 +                              ED_update_for_newframe(CTX_data_main(C), depsgraph);
                        }
                }
        }
        /* 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 {
 -                              ScrArea *sa;
                                ARegion *ar;
  
                                /* XXX context in notifiers? */
                                /* 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);
 +                              ED_screen_areas_iter(win, screen, sa) {
 +                                      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);
                                        }
                                }
                        }
  
                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);
  }
@@@ -616,39 -546,6 +616,39 @@@ int WM_operator_poll_context(bContext *
        return wm_operator_call_internal(C, ot, NULL, NULL, context, true);
  }
  
 +bool WM_operator_check_ui_empty(wmOperatorType *ot)
 +{
 +      if (ot->macro.first != NULL) {
 +              /* for macros, check all have exec() we can call */
 +              wmOperatorTypeMacro *otmacro;
 +              for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
 +                      wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
 +                      if (otm && !WM_operator_check_ui_empty(otm)) {
 +                              return false;
 +                      }
 +              }
 +              return true;
 +      }
 +
 +      /* Assume a ui callback will draw something. */
 +      if (ot->ui) {
 +              return false;
 +      }
 +
 +      PointerRNA ptr;
 +      WM_operator_properties_create_ptr(&ptr, ot);
 +      RNA_STRUCT_BEGIN (&ptr, prop)
 +      {
 +              int flag = RNA_property_flag(prop);
 +              if (flag & PROP_HIDDEN) {
 +                      continue;
 +              }
 +              return false;
 +      }
 +      RNA_STRUCT_END;
 +      return true;
 +}
 +
  /**
   * Sets the active region for this space from the context.
   *
@@@ -790,7 -687,7 +790,7 @@@ void WM_reportf(ReportType type, const 
  /* (caller_owns_reports == true) when called from python */
  static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
  {
 -      if (caller_owns_reports == false) { /* popup */
 +      if (G.background == 0 && caller_owns_reports == false) { /* popup */
                if (op->reports->list.first) {
                        /* FIXME, temp setting window, see other call to UI_popup_menu_reports for why */
                        wmWindow *win_prev = CTX_wm_window(C);
@@@ -979,14 -876,7 +979,14 @@@ int WM_operator_call_notest(bContext *C
   */
  int WM_operator_repeat(bContext *C, wmOperator *op)
  {
 -      return wm_operator_exec(C, op, true, true);
 +      const OperatorRepeatContextHandle *context_info;
 +      int retval;
 +
 +      context_info = ED_operator_repeat_prepare_context(C, op);
 +      retval = wm_operator_exec(C, op, true, true);
 +      ED_operator_repeat_reset_context(C, context_info);
 +
 +      return retval;
  }
  /**
   * \return true if #WM_operator_repeat can run
@@@ -1237,8 -1127,7 +1237,8 @@@ bool WM_operator_last_properties_store(
   */
  static int wm_operator_invoke(
          bContext *C, wmOperatorType *ot, wmEvent *event,
 -        PointerRNA *properties, ReportList *reports, const bool poll_only)
 +        PointerRNA *properties, ReportList *reports,
 +        const bool poll_only, bool use_last_properties)
  {
        int retval = OPERATOR_PASS_THROUGH;
  
                }
  
                /* initialize setting from previous run */
 -              if (!is_nested_call) { /* not called by py script */
 +              if (!is_nested_call && use_last_properties) { /* not called by py script */
                        WM_operator_last_properties_init(op);
                }
  
                if ((event == NULL) || (event->type != MOUSEMOVE)) {
                        CLOG_INFO(WM_LOG_HANDLERS, 2,
 -                                "handle evt %d win %d op %s",
 -                                event ? event->type : 0, CTX_wm_screen(C)->subwinactive, ot->idname);
 +                                "handle evt %d win %p op %s",
 +                                event ? event->type : 0, CTX_wm_screen(C)->active_region, ot->idname);
                }
  
                if (op->type->invoke && event) {
                        /* do nothing, wm_operator_exec() has been called somewhere */
                }
                else if (retval & OPERATOR_FINISHED) {
 -                      const bool store = !is_nested_call;
 +                      const bool store = !is_nested_call && use_last_properties;
                        wm_operator_finished(C, op, false, store);
                }
                else if (retval & OPERATOR_RUNNING_MODAL) {
@@@ -1467,7 -1356,7 +1467,7 @@@ static int wm_operator_call_internal
                                                CTX_wm_region_set(C, ar1);
                                }
  
 -                              retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
 +                              retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
  
                                /* set region back */
                                CTX_wm_region_set(C, ar);
                                ARegion *ar = CTX_wm_region(C);
  
                                CTX_wm_region_set(C, NULL);
 -                              retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
 +                              retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
                                CTX_wm_region_set(C, ar);
  
                                return retval;
  
                                CTX_wm_region_set(C, NULL);
                                CTX_wm_area_set(C, NULL);
 -                              retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
 +                              retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
                                CTX_wm_area_set(C, area);
                                CTX_wm_region_set(C, ar);
  
                        }
                        case WM_OP_EXEC_DEFAULT:
                        case WM_OP_INVOKE_DEFAULT:
 -                              return wm_operator_invoke(C, ot, event, properties, reports, poll_only);
 +                              return wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
                }
        }
  
@@@ -1600,22 -1489,17 +1600,22 @@@ void wm_event_free_handler(wmEventHandl
  /* only set context when area/region is part of screen */
  static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event)
  {
 +      wmWindow *win = CTX_wm_window(C);
        bScreen *screen = CTX_wm_screen(C);
  
        if (screen && handler->op) {
                if (handler->op_area == NULL)
                        CTX_wm_area_set(C, NULL);
                else {
 -                      ScrArea *sa;
 +                      ScrArea *sa = NULL;
  
 -                      for (sa = screen->areabase.first; sa; sa = sa->next)
 -                              if (sa == handler->op_area)
 +                      ED_screen_areas_iter(win, screen, sa_iter) {
 +                              if (sa_iter == handler->op_area) {
 +                                      sa = sa_iter;
                                        break;
 +                              }
 +                      }
 +
                        if (sa == NULL) {
                                /* when changing screen layouts with running modal handlers (like render display), this
                                 * is not an error to print */
@@@ -1726,36 -1610,6 +1726,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)
  {
@@@ -1953,9 -1807,6 +1953,9 @@@ static int wm_handler_operator_call(bCo
                                        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);
        else {
                wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0);
  
 -              if (ot) {
 -                      if (wm_operator_check_locked_interface(C, ot)) {
 -                              retval = wm_operator_invoke(C, ot, event, properties, NULL, false);
 +              if (ot && wm_operator_check_locked_interface(C, ot)) {
 +                      bool use_last_properties = true;
 +                      PointerRNA tool_properties = {{0}};
 +                      bool use_tool_properties = (handler->keymap_tool != NULL);
 +
 +                      if (use_tool_properties) {
 +                              WM_toolsystem_ref_properties_init_for_keymap(handler->keymap_tool, &tool_properties, properties, ot);
 +                              properties = &tool_properties;
 +                              use_last_properties = false;
 +                      }
 +
 +                      retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties);
 +
 +                      if (use_tool_properties) {
 +                              WM_operator_properties_free(&tool_properties);
                        }
                }
        }
@@@ -2021,10 -1860,9 +2021,10 @@@ static int wm_handler_fileselect_do(bCo
                {
                        ScrArea *sa;
  
 -                      /* sa can be null when window A is active, but mouse is over window B */
 -                      /* in this case, open file select in original window A */
 -                      if (handler->op_area == NULL) {
 +                      /* sa can be null when window A is active, but mouse is over window B
 +                       * in this case, open file select in original window A. Also don't
 +                       * use global areas. */
 +                      if (handler->op_area == NULL || ED_area_is_global(handler->op_area)) {
                                bScreen *screen = CTX_wm_screen(C);
                                sa = (ScrArea *)screen->areabase.first;
                        }
@@@ -2264,7 -2102,6 +2264,7 @@@ static int wm_handlers_do_intern(bConte
  
                                        for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
                                                if (wm_eventmatch(event, kmi)) {
 +                                                      struct wmEventHandler_KeymapFn keymap_callback = handler->keymap_callback;
  
                                                        PRINT("%s:     item matched '%s'\n", __func__, kmi->idname);
  
                                                        event->keymap_idname = kmi->idname;
  
                                                        action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
 +
                                                        if (action & WM_HANDLER_BREAK) {
                                                                /* not always_pass here, it denotes removed handler */
                                                                CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname);
 +                                                              if (keymap_callback.handle_post_fn != NULL) {
 +                                                                      keymap_callback.handle_post_fn(keymap, kmi, keymap_callback.user_data);
 +                                                              }
                                                                break;
                                                        }
                                                        else {
                                        }
                                }
                        }
 +                      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;
 +                                              }
 +
 +                                              wmKeyMap *keymap = WM_keymap_active(wm, mgroup->type->keymap);
 +                                              wmKeyMapItem *kmi;
 +
 +                                              PRINT("%s:   checking '%s' ...", __func__, keymap->idname);
 +
 +                                              if (WM_keymap_poll(C, keymap)) {
 +                                                      PRINT("pass\n");
 +                                                      for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
 +                                                              if (wm_eventmatch(event, kmi)) {
 +                                                                      struct wmEventHandler_KeymapFn keymap_callback = handler->keymap_callback;
 +                                                                      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 (keymap_callback.handle_post_fn != NULL) {
 +                                                                                      keymap_callback.handle_post_fn(keymap, kmi, keymap_callback.user_data);
 +                                                                              }
 +
 +                                                                              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);
@@@ -2526,8 -2221,30 +2526,30 @@@ static int wm_handlers_do(bContext *C, 
        if (CTX_wm_window(C) == NULL)
                return action;
  
-       if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) {
+       if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+               if (event->check_drag) {
+                       wmWindow *win = CTX_wm_window(C);
+                       if ((abs(event->x - win->eventstate->prevclickx)) >= U.tweak_threshold ||
+                           (abs(event->y - win->eventstate->prevclicky)) >= U.tweak_threshold)
+                       {
+                               short val = event->val;
+                               short type = event->type;
+                               event->val = KM_CLICK_DRAG;
+                               event->type = win->eventstate->type;
+                               CLOG_INFO(WM_LOG_HANDLERS, 1, "handling PRESS_DRAG");
+                               action |= wm_handlers_do_intern(C, event, handlers);
  
+                               event->val = val;
+                               event->type = type;
+                               win->eventstate->check_click = 0;
+                               win->eventstate->check_drag = 0;
+                       }
+               }
+       }
+       else if (!ELEM(event->type, EVENT_NONE) && !ISTIMER(event->type)) {
                /* test for CLICK events */
                if (wm_action_not_handled(action)) {
                        wmWindow *win = CTX_wm_window(C);
  
                        if (win && event->val == KM_PRESS) {
                                win->eventstate->check_click = true;
+                               win->eventstate->check_drag = true;
                        }
  
                        if (win && win->eventstate->prevtype == event->type) {
                                        }
                                        else {
                                                win->eventstate->check_click = 0;
+                                               win->eventstate->check_drag = 0;
                                        }
                                }
                                else if (event->val == KM_DBL_CLICK) {
@@@ -2593,15 -2312,13 +2617,15 @@@ static int wm_event_inside_i(wmEvent *e
  
  static ScrArea *area_event_inside(bContext *C, const int xy[2])
  {
 +      wmWindow *win = CTX_wm_window(C);
        bScreen *screen = CTX_wm_screen(C);
 -      ScrArea *sa;
  
 -      if (screen)
 -              for (sa = screen->areabase.first; sa; sa = sa->next)
 +      if (screen) {
 +              ED_screen_areas_iter(win, screen, sa) {
                        if (BLI_rcti_isect_pt_v(&sa->totrct, xy))
                                return sa;
 +              }
 +      }
        return NULL;
  }
  
@@@ -2659,19 -2376,17 +2683,19 @@@ static void wm_paintcursor_test(bContex
  
  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;
                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 (win->drawmethod == USER_DRAW_OVERLAP)
 -                      win->screen->do_draw = true;
 -
  }
  
  /* filter out all events of the pie that spawned the last pie unless it's a release event */
@@@ -2720,28 -2441,22 +2744,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);
                                                        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);
 +                                                              Depsgraph *depsgraph = CTX_data_depsgraph(C);
 +                                                              ED_update_for_newframe(CTX_data_main(C), depsgraph);
                                                                WM_event_add_notifier(C, NC_WINDOW, NULL);
                                                        }
                                                }
                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);
                        }
  
                        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);
                                }
                                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);
                        wm_tweakevent_test(C, event, action);
  
                        if ((action & WM_HANDLER_BREAK) == 0) {
 -                              ScrArea *sa;
                                ARegion *ar;
  
                                /* Note: setting subwin active should be done here, after modal handlers have been done */
                                if (event->type == MOUSEMOVE) {
                                        /* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */
 -                                      ED_screen_set_subwinactive(C, event);
 +                                      ED_screen_set_active_region(C, win, &event->x);
                                        /* for regions having custom cursors */
                                        wm_paintcursor_test(C, event);
                                }
                                }
  #endif
  
 -                              for (sa = win->screen->areabase.first; sa; sa = sa->next) {
 +                              ED_screen_areas_iter(win, screen, sa) {
                                        /* 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;
                                        }
  
                                                                                }
                                                                        }
  
 +#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) {
 +                                                                              bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
 +                                                                              if (tref_rt && tref_rt->keymap[0]) {
 +                                                                                      wmKeyMap *km = WM_keymap_find_all(
 +                                                                                              C, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW);
 +                                                                                      if (km != NULL) {
 +                                                                                              sneaky_handler.keymap = km;
 +                                                                                              sneaky_handler.keymap_tool = sa->runtime.tool;
 +
 +                                                                                              /* 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;
  
        /* 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 ************ */
@@@ -3030,26 -2706,24 +3054,26 @@@ void WM_event_add_fileselect(bContext *
  
                if (handler->type == WM_HANDLER_FILESELECT) {
                        bScreen *screen = CTX_wm_screen(C);
 -                      ScrArea *sa;
 +                      bool cancel_handler = true;
  
                        /* find the area with the file selector for this handler */
 -                      for (sa = screen->areabase.first; sa; sa = sa->next) {
 +                      ED_screen_areas_iter(win, screen, sa) {
                                if (sa->spacetype == SPACE_FILE) {
                                        SpaceFile *sfile = sa->spacedata.first;
  
                                        if (sfile->op == handler->op) {
                                                CTX_wm_area_set(C, sa);
                                                wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
 +                                              cancel_handler = false;
                                                break;
                                        }
                                }
                        }
  
                        /* if not found we stop the handler without changing the screen */
 -                      if (!sa)
 +                      if (cancel_handler) {
                                wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
 +                      }
                }
        }
  
@@@ -3103,34 -2777,6 +3127,34 @@@ wmEventHandler *WM_event_add_modal_hand
        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;
@@@ -3190,15 -2836,6 +3214,15 @@@ void WM_event_remove_keymap_handler(Lis
        }
  }
  
 +void WM_event_set_keymap_handler_callback(
 +        wmEventHandler *handler,
 +        void (keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data),
 +        void *user_data)
 +{
 +      handler->keymap_callback.handle_post_fn = keymap_tag;
 +      handler->keymap_callback.user_data = user_data;
 +}
 +
  wmEventHandler *WM_event_add_ui_handler(
          const bContext *C, ListBase *handlers,
          wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,