Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / library.c
index ce118fe9fde8bc1508cecb15ba7d053171f1dfce..978f1acefbaf5c730987da3f7afc5f54ef323519 100644 (file)
@@ -59,6 +59,7 @@
 #include "DNA_movieclip_types.h"
 #include "DNA_mask_types.h"
 #include "DNA_node_types.h"
+#include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_speaker_types.h"
@@ -72,7 +73,7 @@
 #include "BLI_utildefines.h"
 
 #include "BLI_threads.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
 
 #include "BKE_action.h"
 #include "BKE_animsys.h"
 #include "BKE_context.h"
 #include "BKE_curve.h"
 #include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
 #include "BKE_font.h"
 #include "BKE_global.h"
 #include "BKE_group.h"
 #include "BKE_gpencil.h"
+#include "BKE_idcode.h"
 #include "BKE_idprop.h"
 #include "BKE_image.h"
-#include "BKE_ipo.h"
 #include "BKE_key.h"
 #include "BKE_lamp.h"
 #include "BKE_lattice.h"
 #include "BKE_library.h"
+#include "BKE_library_query.h"
 #include "BKE_linestyle.h"
 #include "BKE_mesh.h"
 #include "BKE_material.h"
 #include "BKE_main.h"
 #include "BKE_mball.h"
-#include "BKE_movieclip.h"
 #include "BKE_mask.h"
 #include "BKE_node.h"
 #include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
 #include "BKE_packedFile.h"
 #include "BKE_speaker.h"
-#include "BKE_sound.h"
-#include "BKE_screen.h"
 #include "BKE_scene.h"
 #include "BKE_text.h"
 #include "BKE_texture.h"
 #include "BKE_world.h"
 
+#include "DEG_depsgraph.h"
+
 #include "RNA_access.h"
 
-#ifdef WITH_PYTHON
-#include "BPY_extern.h"
-#endif
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
 
 /* GS reads the memory pointed at in a specific ordering. 
  * only use this definition, makes little and big endian systems
@@ -144,32 +141,73 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
 
 void id_lib_extern(ID *id)
 {
-       if (id) {
-               if (id->flag & LIB_INDIRECT) {
-                       id->flag -= LIB_INDIRECT;
-                       id->flag |= LIB_EXTERN;
+       if (id && ID_IS_LINKED_DATABLOCK(id)) {
+               BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
+               if (id->tag & LIB_TAG_INDIRECT) {
+                       id->tag -= LIB_TAG_INDIRECT;
+                       id->tag |= LIB_TAG_EXTERN;
                }
        }
 }
 
 /* ensure we have a real user */
+/* Note: Now that we have flags, we could get rid of the 'fake_user' special case, flags are enough to ensure
+ *       we always have a real user.
+ *       However, ID_REAL_USERS is used in several places outside of core library.c, so think we can wait later
+ *       to make this change... */
 void id_us_ensure_real(ID *id)
 {
        if (id) {
-               if (ID_REAL_USERS(id) <= 0) {
-                       id->us = MAX2(id->us, 0) + 1;
+               const int limit = ID_FAKE_USERS(id);
+               id->tag |= LIB_TAG_EXTRAUSER;
+               if (id->us <= limit) {
+                       if (id->us < limit || ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER_SET))) {
+                               printf("ID user count error: %s (from '%s')\n", id->name, id->lib ? id->lib->filepath : "[Main]");
+                               BLI_assert(0);
+                       }
+                       id->us = limit + 1;
+                       id->tag |= LIB_TAG_EXTRAUSER_SET;
                }
        }
 }
 
-void id_us_plus(ID *id)
+void id_us_clear_real(ID *id)
+{
+       if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
+               if (id->tag & LIB_TAG_EXTRAUSER_SET) {
+                       id->us--;
+                       BLI_assert(id->us >= ID_FAKE_USERS(id));
+               }
+               id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
+       }
+}
+
+/**
+ * Same as \a id_us_plus, but does not handle lib indirect -> extern.
+ * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
+ */
+void id_us_plus_no_lib(ID *id)
 {
        if (id) {
-               id->us++;
-               if (id->flag & LIB_INDIRECT) {
-                       id->flag -= LIB_INDIRECT;
-                       id->flag |= LIB_EXTERN;
+               if ((id->tag & LIB_TAG_EXTRAUSER) && (id->tag & LIB_TAG_EXTRAUSER_SET)) {
+                       BLI_assert(id->us >= 1);
+                       /* No need to increase count, just tag extra user as no more set.
+                        * Avoids annoying & inconsistent +1 in user count. */
+                       id->tag &= ~LIB_TAG_EXTRAUSER_SET;
                }
+               else {
+                       BLI_assert(id->us >= 0);
+                       id->us++;
+               }
+       }
+}
+
+
+void id_us_plus(ID *id)
+{
+       if (id) {
+               id_us_plus_no_lib(id);
+               id_lib_extern(id);
        }
 }
 
@@ -177,23 +215,64 @@ void id_us_plus(ID *id)
 void id_us_min(ID *id)
 {
        if (id) {
-               if (id->us < 2 && (id->flag & LIB_FAKEUSER)) {
-                       id->us = 1;
-               }
-               else if (id->us <= 0) {
-                       printf("ID user decrement error: %s\n", id->name);
+               const int limit = ID_FAKE_USERS(id);
+
+               if (id->us <= limit) {
+                       printf("ID user decrement error: %s (from '%s'): %d <= %d\n",
+                              id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit);
+                       BLI_assert(0);
+                       id->us = limit;
                }
                else {
                        id->us--;
                }
+
+               if ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER)) {
+                       /* We need an extra user here, but never actually incremented user count for it so far, do it now. */
+                       id_us_ensure_real(id);
+               }
+       }
+}
+
+void id_fake_user_set(ID *id)
+{
+       if (id && !(id->flag & LIB_FAKEUSER)) {
+               id->flag |= LIB_FAKEUSER;
+               id_us_plus(id);
+       }
+}
+
+void id_fake_user_clear(ID *id)
+{
+       if (id && (id->flag & LIB_FAKEUSER)) {
+               id->flag &= ~LIB_FAKEUSER;
+               id_us_min(id);
+       }
+}
+
+static int id_expand_local_callback(
+        void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+{
+       if (*id_pointer) {
+               id_lib_extern(*id_pointer);
        }
+
+       return IDWALK_RET_NOP;
+}
+
+/**
+ * Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions.
+ */
+void BKE_id_expand_local(ID *id)
+{
+       BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
 }
 
 /* calls the appropriate make_local method for the block, unless test. Returns true
  * if the block can be made local. */
-bool id_make_local(ID *id, bool test)
+bool id_make_local(Main *bmain, ID *id, bool test)
 {
-       if (id->flag & LIB_INDIRECT)
+       if (id->tag & LIB_TAG_INDIRECT)
                return false;
 
        switch (GS(id->name)) {
@@ -202,54 +281,45 @@ bool id_make_local(ID *id, bool test)
                case ID_LI:
                        return false; /* can't be linked */
                case ID_OB:
-                       if (!test) BKE_object_make_local((Object *)id);
+                       if (!test) BKE_object_make_local(bmain, (Object *)id);
                        return true;
                case ID_ME:
-                       if (!test) {
-                               BKE_mesh_make_local((Mesh *)id);
-                               BKE_key_make_local(((Mesh *)id)->key);
-                       }
+                       if (!test) BKE_mesh_make_local(bmain, (Mesh *)id);
                        return true;
                case ID_CU:
-                       if (!test) {
-                               BKE_curve_make_local((Curve *)id);
-                               BKE_key_make_local(((Curve *)id)->key);
-                       }
+                       if (!test) BKE_curve_make_local(bmain, (Curve *)id);
                        return true;
                case ID_MB:
-                       if (!test) BKE_mball_make_local((MetaBall *)id);
+                       if (!test) BKE_mball_make_local(bmain, (MetaBall *)id);
                        return true;
                case ID_MA:
-                       if (!test) BKE_material_make_local((Material *)id);
+                       if (!test) BKE_material_make_local(bmain, (Material *)id);
                        return true;
                case ID_TE:
-                       if (!test) BKE_texture_make_local((Tex *)id);
+                       if (!test) BKE_texture_make_local(bmain, (Tex *)id);
                        return true;
                case ID_IM:
-                       if (!test) BKE_image_make_local((Image *)id);
+                       if (!test) BKE_image_make_local(bmain, (Image *)id);
                        return true;
                case ID_LT:
-                       if (!test) {
-                               BKE_lattice_make_local((Lattice *)id);
-                               BKE_key_make_local(((Lattice *)id)->key);
-                       }
+                       if (!test) BKE_lattice_make_local(bmain, (Lattice *)id);
                        return true;
                case ID_LA:
-                       if (!test) BKE_lamp_make_local((Lamp *)id);
+                       if (!test) BKE_lamp_make_local(bmain, (Lamp *)id);
                        return true;
                case ID_CA:
-                       if (!test) BKE_camera_make_local((Camera *)id);
+                       if (!test) BKE_camera_make_local(bmain, (Camera *)id);
                        return true;
                case ID_SPK:
-                       if (!test) BKE_speaker_make_local((Speaker *)id);
+                       if (!test) BKE_speaker_make_local(bmain, (Speaker *)id);
                        return true;
                case ID_IP:
                        return false; /* deprecated */
                case ID_KE:
-                       if (!test) BKE_key_make_local((Key *)id);
+                       if (!test) BKE_key_make_local(bmain, (Key *)id);
                        return true;
                case ID_WO:
-                       if (!test) BKE_world_make_local((World *)id);
+                       if (!test) BKE_world_make_local(bmain, (World *)id);
                        return true;
                case ID_SCR:
                        return false; /* can't be linked */
@@ -257,26 +327,21 @@ bool id_make_local(ID *id, bool test)
                        return false; /* not implemented */
                case ID_TXT:
                        return false; /* not implemented */
-               case ID_SCRIPT:
-                       return false; /* deprecated */
                case ID_SO:
                        return false; /* not implemented */
                case ID_GR:
                        return false; /* not implemented */
                case ID_AR:
-                       if (!test) BKE_armature_make_local((bArmature *)id);
+                       if (!test) BKE_armature_make_local(bmain, (bArmature *)id);
                        return true;
                case ID_AC:
-                       if (!test) BKE_action_make_local((bAction *)id);
+                       if (!test) BKE_action_make_local(bmain, (bAction *)id);
                        return true;
                case ID_NT:
-                       if (!test) ntreeMakeLocal((bNodeTree *)id);
+                       if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true);
                        return true;
                case ID_BR:
-                       if (!test) BKE_brush_make_local((Brush *)id);
-                       return true;
-               case ID_PA:
-                       if (!test) BKE_particlesettings_make_local((ParticleSettings *)id);
+                       if (!test) BKE_brush_make_local(bmain, (Brush *)id);
                        return true;
                case ID_WM:
                        return false; /* can't be linked */
@@ -291,11 +356,13 @@ bool id_make_local(ID *id, bool test)
 
 /**
  * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true iff the block can be copied.
+ * newid, unless test. Returns true if the block can be copied.
  */
-bool id_copy(ID *id, ID **newid, bool test)
+bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
 {
-       if (!test) *newid = NULL;
+       if (!test) {
+               *newid = NULL;
+       }
 
        /* conventions:
         * - make shallow copy, only this ID block
@@ -306,122 +373,86 @@ bool id_copy(ID *id, ID **newid, bool test)
                case ID_LI:
                        return false;  /* can't be copied from here */
                case ID_OB:
-                       if (!test) *newid = (ID *)BKE_object_copy((Object *)id);
+                       if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id);
                        return true;
                case ID_ME:
-                       if (!test) *newid = (ID *)BKE_mesh_copy((Mesh *)id);
+                       if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id);
                        return true;
                case ID_CU:
-                       if (!test) *newid = (ID *)BKE_curve_copy((Curve *)id);
+                       if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id);
                        return true;
                case ID_MB:
-                       if (!test) *newid = (ID *)BKE_mball_copy((MetaBall *)id);
+                       if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id);
                        return true;
                case ID_MA:
-                       if (!test) *newid = (ID *)BKE_material_copy((Material *)id);
+                       if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id);
                        return true;
                case ID_TE:
-                       if (!test) *newid = (ID *)BKE_texture_copy((Tex *)id);
+                       if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id);
                        return true;
                case ID_IM:
-                       if (!test) *newid = (ID *)BKE_image_copy(G.main, (Image *)id);
+                       if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id);
                        return true;
                case ID_LT:
-                       if (!test) *newid = (ID *)BKE_lattice_copy((Lattice *)id);
+                       if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id);
                        return true;
                case ID_LA:
-                       if (!test) *newid = (ID *)BKE_lamp_copy((Lamp *)id);
+                       if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id);
                        return true;
                case ID_SPK:
-                       if (!test) *newid = (ID *)BKE_speaker_copy((Speaker *)id);
+                       if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id);
                        return true;
                case ID_CA:
-                       if (!test) *newid = (ID *)BKE_camera_copy((Camera *)id);
+                       if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id);
                        return true;
                case ID_IP:
                        return false;  /* deprecated */
                case ID_KE:
-                       if (!test) *newid = (ID *)BKE_key_copy((Key *)id);
+                       if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id);
                        return true;
                case ID_WO:
-                       if (!test) *newid = (ID *)BKE_world_copy((World *)id);
+                       if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id);
                        return true;
                case ID_SCR:
                        return false;  /* can't be copied from here */
                case ID_VF:
                        return false;  /* not implemented */
                case ID_TXT:
-                       if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id);
+                       if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id);
                        return true;
-               case ID_SCRIPT:
-                       return false;  /* deprecated */
                case ID_SO:
                        return false;  /* not implemented */
                case ID_GR:
-                       if (!test) *newid = (ID *)BKE_group_copy((Group *)id);
+                       if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id);
                        return true;
                case ID_AR:
-                       if (!test) *newid = (ID *)BKE_armature_copy((bArmature *)id);
+                       if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id);
                        return true;
                case ID_AC:
-                       if (!test) *newid = (ID *)BKE_action_copy((bAction *)id);
+                       if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id);
                        return true;
                case ID_NT:
-                       if (!test) *newid = (ID *)ntreeCopyTree((bNodeTree *)id);
+                       if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id);
                        return true;
                case ID_BR:
-                       if (!test) *newid = (ID *)BKE_brush_copy((Brush *)id);
-                       return true;
-               case ID_PA:
-                       if (!test) *newid = (ID *)BKE_particlesettings_copy((ParticleSettings *)id);
+                       if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id);
                        return true;
                case ID_WM:
                        return false;  /* can't be copied from here */
                case ID_GD:
-                       if (!test) *newid = (ID *)gpencil_data_duplicate((bGPdata *)id, false);
+                       if (!test) *newid = (ID *)gpencil_data_duplicate(bmain, (bGPdata *)id, false);
                        return true;
                case ID_MSK:
-                       if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
+                       if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id);
                        return true;
                case ID_LS:
-                       if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id);
+                       if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id);
                        return true;
        }
        
        return false;
 }
 
-bool id_unlink(ID *id, int test)
-{
-       Main *mainlib = G.main;
-       short type = GS(id->name);
-
-       switch (type) {
-               case ID_TXT:
-                       if (test) return true;
-                       BKE_text_unlink(mainlib, (Text *)id);
-                       break;
-               case ID_GR:
-                       if (test) return true;
-                       BKE_group_unlink((Group *)id);
-                       break;
-               case ID_OB:
-                       if (test) return true;
-                       BKE_object_unlink((Object *)id);
-                       break;
-       }
-
-       if (id->us == 0) {
-               if (test) return true;
-
-               BKE_libblock_free(mainlib, id);
-
-               return true;
-       }
-
-       return false;
-}
-
 bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
 {
        ID *newid = NULL;
@@ -430,7 +461,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
        if (id) {
                /* if property isn't editable, we're going to have an extra block hanging around until we save */
                if (RNA_property_editable(ptr, prop)) {
-                       if (id_copy(id, &newid, false) && newid) {
+                       if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
                                /* copy animation actions too */
                                BKE_animdata_copy_id_action(id);
                                /* us is 1 by convention, but RNA_property_pointer_set
@@ -489,8 +520,6 @@ ListBase *which_libbase(Main *mainlib, short type)
                        return &(mainlib->vfont);
                case ID_TXT:
                        return &(mainlib->text);
-               case ID_SCRIPT:
-                       return &(mainlib->script);
                case ID_SPK:
                        return &(mainlib->speaker);
                case ID_SO:
@@ -505,8 +534,6 @@ ListBase *which_libbase(Main *mainlib, short type)
                        return &(mainlib->nodetree);
                case ID_BR:
                        return &(mainlib->brush);
-               case ID_PA:
-                       return &(mainlib->particle);
                case ID_WM:
                        return &(mainlib->wm);
                case ID_GD:
@@ -525,21 +552,71 @@ ListBase *which_libbase(Main *mainlib, short type)
        return NULL;
 }
 
-/* Flag all ids in listbase */
-void BKE_main_id_flag_listbase(ListBase *lb, const short flag, const bool value)
+/**
+ * Clear or set given tags for all ids in listbase (runtime tags).
+ */
+void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
 {
        ID *id;
        if (value) {
-               for (id = lb->first; id; id = id->next) id->flag |= flag;
+               for (id = lb->first; id; id = id->next) {
+                       id->tag |= tag;
+               }
        }
        else {
-               const short nflag = ~flag;
-               for (id = lb->first; id; id = id->next) id->flag &= nflag;
+               const int ntag = ~tag;
+               for (id = lb->first; id; id = id->next) {
+                       id->tag &= ntag;
+               }
        }
 }
 
-/* Flag all ids in listbase */
-void BKE_main_id_flag_all(Main *bmain, const short flag, const bool value)
+/**
+ * Clear or set given tags for all ids of given type in bmain (runtime tags).
+ */
+void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value)
+{
+       ListBase *lb = which_libbase(mainvar, type);
+
+       BKE_main_id_tag_listbase(lb, tag, value);
+}
+
+/**
+ * Clear or set given tags for all ids in bmain (runtime tags).
+ */
+void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
+{
+       ListBase *lbarray[MAX_LIBARRAY];
+       int a;
+
+       a = set_listbasepointers(mainvar, lbarray);
+       while (a--) {
+               BKE_main_id_tag_listbase(lbarray[a], tag, value);
+       }
+}
+
+
+/**
+ * Clear or set given flags for all ids in listbase (persistent flags).
+ */
+void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
+{
+       ID *id;
+       if (value) {
+               for (id = lb->first; id; id = id->next)
+                       id->tag |= flag;
+       }
+       else {
+               const int nflag = ~flag;
+               for (id = lb->first; id; id = id->next)
+                       id->tag &= nflag;
+       }
+}
+
+/**
+ * Clear or set given flags for all ids in bmain (persistent flags).
+ */
+void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
 {
        ListBase *lbarray[MAX_LIBARRAY];
        int a;
@@ -554,9 +631,11 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
        Object *ob;
 
        /* flag for full recalc */
-       for (ob = bmain->object.first; ob; ob = ob->id.next)
-               if (ob->id.lib)
-                       ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+       for (ob = bmain->object.first; ob; ob = ob->id.next) {
+               if (ID_IS_LINKED_DATABLOCK(ob)) {
+                       DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+               }
+       }
 
        DAG_id_type_tag(bmain, ID_OB);
 }
@@ -575,8 +654,9 @@ int set_listbasepointers(Main *main, ListBase **lb)
        /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
         * This is important because freeing data decreases usercounts of other datablocks,
         * if this data is its self freed it can crash. */
+       lb[a++] = &(main->library);  /* Libraries may be accessed from pretty much any other ID... */
        lb[a++] = &(main->ipo);
-       lb[a++] = &(main->action); // xxx moved here to avoid problems when freeing with animato (aligorith)
+       lb[a++] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
        lb[a++] = &(main->key);
        lb[a++] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
        lb[a++] = &(main->nodetree);
@@ -605,8 +685,6 @@ int set_listbasepointers(Main *main, ListBase **lb)
        lb[a++] = &(main->palettes);
        lb[a++] = &(main->paintcurves);
        lb[a++] = &(main->brush);
-       lb[a++] = &(main->script);
-       lb[a++] = &(main->particle);
        lb[a++] = &(main->speaker);
 
        lb[a++] = &(main->world);
@@ -615,7 +693,6 @@ int set_listbasepointers(Main *main, ListBase **lb)
        lb[a++] = &(main->object);
        lb[a++] = &(main->linestyle); /* referenced by scenes */
        lb[a++] = &(main->scene);
-       lb[a++] = &(main->library);
        lb[a++] = &(main->wm);
        lb[a++] = &(main->mask);
        
@@ -640,7 +717,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
  * Allocates and returns memory of the right size for the specified block type,
  * initialized to zero.
  */
-static ID *alloc_libblock_notest(short type)
+void *BKE_libblock_alloc_notest(short type)
 {
        ID *id = NULL;
        
@@ -699,9 +776,6 @@ static ID *alloc_libblock_notest(short type)
                case ID_TXT:
                        id = MEM_callocN(sizeof(Text), "text");
                        break;
-               case ID_SCRIPT:
-                       //XXX id = MEM_callocN(sizeof(Script), "script");
-                       break;
                case ID_SPK:
                        id = MEM_callocN(sizeof(Speaker), "speaker");
                        break;
@@ -723,9 +797,6 @@ static ID *alloc_libblock_notest(short type)
                case ID_BR:
                        id = MEM_callocN(sizeof(Brush), "brush");
                        break;
-               case ID_PA:
-                       id = MEM_callocN(sizeof(ParticleSettings), "ParticleSettings");
-                       break;
                case ID_WM:
                        id = MEM_callocN(sizeof(wmWindowManager), "Window manager");
                        break;
@@ -762,7 +833,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
        ID *id = NULL;
        ListBase *lb = which_libbase(bmain, type);
        
-       id = alloc_libblock_notest(type);
+       id = BKE_libblock_alloc_notest(type);
        if (id) {
                BKE_main_lock(bmain);
                BLI_addtail(lb, id);
@@ -777,6 +848,115 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
        return id;
 }
 
+/**
+ * Initialize an ID of given type, such that it has valid 'empty' data.
+ * ID is assumed to be just calloc'ed.
+ */
+void BKE_libblock_init_empty(ID *id)
+{
+       /* Note that only ID types that are not valid when filled of zero should have a callback here. */
+       switch (GS(id->name)) {
+               case ID_SCE:
+                       BKE_scene_init((Scene *)id);
+                       break;
+               case ID_LI:
+                       /* Nothing to do. */
+                       break;
+               case ID_OB:
+               {
+                       Object *ob = (Object *)id;
+                       ob->type = OB_EMPTY;
+                       BKE_object_init(ob);
+                       break;
+               }
+               case ID_ME:
+                       BKE_mesh_init((Mesh *)id);
+                       break;
+               case ID_CU:
+                       BKE_curve_init((Curve *)id);
+                       break;
+               case ID_MB:
+                       BKE_mball_init((MetaBall *)id);
+                       break;
+               case ID_MA:
+                       BKE_material_init((Material *)id);
+                       break;
+               case ID_TE:
+                       BKE_texture_default((Tex *)id);
+                       break;
+               case ID_IM:
+                       BKE_image_init((Image *)id);
+                       break;
+               case ID_LT:
+                       BKE_lattice_init((Lattice *)id);
+                       break;
+               case ID_LA:
+                       BKE_lamp_init((Lamp *)id);
+                       break;
+               case ID_SPK:
+                       BKE_speaker_init((Speaker *)id);
+                       break;
+               case ID_CA:
+                       BKE_camera_init((Camera *)id);
+                       break;
+               case ID_IP:
+                       /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
+                       BLI_assert(0);
+                       break;
+               case ID_KE:
+                       /* Shapekeys are a complex topic too - they depend on their 'user' data type...
+                        * They are not linkable, though, so it should never reach here anyway. */
+                       BLI_assert(0);
+                       break;
+               case ID_WO:
+                       BKE_world_init((World *)id);
+                       break;
+               case ID_SCR:
+                       /* Nothing to do. */
+                       break;
+               case ID_VF:
+                       BKE_vfont_init((VFont *)id);
+                       break;
+               case ID_TXT:
+                       BKE_text_init((Text *)id);
+                       break;
+               case ID_SO:
+                       /* Another fuzzy case, think NULLified content is OK here... */
+                       break;
+               case ID_GR:
+                       /* Nothing to do. */
+                       break;
+               case ID_AR:
+                       /* Nothing to do. */
+                       break;
+               case ID_AC:
+                       /* Nothing to do. */
+                       break;
+               case ID_NT:
+                       ntreeInitDefault((bNodeTree *)id);
+                       break;
+               case ID_BR:
+                       BKE_brush_init((Brush *)id);
+                       break;
+               case ID_PC:
+                       /* Nothing to do. */
+                       break;
+               case ID_WM:
+                       /* We should never reach this. */
+                       BLI_assert(0);
+                       break;
+               case ID_GD:
+                       /* Nothing to do. */
+                       break;
+               case ID_MSK:
+                       /* Nothing to do. */
+                       break;
+               case ID_LS:
+                       BKE_linestyle_init((FreestyleLineStyle *)id);
+                       break;
+       }
+}
+
 /* by spec, animdata is first item after ID */
 /* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */
 static void id_copy_animdata(ID *id, const bool do_action)
@@ -800,7 +980,7 @@ void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action)
 }
 
 /* used everywhere in blenkernel */
-void *BKE_libblock_copy_ex(Main *bmain, ID *id)
+void *BKE_libblock_copy(Main *bmain, ID *id)
 {
        ID *idn;
        size_t idn_len;
@@ -818,7 +998,7 @@ void *BKE_libblock_copy_ex(Main *bmain, ID *id)
        }
        
        id->newid = idn;
-       idn->flag |= LIB_NEW;
+       idn->tag |= LIB_TAG_NEW;
 
        BKE_libblock_copy_data(idn, id, false);
        
@@ -830,7 +1010,7 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
        ID *idn;
        size_t idn_len;
 
-       idn = alloc_libblock_notest(GS(id->name));
+       idn = BKE_libblock_alloc_notest(GS(id->name));
        assert(idn != NULL);
 
        BLI_strncpy(idn->name, id->name, sizeof(idn->name));
@@ -844,7 +1024,7 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
        }
 
        id->newid = idn;
-       idn->flag |= LIB_NEW;
+       idn->tag |= LIB_TAG_NEW;
        idn->us = 1;
 
        BKE_libblock_copy_data(idn, id, do_action);
@@ -852,237 +1032,41 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
        return idn;
 }
 
-void *BKE_libblock_copy(ID *id)
-{
-       return BKE_libblock_copy_ex(G.main, id);
-}
-
-static void BKE_library_free(Library *lib)
-{
-       if (lib->packedfile)
-               freePackedFile(lib->packedfile);
-}
-
-static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL;
-
-void BKE_library_callback_free_window_manager_set(void (*func)(bContext *C, wmWindowManager *) )
+static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
 {
-       free_windowmanager_cb = func;
-}
-
-static void (*free_notifier_reference_cb)(const void *) = NULL;
-
-void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *) )
-{
-       free_notifier_reference_cb = func;
-}
-
-static void (*free_editor_id_reference_cb)(const ID *) = NULL;
-
-void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *))
-{
-       free_editor_id_reference_cb = func;
-}
-
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
-{
-       ChannelDriver *driver;
-       FCurve *fcu;
-
-       /* find the driver this belongs to and update it */
-       for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
-               driver = fcu->driver;
-               
-               if (driver) {
-                       DriverVar *dvar;
-                       for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
-                               DRIVER_TARGETS_USED_LOOPER(dvar) 
-                               {
-                                       if (dtar->id == userdata)
-                                               dtar->id = NULL;
-                               }
-                               DRIVER_TARGETS_LOOPER_END
-                       }
+       ID *id = *id_pointer;
+       if (id) {
+               /* See: NEW_ID macro */
+               if (id->newid) {
+                       BKE_library_update_ID_link_user(id->newid, id, cd_flag);
+                       *id_pointer = id->newid;
+               }
+               else if (id->tag & LIB_TAG_NEW) {
+                       id->tag &= ~LIB_TAG_NEW;
+                       BKE_libblock_relink(id);
                }
        }
+       return IDWALK_RET_NOP;
 }
 
-void BKE_libblock_free_data(Main *bmain, ID *id)
-{
-       if (id->properties) {
-               IDP_FreeProperty(id->properties);
-               MEM_freeN(id->properties);
-       }
-       
-       /* this ID may be a driver target! */
-       BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
-}
-
-/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */
-void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
+void BKE_libblock_relink(ID *id)
 {
-       ID *id = idv;
-       short type = GS(id->name);
-       ListBase *lb = which_libbase(bmain, type);
-
-       DAG_id_type_tag(bmain, type);
-
-#ifdef WITH_PYTHON
-       BPY_id_release(id);
-#endif
-
-       switch (type) {    /* GetShort from util.h */
-               case ID_SCE:
-                       BKE_scene_free((Scene *)id);
-                       break;
-               case ID_LI:
-                       BKE_library_free((Library *)id);
-                       break;
-               case ID_OB:
-                       BKE_object_free_ex((Object *)id, do_id_user);
-                       break;
-               case ID_ME:
-                       BKE_mesh_free((Mesh *)id, 1);
-                       break;
-               case ID_CU:
-                       BKE_curve_free((Curve *)id);
-                       break;
-               case ID_MB:
-                       BKE_mball_free((MetaBall *)id);
-                       break;
-               case ID_MA:
-                       BKE_material_free((Material *)id);
-                       break;
-               case ID_TE:
-                       BKE_texture_free((Tex *)id);
-                       break;
-               case ID_IM:
-                       BKE_image_free((Image *)id);
-                       break;
-               case ID_LT:
-                       BKE_lattice_free((Lattice *)id);
-                       break;
-               case ID_LA:
-                       BKE_lamp_free((Lamp *)id);
-                       break;
-               case ID_CA:
-                       BKE_camera_free((Camera *) id);
-                       break;
-               case ID_IP:
-                       BKE_ipo_free((Ipo *)id);
-                       break;
-               case ID_KE:
-                       BKE_key_free((Key *)id);
-                       break;
-               case ID_WO:
-                       BKE_world_free((World *)id);
-                       break;
-               case ID_SCR:
-                       BKE_screen_free((bScreen *)id);
-                       break;
-               case ID_VF:
-                       BKE_vfont_free((VFont *)id);
-                       break;
-               case ID_TXT:
-                       BKE_text_free((Text *)id);
-                       break;
-               case ID_SCRIPT:
-                       /* deprecated */
-                       break;
-               case ID_SPK:
-                       BKE_speaker_free((Speaker *)id);
-                       break;
-               case ID_SO:
-                       BKE_sound_free((bSound *)id);
-                       break;
-               case ID_GR:
-                       BKE_group_free((Group *)id);
-                       break;
-               case ID_AR:
-                       BKE_armature_free((bArmature *)id);
-                       break;
-               case ID_AC:
-                       BKE_action_free((bAction *)id);
-                       break;
-               case ID_NT:
-                       ntreeFreeTree_ex((bNodeTree *)id, do_id_user);
-                       break;
-               case ID_BR:
-                       BKE_brush_free((Brush *)id);
-                       break;
-               case ID_PA:
-                       BKE_particlesettings_free((ParticleSettings *)id);
-                       break;
-               case ID_WM:
-                       if (free_windowmanager_cb)
-                               free_windowmanager_cb(NULL, (wmWindowManager *)id);
-                       break;
-               case ID_GD:
-                       BKE_gpencil_free((bGPdata *)id);
-                       break;
-               case ID_MC:
-                       BKE_movieclip_free((MovieClip *)id);
-                       break;
-               case ID_MSK:
-                       BKE_mask_free(bmain, (Mask *)id);
-                       break;
-               case ID_LS:
-                       BKE_linestyle_free((FreestyleLineStyle *)id);
-                       break;
-               case ID_PAL:
-                       BKE_palette_free((Palette *)id);
-                       break;
-               case ID_PC:
-                       BKE_paint_curve_free((PaintCurve *)id);
-                       break;
-       }
-
-       /* avoid notifying on removed data */
-       BKE_main_lock(bmain);
-
-       if (free_notifier_reference_cb) {
-               free_notifier_reference_cb(id);
-       }
-
-       if (free_editor_id_reference_cb) {
-               free_editor_id_reference_cb(id);
-       }
-
-       BLI_remlink(lb, id);
-
-       BKE_libblock_free_data(bmain, id);
-       BKE_main_unlock(bmain);
-
-       MEM_freeN(id);
-}
+       if (ID_IS_LINKED_DATABLOCK(id))
+               return;
 
-void BKE_libblock_free(Main *bmain, void *idv)
-{
-       BKE_libblock_free_ex(bmain, idv, true);
+       BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
 }
 
-void BKE_libblock_free_us(Main *bmain, void *idv)      /* test users */
+void BKE_library_free(Library *lib)
 {
-       ID *id = idv;
-       
-       id->us--;
-
-       if (id->us < 0) {
-               if (id->lib) printf("ERROR block %s %s users %d\n", id->lib->name, id->name, id->us);
-               else printf("ERROR block %s users %d\n", id->name, id->us);
-       }
-       if (id->us == 0) {
-               if (GS(id->name) == ID_OB) BKE_object_unlink((Object *)id);
-               
-               BKE_libblock_free(bmain, id);
-       }
+       if (lib->packedfile)
+               freePackedFile(lib->packedfile);
 }
 
 Main *BKE_main_new(void)
 {
        Main *bmain = MEM_callocN(sizeof(Main), "new main");
-       bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext),
-                                     "EvaluationContext");
+       bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
        bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
        BLI_spin_init((SpinLock *)bmain->lock);
        return bmain;
@@ -1094,6 +1078,8 @@ void BKE_main_free(Main *mainvar)
        ListBase *lbarray[MAX_LIBARRAY];
        int a;
 
+       MEM_SAFE_FREE(mainvar->blen_thumb);
+
        a = set_listbasepointers(mainvar, lbarray);
        while (a--) {
                ListBase *lb = lbarray[a];
@@ -1139,6 +1125,7 @@ void BKE_main_free(Main *mainvar)
                                case  30: BKE_libblock_free_ex(mainvar, id, false); break;
                                case  31: BKE_libblock_free_ex(mainvar, id, false); break;
                                case  32: BKE_libblock_free_ex(mainvar, id, false); break;
+                               case  33: BKE_libblock_free_ex(mainvar, id, false); break;
                                default:
                                        BLI_assert(0);
                                        break;
@@ -1149,7 +1136,7 @@ void BKE_main_free(Main *mainvar)
 
        BLI_spin_end((SpinLock *)mainvar->lock);
        MEM_freeN(mainvar->lock);
-       MEM_freeN(mainvar->eval_ctx);
+       DEG_evaluation_context_free(mainvar->eval_ctx);
        MEM_freeN(mainvar);
 }
 
@@ -1163,6 +1150,74 @@ void BKE_main_unlock(struct Main *bmain)
        BLI_spin_unlock((SpinLock *) bmain->lock);
 }
 
+/**
+ * Generates a raw .blend file thumbnail data from given image.
+ *
+ * \param bmain If not NULL, also store generated data in this Main.
+ * \param img ImBuf image to generate thumbnail data from.
+ * \return The generated .blend file raw thumbnail data.
+ */
+BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
+{
+       BlendThumbnail *data = NULL;
+
+       if (bmain) {
+               MEM_SAFE_FREE(bmain->blen_thumb);
+       }
+
+       if (img) {
+               const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
+               data = MEM_mallocN(sz, __func__);
+
+               IMB_rect_from_float(img);  /* Just in case... */
+               data->width = img->x;
+               data->height = img->y;
+               memcpy(data->rect, img->rect, sz - sizeof(*data));
+       }
+
+       if (bmain) {
+               bmain->blen_thumb = data;
+       }
+       return data;
+}
+
+/**
+ * Generates an image from raw .blend file thumbnail \a data.
+ *
+ * \param bmain Use this bmain->blen_thumb data if given \a data is NULL.
+ * \param data Raw .blend file thumbnail data.
+ * \return An ImBuf from given data, or NULL if invalid.
+ */
+ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
+{
+       ImBuf *img = NULL;
+
+       if (!data && bmain) {
+               data = bmain->blen_thumb;
+       }
+
+       if (data) {
+               /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail
+                *       here (we do not want to pass the first two ints!). */
+               img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata);
+               memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data));
+       }
+
+       return img;
+}
+
+/**
+ * Generates an empty (black) thumbnail for given Main.
+ */
+void BKE_main_thumbnail_create(struct Main *bmain)
+{
+       MEM_SAFE_FREE(bmain->blen_thumb);
+
+       bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__);
+       bmain->blen_thumb->width = BLEN_THUMB_SIZE;
+       bmain->blen_thumb->height = BLEN_THUMB_SIZE;
+}
+
 /* ***************** ID ************************ */
 ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name)
 {
@@ -1210,7 +1265,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
        
        for (idtest = lb->first; idtest; idtest = idtest->next) {
                /* if idtest is not a lib */ 
-               if (id != idtest && idtest->lib == NULL) {
+               if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) {
                        /* do not test alphabetic! */
                        /* optimized */
                        if (idtest->name[2] == name[0]) {
@@ -1270,7 +1325,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
                for (idtest = lb->first; idtest; idtest = idtest->next) {
                        int nrtest;
                        if ( (id != idtest) &&
-                            (idtest->lib == NULL) &&
+                            !ID_IS_LINKED_DATABLOCK(idtest) &&
                             (*name == *(idtest->name + 2)) &&
                             STREQLEN(name, idtest->name + 2, left_len) &&
                             (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)
@@ -1352,7 +1407,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
        char name[MAX_ID_NAME - 2];
 
        /* if library, don't rename */
-       if (id->lib)
+       if (ID_IS_LINKED_DATABLOCK(id))
                return false;
 
        /* if no libdata given, look up based on ID */
@@ -1397,20 +1452,18 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
  * Pull an ID out of a library (make it local). Only call this for IDs that
  * don't have other library users.
  */
-void id_clear_lib_data(Main *bmain, ID *id)
+void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist)
 {
        bNodeTree *ntree = NULL;
 
        BKE_id_lib_local_paths(bmain, id->lib, id);
 
-       if (id->flag & LIB_FAKEUSER) {
-               id->us--;
-               id->flag &= ~LIB_FAKEUSER;
-       }
+       id_fake_user_clear(id);
 
        id->lib = NULL;
-       id->flag = LIB_LOCAL;
-       new_id(which_libbase(bmain, GS(id->name)), id, NULL);
+       id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
+       if (id_in_mainlist)
+               new_id(which_libbase(bmain, GS(id->name)), id, NULL);
 
        /* internal bNodeTree blocks inside ID types below
         * also stores id->lib, make sure this stays in sync.
@@ -1418,10 +1471,24 @@ void id_clear_lib_data(Main *bmain, ID *id)
        ntree = ntreeFromID(id);
 
        if (ntree) {
-               ntree->id.lib = NULL;
+               ntreeMakeLocal(bmain, ntree, false);
+       }
+
+       if (GS(id->name) == ID_OB) {
+               Object *object = (Object *)id;
+               if (object->proxy_from != NULL) {
+                       object->proxy_from->proxy = NULL;
+                       object->proxy_from->proxy_group = NULL;
+               }
+               object->proxy = object->proxy_from = object->proxy_group = NULL;
        }
 }
 
+void id_clear_lib_data(Main *bmain, ID *id)
+{
+       id_clear_lib_data_ex(bmain, id, true);
+}
+
 /* next to indirect usage in read/writefile also in editobject.c scene.c */
 void BKE_main_id_clear_newpoins(Main *bmain)
 {
@@ -1434,17 +1501,18 @@ void BKE_main_id_clear_newpoins(Main *bmain)
                id = lbarray[a]->first;
                while (id) {
                        id->newid = NULL;
-                       id->flag &= ~LIB_NEW;
+                       id->tag &= ~LIB_TAG_NEW;
                        id = id->next;
                }
        }
 }
 
-static void lib_indirect_test_id(ID *id, Library *lib)
+static void lib_indirect_test_id(ID *id, const Library *lib)
 {
-#define LIBTAG(a)   if (a && a->id.lib) { a->id.flag &= ~LIB_INDIRECT; a->id.flag |= LIB_EXTERN; } (void)0
+#define LIBTAG(a) \
+       if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0
        
-       if (id->lib) {
+       if (ID_IS_LINKED_DATABLOCK(id)) {
                /* datablocks that were indirectly related are now direct links
                 * without this, appending data that has a link to other data will fail to write */
                if (lib && id->lib->parent == lib) {
@@ -1486,42 +1554,14 @@ static void lib_indirect_test_id(ID *id, Library *lib)
 #undef LIBTAG
 }
 
-void BKE_main_id_tag_listbase(ListBase *lb, const bool tag)
-{
-       ID *id;
-       if (tag) {
-               for (id = lb->first; id; id = id->next) {
-                       id->flag |= LIB_DOIT;
-               }
-       }
-       else {
-               for (id = lb->first; id; id = id->next) {
-                       id->flag &= ~LIB_DOIT;
-               }
-       }
-}
-
-void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const bool tag)
-{
-       ListBase *lb = which_libbase(mainvar, type);
-
-       BKE_main_id_tag_listbase(lb, tag);
-}
-
-void BKE_main_id_tag_all(struct Main *mainvar, const bool tag)
-{
-       ListBase *lbarray[MAX_LIBARRAY];
-       int a;
-
-       a = set_listbasepointers(mainvar, lbarray);
-       while (a--) {
-               BKE_main_id_tag_listbase(lbarray[a], tag);
-       }
-}
-
-/* if lib!=NULL, only all from lib local
- * bmain is almost certainly G.main */
-void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only)
+/** Make linked datablocks local.
+ *
+ * \param bmain Almost certainly G.main.
+ * \param lib If not NULL, only make local datablocks from this library.
+ * \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
+ * \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
+ */
+void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
 {
        ListBase *lbarray[MAX_LIBARRAY];
        ID *id, *idn;
@@ -1535,30 +1575,38 @@ void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only)
                        id->newid = NULL;
                        idn = id->next;      /* id is possibly being inserted again */
                        
-                       /* The check on the second line (LIB_PRE_EXISTING) is done so its
+                       /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
                         * possible to tag data you don't want to be made local, used for
                         * appending data, so any libdata already linked wont become local
                         * (very nasty to discover all your links are lost after appending)  
                         * */
-                       if (id->flag & (LIB_EXTERN | LIB_INDIRECT | LIB_NEW) &&
-                           ((untagged_only == false) || !(id->flag & LIB_PRE_EXISTING)))
+                       if (id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+                           ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
                        {
                                if (lib == NULL || id->lib == lib) {
                                        if (id->lib) {
                                                /* for Make Local > All we should be calling id_make_local,
                                                 * but doing that breaks append (see #36003 and #36006), we
                                                 * we should make it work with all datablocks and id.us==0 */
-                                               id_clear_lib_data(bmain, id); /* sets 'id->flag' */
+                                               id_clear_lib_data(bmain, id); /* sets 'id->tag' */
 
                                                /* why sort alphabetically here but not in
                                                 * id_clear_lib_data() ? - campbell */
                                                id_sort_by_name(lbarray[a], id);
                                        }
                                        else {
-                                               id->flag &= ~(LIB_EXTERN | LIB_INDIRECT | LIB_NEW);
+                                               id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+                                       }
+                               }
+
+                               if (set_fake) {
+                                       if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
+                                               /* do not set fake user on objects, groups (instancing) */
+                                               id_fake_user_set(id);
                                        }
                                }
                        }
+
                        id = idn;
                }
        }
@@ -1570,21 +1618,23 @@ void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only)
        }
 }
 
-
-void test_idbutton(char *name)
+/**
+ * Use after setting the ID's name
+ * When name exists: call 'new_id'
+ */
+void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
 {
-       /* called from buttons: when name already exists: call new_id */
        ListBase *lb;
        ID *idtest;
-       
 
-       lb = which_libbase(G.main, GS(name));
+
+       lb = which_libbase(bmain, GS(name));
        if (lb == NULL) return;
        
        /* search for id */
        idtest = BLI_findstring(lb, name + 2, offsetof(ID, name) + 2);
 
-       if (idtest && !new_id(lb, idtest, name + 2)) {
+       if (idtest && !new_id(lb, idtest, idtest->name + 2)) {
                id_sort_by_name(lb, idtest);
        }
 }
@@ -1592,13 +1642,9 @@ void test_idbutton(char *name)
 /**
  * Sets the name of a block to name, suitably adjusted for uniqueness.
  */
-void rename_id(ID *id, const char *name)
+void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
 {
-       ListBase *lb;
-
-       BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
-       lb = which_libbase(G.main, GS(id->name));
-       
+       ListBase *lb = which_libbase(bmain, GS(id->name));
        new_id(lb, id, name);
 }
 
@@ -1606,10 +1652,10 @@ void rename_id(ID *id, const char *name)
  * Returns in name the name of the block, with a 3-character prefix prepended
  * indicating whether it comes from a library, has a fake user, or no users.
  */
-void name_uiprefix_id(char *name, const ID *id)
+void BKE_id_ui_prefix(char name[MAX_ID_NAME + 1], const ID *id)
 {
-       name[0] = id->lib ? 'L' : ' ';
-       name[1] = id->flag & LIB_FAKEUSER ? 'F' : (id->us == 0) ? '0' : ' ';
+       name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ' ';
+       name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
        name[2] = ' ';
 
        strcpy(name + 3, id->name + 2);