[#20093] Consistent Crash in properties window
authorMartin Poirier <theeth@yahoo.com>
Tue, 12 Jan 2010 23:30:19 +0000 (23:30 +0000)
committerMartin Poirier <theeth@yahoo.com>
Tue, 12 Jan 2010 23:30:19 +0000 (23:30 +0000)
Fun bug, took me the better part of the day to track down.

Happens because maximizing swaps spacedata lists between the old area and the newly created maximized area (this one being empty) while ui handlers are still hanging with references to the first area (then trying to access spacedata when handled). And then only if a maximizing operator was run before the UI realign timer event from the previous maximize was handled (fun, I told you).

After discussion with Matt on irc, we decided the best way to deal with that was to remove ui handlers that reference areas of a screen that is no longer used. That solution reflects the fact that the bug is more general that the reproducing steps would lead to believe. There's also absolutely no reason to run UI handlers on invisible areas.

source/blender/editors/screen/screen_edit.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_event_system.c

index f0003669a123a40b354848c6a60b147b253b1b13..2069858c97d3af215cce1ea7ced2566343f7764c 100644 (file)
@@ -1271,7 +1271,13 @@ void ED_screen_set(bContext *C, bScreen *sc)
        
        if (oldscreen != sc) {
                wmTimer *wt= oldscreen->animtimer;
-               
+               ScrArea *sa;
+
+               /* remove handlers referencing areas in old screen */
+               for(sa = oldscreen->areabase.first; sa; sa = sa->next) {
+                       WM_event_remove_area_handler(&win->modalhandlers, sa);
+               }
+
                /* we put timer to sleep, so screen_exit has to think there's no timer */
                oldscreen->animtimer= NULL;
                if(wt)
index 94cd6ed85a08c38566090d9fe90bf5dbfafa045e..4cc116e7bbda2025797ac8ff672bc3797fa39178 100644 (file)
@@ -150,6 +150,7 @@ struct wmEventHandler *WM_event_add_ui_handler(const struct bContext *C, ListBas
 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           WM_event_remove_area_handler(struct ListBase *handlers, void *area);
 
 struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
 void           WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
index 9a6d02790e5413ee9eb0048c99ec28adb5cbabe4..f437e096755c9cbbb72d3671aca293dde51d7b3e 100644 (file)
@@ -1620,6 +1620,25 @@ void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHa
        }
 }
 
+void WM_event_remove_area_handler(ListBase *handlers, void *area)
+{
+       wmEventHandler *handler, *nexthandler;
+
+       for(handler = handlers->first; handler; handler= nexthandler) {
+               nexthandler = handler->next;
+               if (handler->ui_area == area || handler->op_area == area) {
+                       BLI_remlink(handlers, handler);
+                       wm_event_free_handler(handler);
+               }
+       }
+}
+
+void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
+{
+       BLI_remlink(handlers, handler);
+       wm_event_free_handler(handler);
+}
+
 void WM_event_add_mousemove(bContext *C)
 {
        wmWindow *window= CTX_wm_window(C);