diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-01-22 10:16:49 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-01-22 10:16:49 +0400 |
commit | 761b380b841e5660356616a0e0b46880e5a01c4e (patch) | |
tree | 51b0f10430e1262d6700ec84daf75e35978a33cc | |
parent | 3eb41c7a5f96c6a7199a81e8a73b1da3053806ea (diff) |
fix [#33841] Disabling and re-enabling live addon crashes blender (modal/draw handler)
-rw-r--r-- | source/blender/makesrna/intern/rna_wm.c | 5 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm.c | 25 | ||||
-rw-r--r-- | source/blender/windowmanager/wm_event_system.h | 17 |
4 files changed, 37 insertions, 11 deletions
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index c0fb2a7238f..0c1c5d8f64a 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -853,8 +853,11 @@ static void rna_Operator_unregister(struct Main *bmain, StructRNA *type) /* update while blender is running */ wm = bmain->wm.first; - if (wm) + if (wm) { WM_operator_stack_clear(wm); + + WM_operator_handlers_clear(wm, ot); + } WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); RNA_struct_free_extension(type, &ot->ext); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 1b8bf29d92a..bea54154e47 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -202,6 +202,7 @@ int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, con /* operator api */ void WM_operator_free (struct wmOperator *op); void WM_operator_stack_clear(struct wmWindowManager *wm); +void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot); struct wmOperatorType *WM_operatortype_find(const char *idnamem, int quiet); struct GHashIterator *WM_operatortype_iter(void); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 53e67e91bd2..a01f7301ec2 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -149,6 +149,31 @@ void WM_operator_stack_clear(wmWindowManager *wm) WM_main_add_notifier(NC_WM | ND_HISTORY, NULL); } +/** + * This function is needed in the case when an addon id disabled + * while a modal operator it defined is running. + */ +void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot) +{ + wmWindow *win; + for (win = wm->windows.first; win; win = win->next) { + ListBase *lb[2] = {&win->handlers, &win->modalhandlers}; + wmEventHandler *handler; + int i; + + for (i = 0; i < 2; i++) { + for (handler = lb[i]->first; handler; handler = handler->next) { + if (handler->op && handler->op->type == ot) { + /* don't run op->cancel because it needs the context, + * assume whoever unregisters the operator will cleanup */ + handler->flag |= WM_HANDLER_DO_FREE; + WM_operator_free(handler->op); + handler->op = NULL; + } + } + } + } +} /* ************ uiListType handling ************** */ diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 2fbfdc41bce..d12e1d47fa0 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -45,7 +45,8 @@ struct ARegion; typedef struct wmEventHandler { struct wmEventHandler *next, *prev; - int type, flag; /* type default=0, rest is custom */ + int type; /* WM_HANDLER_DEFAULT, ... */ + int flag; /* WM_HANDLER_BLOCKING, ... */ /* keymap handler */ wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ @@ -72,21 +73,17 @@ typedef struct wmEventHandler { } 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 - - - /* custom types for handlers, for signalling, freeing */ enum { WM_HANDLER_DEFAULT, WM_HANDLER_FILESELECT }; +/* handler flag */ +enum { + WM_HANDLER_BLOCKING = 1, /* after this handler all others are ignored */ + WM_HANDLER_DO_FREE = 2 /* handler tagged to be freed in wm_handlers_do() */ +}; /* wm_event_system.c */ void wm_event_free_all (wmWindow *win); |