Fix #113309: Broken key-map after "Reload Scripts"

Regression caused by [0]. Resolve by adding a 'keep_properties' argument
to KeyConfig.update so the key-map items can be restored after the
operators have been reloaded.

[0]: 88a875ec3a
This commit is contained in:
Campbell Barton
2023-10-13 14:20:30 +11:00
parent 604c0d8d5c
commit 08e5f94a70
4 changed files with 52 additions and 13 deletions

View File

@@ -292,7 +292,7 @@ def load_scripts(*, reload_scripts=False, refresh_scripts=False, extensions=True
# however reloading scripts re-enable all add-ons immediately (which may inspect key-maps).
# For this reason it's important to update key-maps which will have been tagged to update.
# Without this, add-on register functions accessing key-map properties can crash, see: #111702.
_bpy.context.window_manager.keyconfigs.update()
_bpy.context.window_manager.keyconfigs.update(keep_properties=True)
from bpy_restrict_state import RestrictBlend
@@ -308,6 +308,11 @@ def load_scripts(*, reload_scripts=False, refresh_scripts=False, extensions=True
for mod in modules_from_path(path, loaded_modules):
test_register(mod)
if reload_scripts:
# Update key-maps for key-map items referencing operators defined in "startup".
# Without this, key-map items wont be set properly, see: #113309.
_bpy.context.window_manager.keyconfigs.update()
if extensions:
load_scripts_extensions(reload_scripts=reload_scripts)

View File

@@ -539,9 +539,9 @@ static PointerRNA rna_KeyConfig_find_item_from_operator(wmWindowManager *wm,
return kmi_ptr;
}
static void rna_KeyConfig_update(wmWindowManager *wm)
static void rna_KeyConfig_update(wmWindowManager *wm, bool keep_properties)
{
WM_keyconfig_update(wm);
WM_keyconfig_update_ex(wm, keep_properties);
}
/* popup menu wrapper */
@@ -1335,7 +1335,13 @@ void RNA_api_keyconfigs(StructRNA *srna)
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_RNAPTR);
RNA_def_function_return(func, parm);
RNA_def_function(srna, "update", "rna_KeyConfig_update"); /* WM_keyconfig_update */
func = RNA_def_function(srna, "update", "rna_KeyConfig_update"); /* WM_keyconfig_update */
RNA_def_boolean(
func,
"keep_properties",
false,
"Keep Properties",
"Operator properties are kept to allow the operators to be registered again in the future");
}
#endif

View File

@@ -27,6 +27,12 @@ void WM_keyconfig_free(wmKeyConfig *keyconf);
void WM_keyconfig_set_active(wmWindowManager *wm, const char *idname);
/**
* \param keep_properties: When true, the properties for operators which cannot be found are kept.
* This is needed for operator reloading that validates key-map items for operators that may have
* their operators loaded back in the future, see: #113309.
*/
void WM_keyconfig_update_ex(wmWindowManager *wm, bool keep_properties);
void WM_keyconfig_update(wmWindowManager *wm);
void WM_keyconfig_update_tag(wmKeyMap *keymap, wmKeyMapItem *kmi);
void WM_keyconfig_update_operatortype();

View File

@@ -94,6 +94,17 @@ static void wm_keymap_item_free_data(wmKeyMapItem *kmi)
}
}
static void wm_keymap_item_clear_runtime(wmKeyMapItem *kmi)
{
IDProperty *properties = kmi->properties;
kmi->properties = nullptr;
if (kmi->ptr) {
kmi->ptr->data = nullptr;
}
wm_keymap_item_free_data(kmi);
kmi->properties = properties;
}
static void wm_keymap_item_properties_set(wmKeyMapItem *kmi)
{
WM_operator_properties_alloc(&(kmi->ptr), &(kmi->properties), kmi->idname);
@@ -107,7 +118,7 @@ static void wm_keymap_item_properties_set(wmKeyMapItem *kmi)
* 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)
static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi, const bool keep_properties)
{
if (kmi->idname[0] == 0) {
BLI_assert(kmi->ptr == nullptr);
@@ -137,25 +148,31 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
}
}
else {
/* zombie keymap item */
wm_keymap_item_free_data(kmi);
/* Zombie key-map item. */
if (keep_properties) {
wm_keymap_item_clear_runtime(kmi);
}
else {
wm_keymap_item_free_data(kmi);
}
}
}
}
static void wm_keymap_item_properties_update_ot_from_list(ListBase *km_lb)
static void wm_keymap_item_properties_update_ot_from_list(ListBase *km_lb,
const bool keep_properties)
{
LISTBASE_FOREACH (wmKeyMap *, km, km_lb) {
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
wm_keymap_item_properties_update_ot(kmi);
wm_keymap_item_properties_update_ot(kmi, keep_properties);
}
LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) {
if (kmdi->add_item) {
wm_keymap_item_properties_update_ot(kmdi->add_item);
wm_keymap_item_properties_update_ot(kmdi->add_item, keep_properties);
}
if (kmdi->remove_item) {
wm_keymap_item_properties_update_ot(kmdi->remove_item);
wm_keymap_item_properties_update_ot(kmdi->remove_item, keep_properties);
}
}
}
@@ -1873,6 +1890,11 @@ static wmKeyMap *wm_keymap_preset(wmWindowManager *wm, wmKeyMap *km)
}
void WM_keyconfig_update(wmWindowManager *wm)
{
WM_keyconfig_update_ex(wm, false);
}
void WM_keyconfig_update_ex(wmWindowManager *wm, bool keep_properties)
{
bool compat_update = false;
@@ -1883,9 +1905,9 @@ void WM_keyconfig_update(wmWindowManager *wm)
if (wm_keymap_update_flag & WM_KEYMAP_UPDATE_OPERATORTYPE) {
/* One or more operator-types have been removed, this won't happen often
* but when it does we have to check _every_ key-map item. */
wm_keymap_item_properties_update_ot_from_list(&U.user_keymaps);
wm_keymap_item_properties_update_ot_from_list(&U.user_keymaps, keep_properties);
LISTBASE_FOREACH (wmKeyConfig *, kc, &wm->keyconfigs) {
wm_keymap_item_properties_update_ot_from_list(&kc->keymaps);
wm_keymap_item_properties_update_ot_from_list(&kc->keymaps, keep_properties);
}
wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_OPERATORTYPE;
}