Commit: f0c6c85788ac7ba9f8edef0b7d331c72965ab004
Author: Bastien Montagne
Date: Fri Nov 6 18:00:09 2015 +0100
Branches: id-remap
https://developer.blender.org/rBf0c6c85788ac7ba9f8edef0b7d331c72965ab004
Attempt to fix the 'user_one' mess...
Seems to work (though will need much more tests), but makes code more ugly. :|
===================================================================
M source/blender/blenkernel/BKE_library.h
M source/blender/blenkernel/BKE_screen.h
M source/blender/blenkernel/intern/library.c
M source/blender/blenkernel/intern/screen.c
M source/blender/editors/include/ED_util.h
M source/blender/editors/space_buttons/space_buttons.c
M source/blender/editors/space_clip/space_clip.c
M source/blender/editors/space_image/space_image.c
M source/blender/editors/space_logic/space_logic.c
M source/blender/editors/space_node/space_node.c
M source/blender/editors/space_outliner/space_outliner.c
M source/blender/editors/space_sequencer/space_sequencer.c
M source/blender/editors/space_text/space_text.c
M source/blender/editors/space_view3d/space_view3d.c
M source/blender/editors/util/ed_util.c
M source/blender/windowmanager/WM_api.h
M source/blender/windowmanager/intern/wm_event_system.c
===================================================================
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 090145d..770010d 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -127,7 +127,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_
void BKE_library_callback_free_window_manager_set(void (*func)(struct bContext *, struct wmWindowManager *));
void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *));
-void BKE_library_callback_remap_editor_id_reference_set(void (*func)(struct ID *, struct ID *));
+void BKE_library_callback_remap_editor_id_reference_set(bool (*func)(struct ID *, struct ID *));
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index d74a61c..e89888c 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -99,7 +99,7 @@ typedef struct SpaceType {
int (*context)(const struct bContext *, const char *, struct bContextDataResult *);
/* Used when we want to replace an ID by another (or NULL). */
- void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);
+ bool (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);
/* region type definitions */
ListBase regiontypes;
@@ -276,7 +276,7 @@ void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
-void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
+void BKE_spacedata_callback_id_remap_set(bool (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);
/* area/regions */
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 4de1909..e4b2459 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -982,9 +982,9 @@ void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *)
free_notifier_reference_cb = func;
}
-static void (*remap_editor_id_reference_cb)(ID *, ID *) = NULL;
+static bool (*remap_editor_id_reference_cb)(ID *, ID *) = NULL;
-void BKE_library_callback_remap_editor_id_reference_set(void (*func)(ID *, ID *))
+void BKE_library_callback_remap_editor_id_reference_set(bool (*func)(ID *, ID *))
{
remap_editor_id_reference_cb = func;
}
@@ -994,10 +994,11 @@ typedef struct IDRemap {
ID *old_id;
ID *new_id;
ID *id; /* The ID in which we are replacing old_id by new_id usages. */
- /* XXX TODO: keeping this for now (also as debug data), in theory we can get rid of it. */
- int skipped_direct; /* Number of direct usecase that could not be remapped (e.g.: obdata when in edit mode). */
- int skipped_indirect; /* Number of indirect usecase that could not be remapped. */
int flag;
+
+ int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
+ int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
+ int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
} IDRemap;
enum {
@@ -1006,6 +1007,8 @@ enum {
/* Set by callback. */
ID_REMAP_IS_LINKED_DIRECT = 1 << 16, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE = 1 << 17, /* old_id was used by some nasty 'user_one' stuff (like image editor). */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 18, /* there was some skipped 'user_one' usages of old_id. */
};
static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_flag)
@@ -1030,18 +1033,29 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_indirect = (id->lib != NULL);
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL));
printf("\t\tIn %s (%p): remapping %s (%p) to %s (%p)\n",
id->name, id, old_id->name, old_id, new_id ? new_id->name : "", new_id);
/* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
- if ((is_obj_editmode && (((Object *)id)->data == *id_p)) || (skip_indirect && (is_proxy || is_indirect))) {
- if (is_proxy || is_obj_editmode) {
+ if (is_never_null ||
+ (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
+ (skip_indirect && (is_proxy || is_indirect)))
+ {
+ if (is_never_null || is_proxy || is_obj_editmode) {
id_remap_data->skipped_direct++;
}
else {
id_remap_data->skipped_indirect++;
}
+ if (cb_flag & IDWALK_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ /* We cannot affect old_id->us directly, flag it as such for final handling... */
+ id_remap_data->flag |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
}
else {
*id_p = new_id;
@@ -1050,6 +1064,11 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
if (new_id)
new_id->us++;
}
+ else if (cb_flag & IDWALK_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, flag it as such for final handling... */
+ id_remap_data->flag |= ID_REMAP_IS_USER_ONE;
+ }
DAG_id_tag_update_ex(bmain, id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
if (!is_indirect) {
id_remap_data->flag |= ID_REMAP_IS_LINKED_DIRECT;
@@ -1060,25 +1079,54 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
return true;
}
-static void libblock_remap_do(
- Main *bmain, ID *id, ID *old_id, ID *new_id, const bool skip_indirect_usage,
- int *r_skipped_direct, int *r_skipped_indirect)
+/**
+ * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
+ *
+ * Behavior differs depending on whether given \a id is NULL or not:
+ * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
+ * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
+ * are remapped to \a new_id.
+ * - \a id is non-NULL:
+ * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
+ * does not references any other datablock anymore).
+ * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
+ *
+ * \param bmain the Main data storage to operate on (if \a id is NULL).
+ * \param id the datablock to operate on (may be NULL).
+ * \param old_id the datablock to dereference (may be NULL if \a id is non-NULL).
+ * \param new_id the new datablock to replace \a old_id references with (may be NULL).
+ * \param skip_indirect_usage if true, do not remap/unlink indirect usages of \a old_id datablock.
+ * \param r_skipped_direct if non-NULL, the number of direct references that could not be replaced.
+ * \param r_skipped_indirect if non-NULL, the number of indirect references that could not be replaced.
+ * \param r_skipped_refcounted if non-NULL, the number of refcounted references that could not be replaced.
+ * \return true is there was some 'user_one' users of \a old_id (needed to handle correctly #old_id->us count).
+ */
+static bool libblock_remap_data(
+ Main *bmain, ID *id, ID *old_id, ID *new_id, const bool skip_indirect_usage, IDRemap *r_id_remap_data)
{
- IDRemap id_remap_data = {bmain, old_id, new_id, NULL};
+ IDRemap id_remap_data;
ListBase *lb_array[MAX_LIBARRAY];
int i;
+ if (r_id_remap_data == NULL) {
+ r_id_remap_data = &id_remap_data;
+ }
+ r_id_remap_data->bmain = bmain;
+ r_id_remap_data->old_id = old_id;
+ r_id_remap_data->new_id = new_id;
+ r_id_remap_data->id = NULL;
+ r_id_remap_data->flag = skip_indirect_usage ? ID_REMAP_SKIP_INDIRECT_USAGE : 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
printf("%s: %s (%p) replaced by %s (%p)\n", __func__,
old_id ? old_id->name : "", old_id, new_id ? new_id->name : "", new_id);
- if (skip_indirect_usage) {
- id_remap_data.flag |= ID_REMAP_SKIP_INDIRECT_USAGE;
- }
-
if (id) {
printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
- id_remap_data.id = id;
- BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)&id_remap_data, IDWALK_NOP);
+ r_id_remap_data->id = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
else {
i = set_listbasepointers(bmain, lb_array);
@@ -1094,38 +1142,37 @@ static void libblock_remap_do(
* the user count handling...
* XXX No more true (except for debug usage of those skipping counters). */
printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
- id_remap_data.id = id;
- BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)&id_remap_data, IDWALK_NOP);
+ r_id_remap_data->id = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
}
}
if (old_id && (old_id->flag & LIB_FAKEUSER)) {
- id_remap_data.skipped_direct++;
+ r_id_remap_data->skipped_direct++;
+ r_id_remap_data->skipped_refcounted++;
}
- if (new_id && (new_id->flag & LIB_INDIRECT) && (id_remap_data.flag & ID_REMAP_IS_LINKED_DIRECT)) {
+ if (new_id && (new_id->flag & LIB_INDIRECT) && (r_id_remap_data->flag & ID_REMAP_IS_LINKED_DIRECT)) {
new_id->flag &= ~LIB_INDIRECT;
new_id->flag |= LIB_EXTERN;
}
- if (r_skipped_direct)
- *r_skipped_direct = id_remap_data.skipped_direct;
-
- if (r_skipped_indirect)
- *r_skipped_indirect = id_remap_data.skipped_indirect;
-
printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __
@@ Diff output truncated at 10240 characters. @@