Fix T65899, T66314, T61808: various issues appending workspaces
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 3 Jul 2019 18:36:49 +0000 (20:36 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 3 Jul 2019 18:44:04 +0000 (20:44 +0200)
This fixes crashes, wrong names and inability to append workspaces in
edit mode. We now bypass the append operator so we can easily return
a datablock pointer and work in any mode.

source/blender/editors/screen/workspace_edit.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_files_link.c

index f4138dd78476d3769362843366491f85d9e77285..e2c4331b3ba9e0da77b908d8fdf64b7ea7be15d5 100644 (file)
@@ -331,30 +331,6 @@ static void WORKSPACE_OT_delete(wmOperatorType *ot)
   ot->exec = workspace_delete_exec;
 }
 
-static bool workspace_append_activate_poll(bContext *C)
-{
-  wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
-  return WM_operator_poll(C, ot);
-}
-
-static int workspace_append(bContext *C, const char *directory, const char *idname)
-{
-  wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
-  PointerRNA opptr;
-  int retval;
-
-  WM_operator_properties_create_ptr(&opptr, ot);
-  RNA_string_set(&opptr, "directory", directory);
-  RNA_string_set(&opptr, "filename", idname);
-  RNA_boolean_set(&opptr, "autoselect", false);
-
-  retval = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &opptr);
-
-  WM_operator_properties_free(&opptr);
-
-  return retval;
-}
-
 static int workspace_append_activate_exec(bContext *C, wmOperator *op)
 {
   Main *bmain = CTX_data_main(C);
@@ -367,23 +343,20 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op)
   RNA_string_get(op->ptr, "idname", idname);
   RNA_string_get(op->ptr, "filepath", filepath);
 
-  if (workspace_append(C, filepath, idname) != OPERATOR_CANCELLED) {
-    WorkSpace *appended_workspace = BLI_findstring(
-        &bmain->workspaces, idname, offsetof(ID, name) + 2);
-    BLI_assert(appended_workspace != NULL);
+  WorkSpace *appended_workspace = (WorkSpace *)WM_file_append_datablock(
+      C, filepath, ID_WS, idname);
 
-    if (appended_workspace) {
-      /* Set defaults. */
-      BLO_update_defaults_workspace(appended_workspace, NULL);
+  if (appended_workspace) {
+    /* Set defaults. */
+    BLO_update_defaults_workspace(appended_workspace, NULL);
 
-      /* Reorder to last position. */
-      BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true);
+    /* Reorder to last position. */
+    BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true);
 
-      /* Changing workspace changes context. Do delayed! */
-      WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace);
+    /* Changing workspace changes context. Do delayed! */
+    WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace);
 
-      return OPERATOR_FINISHED;
-    }
+    return OPERATOR_FINISHED;
   }
 
   return OPERATOR_CANCELLED;
@@ -398,7 +371,6 @@ static void WORKSPACE_OT_append_activate(wmOperatorType *ot)
 
   /* api callbacks */
   ot->exec = workspace_append_activate_exec;
-  ot->poll = workspace_append_activate_poll;
 
   RNA_def_string(ot->srna,
                  "idname",
@@ -449,20 +421,17 @@ static void workspace_append_button(uiLayout *layout,
 {
   const ID *id = (ID *)workspace;
   PointerRNA opptr;
-  char lib_path[FILE_MAX_LIBEXTRA];
   const char *filepath = from_main->name;
 
   if (strlen(filepath) == 0) {
     filepath = BLO_EMBEDDED_STARTUP_BLEND;
   }
 
-  BLI_path_join(lib_path, sizeof(lib_path), filepath, BKE_idcode_to_name(GS(id->name)), NULL);
-
   BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate"));
   uiItemFullO_ptr(
       layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
   RNA_string_set(&opptr, "idname", id->name + 2);
-  RNA_string_set(&opptr, "filepath", lib_path);
+  RNA_string_set(&opptr, "filepath", filepath);
 }
 
 static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v)
index d3c1e5f146d3510906992a20ad41840e7ddaaaf8..04e3f7e88dca9f3b1fa8baab2c8c79b9d46031a0 100644 (file)
@@ -42,6 +42,7 @@ extern "C" {
 struct ARegion;
 struct GHashIterator;
 struct GPUViewport;
+struct ID;
 struct IDProperty;
 struct ImBuf;
 struct ImageFormatData;
@@ -178,6 +179,10 @@ void WM_autosave_init(struct wmWindowManager *wm);
 void WM_recover_last_session(struct bContext *C, struct ReportList *reports);
 void WM_file_tag_modified(void);
 
+struct ID *WM_file_append_datablock(struct bContext *C,
+                                    const char *filepath,
+                                    const short id_code,
+                                    const char *id_name);
 void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports);
 
 /* mouse cursors */
index 069dc8f441feec321703f7ad1529f5c156a39f5d..5a6606984ba945ce99982384c4e5e241eba4e26d 100644 (file)
@@ -618,10 +618,50 @@ void WM_OT_append(wmOperatorType *ot)
       "Localize all appended data, including those indirectly linked from other libraries");
 }
 
-/** \name Reload/relocate libraries.
+/** \name Append single datablock and return it.
+ *
+ * Used for appending workspace from startup files.
  *
  * \{ */
 
+ID *WM_file_append_datablock(bContext *C,
+                             const char *filepath,
+                             const short id_code,
+                             const char *id_name)
+{
+  Main *bmain = CTX_data_main(C);
+
+  /* Tag everything so we can make local only the new datablock. */
+  BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+  /* Define working data, with just the one item we want to append. */
+  WMLinkAppendData *lapp_data = wm_link_append_data_new(0);
+
+  wm_link_append_data_library_add(lapp_data, filepath);
+  WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL);
+  BLI_BITMAP_ENABLE(item->libraries, 0);
+
+  /* Link datablock. */
+  Scene *scene = CTX_data_scene(C);
+  ViewLayer *view_layer = CTX_data_view_layer(C);
+  View3D *v3d = CTX_wm_view3d(C);
+  wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
+
+  /* Get linked datablock and free working data. */
+  ID *id = item->new_id;
+  wm_link_append_data_free(lapp_data);
+
+  /* Make datablock local. */
+  BKE_library_make_local(bmain, NULL, NULL, true, false);
+
+  /* Clear pre existing tag. */
+  BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+  return id;
+}
+
+/** \} */
+
 static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
 {
   Library *lib;