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.
This commit is contained in:
Campbell Barton 2019-06-28 18:10:43 +10:00
parent eac11046a1
commit 9bcab8050f
Notes: blender-bot 2023-02-14 05:12:59 +01:00
Referenced by issue #63694, Multi window measure crash
6 changed files with 96 additions and 1 deletions

View File

@ -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;

View File

@ -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__ */

View File

@ -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 *);

View File

@ -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);
}
}
}
}
}
/** \} */

View File

@ -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
*

View File

@ -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) {