Top bar: Add -> Mesh -> UV Sphere + Enter crashed.
It didn't crash with leftmouse, but that was coincidentally working.

Menus were freeing modal handlers in Window, while handlers were still 
in use. Fix provides to tag handlers for being freed now.

Will add on my attention list for more elaborate checking work here, for
upcoming 2.57a I rather stick to minimal change in code here.
This commit is contained in:
Ton Roosendaal 2011-04-20 11:15:58 +00:00
parent 141be02c90
commit 069a3c193c
5 changed files with 30 additions and 11 deletions

@ -4898,7 +4898,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
} }
else { else {
if(button_modal_state(data->state)) if(button_modal_state(data->state))
WM_event_remove_ui_handler(&data->window->modalhandlers, ui_handler_region_menu, NULL, data); WM_event_remove_ui_handler(&data->window->modalhandlers, ui_handler_region_menu, NULL, data, 1); /* 1 = postpone free */
} }
} }
@ -6154,7 +6154,7 @@ static void ui_handler_remove_popup(bContext *C, void *userdata)
void UI_add_region_handlers(ListBase *handlers) void UI_add_region_handlers(ListBase *handlers)
{ {
WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL); WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, 0);
WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL); WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL);
} }
@ -6165,7 +6165,7 @@ void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *
void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup) void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup)
{ {
WM_event_remove_ui_handler(handlers, ui_handler_popup, ui_handler_remove_popup, popup); WM_event_remove_ui_handler(handlers, ui_handler_popup, ui_handler_remove_popup, popup, 0);
} }

@ -1211,7 +1211,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
MEM_freeN(data); MEM_freeN(data);
pa->activedata= NULL; pa->activedata= NULL;
WM_event_remove_ui_handler(&win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa); WM_event_remove_ui_handler(&win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
} }
else { else {
if(!data) { if(!data) {

@ -173,7 +173,7 @@ struct wmEventHandler *WM_event_add_ui_handler(const struct bContext *C, ListBas
void (*remove)(struct bContext *C, void *userdata), void *userdata); void (*remove)(struct bContext *C, void *userdata), void *userdata);
void WM_event_remove_ui_handler(ListBase *handlers, void WM_event_remove_ui_handler(ListBase *handlers,
int (*func)(struct bContext *C, struct wmEvent *event, void *userdata), int (*func)(struct bContext *C, struct wmEvent *event, void *userdata),
void (*remove)(struct bContext *C, void *userdata), void *userdata); void (*remove)(struct bContext *C, void *userdata), void *userdata, int postpone);
void WM_event_remove_area_handler(struct ListBase *handlers, void *area); void WM_event_remove_area_handler(struct ListBase *handlers, void *area);
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op); struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);

@ -1452,10 +1452,13 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
/* modal handlers can get removed in this loop, we keep the loop this way */ /* modal handlers can get removed in this loop, we keep the loop this way */
for(handler= handlers->first; handler; handler= nexthandler) { for(handler= handlers->first; handler; handler= nexthandler) {
nexthandler= handler->next; nexthandler= handler->next;
/* optional boundbox */ /* during this loop, ui handlers for nested menus can tag multiple handlers free */
if(handler_boundbox_test(handler, event)) { if(handler->flag & WM_HANDLER_DO_FREE);
/* optional boundbox */
else if(handler_boundbox_test(handler, event)) {
/* in advance to avoid access to freed event on window close */ /* in advance to avoid access to freed event on window close */
always_pass= wm_event_always_pass(event); always_pass= wm_event_always_pass(event);
@ -1534,6 +1537,13 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
} }
} }
/* modal ui handler can be tagged to be freed */
if(handler->flag & WM_HANDLER_DO_FREE) {
BLI_remlink(handlers, handler);
wm_event_free_handler(handler);
}
/* XXX fileread case */ /* XXX fileread case */
if(CTX_wm_window(C)==NULL) if(CTX_wm_window(C)==NULL)
return action; return action;
@ -2067,14 +2077,21 @@ wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, w
return handler; return handler;
} }
void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata) /* set "postpone" for win->modalhandlers, this is in a running for() loop in wm_handlers_do() */
void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, int postpone)
{ {
wmEventHandler *handler; wmEventHandler *handler;
for(handler= handlers->first; handler; handler= handler->next) { for(handler= handlers->first; handler; handler= handler->next) {
if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) { if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
BLI_remlink(handlers, handler); /* handlers will be freed in wm_handlers_do() */
wm_event_free_handler(handler); if(postpone) {
handler->flag |= WM_HANDLER_DO_FREE;
}
else {
BLI_remlink(handlers, handler);
wm_event_free_handler(handler);
}
break; break;
} }
} }

@ -78,6 +78,8 @@ typedef struct wmEventHandler {
/* handler flag */ /* handler flag */
/* after this handler all others are ignored */ /* after this handler all others are ignored */
#define WM_HANDLER_BLOCKING 1 #define WM_HANDLER_BLOCKING 1
/* handler tagged to be freed in wm_handlers_do() */
#define WM_HANDLER_DO_FREE 2