diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_event_system.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 543 |
1 files changed, 460 insertions, 83 deletions
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index cd436899410..6047f801037 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -55,10 +55,12 @@ #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" @@ -71,14 +73,15 @@ #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" @@ -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 @@ -182,7 +187,6 @@ static bool wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, v /* 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; @@ -196,10 +200,6 @@ void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference 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,6 +250,14 @@ void WM_main_remove_notifier_reference(const void *reference) wm_notifier_clear(note); } } + + /* Remap instead. */ +#if 0 + if (wm->message_bus) { + WM_msg_id_remove(wm->message_bus, reference); + } +#endif + } } @@ -269,6 +277,17 @@ void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id) } } } + + wmWindowManager *wm = bmain->wm.first; + if (wm && wm->message_bus) { + struct wmMsgBus *mbus = wm->message_bus; + if (new_id != NULL) { + WM_msg_id_update(mbus, old_id, new_id); + } + else { + WM_msg_id_remove(mbus, old_id); + } + } } static void wm_notifier_clear(wmNotifier *note) @@ -288,15 +307,20 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C) /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */ for (wmWindow *win = wm->windows.first; win; win = win->next) { - win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen); + const Scene *scene = WM_window_get_active_scene(win); + const bScreen *screen = WM_window_get_active_screen(win); + + win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen); } /* cached: editor refresh callbacks now, they get context */ for (wmWindow *win = wm->windows.first; win; win = win->next) { + const bScreen *screen = WM_window_get_active_screen(win); + Scene *scene = WM_window_get_active_scene(win); ScrArea *sa; CTX_wm_window_set(C, win); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { + for (sa = screen->areabase.first; sa; sa = sa->next) { if (sa->do_refresh) { CTX_wm_area_set(C, sa); ED_area_do_refresh(C, sa); @@ -309,12 +333,14 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C) Main *bmain = CTX_data_main(C); /* copied to set's in scene_update_tagged_recursive() */ - win->screen->scene->customdata_mask = win_combine_v3d_datamask; + scene->customdata_mask = win_combine_v3d_datamask; /* XXX, hack so operators can enforce datamasks [#26482], gl render */ - win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal; + scene->customdata_mask |= scene->customdata_mask_modal; - BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene); + WorkSpace *workspace = WM_window_get_active_workspace(win); + + BKE_workspace_update_tagged(bmain, workspace, scene); } } @@ -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); @@ -350,23 +379,46 @@ void wm_event_do_notifiers(bContext *C) } if (note->window == win) { if (note->category == NC_SCREEN) { - if (note->data == ND_SCREENBROWSE) { + if (note->data == ND_WORKSPACE_SET) { + WorkSpace *ref_ws = note->reference; + + UI_popup_handlers_remove_all(C, &win->modalhandlers); + + ED_workspace_change(ref_ws, C, 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) @@ -374,19 +426,20 @@ void wm_event_do_notifiers(bContext *C) } } if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) { - ED_info_stats_clear(win->screen->scene); + ViewLayer *view_layer = CTX_data_view_layer(C); + ED_info_stats_clear(view_layer); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL); } } if (do_anim) { /* XXX, quick frame changes can cause a crash if framechange and rendering - * collide (happens on slow scenes), BKE_scene_update_for_newframe can be called + * collide (happens on slow scenes), BKE_scene_graph_update_for_newframe can be called * twice which can depgraph update the same object at once */ if (G.is_rendering == false) { - /* depsgraph gets called, might send more notifiers */ - ED_update_for_newframe(CTX_data_main(C), win->screen->scene, 1); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_update_for_newframe(CTX_data_main(C), depsgraph); } } } @@ -394,16 +447,23 @@ void wm_event_do_notifiers(bContext *C) /* the notifiers are sent without context, to keep it clean */ while ((note = BLI_pophead(&wm->queue))) { for (win = wm->windows.first; win; win = win->next) { + Scene *scene = WM_window_get_active_scene(win); + bScreen *screen = WM_window_get_active_screen(win); + WorkSpace *workspace = WM_window_get_active_workspace(win); /* filter out notifiers */ - if (note->category == NC_SCREEN && note->reference && note->reference != win->screen) { + if (note->category == NC_SCREEN && + note->reference && + note->reference != screen && + note->reference != workspace && + note->reference != WM_window_get_active_layout(win)) + { /* pass */ } - else if (note->category == NC_SCENE && note->reference && note->reference != win->screen->scene) { + else if (note->category == NC_SCENE && note->reference && note->reference != scene) { /* pass */ } else { - ScrArea *sa; ARegion *ar; /* XXX context in notifiers? */ @@ -412,14 +472,14 @@ void wm_event_do_notifiers(bContext *C) /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name + 2, note->category); */ ED_screen_do_listen(C, note); - for (ar = win->screen->regionbase.first; ar; ar = ar->next) { - ED_region_do_listen(win->screen, NULL, ar, note); + for (ar = screen->regionbase.first; ar; ar = ar->next) { + ED_region_do_listen(screen, NULL, ar, note, scene); } - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - ED_area_do_listen(win->screen, sa, note); + 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); } } } @@ -427,6 +487,16 @@ void wm_event_do_notifiers(bContext *C) MEM_freeN(note); } +#endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */ + + /* Handle message bus. */ + { + for (win = wm->windows.first; win; win = win->next) { + CTX_wm_window_set(C, win); + WM_msgbus_handle(wm->message_bus, C); + } + CTX_wm_window_set(C, NULL); + } wm_event_do_refresh_wm_and_depsgraph(C); } @@ -546,6 +616,39 @@ int WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context) 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. * @@ -687,7 +790,7 @@ void WM_reportf(ReportType type, const char *format, ...) /* (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); @@ -740,6 +843,7 @@ static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot) static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store) { wmWindowManager *wm = CTX_wm_manager(C); + enum { NOP, SET, CLEAR, } hud_status = NOP; op->customdata = NULL; @@ -751,10 +855,19 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, * called from operators that already do an undo push. usually * this will happen for python operators that call C operators */ if (wm->op_undo_depth == 0) { - if (op->type->flag & OPTYPE_UNDO) + if (op->type->flag & OPTYPE_UNDO) { ED_undo_push_op(C, op); - else if (op->type->flag & OPTYPE_UNDO_GROUPED) + if (repeat == 0) { + hud_status = CLEAR; + } + } + else if (op->type->flag & OPTYPE_UNDO_GROUPED) { ED_undo_grouped_push_op(C, op); + if (repeat == 0) { + hud_status = CLEAR; + } + } + } if (repeat == 0) { @@ -770,11 +883,29 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, wm_operator_register(C, op); WM_operator_region_active_win_set(C); + + /* Show the redo panel. */ + hud_status = SET; } else { WM_operator_free(op); } } + + if (hud_status != NOP) { + if (hud_status == SET) { + ScrArea *sa = CTX_wm_area(C); + if (sa) { + ED_area_type_hud_ensure(C, sa); + } + } + else if (hud_status == CLEAR) { + ED_area_type_hud_clear(wm, NULL); + } + else { + BLI_assert(0); + } + } } /* if repeat is true, it doesn't register again, nor does it free */ @@ -1127,7 +1258,8 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) */ 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; @@ -1145,14 +1277,14 @@ static int wm_operator_invoke( } /* 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) { @@ -1193,7 +1325,7 @@ static int wm_operator_invoke( /* 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) { @@ -1356,7 +1488,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); @@ -1370,7 +1502,7 @@ static int wm_operator_call_internal( 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; @@ -1384,7 +1516,7 @@ static int wm_operator_call_internal( 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); @@ -1392,7 +1524,7 @@ static int wm_operator_call_internal( } 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); } } @@ -1489,17 +1621,22 @@ void wm_event_free_handler(wmEventHandler *handler) /* 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 */ @@ -1837,6 +1974,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand CTX_wm_region_set(C, NULL); } + /* update manipulators during modal handlers */ + wm_manipulatormaps_handled_modal_update(C, event, handler); + /* remove modal handler, operator itself should have been canceled and freed */ if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) { WM_cursor_grab_disable(CTX_wm_window(C), NULL); @@ -1856,9 +1996,21 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand 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); } } } @@ -1890,9 +2042,10 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand { 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; } @@ -2132,6 +2285,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers 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); @@ -2139,9 +2293,13 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers 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 { @@ -2204,6 +2362,143 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } } } + else if (handler->manipulator_map) { + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + wmManipulatorMap *mmap = handler->manipulator_map; + wmManipulator *mpr = wm_manipulatormap_highlight_get(mmap); + + if (region->manipulator_map != handler->manipulator_map) { + WM_manipulatormap_tag_refresh(handler->manipulator_map); + } + + wm_manipulatormap_handler_context(C, handler); + wm_region_mouse_co(C, event); + + /* handle manipulator highlighting */ + if (event->type == MOUSEMOVE && !wm_manipulatormap_modal_get(mmap)) { + int part; + mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part); + if (wm_manipulatormap_highlight_set(mmap, C, mpr, part) && 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); @@ -2360,13 +2655,15 @@ static int wm_event_inside_i(wmEvent *event, rcti *rect) 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; } @@ -2424,17 +2721,19 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event) static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event) { + bScreen *screen = WM_window_get_active_screen(win); + if (BLI_listbase_is_empty(&wm->drags)) { return; } if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) { - win->screen->do_draw_drag = true; + screen->do_draw_drag = true; } else if (event->type == ESCKEY) { WM_drag_free_list(&wm->drags); - win->screen->do_draw_drag = true; + screen->do_draw_drag = true; } else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { event->type = EVT_DROP; @@ -2450,17 +2749,11 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even event->customdatafree = 1; /* clear drop icon */ - win->screen->do_draw_drag = true; + screen->do_draw_drag = true; /* restore cursor (disabled, see wm_dragdrop.c) */ // WM_cursor_modal_restore(win); } - - /* overlap fails otherwise */ - if (win->screen->do_draw_drag) - if (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 */ @@ -2489,22 +2782,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); @@ -2521,7 +2820,8 @@ void wm_event_do_handlers(bContext *C) int ncfra = time * (float)FPS + 0.5f; if (ncfra != scene->r.cfra) { scene->r.cfra = ncfra; - ED_update_for_newframe(CTX_data_main(C), scene, 1); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_update_for_newframe(CTX_data_main(C), depsgraph); WM_event_add_notifier(C, NC_WINDOW, NULL); } } @@ -2537,9 +2837,11 @@ void wm_event_do_handlers(bContext *C) while ( (event = win->queue.first) ) { int action = WM_HANDLER_CONTINUE; + /* active screen might change during handlers, update pointer */ + screen = WM_window_get_active_screen(win); + if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { printf("\n%s: Handling event\n", __func__); - WM_event_print(event); } @@ -2556,7 +2858,7 @@ void wm_event_do_handlers(bContext *C) CTX_wm_window_set(C, win); /* Clear tool-tip on mouse move. */ - if (win->screen->tool_tip && win->screen->tool_tip->exit_on_event) { + if (screen->tool_tip && screen->tool_tip->exit_on_event) { if (ISMOUSE(event->type)) { WM_tooltip_clear(C, win); } @@ -2580,8 +2882,7 @@ void wm_event_do_handlers(bContext *C) return; /* check for a tooltip */ - { - bScreen *screen = CTX_wm_window(C)->screen; + if (screen == WM_window_get_active_screen(win)) { if (screen->tool_tip && screen->tool_tip->timer) { if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) { WM_tooltip_init(C, win); @@ -2596,13 +2897,12 @@ void wm_event_do_handlers(bContext *C) 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); } @@ -2612,12 +2912,12 @@ void wm_event_do_handlers(bContext *C) } #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; } @@ -2645,8 +2945,47 @@ void wm_event_do_handlers(bContext *C) } } +#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; @@ -2711,8 +3050,7 @@ void wm_event_do_handlers(bContext *C) /* update key configuration after handling events */ WM_keyconfig_update(wm); - - GPU_ASSERT_NO_GL_ERRORS("wm_event_do_handlers"); + WM_manipulatorconfig_update(CTX_data_main(C)); } /* ********** filesector handling ************ */ @@ -2754,24 +3092,26 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) 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); + } } } @@ -2825,6 +3165,34 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) return handler; } +/** + * Modal handlers store a pointer to an area which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_area. + */ +void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area) +{ + for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) { + /* fileselect handler is quite special... it needs to keep old area stored in handler, so don't change it */ + if ((handler->op_area == old_area) && (handler->type != WM_HANDLER_FILESELECT)) { + handler->op_area = new_area; + } + } +} + +/** + * Modal handlers store a pointer to a region which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_region. + */ +void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region) +{ + for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) { + if (handler->op_region == old_region) { + handler->op_region = new_region; + handler->op_region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW; + } + } +} + wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap) { wmEventHandler *handler; @@ -2884,6 +3252,15 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) } } +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, |