forked from bartvdbraak/blender
Fix T38042: Keymap crash after reloading operators
After some investigation with mont29, seems like the best way to ensure keymaps point to valid operators is using WM_keyconfig_update().
This commit is contained in:
parent
b64f897606
commit
1713db2035
@ -51,6 +51,7 @@ void WM_keyconfig_set_active(struct wmWindowManager *wm, const char *idname);
|
||||
|
||||
void WM_keyconfig_update(struct wmWindowManager *wm);
|
||||
void WM_keyconfig_update_tag(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
|
||||
void WM_keyconfig_update_operatortype(void);
|
||||
|
||||
/* Keymap */
|
||||
|
||||
|
@ -98,6 +98,56 @@ static void wm_keymap_item_properties_set(wmKeyMapItem *kmi)
|
||||
WM_operator_properties_sanitize(kmi->ptr, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to #wm_keymap_item_properties_set but checks for the wmOperatorType having changed, see [#38042]
|
||||
*/
|
||||
static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
|
||||
{
|
||||
if (kmi->idname[0] == 0) {
|
||||
BLI_assert(kmi->ptr == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kmi->ptr == NULL) {
|
||||
wm_keymap_item_properties_set(kmi);
|
||||
}
|
||||
else {
|
||||
wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
|
||||
if (ot) {
|
||||
if (ot->srna != kmi->ptr->type) {
|
||||
/* matches wm_keymap_item_properties_set but doesnt alloc new ptr */
|
||||
WM_operator_properties_create_ptr(kmi->ptr, ot);
|
||||
WM_operator_properties_sanitize(kmi->ptr, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* zombie keymap item */
|
||||
MEM_SAFE_FREE(kmi->ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_keyconfig_properties_update_ot(ListBase *km_lb)
|
||||
{
|
||||
wmKeyMap *km;
|
||||
wmKeyMapItem *kmi;
|
||||
|
||||
for (km = km_lb->first; km; km = km->next) {
|
||||
wmKeyMapDiffItem *kmdi;
|
||||
|
||||
for (kmi = km->items.first; kmi; kmi = kmi->next) {
|
||||
wm_keymap_item_properties_update_ot(kmi);
|
||||
}
|
||||
|
||||
for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
|
||||
if (kmdi->add_item)
|
||||
wm_keymap_item_properties_update_ot(kmdi->add_item);
|
||||
if (kmdi->remove_item)
|
||||
wm_keymap_item_properties_update_ot(kmdi->remove_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
|
||||
{
|
||||
if (strcmp(a->idname, b->idname) != 0)
|
||||
@ -1087,12 +1137,20 @@ int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2)
|
||||
* the preset, addon and user preferences keymaps. We also test if the final
|
||||
* configuration changed and write the changes to the user preferences. */
|
||||
|
||||
static bool WM_KEYMAP_UPDATE = false;
|
||||
/* so operator removal can trigger update */
|
||||
enum {
|
||||
WM_KEYMAP_UPDATE_RECONFIGURE = (1 << 0),
|
||||
|
||||
/* ensure all wmKeyMap have their operator types validated after removing an operator */
|
||||
WM_KEYMAP_UPDATE_OPERATORTYPE = (1 << 1),
|
||||
};
|
||||
|
||||
static char wm_keymap_update_flag = 0;
|
||||
|
||||
void WM_keyconfig_update_tag(wmKeyMap *km, wmKeyMapItem *kmi)
|
||||
{
|
||||
/* quick tag to do delayed keymap updates */
|
||||
WM_KEYMAP_UPDATE = true;
|
||||
wm_keymap_update_flag |= WM_KEYMAP_UPDATE_RECONFIGURE;
|
||||
|
||||
if (km)
|
||||
km->flag |= KEYMAP_UPDATE;
|
||||
@ -1100,6 +1158,11 @@ void WM_keyconfig_update_tag(wmKeyMap *km, wmKeyMapItem *kmi)
|
||||
kmi->flag |= KMI_UPDATE;
|
||||
}
|
||||
|
||||
void WM_keyconfig_update_operatortype(void)
|
||||
{
|
||||
wm_keymap_update_flag |= WM_KEYMAP_UPDATE_OPERATORTYPE;
|
||||
}
|
||||
|
||||
static int wm_keymap_test_and_clear_update(wmKeyMap *km)
|
||||
{
|
||||
wmKeyMapItem *kmi;
|
||||
@ -1137,8 +1200,39 @@ void WM_keyconfig_update(wmWindowManager *wm)
|
||||
|
||||
if (G.background)
|
||||
return;
|
||||
if (!WM_KEYMAP_UPDATE)
|
||||
|
||||
if (wm_keymap_update_flag == 0)
|
||||
return;
|
||||
|
||||
if (wm_keymap_update_flag & WM_KEYMAP_UPDATE_OPERATORTYPE) {
|
||||
/* an operatortype has been removed, this wont happen often
|
||||
* but when it does we have to check _every_ keymap item */
|
||||
wmKeyConfig *kc;
|
||||
|
||||
ListBase *keymaps_lb[] = {
|
||||
&U.user_keymaps,
|
||||
&wm->userconf->keymaps,
|
||||
&wm->defaultconf->keymaps,
|
||||
&wm->addonconf->keymaps,
|
||||
NULL};
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; keymaps_lb[i]; i++) {
|
||||
wm_keyconfig_properties_update_ot(keymaps_lb[i]);
|
||||
}
|
||||
|
||||
for (kc = wm->keyconfigs.first; kc; kc = kc->next) {
|
||||
wm_keyconfig_properties_update_ot(&kc->keymaps);
|
||||
}
|
||||
|
||||
wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_OPERATORTYPE;
|
||||
}
|
||||
|
||||
|
||||
if (wm_keymap_update_flag == 0)
|
||||
return;
|
||||
|
||||
|
||||
/* update operator properties for non-modal user keymaps */
|
||||
for (km = U.user_keymaps.first; km; km = km->next) {
|
||||
@ -1188,9 +1282,12 @@ void WM_keyconfig_update(wmWindowManager *wm)
|
||||
|
||||
/* in case of old non-diff keymaps, force extra update to create diffs */
|
||||
compat_update = compat_update || (usermap && !(usermap->flag & KEYMAP_DIFF));
|
||||
|
||||
}
|
||||
|
||||
WM_KEYMAP_UPDATE = false;
|
||||
wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_RECONFIGURE;
|
||||
|
||||
BLI_assert(wm_keymap_update_flag == 0);
|
||||
|
||||
if (compat_update) {
|
||||
WM_keyconfig_update_tag(NULL, NULL);
|
||||
|
@ -477,6 +477,8 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot)
|
||||
|
||||
BLI_ghash_remove(global_ops_hash, (void *)ot->idname, NULL, NULL);
|
||||
|
||||
WM_keyconfig_update_operatortype();
|
||||
|
||||
MEM_freeN(ot);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user