Bugfix #27058
authorTon Roosendaal <ton@blender.org>
Wed, 20 Apr 2011 11:15:58 +0000 (11:15 +0000)
committerTon Roosendaal <ton@blender.org>
Wed, 20 Apr 2011 11:15:58 +0000 (11:15 +0000)
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.

source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_panel.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/wm_event_system.h

index d3aa5bc91325a0f65878acc1c7f86f70f9866d6d..cf11effc57b25787ff2bdb955d5dcb6048982355 100644 (file)
@@ -4898,7 +4898,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
                }
                else {
                        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)
 {
-       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);
 }
 
@@ -6165,7 +6165,7 @@ void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *
 
 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);
 }
 
 
index b47194ba1b4a4c66c41acb52b54647a598af1545..6677f2b1bae065318971a1d9839192e0603c7b61 100644 (file)
@@ -1211,7 +1211,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
                MEM_freeN(data);
                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 {
                if(!data) {
index dafa05fd9748f6d0b52207da6edf76ef5b84c15e..1b4fff8cd13a8ae03ceeb9e3a942eb1b195b570c 100644 (file)
@@ -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           WM_event_remove_ui_handler(ListBase *handlers,
                        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);
 
 struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
index 2b74d35d59e55c94e319a25a4d10002ff40dfdd6..c9e2567a45b372f835cd8ac9f2faa0436ac5e417 100644 (file)
@@ -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 */
        for(handler= handlers->first; handler; handler= nexthandler) {
+               
                nexthandler= handler->next;
-
-               /* optional boundbox */
-               if(handler_boundbox_test(handler, event)) {
+               
+               /* during this loop, ui handlers for nested menus can tag multiple handlers free */
+               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 */
                        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 */
                if(CTX_wm_window(C)==NULL)
                        return action;
@@ -2067,14 +2077,21 @@ wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, w
        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;
        
        for(handler= handlers->first; handler; handler= handler->next) {
                if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
-                       BLI_remlink(handlers, handler);
-                       wm_event_free_handler(handler);
+                       /* handlers will be freed in wm_handlers_do() */
+                       if(postpone) {
+                               handler->flag |= WM_HANDLER_DO_FREE;
+                       }
+                       else {
+                               BLI_remlink(handlers, handler);
+                               wm_event_free_handler(handler);
+                       }
                        break;
                }
        }
index 6ad9d1daede120c49af0ccb269c3c0f52d96297b..cd110d3bc1ab83da9bb9062f04f80854fa13a8c3 100644 (file)
@@ -78,6 +78,8 @@ typedef struct wmEventHandler {
 /* handler flag */
                /* after this handler all others are ignored */
 #define WM_HANDLER_BLOCKING            1
+               /* handler tagged to be freed in wm_handlers_do() */
+#define WM_HANDLER_DO_FREE             2