Proper fix for crash when joining areas that doesn't break manipulators

Turns out CTX_wm_region returns mostly NULL in wm_manipulatormaps_handled_modal_update. Now propertly unsetting area/region data of handlers when deleting area/region.
This commit is contained in:
Julian Eisel 2016-10-17 19:25:56 +02:00
parent e7fddc0772
commit 4811b2d356
Notes: blender-bot 2023-02-14 10:35:28 +01:00
Referenced by commit 82ba89b042, Fix T49961: Blender 2.8 Crashes on saving an image
4 changed files with 45 additions and 7 deletions

View File

@ -1277,25 +1277,28 @@ void ED_screens_initialize(wmWindowManager *wm)
void ED_region_exit(bContext *C, ARegion *ar)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ARegion *prevar = CTX_wm_region(C);
if (ar->type && ar->type->exit)
ar->type->exit(wm, ar);
CTX_wm_region_set(C, ar);
WM_event_remove_handlers(C, &ar->handlers);
WM_event_modal_handler_region_replace(win, ar, NULL);
if (ar->swinid) {
wm_subwindow_close(CTX_wm_window(C), ar->swinid);
wm_subwindow_close(win, ar->swinid);
ar->swinid = 0;
}
if (ar->headerstr) {
MEM_freeN(ar->headerstr);
ar->headerstr = NULL;
}
if (ar->regiontimer) {
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ar->regiontimer);
WM_event_remove_timer(wm, win, ar->regiontimer);
ar->regiontimer = NULL;
}
@ -1305,6 +1308,7 @@ void ED_region_exit(bContext *C, ARegion *ar)
void ED_area_exit(bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *ar;
@ -1312,10 +1316,13 @@ void ED_area_exit(bContext *C, ScrArea *sa)
sa->type->exit(wm, sa);
CTX_wm_area_set(C, sa);
for (ar = sa->regionbase.first; ar; ar = ar->next)
ED_region_exit(C, ar);
WM_event_remove_handlers(C, &sa->handlers);
WM_event_modal_handler_area_replace(win, sa, NULL);
CTX_wm_area_set(C, prevsa);
}

View File

@ -67,6 +67,7 @@ struct wmDrag;
struct ImBuf;
struct ImageFormatData;
struct ARegion;
struct ScrArea;
#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
@ -177,6 +178,9 @@ void WM_event_free_ui_handler_all(
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove);
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
void WM_event_modal_handler_area_replace(wmWindow *win, const struct ScrArea *old_area, struct ScrArea *new_area);
void WM_event_modal_handler_region_replace(wmWindow *win, const struct ARegion *old_region, struct ARegion *new_region);
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
/* handler flag */

View File

@ -2717,6 +2717,33 @@ 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) {
if (handler->op_area == old_area) {
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;

View File

@ -394,12 +394,10 @@ void wm_manipulatormaps_handled_modal_update(
bContext *C, wmEvent *event, wmEventHandler *handler,
const wmOperatorType *ot)
{
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
const bool modal_running = (handler->op != NULL);
/* happens on render or when joining areas */
if (!region || !region->manipulator_map)
if (!handler->op_region || !handler->op_region->manipulator_map)
return;
/* hide operator manipulators */
@ -407,8 +405,10 @@ void wm_manipulatormaps_handled_modal_update(
ot->mgrouptype->op = NULL;
}
wmManipulatorMap *mmap = region->manipulator_map;
wmManipulatorMap *mmap = handler->op_region->manipulator_map;
wmManipulator *manipulator = wm_manipulatormap_get_active_manipulator(mmap);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
wm_manipulatormap_handler_context(C, handler);