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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager/intern/wm_event_system.c')
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c543
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,