From 9bcab8050f44e5bd36a0715811ee0355e4b221b6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 28 Jun 2019 18:10:43 +1000 Subject: Fix T63694: Crash using tool gizmos with multiple windows Gizmo group types now store a user count so they aren't unlinked while other tools are using them. The tool system now works with multiple windows. --- source/blender/editors/util/gizmo_utils.c | 7 +++- source/blender/windowmanager/gizmo/WM_gizmo_api.h | 9 +++++ .../blender/windowmanager/gizmo/WM_gizmo_types.h | 8 +++++ .../windowmanager/gizmo/intern/wm_gizmo_group.c | 32 ++++++++++++++++++ .../windowmanager/gizmo/intern/wm_gizmo_intern.h | 3 ++ .../windowmanager/gizmo/intern/wm_gizmo_map.c | 38 ++++++++++++++++++++++ 6 files changed, 96 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c index d330019c816..b856c831424 100644 --- a/source/blender/editors/util/gizmo_utils.c +++ b/source/blender/editors/util/gizmo_utils.c @@ -59,7 +59,12 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C, { bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); if ((tref_rt == NULL) || !STREQ(gzgt_idname, tref_rt->gizmo_group)) { - WM_gizmo_group_type_unlink_delayed_ptr(gzgt); + ScrArea *sa = CTX_wm_area(C); + wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params); + WM_gizmo_group_unlink_delayed_ptr_from_space(gzgt, gzmap_type, sa); + if (gzgt->users == 0) { + WM_gizmo_group_type_unlink_delayed_ptr(gzgt); + } return false; } return true; diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h index 293b0cd91dc..5896424d5fe 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h @@ -34,6 +34,7 @@ struct GHashIterator; struct IDProperty; struct Main; struct PropertyRNA; +struct ScrArea; struct bToolRef; struct wmGizmo; struct wmGizmoGroup; @@ -166,6 +167,8 @@ void WM_gizmoconfig_update_tag_group_type_remove(struct wmGizmoMapType *gzmap_ty struct wmGizmoGroupType *gzgt); void WM_gizmoconfig_update(struct Main *bmain); +void WM_gizmoconfig_update_tag_group_remove(struct wmGizmoMap *gzmap); + /* wm_maniulator_target_props.c */ struct wmGizmoProperty *WM_gizmo_target_property_array(struct wmGizmo *gz); struct wmGizmoProperty *WM_gizmo_target_property_at_index(struct wmGizmo *gz, int index); @@ -354,6 +357,10 @@ void WM_gizmo_group_type_unlink_delayed_ptr_ex(struct wmGizmoGroupType *gzgt, void WM_gizmo_group_type_unlink_delayed_ptr(struct wmGizmoGroupType *gzgt); void WM_gizmo_group_type_unlink_delayed(const char *idname); +void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt, + struct wmGizmoMapType *gzmap_type, + struct ScrArea *sa); + /* Has the result of unlinking and linking (re-initializes gizmo's). */ void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain, struct wmGizmoGroupType *gzgt, @@ -370,4 +377,6 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C, const struct wmGizmoGroupType *gzgt, const struct bToolRef *tref); +void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup); + #endif /* __WM_GIZMO_API_H__ */ diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index 7afd2908b8e..68ecdeea936 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -417,6 +417,12 @@ typedef struct wmGizmoGroupType { /** Same as gizmo-maps, so registering/unregistering goes to the correct region. */ struct wmGizmoMapType_Params gzmap_params; + /** + * Number of #wmGizmoGroup instances. + * Decremented when 'tag_remove' is set, or when removed. + */ + int users; + } wmGizmoGroupType; typedef struct wmGizmoGroup { @@ -432,6 +438,8 @@ typedef struct wmGizmoGroup { /** Errors and warnings storage. */ struct ReportList *reports; + bool tag_remove; + void *customdata; /** For freeing customdata from above. */ void (*customdata_free)(void *); diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c index f996d938dd7..40d99ce8ba6 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c @@ -70,7 +70,9 @@ wmGizmoGroup *wm_gizmogroup_new_from_type(wmGizmoMap *gzmap, wmGizmoGroupType *gzgt) { wmGizmoGroup *gzgroup = MEM_callocN(sizeof(*gzgroup), "gizmo-group"); + gzgroup->type = gzgt; + gzgroup->type->users += 1; /* keep back-link */ gzgroup->parent_gzmap = gzmap; @@ -130,9 +132,23 @@ void wm_gizmogroup_free(bContext *C, wmGizmoGroup *gzgroup) BLI_remlink(&gzmap->groups, gzgroup); + if (gzgroup->tag_remove == false) { + gzgroup->type->users -= 1; + } + MEM_freeN(gzgroup); } +void WM_gizmo_group_tag_remove(wmGizmoGroup *gzgroup) +{ + if (gzgroup->tag_remove == false) { + gzgroup->tag_remove = true; + gzgroup->type->users -= 1; + BLI_assert(gzgroup->type->users >= 0); + WM_gizmoconfig_update_tag_group_remove(gzgroup->parent_gzmap); + } +} + /** * Add \a gizmo to \a gzgroup and make sure its name is unique within the group. */ @@ -1099,4 +1115,20 @@ void WM_gizmo_group_type_unlink_delayed(const char *idname) WM_gizmo_group_type_unlink_delayed_ptr(gzgt); } +void WM_gizmo_group_unlink_delayed_ptr_from_space(wmGizmoGroupType *gzgt, + wmGizmoMapType *gzmap_type, + ScrArea *sa) +{ + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { + wmGizmoMap *gzmap = ar->gizmo_map; + if (gzmap && gzmap->type == gzmap_type) { + for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + if (gzgroup->type == gzgt) { + WM_gizmo_group_tag_remove(gzgroup); + } + } + } + } +} + /** \} */ diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h index 98c3ad8295c..f0771437518 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h @@ -99,6 +99,9 @@ struct wmGizmoMap { /** Private, true when not yet used. */ bool is_init; + /** When set, one of of the items in 'groups' has #wmGizmoGroup.tag_remove set. */ + bool tag_remove_group; + /** * \brief Gizmo map runtime context * diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index edf376b1259..be123bee5df 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -69,8 +69,13 @@ static ListBase gizmomaptypes = {NULL, NULL}; */ /* so operator removal can trigger update */ typedef enum eWM_GizmoFlagGroupTypeGlobalFlag { + /** Initialize by #wmGroupType.type_update_flag. */ WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT = (1 << 0), + /** Remove by #wmGroupType.type_update_flag. */ WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE = (1 << 1), + + /** Remove by #wmGroup.tag_remove. */ + WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE = (1 << 2), } eWM_GizmoFlagGroupTypeGlobalFlag; static eWM_GizmoFlagGroupTypeGlobalFlag wm_gzmap_type_update_flag = 0; @@ -1257,6 +1262,13 @@ void WM_gizmoconfig_update_tag_group_type_remove(wmGizmoMapType *gzmap_type, wm_gzmap_type_update_flag |= WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE; } +void WM_gizmoconfig_update_tag_group_remove(wmGizmoMap *gzmap) +{ + gzmap->tag_remove_group = true; + + wm_gzmap_type_update_flag |= WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE; +} + /** * Run in case new types have been added (runs often, early exit where possible). * Follows #WM_keyconfig_update conventions. @@ -1271,6 +1283,32 @@ void WM_gizmoconfig_update(struct Main *bmain) return; } + if (wm_gzmap_type_update_flag & WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE) { + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + for (ARegion *ar = regionbase->first; ar; ar = ar->next) { + wmGizmoMap *gzmap = ar->gizmo_map; + if (gzmap != NULL && gzmap->tag_remove_group) { + gzmap->tag_remove_group = false; + + for (wmGizmoGroup *gzgroup = gzmap->groups.first, *gzgroup_next; gzgroup; + gzgroup = gzgroup_next) { + gzgroup_next = gzgroup->next; + if (gzgroup->tag_remove) { + wm_gizmogroup_free(NULL, gzgroup); + ED_region_tag_redraw(ar); + } + } + } + } + } + } + } + wm_gzmap_type_update_flag &= ~WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE; + } + if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) { for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; gzmap_type = gzmap_type->next) { -- cgit v1.2.3