Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Thu, 7 Jun 2018 18:41:10 +0000 (20:41 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 7 Jun 2018 18:41:10 +0000 (20:41 +0200)
1  2 
intern/ghost/intern/GHOST_SystemX11.cpp
source/blender/windowmanager/intern/wm_event_system.c

index 42bb05c01773c9947b3af36e35a6ae7aadd04898,62befc2f2278fb1a47fedfdb6bb27f62717d01e1..5d14ff5bb93c9ba9d3fca7afb57d23b593f8a2ec
  
  #include "GHOST_Debug.h"
  
 +#if defined(WITH_GL_EGL)
 +#  include "GHOST_ContextEGL.h"
 +#else
 +#  include "GHOST_ContextGLX.h"
 +#endif
 +
  #ifdef WITH_XF86KEYSYM
  #include <X11/XF86keysym.h>
  #endif
@@@ -119,7 -113,6 +119,7 @@@ GHOST_SystemX11
      : GHOST_System(),
        m_start_time(0)
  {
 +      XInitThreads();
        m_display = XOpenDisplay(NULL);
  
        if (!m_display) {
@@@ -391,97 -384,6 +391,97 @@@ bool GHOST_SystemX11::supportsNativeDia
        return false;
  }
  
 +/**
 + * Create a new offscreen context.
 + * Never explicitly delete the context, use disposeContext() instead.
 + * \return  The new context (or 0 if creation failed).
 + */
 +GHOST_IContext *
 +GHOST_SystemX11::
 +createOffscreenContext()
 +{
 +      // During development:
 +      //   try 4.x compatibility profile
 +      //   try 3.3 compatibility profile
 +      //   fall back to 3.0 if needed
 +      //
 +      // Final Blender 2.8:
 +      //   try 4.x core profile
 +      //   try 3.3 core profile
 +      //   no fallbacks
 +
 +#if defined(WITH_GL_PROFILE_CORE)
 +      {
 +              const char *version_major = (char*)glewGetString(GLEW_VERSION_MAJOR);
 +              if (version_major != NULL && version_major[0] == '1') {
 +                      fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
 +                      abort();
 +              }
 +      }
 +#endif
 +
 +      const int profile_mask =
 +#if defined(WITH_GL_PROFILE_CORE)
 +              GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
 +#elif defined(WITH_GL_PROFILE_COMPAT)
 +              GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
 +#else
 +#  error // must specify either core or compat at build time
 +#endif
 +
 +      GHOST_Context *context;
 +
 +      for (int minor = 5; minor >= 0; --minor) {
 +              context = new GHOST_ContextGLX(
 +                      false,
 +                      0,
 +                      (Window)NULL,
 +                      m_display,
 +                      (GLXFBConfig)NULL,
 +                      profile_mask,
 +                      4, minor,
 +                      GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
 +                      GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
 +
 +              if (context->initializeDrawingContext())
 +                      return context;
 +              else
 +                      delete context;
 +      }
 +
 +      context = new GHOST_ContextGLX(
 +              false,
 +              0,
 +              (Window)NULL,
 +              m_display,
 +              (GLXFBConfig)NULL,
 +              profile_mask,
 +              3, 3,
 +              GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
 +              GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
 +
 +      if (context->initializeDrawingContext())
 +              return context;
 +      else
 +              delete context;
 +
 +      return NULL;
 +}
 +
 +/**
 + * Dispose of a context.
 + * \param   context Pointer to the context to be disposed.
 + * \return  Indication of success.
 + */
 +GHOST_TSuccess
 +GHOST_SystemX11::
 +disposeContext(GHOST_IContext *context)
 +{
 +      delete context;
 +
 +      return GHOST_kSuccess;
 +}
 +
  #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
  static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
  {
@@@ -669,10 -571,8 +669,8 @@@ processEvents
                        }
  
                        /* dispatch event to XIM server */
-                       if ((XFilterEvent(&xevent, (Window)NULL) == True) && (xevent.type != KeyRelease)) {
-                               /* do nothing now, the event is consumed by XIM.
-                                * however, KeyRelease event should be processed
-                                * here, otherwise modifiers remain activated.   */
+                       if ((XFilterEvent(&xevent, (Window)NULL) == True)) {
+                               /* do nothing now, the event is consumed by XIM. */
                                continue;
                        }
  #endif
index 02c585fc677770179f3d6cedf82457c811487b84,5974d4fddeead432a236582189ed00e0ea6532d1..fdca1d96b4b1b8db8e4a48ead45dff24fe058666
  #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);
@@@ -2557,9 -2252,14 +2557,14 @@@ static int wm_handlers_do(bContext *C, 
                        /* eventstate stores if previous event was a KM_PRESS, in case that
                         * wasn't handled, the KM_RELEASE will become a KM_CLICK */
  
-                       if (win && event->val == KM_PRESS) {
-                               win->eventstate->check_click = true;
-                               win->eventstate->check_drag = true;
+                       if (win != NULL) {
+                               if (event->val == KM_PRESS) {
+                                       win->eventstate->check_click = true;
+                                       win->eventstate->check_drag = true;
+                               }
+                               else if (event->val == KM_RELEASE) {
+                                       win->eventstate->check_drag = false;
+                               }
                        }
  
                        if (win && win->eventstate->prevtype == event->type) {
@@@ -2617,15 -2317,13 +2622,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;
  }
  
@@@ -2683,19 -2381,17 +2688,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 */
@@@ -2744,28 -2446,22 +2749,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 ************ */
@@@ -3054,26 -2711,24 +3059,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);
 +                      }
                }
        }
  
@@@ -3127,34 -2782,6 +3132,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;
@@@ -3214,15 -2841,6 +3219,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,