fix for WM_keymap_remove_item() writing to freed memory.
[blender.git] / source / blender / windowmanager / intern / wm_keymap.c
index af56211a4e323fb15d9204c0cb64e25a93131ab8..3739462ac2cc20eef2b26ff86b29d1135b5c6a55 100644 (file)
@@ -61,7 +61,7 @@
 #include "wm_event_types.h"
 
 /******************************* Keymap Item **********************************
-* Item in a keymap, that maps from an event to an operator or modal map item */
+ * Item in a keymap, that maps from an event to an operator or modal map item */
 
 static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
 {
@@ -101,8 +101,7 @@ static int wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
        if (strcmp(a->idname, b->idname) != 0)
                return 0;
        
-       if (!((a->ptr == NULL && b->ptr == NULL) ||
-             (a->ptr && b->ptr && IDP_EqualsProperties(a->ptr->data, b->ptr->data))))
+       if (!RNA_struct_equals(a->ptr, b->ptr))
                return 0;
        
        if ((a->flag & KMI_INACTIVE) != (b->flag & KMI_INACTIVE))
@@ -188,9 +187,9 @@ wmKeyConfig *WM_keyconfig_new_user(wmWindowManager *wm, const char *idname)
        return keyconf;
 }
 
-void WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
+int WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
 {
-       if (keyconf) {
+       if (BLI_findindex(&wm->keyconfigs, keyconf) != -1) {
                if (strncmp(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr)) == 0) {
                        BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr));
                        WM_keyconfig_update_tag(NULL, NULL);
@@ -198,6 +197,11 @@ void WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
 
                BLI_remlink(&wm->keyconfigs, keyconf);
                WM_keyconfig_free(keyconf);
+
+               return TRUE;
+       }
+       else {
+               return FALSE;
        }
 }
 
@@ -327,7 +331,7 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
                kmi->id = keymap->kmi_id;
        }
        else {
-               kmi->id = -keymap->kmi_id; // User defined keymap entries have negative ids
+               kmi->id = -keymap->kmi_id; /* User defined keymap entries have negative ids */
        }
 }
 
@@ -379,7 +383,7 @@ wmKeyMapItem *WM_keymap_add_menu(wmKeyMap *keymap, const char *idname, int type,
        return kmi;
 }
 
-void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
+int WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
 {
        if (BLI_findindex(&keymap->items, kmi) != -1) {
                if (kmi->ptr) {
@@ -388,7 +392,11 @@ void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
                }
                BLI_freelinkN(&keymap->items, kmi);
 
-               WM_keyconfig_update_tag(keymap, kmi);
+               WM_keyconfig_update_tag(keymap, NULL);
+               return TRUE;
+       }
+       else {
+               return FALSE;
        }
 }
 
@@ -534,7 +542,7 @@ static wmKeyMap *wm_keymap_patch_update(ListBase *lb, wmKeyMap *defaultmap, wmKe
 
        /* copy new keymap from an existing one */
        if (usermap && !(usermap->flag & KEYMAP_DIFF)) {
-               /* for compatibiltiy with old user preferences with non-diff
+               /* for compatibility with old user preferences with non-diff
                 * keymaps we override the original entirely */
                wmKeyMapItem *kmi, *orig_kmi;
 
@@ -710,6 +718,22 @@ wmKeyMapItem *WM_modalkeymap_add_item(wmKeyMap *km, int type, int val, int modif
        return kmi;
 }
 
+wmKeyMapItem *WM_modalkeymap_add_item_str(wmKeyMap *km, int type, int val, int modifier, int keymodifier, const char *value)
+{
+       wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
+
+       BLI_addtail(&km->items, kmi);
+       BLI_strncpy(kmi->propvalue_str, value, sizeof(kmi->propvalue_str));
+
+       keymap_event_set(kmi, type, val, modifier, keymodifier);
+
+       keymap_item_set_id(km, kmi);
+
+       WM_keyconfig_update_tag(km, kmi);
+
+       return kmi;
+}
+
 void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
 {
        wmOperatorType *ot = WM_operatortype_find(opname, 0);
@@ -720,6 +744,33 @@ void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
                printf("error: modalkeymap_assign, unknown operator %s\n", opname);
 }
 
+static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
+{
+       /* here we convert propvalue string values delayed, due to python keymaps
+        * being created before the actual modal keymaps, so no modal_items */
+       wmKeyMap *defaultkm;
+       wmKeyMapItem *kmi;
+       int propvalue;
+
+       if (km && (km->flag & KEYMAP_MODAL) && !km->modal_items) {
+               defaultkm = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, 0, 0);
+
+               if (!defaultkm)
+                       return;
+
+               km->modal_items = defaultkm->modal_items;
+               km->poll = defaultkm->poll;
+
+               for (kmi = km->items.first; kmi; kmi = kmi->next) {
+                       if (kmi->propvalue_str[0]) {
+                               if (RNA_enum_value_from_id(km->modal_items, kmi->propvalue_str, &propvalue))
+                                       kmi->propvalue = propvalue;
+                               kmi->propvalue_str[0] = '\0';
+                       }
+               }
+       }
+}
+
 /* ***************** get string from key events **************** */
 
 const char *WM_key_event_string(short type)
@@ -740,8 +791,8 @@ char *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len)
        if (kmi->shift == KM_ANY &&
            kmi->ctrl == KM_ANY &&
            kmi->alt == KM_ANY &&
-           kmi->oskey == KM_ANY) {
-
+           kmi->oskey == KM_ANY)
+       {
                strcat(buf, "Any ");
        }
        else {
@@ -770,8 +821,8 @@ char *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len)
 }
 
 static wmKeyMapItem *wm_keymap_item_find_handlers(
-    const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext),
-    IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
+        const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext),
+        IDProperty *properties, int is_strict, int hotkey, wmKeyMap **keymap_r)
 {
        wmWindowManager *wm = CTX_wm_manager(C);
        wmEventHandler *handler;
@@ -789,9 +840,22 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
                                        if (hotkey)
                                                if (!ISHOTKEY(kmi->type))
                                                        continue;
-                                       
-                                       if (compare_props) {
-                                               if (kmi->ptr && IDP_EqualsProperties(properties, kmi->ptr->data)) {
+
+                                       if (properties) {
+
+                                               /* example of debugging keymaps */
+#if 0
+                                               if (kmi->ptr) {
+                                                       if (strcmp("MESH_OT_rip_move", opname) == 0) {
+                                                               printf("OPERATOR\n");
+                                                               IDP_spit(properties);
+                                                               printf("KEYMAP\n");
+                                                               IDP_spit(kmi->ptr->data);
+                                                       }
+                                               }
+#endif
+
+                                               if (kmi->ptr && IDP_EqualsProperties_ex(properties, kmi->ptr->data, is_strict)) {
                                                        if (keymap_r) *keymap_r = keymap;
                                                        return kmi;
                                                }
@@ -811,8 +875,8 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
 }
 
 static wmKeyMapItem *wm_keymap_item_find_props(
-    const bContext *C, const char *opname, int opcontext,
-    IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
+        const bContext *C, const char *opname, int opcontext,
+        IDProperty *properties, int is_strict, int hotkey, wmKeyMap **keymap_r)
 {
        wmWindow *win = CTX_wm_window(C);
        ScrArea *sa = CTX_wm_area(C);
@@ -821,11 +885,10 @@ static wmKeyMapItem *wm_keymap_item_find_props(
 
        /* look into multiple handler lists to find the item */
        if (win)
-               found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
-       
+               found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
 
        if (sa && found == NULL)
-               found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
+               found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
 
        if (found == NULL) {
                if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
@@ -834,7 +897,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(
                                        ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
                                
                                if (ar)
-                                       found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
+                                       found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
                        }
                }
                else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) {
@@ -842,39 +905,55 @@ static wmKeyMapItem *wm_keymap_item_find_props(
                                ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
 
                        if (ar)
-                               found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
+                               found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
                }
                else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) {
                        if (!(ar && ar->regiontype == RGN_TYPE_PREVIEW))
                                ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
 
                        if (ar)
-                               found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
+                               found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
                }
                else {
                        if (ar)
-                               found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
+                               found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
                }
        }
-       
+
        return found;
 }
 
 static wmKeyMapItem *wm_keymap_item_find(
-    const bContext *C, const char *opname, int opcontext,
-    IDProperty *properties, const short hotkey, const short sloppy, wmKeyMap **keymap_r)
+        const bContext *C, const char *opname, int opcontext,
+        IDProperty *properties, const short hotkey, const short UNUSED(sloppy), wmKeyMap **keymap_r)
 {
        wmKeyMapItem *found = wm_keymap_item_find_props(C, opname, opcontext, properties, 1, hotkey, keymap_r);
 
-       if (!found && sloppy)
-               found = wm_keymap_item_find_props(C, opname, opcontext, NULL, 0, hotkey, keymap_r);
+       if (!found && properties) {
+               wmOperatorType *ot = WM_operatortype_find(opname, TRUE);
+               if (ot) {
+                       /* make a copy of the properties and set any unset props
+                        * to their default values, so the ID property compare function succeeds */
+                       PointerRNA opptr;
+                       IDProperty *properties_default = IDP_CopyProperty(properties);
+
+                       RNA_pointer_create(NULL, ot->srna, properties_default, &opptr);
+
+                       if (WM_operator_properties_default(&opptr, TRUE)) {
+                               found = wm_keymap_item_find_props(C, opname, opcontext, properties_default, 0, hotkey, keymap_r);
+                       }
+
+                       IDP_FreeProperty(properties_default);
+                       MEM_freeN(properties_default);
+               }
+       }
 
        return found;
 }
 
 char *WM_key_event_operator_string(
-    const bContext *C, const char *opname, int opcontext,
-    IDProperty *properties, const short sloppy, char *str, int len)
+        const bContext *C, const char *opname, int opcontext,
+        IDProperty *properties, const short sloppy, char *str, int len)
 {
        wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, 0, sloppy, NULL);
        
@@ -887,8 +966,8 @@ char *WM_key_event_operator_string(
 }
 
 int WM_key_event_operator_id(
-    const bContext *C, const char *opname, int opcontext,
-    IDProperty *properties, int hotkey, wmKeyMap **keymap_r)
+        const bContext *C, const char *opname, int opcontext,
+        IDProperty *properties, int hotkey, wmKeyMap **keymap_r)
 {
        wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, hotkey, TRUE, keymap_r);
        
@@ -1034,6 +1113,8 @@ void WM_keyconfig_update(wmWindowManager *wm)
                addonmap = WM_keymap_list_find(&wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
                usermap = WM_keymap_list_find(&U.user_keymaps, km->idname, km->spaceid, km->regionid);
 
+               wm_user_modal_keymap_set_items(wm, defaultmap);
+
                /* add */
                kmn = wm_keymap_patch_update(&wm->userconf->keymaps, defaultmap, addonmap, usermap);