Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJulian Eisel <eiseljulian@gmail.com>2017-06-01 20:56:58 +0300
committerJulian Eisel <eiseljulian@gmail.com>2017-06-01 20:59:37 +0300
commit7f564d74f9edaaa41ce27c6e854869096f70b4da (patch)
tree4574418151f198fa0bab327ec58fa36819c2028e /source
parent0af93cf1ac276456619fc2e903c52a97fd09b9fb (diff)
Main Workspace Integration
This commit does the main integration of workspaces, which is a design we agreed on during the 2.8 UI workshop (see https://wiki.blender.org/index.php/Dev:2.8/UI/Workshop_Writeup) Workspaces should generally be stable, I'm not aware of any remaining bugs (or I've forgotten them :) ). If you find any, let me know! (Exception: mode switching button might get out of sync with actual mode in some cases, would consider that a limitation/ToDo. Needs to be resolved at some point.) == Main Changes/Features * Introduces the new Workspaces as data-blocks. * Allow storing a number of custom workspaces as part of the user configuration. Needs further work to allow adding and deleting individual workspaces. * Bundle a default workspace configuration with Blender (current screen-layouts converted to workspaces). * Pressing button to add a workspace spawns a menu to select between "Duplicate Current" and the workspaces from the user configuration. If no workspaces are stored in the user configuration, the default workspaces are listed instead. * Store screen-layouts (`bScreen`) per workspace. * Store an active screen-layout per workspace. Changing the workspace will enable this layout. * Store active mode in workspace. Changing the workspace will also enter the mode of the new workspace. (Note that we still store the active mode in the object, moving this completely to workspaces is a separate project.) * Store an active render layer per workspace. * Moved mode switch from 3D View header to Info Editor header. * Store active scene in window (not directly workspace related, but overlaps quite a bit). * Removed 'Use Global Scene' User Preference option. * Compatibility with old files - a new workspace is created for every screen-layout of old files. Old Blender versions should be able to read files saved with workspace support as well. * Default .blend only contains one workspace ("General"). * Support appending workspaces. Opening files without UI and commandline rendering should work fine. Note that the UI is temporary! We plan to introduce a new global topbar that contains the workspace options and tabs for switching workspaces. == Technical Notes * Workspaces are data-blocks. * Adding and removing `bScreen`s should be done through `ED_workspace_layout` API now. * A workspace can be active in multiple windows at the same time. * The mode menu (which is now in the Info Editor header) doesn't display "Grease Pencil Edit" mode anymore since its availability depends on the active editor. Will be fixed by making Grease Pencil an own object type (as planned). * The button to change the active workspace object mode may get out of sync with the mode of the active object. Will either be resolved by moving mode out of object data, or we'll disable workspace modes again (there's a `#define USE_WORKSPACE_MODE` for that). * Screen-layouts (`bScreen`) are IDs and thus stored in a main list-base. Had to add a wrapper `WorkSpaceLayout` so we can store them in a list-base within workspaces, too. On the long run we could completely replace `bScreen` by workspace structs. * `WorkSpace` types use some special compiler trickery to allow marking structs and struct members as private. BKE_workspace API should be used for accessing those. * Added scene operators `SCENE_OT_`. Was previously done through screen operators. == BPY API Changes * Removed `Screen.scene`, added `Window.scene` * Removed `UserPreferencesView.use_global_scene` * Added `Context.workspace`, `Window.workspace` and `BlendData.workspaces` * Added `bpy.types.WorkSpace` containing `screens`, `object_mode` and `render_layer` * Added Screen.layout_name for the layout name that'll be displayed in the UI (may differ from internal name) == What's left? * There are a few open design questions (T50521). We should find the needed answers and implement them. * Allow adding and removing individual workspaces from workspace configuration (needs UI design). * Get the override system ready and support overrides per workspace. * Support custom UI setups as part of workspaces (hidden panels, hidden buttons, customizable toolbars, etc). * Allow enabling add-ons per workspace. * Support custom workspace keymaps. * Remove special exception for workspaces in linking code (so they're always appended, never linked). Depends on a few things, so best to solve later. * Get the topbar done. * Workspaces need a proper icon, current one is just a placeholder :) Reviewed By: campbellbarton, mont29 Tags: #user_interface, #bf_blender_2.8 Maniphest Tasks: T50521 Differential Revision: https://developer.blender.org/D2451
Diffstat (limited to 'source')
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/BKE_appdir.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h4
-rw-r--r--source/blender/blenkernel/BKE_context.h1
-rw-r--r--source/blender/blenkernel/BKE_layer.h1
-rw-r--r--source/blender/blenkernel/BKE_library.h2
-rw-r--r--source/blender/blenkernel/BKE_main.h1
-rw-r--r--source/blender/blenkernel/BKE_scene.h12
-rw-r--r--source/blender/blenkernel/BKE_screen.h5
-rw-r--r--source/blender/blenkernel/BKE_workspace.h116
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c94
-rw-r--r--source/blender/blenkernel/intern/context.c18
-rw-r--r--source/blender/blenkernel/intern/idcode.c5
-rw-r--r--source/blender/blenkernel/intern/image.c6
-rw-r--r--source/blender/blenkernel/intern/layer.c23
-rw-r--r--source/blender/blenkernel/intern/library.c12
-rw-r--r--source/blender/blenkernel/intern/library_query.c45
-rw-r--r--source/blender/blenkernel/intern/library_remap.c4
-rw-r--r--source/blender/blenkernel/intern/scene.c10
-rw-r--r--source/blender/blenkernel/intern/screen.c36
-rw-r--r--source/blender/blenkernel/intern/workspace.c399
-rw-r--r--source/blender/blenloader/BLO_readfile.h20
-rw-r--r--source/blender/blenloader/intern/readfile.c286
-rw-r--r--source/blender/blenloader/intern/versioning_280.c133
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c40
-rw-r--r--source/blender/blenloader/intern/writefile.c53
-rw-r--r--source/blender/blentranslation/BLT_translation.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc1
-rw-r--r--source/blender/editors/CMakeLists.txt3
-rw-r--r--source/blender/editors/animation/anim_markers.c4
-rw-r--r--source/blender/editors/include/ED_scene.h40
-rw-r--r--source/blender/editors/include/ED_screen.h47
-rw-r--r--source/blender/editors/include/ED_view3d.h7
-rw-r--r--source/blender/editors/interface/interface.c11
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c19
-rw-r--r--source/blender/editors/interface/interface_regions.c7
-rw-r--r--source/blender/editors/interface/interface_templates.c4
-rw-r--r--source/blender/editors/interface/interface_utils.c3
-rw-r--r--source/blender/editors/interface/resources.c17
-rw-r--r--source/blender/editors/object/object_add.c4
-rw-r--r--source/blender/editors/object/object_edit.c20
-rw-r--r--source/blender/editors/object/object_select.c8
-rw-r--r--source/blender/editors/render/render_internal.c10
-rw-r--r--source/blender/editors/render/render_update.c4
-rw-r--r--source/blender/editors/render/render_view.c15
-rw-r--r--source/blender/editors/scene/CMakeLists.txt43
-rw-r--r--source/blender/editors/scene/scene_edit.c202
-rw-r--r--source/blender/editors/screen/CMakeLists.txt3
-rw-r--r--source/blender/editors/screen/area.c11
-rw-r--r--source/blender/editors/screen/screen_context.c8
-rw-r--r--source/blender/editors/screen/screen_draw.c9
-rw-r--r--source/blender/editors/screen/screen_edit.c427
-rw-r--r--source/blender/editors/screen/screen_intern.h11
-rw-r--r--source/blender/editors/screen/screen_ops.c229
-rw-r--r--source/blender/editors/screen/workspace_edit.c426
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c198
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c16
-rw-r--r--source/blender/editors/space_action/space_action.c6
-rw-r--r--source/blender/editors/space_api/spacetypes.c3
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c15
-rw-r--r--source/blender/editors/space_clip/clip_editor.c11
-rw-r--r--source/blender/editors/space_file/file_utils.c1
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_graph/space_graph.c5
-rw-r--r--source/blender/editors/space_image/space_image.c7
-rw-r--r--source/blender/editors/space_info/space_info.c3
-rw-r--r--source/blender/editors/space_nla/space_nla.c5
-rw-r--r--source/blender/editors/space_node/node_edit.c2
-rw-r--r--source/blender/editors/space_node/space_node.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h2
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c12
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c5
-rw-r--r--source/blender/editors/space_time/space_time.c5
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c30
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c41
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c10
-rw-r--r--source/blender/editors/transform/transform_ops.c4
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c1
-rw-r--r--source/blender/makesdna/DNA_ID.h5
-rw-r--r--source/blender/makesdna/DNA_defs.h6
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h6
-rw-r--r--source/blender/makesdna/DNA_screen_types.h8
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h2
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h10
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h132
-rw-r--r--source/blender/makesdna/intern/makesdna.c18
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesrna/intern/makesrna.c1
-rw-r--r--source/blender/makesrna/intern/rna_ID.c3
-rw-r--r--source/blender/makesrna/intern/rna_context.c11
-rw-r--r--source/blender/makesrna/intern/rna_internal.h2
-rw-r--r--source/blender/makesrna/intern/rna_main.c7
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c32
-rw-r--r--source/blender/makesrna/intern/rna_scene.c8
-rw-r--r--source/blender/makesrna/intern/rna_screen.c86
-rw-r--r--source/blender/makesrna/intern/rna_space.c53
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c10
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c5
-rw-r--r--source/blender/makesrna/intern/rna_wm.c142
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c144
-rw-r--r--source/blender/python/intern/bpy_library_load.c7
-rw-r--r--source/blender/python/intern/bpy_rna.c2
-rw-r--r--source/blender/windowmanager/WM_api.h15
-rw-r--r--source/blender/windowmanager/WM_types.h11
-rw-r--r--source/blender/windowmanager/intern/wm.c8
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c69
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c105
-rw-r--r--source/blender/windowmanager/intern/wm_files.c72
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c60
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c9
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c15
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c4
-rw-r--r--source/blender/windowmanager/intern/wm_window.c244
-rw-r--r--source/blender/windowmanager/wm_files.h1
-rw-r--r--source/blender/windowmanager/wm_window.h4
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c8
-rw-r--r--source/creator/CMakeLists.txt6
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp3
126 files changed, 3610 insertions, 1060 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 448e66ec540..1788c889719 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -90,6 +90,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view2d_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_windowmanager_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_workspace_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_world_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_movieclip_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_tracking_types.h
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index ac8f861fa56..ffbdc6972f4 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -82,6 +82,7 @@ enum {
#define BLENDER_STARTUP_FILE "startup.blend"
#define BLENDER_USERPREF_FILE "userpref.blend"
+#define BLENDER_WORKSPACES_FILE "workspaces.blend"
#define BLENDER_QUIT_FILE "quit.blend"
#define BLENDER_BOOKMARK_FILE "bookmarks.txt"
#define BLENDER_HISTORY_FILE "recent-files.txt"
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index bc3db11f34b..ae87f1097d1 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 0
+#define BLENDER_SUBVERSION 1
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index ac58451e412..d9fff5343b0 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -60,6 +60,10 @@ struct UserDef *BKE_blendfile_userdef_read_from_memory(
int BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
+struct WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, struct ReportList *reports);
+bool BKE_blendfile_workspace_config_write(struct Main *bmain, const char *filepath, struct ReportList *reports);
+void BKE_blendfile_workspace_config_data_free(struct WorkspaceConfigFileData *workspace_config);
+
/* partial blend file writing */
void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index c911d9ec952..b71f5a4aa8e 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -145,6 +145,7 @@ void CTX_py_dict_set(bContext *C, void *value);
struct wmWindowManager *CTX_wm_manager(const bContext *C);
struct wmWindow *CTX_wm_window(const bContext *C);
+struct WorkSpace *CTX_wm_workspace(const bContext *C);
struct bScreen *CTX_wm_screen(const bContext *C);
struct ScrArea *CTX_wm_area(const bContext *C);
struct SpaceLink *CTX_wm_space_data(const bContext *C);
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index c6ec7e9df25..17ab0bf0d2b 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -60,6 +60,7 @@ struct SceneLayer;
void BKE_layer_exit(void);
struct SceneLayer *BKE_scene_layer_render_active(const struct Scene *scene);
+struct SceneLayer *BKE_scene_layer_context_active_ex(const struct Main *bmain, const struct Scene *scene);
struct SceneLayer *BKE_scene_layer_context_active(const struct Scene *scene);
struct SceneLayer *BKE_scene_layer_add(struct Scene *scene, const char *name);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 6649cfbb585..dcc15c66c3e 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -95,7 +95,7 @@ void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_ma
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 35
+#define MAX_LIBARRAY 36
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
/* Main API */
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 387045878f3..a616429fa95 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -123,6 +123,7 @@ typedef struct Main {
ListBase mask;
ListBase linestyle;
ListBase cachefiles;
+ ListBase workspaces;
char id_tag_update[MAX_LIBARRAY];
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 454fba0126e..cd59ef98903 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -52,11 +52,13 @@ struct SceneLayer;
struct UnitSettings;
struct Main;
-#define SCE_COPY_NEW 0
-#define SCE_COPY_EMPTY 1
-#define SCE_COPY_LINK_OB 2
-#define SCE_COPY_LINK_DATA 3
-#define SCE_COPY_FULL 4
+typedef enum eSceneCopyMethod {
+ SCE_COPY_NEW = 0,
+ SCE_COPY_EMPTY = 1,
+ SCE_COPY_LINK_OB = 2,
+ SCE_COPY_LINK_DATA = 3,
+ SCE_COPY_FULL = 4,
+} eSceneCopyMethod;
/* Use as the contents of a 'for' loop: for (SETLOOPER(...)) { ... */
#define SETLOOPER(_sce_basis, _sce_iter, _base) \
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 7def41d0540..645a99d592f 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -308,11 +308,12 @@ unsigned int BKE_screen_view3d_layer_active(
unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene);
-void BKE_screen_view3d_scene_sync(struct bScreen *sc);
-void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene);
+void BKE_screen_view3d_scene_sync(struct bScreen *sc, struct Scene *scene);
void BKE_screen_view3d_twmode_remove(struct View3D *v3d, const int i);
void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, struct Scene *scene, const int i);
void BKE_screen_gpu_fx_validate(struct GPUFXSettings *fx_settings);
+bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* zoom factor conversion */
float BKE_screen_view3d_zoom_to_fac(float camzoom);
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
new file mode 100644
index 00000000000..e7eaf72dd15
--- /dev/null
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -0,0 +1,116 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_workspace.h
+ * \ingroup bke
+ */
+
+#ifndef __BKE_WORKSPACE_H__
+#define __BKE_WORKSPACE_H__
+
+#include "BLI_compiler_attrs.h"
+
+struct bScreen;
+
+typedef struct WorkSpace WorkSpace;
+typedef struct WorkSpaceInstanceHook WorkSpaceInstanceHook;
+typedef struct WorkSpaceLayout WorkSpaceLayout;
+
+/**
+ * Plan is to store the object-mode per workspace, not per object anymore.
+ * However, there's quite some work to be done for that, so for now, there is just a basic
+ * implementation of an object <-> workspace object-mode syncing for testing, with some known
+ * problems. Main problem being that the modes can get out of sync when changing object selection.
+ * Would require a pile of temporary changes to always sync modes when changing selection. So just
+ * leaving this here for some testing until object-mode is really a workspace level setting.
+ */
+#define USE_WORKSPACE_MODE
+
+
+/* -------------------------------------------------------------------- */
+/* Create, delete, init */
+
+WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name);
+void BKE_workspace_free(WorkSpace *workspace);
+void BKE_workspace_remove(struct Main *bmain, WorkSpace *workspace);
+
+WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain);
+void BKE_workspace_instance_hook_free(const struct Main *bmain, WorkSpaceInstanceHook *hook);
+
+struct WorkSpaceLayout *BKE_workspace_layout_add(
+ WorkSpace *workspace,
+ struct bScreen *screen,
+ const char *name) ATTR_NONNULL();
+void BKE_workspace_layout_remove(
+ struct Main *bmain,
+ WorkSpace *workspace, WorkSpaceLayout *layout) ATTR_NONNULL();
+
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+WorkSpaceLayout *BKE_workspace_layout_find(
+ const WorkSpace *workspace, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+WorkSpaceLayout *BKE_workspace_layout_find_global(
+ const struct Main *bmain, const struct bScreen *screen,
+ WorkSpace **r_workspace) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
+
+WorkSpaceLayout *BKE_workspace_layout_iter_circular(
+ const WorkSpace *workspace, WorkSpaceLayout *start,
+ bool (*callback)(const WorkSpaceLayout *layout, void *arg),
+ void *arg, const bool iter_backward);
+
+
+/* -------------------------------------------------------------------- */
+/* Getters/Setters */
+
+#define GETTER_ATTRS ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
+#define SETTER_ATTRS ATTR_NONNULL(1)
+
+WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) SETTER_ATTRS;
+WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout) SETTER_ATTRS;
+struct bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_screen_set(
+ WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct bScreen *screen) SETTER_ATTRS;
+enum ObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace) GETTER_ATTRS;
+#ifdef USE_WORKSPACE_MODE
+void BKE_workspace_object_mode_set(WorkSpace *workspace, const enum ObjectMode mode) SETTER_ATTRS;
+#endif
+struct SceneLayer *BKE_workspace_render_layer_get(const WorkSpace *workspace) GETTER_ATTRS;
+void BKE_workspace_render_layer_set(WorkSpace *workspace, struct SceneLayer *layer) SETTER_ATTRS;
+struct ListBase *BKE_workspace_layouts_get(WorkSpace *workspace) GETTER_ATTRS;
+
+const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout) GETTER_ATTRS;
+void BKE_workspace_layout_name_set(
+ WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name) ATTR_NONNULL();
+struct bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout) GETTER_ATTRS;
+void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, struct bScreen *screen) SETTER_ATTRS;
+
+WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+ const WorkSpaceInstanceHook *hook, const WorkSpace *workspace) GETTER_ATTRS;
+void BKE_workspace_hook_layout_for_workspace_set(
+ WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout) ATTR_NONNULL();
+
+#undef GETTER_ATTRS
+#undef SETTER_ATTRS
+
+#endif /* __BKE_WORKSPACE_H__ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1ddc6fce818..71aeb393c97 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -190,6 +190,7 @@ set(SRC
intern/tracking_stabilize.c
intern/tracking_util.c
intern/unit.c
+ intern/workspace.c
intern/world.c
intern/writeavi.c
intern/writeframeserver.c
@@ -302,6 +303,7 @@ set(SRC
BKE_tracking.h
BKE_unit.h
BKE_utildefines.h
+ BKE_workspace.h
BKE_world.h
BKE_writeavi.h
BKE_writeframeserver.h
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index a521d671ea4..9e244246e16 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -48,11 +49,13 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_ipo.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -93,7 +96,7 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
{
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->scene == scene) {
+ if (win->scene == scene) {
return true;
}
}
@@ -162,17 +165,22 @@ static void setup_app_data(
* (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
* see: T43424
*/
+ wmWindow *win;
bScreen *curscreen = NULL;
+ SceneLayer *cur_render_layer;
bool track_undo_scene;
/* comes from readfile.c */
SWAP(ListBase, G.main->wm, bfd->main->wm);
+ SWAP(ListBase, G.main->workspaces, bfd->main->workspaces);
SWAP(ListBase, G.main->screen, bfd->main->screen);
- /* we re-use current screen */
+ /* we re-use current window and screen */
+ win = CTX_wm_window(C);
curscreen = CTX_wm_screen(C);
- /* but use new Scene pointer */
+ /* but use Scene pointer from new file */
curscene = bfd->curscene;
+ cur_render_layer = bfd->cur_render_layer;
track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
@@ -183,32 +191,31 @@ static void setup_app_data(
if (curscene == NULL) {
curscene = BKE_scene_add(bfd->main, "Empty");
}
+ if (cur_render_layer == NULL) {
+ /* fallback to scene layer */
+ cur_render_layer = BKE_scene_layer_render_active(curscene);
+ }
if (track_undo_scene) {
/* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
* replace it with 'curscene' if its needed */
}
- else {
- /* and we enforce curscene to be in current screen */
- if (curscreen) {
- /* can run in bgmode */
- curscreen->scene = curscene;
- }
+ /* and we enforce curscene to be in current screen */
+ else if (win) { /* can run in bgmode */
+ win->scene = curscene;
}
/* BKE_blender_globals_clear will free G.main, here we can still restore pointers */
- blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
- /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
- if (curscreen) {
- curscene = curscreen->scene;
+ blo_lib_link_restore(bfd->main, CTX_wm_manager(C), curscene, cur_render_layer);
+ if (win) {
+ curscene = win->scene;
}
if (track_undo_scene) {
wmWindowManager *wm = bfd->main->wm.first;
if (wm_scene_is_visible(wm, bfd->curscene) == false) {
curscene = bfd->curscene;
- curscreen->scene = curscene;
- BKE_screen_view3d_scene_sync(curscreen);
+ BKE_screen_view3d_scene_sync(curscreen, curscene);
}
}
}
@@ -262,12 +269,14 @@ static void setup_app_data(
/* this can happen when active scene was lib-linked, and doesn't exist anymore */
if (CTX_data_scene(C) == NULL) {
+ wmWindow *win = CTX_wm_window(C);
+
/* in case we don't even have a local scene, add one */
if (!G.main->scene.first)
BKE_scene_add(G.main, "Empty");
CTX_data_scene_set(C, G.main->scene.first);
- CTX_wm_screen(C)->scene = CTX_data_scene(C);
+ win->scene = CTX_data_scene(C);
curscene = CTX_data_scene(C);
}
@@ -316,12 +325,10 @@ static void setup_app_data(
wmWindowManager *wm = G.main->wm.first;
if (wm) {
- wmWindow *win;
-
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen && win->screen->scene) /* zealous check... */
- if (win->screen->scene != curscene)
- BKE_scene_set_background(G.main, win->screen->scene);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene && win->scene != curscene) {
+ BKE_scene_set_background(G.main, win->scene);
+ }
}
}
}
@@ -509,6 +516,49 @@ int BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
return retval;
}
+WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, ReportList *reports)
+{
+ BlendFileData *bfd;
+ WorkspaceConfigFileData *workspace_config = NULL;
+
+ bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_USERDEF);
+ if (bfd) {
+ workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__);
+ workspace_config->main = bfd->main;
+ workspace_config->workspaces = bfd->main->workspaces;
+
+ MEM_freeN(bfd);
+ }
+
+ return workspace_config;
+}
+
+bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports)
+{
+ int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+ bool retval = false;
+
+ BKE_blendfile_write_partial_begin(bmain);
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
+ }
+
+ if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) {
+ retval = true;
+ }
+
+ BKE_blendfile_write_partial_end(bmain);
+
+ return retval;
+}
+
+void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config)
+{
+ BKE_main_free(workspace_config->main);
+ MEM_freeN(workspace_config);
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index ec0e14d814f..7f24f1c2e5e 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -53,6 +53,7 @@
#include "BKE_main.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
@@ -69,6 +70,7 @@ struct bContext {
struct {
struct wmWindowManager *manager;
struct wmWindow *window;
+ struct WorkSpace *workspace;
struct bScreen *screen;
struct ScrArea *area;
struct ARegion *region;
@@ -630,6 +632,11 @@ wmWindow *CTX_wm_window(const bContext *C)
return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window);
}
+WorkSpace *CTX_wm_workspace(const bContext *C)
+{
+ return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace);
+}
+
bScreen *CTX_wm_screen(const bContext *C)
{
return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen);
@@ -829,9 +836,11 @@ void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
void CTX_wm_window_set(bContext *C, wmWindow *win)
{
C->wm.window = win;
- C->wm.screen = (win) ? win->screen : NULL;
- if (C->wm.screen)
- C->data.scene = C->wm.screen->scene;
+ if (win) {
+ C->data.scene = win->scene;
+ }
+ C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL;
+ C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL;
C->wm.area = NULL;
C->wm.region = NULL;
}
@@ -839,9 +848,6 @@ void CTX_wm_window_set(bContext *C, wmWindow *win)
void CTX_wm_screen_set(bContext *C, bScreen *screen)
{
C->wm.screen = screen;
- if (C->wm.screen) {
- CTX_data_scene_set(C, C->wm.screen->scene);
- }
C->wm.area = NULL;
C->wm.region = NULL;
}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 70d037d85f3..e905eaeed76 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -82,7 +82,7 @@ static IDType idtypes[] = {
{ ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, 0 },
+ { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE },
{ ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
{ ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE },
{ ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE },
@@ -91,6 +91,7 @@ static IDType idtypes[] = {
{ ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+ { ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE },
/** Keep last, not an ID exactly, only include for completeness */
{ ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
@@ -210,6 +211,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(WO);
+ CASE_IDFILTER(WS);
default:
return 0;
}
@@ -303,6 +305,7 @@ int BKE_idcode_to_index(const short idcode)
CASE_IDINDEX(VF);
CASE_IDINDEX(WM);
CASE_IDINDEX(WO);
+ CASE_IDINDEX(WS);
}
BLI_assert(0);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 9b28d9732e5..7ee4afd052d 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -81,6 +81,7 @@
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_sequencer.h" /* seq_foreground_frame_get() */
+#include "BKE_workspace.h"
#include "BLF_api.h"
@@ -2544,8 +2545,9 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
/* image window, compo node users */
for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_VIEW3D) {
View3D *v3d = sa->spacedata.first;
BGpic *bgpic;
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index d2fa09fa9e9..b088c7b4745 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -38,12 +38,14 @@
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_workspace.h"
#include "DNA_ID.h"
#include "DNA_layer_types.h"
#include "DNA_object_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
#include "DRW_engine.h"
@@ -76,14 +78,25 @@ SceneLayer *BKE_scene_layer_render_active(const Scene *scene)
}
/**
- * Returns the SceneLayer to be used for drawing, outliner, and
- * other context related areas.
+ * Returns the SceneLayer to be used for drawing, outliner, and other context related areas.
*/
+SceneLayer *BKE_scene_layer_context_active_ex(const Main *bmain, const Scene *UNUSED(scene))
+{
+ /* XXX We should really pass the workspace as argument, but would require
+ * some bigger changes since it's often not available where we call this.
+ * Just working around this by getting active window from WM for now */
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ /* Called on startup, so 'winactive' may not be set, in that case fall back to first window. */
+ wmWindow *win = wm->winactive ? wm->winactive : wm->windows.first;
+ const WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ return BKE_workspace_render_layer_get(workspace);
+ }
+
+ return NULL;
+}
SceneLayer *BKE_scene_layer_context_active(const Scene *scene)
{
- /* waiting for workspace to get the layer from context*/
- TODO_LAYER_CONTEXT;
- return BKE_scene_layer_render_active(scene);
+ return BKE_scene_layer_context_active_ex(G.main, scene);
}
/**
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 4da2108b9d0..b81465a1b1d 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -70,6 +70,7 @@
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -471,7 +472,11 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_CF:
if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
return true;
+ case ID_WS:
case ID_SCR:
+ /* A bit special: can be appended but not linked. Return false
+ * since supporting make-local doesn't make much sense. */
+ return false;
case ID_LI:
case ID_KE:
case ID_WM:
@@ -578,6 +583,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
case ID_CF:
if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id);
return true;
+ case ID_WS:
case ID_SCE:
case ID_LI:
case ID_SCR:
@@ -693,6 +699,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->paintcurves);
case ID_CF:
return &(mainlib->cachefiles);
+ case ID_WS:
+ return &(mainlib->workspaces);
}
return NULL;
}
@@ -838,6 +846,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_OB] = &(main->object);
lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */
lb[INDEX_ID_SCE] = &(main->scene);
+ lb[INDEX_ID_WS] = &(main->workspaces); /* before wm, so it's freed after it! */
lb[INDEX_ID_WM] = &(main->wm);
lb[INDEX_ID_MSK] = &(main->mask);
@@ -967,6 +976,9 @@ void *BKE_libblock_alloc_notest(short type)
case ID_CF:
id = MEM_callocN(sizeof(CacheFile), "Cache File");
break;
+ case ID_WS:
+ id = MEM_callocN(sizeof(WorkSpace), "Workspace");
+ break;
}
return id;
}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 0c89a5bea42..d2ee11cc397 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -61,6 +61,8 @@
#include "DNA_sound_types.h"
#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
@@ -83,6 +85,7 @@
#include "BKE_sca.h"
#include "BKE_sequencer.h"
#include "BKE_tracking.h"
+#include "BKE_workspace.h"
#define FOREACH_FINALIZE _finalize
@@ -746,13 +749,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
- case ID_SCR:
- {
- bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE);
- break;
- }
-
case ID_WO:
{
World *world = (World *) id;
@@ -963,6 +959,38 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
break;
}
+
+ case ID_WM:
+ {
+ wmWindowManager *wm = (wmWindowManager *)id;
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
+
+ CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
+
+ CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
+ /* allow callback to set a different workspace */
+ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ }
+ break;
+ }
+
+ case ID_WS:
+ {
+ WorkSpace *workspace = (WorkSpace *)id;
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ CALLBACK_INVOKE(screen, IDWALK_CB_NOP);
+ /* allow callback to set a different screen */
+ BKE_workspace_layout_screen_set(layout, screen);
+ }
+
+ break;
+ }
case ID_GD:
{
bGPdata *gpencil = (bGPdata *) id;
@@ -974,11 +1002,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
/* Nothing needed for those... */
+ case ID_SCR:
case ID_IM:
case ID_VF:
case ID_TXT:
case ID_SO:
- case ID_WM:
case ID_PAL:
case ID_PC:
case ID_CF:
@@ -1106,6 +1134,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
case ID_LS:
return (ELEM(id_type_used, ID_TE, ID_OB));
+ case ID_WS:
case ID_IM:
case ID_VF:
case ID_TXT:
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 02128ae9c3a..235b10dd1da 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -106,6 +106,7 @@
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
@@ -883,6 +884,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b
case ID_CF:
BKE_cachefile_free((CacheFile *)id);
break;
+ case ID_WS:
+ BKE_workspace_free((WorkSpace *)id);
+ break;
}
/* avoid notifying on removed data */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 9de3ab5a93b..92f5dade0a5 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -93,6 +93,7 @@
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_unit.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
@@ -1004,7 +1005,7 @@ BaseLegacy *BKE_scene_base_find(Scene *scene, Object *ob)
/**
* Sets the active scene, mainly used when running in background mode (``--scene`` command line argument).
* This is also called to set the scene directly, bypassing windowing code.
- * Otherwise #ED_screen_set_scene is used when changing scenes by the user.
+ * Otherwise #WM_window_change_active_scene is used when changing scenes by the user.
*/
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
@@ -1442,8 +1443,8 @@ static bool check_rendered_viewport_visible(Main *bmain)
wmWindowManager *wm = bmain->wm.first;
wmWindow *window;
for (window = wm->windows.first; window != NULL; window = window->next) {
- bScreen *screen = window->screen;
- Scene *scene = screen->scene;
+ const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Scene *scene = window->scene;
ScrArea *area;
RenderEngineType *type = RE_engines_find(scene->r.engine);
if ((type->draw_engine != NULL) || (type->render_to_view == NULL)) {
@@ -1755,6 +1756,9 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base)
/* for the first loop we should get the layer from context */
SceneLayer *sl = BKE_scene_layer_context_active((*sce_iter));
+ /* TODO For first scene (non-background set), we should pass the render layer as argument.
+ * In some cases we want it to be the workspace one, in other the scene one. */
+ TODO_LAYER;
if (sl->object_bases.first) {
return (Base *)sl->object_bases.first;
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index c5d00d63b6d..b1f8f574b7e 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -596,7 +596,7 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
}
}
-void BKE_screen_view3d_scene_sync(bScreen *sc)
+void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
{
/* are there cameras in the views that are not in the scene? */
ScrArea *sa;
@@ -605,41 +605,25 @@ void BKE_screen_view3d_scene_sync(bScreen *sc)
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *) sl;
- BKE_screen_view3d_sync(v3d, sc->scene);
+ BKE_screen_view3d_sync(v3d, scene);
}
}
}
}
-void BKE_screen_view3d_main_sync(ListBase *screen_lb, Scene *scene)
-{
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *sl;
-
- /* from scene copy to the other views */
- for (sc = screen_lb->first; sc; sc = sc->id.next) {
- if (sc->scene != scene)
- continue;
-
- for (sa = sc->areabase.first; sa; sa = sa->next)
- for (sl = sa->spacedata.first; sl; sl = sl->next)
- if (sl->spacetype == SPACE_VIEW3D)
- BKE_screen_view3d_sync((View3D *)sl, scene);
- }
-}
-
+/* XXX apply D2687 */
void BKE_screen_view3d_twmode_remove(View3D *v3d, const int i)
{
const int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
if (selected_index == i) {
- v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
+ v3d->twmode = V3D_MANIP_GLOBAL;
}
else if (selected_index > i) {
v3d->twmode--;
}
}
+/* XXX apply D2687 */
void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, Scene *scene, const int i)
{
bScreen *sc;
@@ -700,3 +684,13 @@ void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings)
GPU_fx_compositor_init_ssao_settings(fx_ssao);
}
}
+
+bool BKE_screen_is_fullscreen_area(const bScreen *screen)
+{
+ return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
+}
+
+bool BKE_screen_is_used(const bScreen *screen)
+{
+ return (screen->winid != 0);
+}
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
new file mode 100644
index 00000000000..8afad317dce
--- /dev/null
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -0,0 +1,399 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/workspace.c
+ * \ingroup bke
+ */
+
+/* allow accessing private members of DNA_workspace_types.h */
+#define DNA_PRIVATE_WORKSPACE_ALLOW
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_workspace.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Internal utils */
+
+static void workspace_layout_name_set(
+ WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ BLI_strncpy(layout->name, new_name, sizeof(layout->name));
+ BLI_uniquename(&workspace->layouts, layout, "Layout", '.', offsetof(WorkSpaceLayout, name), sizeof(layout->name));
+}
+
+/**
+ * This should only be used directly when it is to be expected that there isn't
+ * a layout within \a workspace that wraps \a screen. Usually - especially outside
+ * of BKE_workspace - #BKE_workspace_layout_find should be used!
+ */
+static WorkSpaceLayout *workspace_layout_find_exec(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen));
+}
+
+static void workspace_relation_add(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__);
+ relation->parent = parent;
+ relation->value = data;
+ /* add to head, if we switch back to it soon we find it faster. */
+ BLI_addhead(relation_list, relation);
+}
+static void workspace_relation_remove(
+ ListBase *relation_list, WorkSpaceDataRelation *relation)
+{
+ BLI_remlink(relation_list, relation);
+ MEM_freeN(relation);
+}
+
+static void workspace_relation_ensure_updated(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ relation->value = data;
+ /* reinsert at the head of the list, so that more commonly used relations are found faster. */
+ BLI_remlink(relation_list, relation);
+ BLI_addhead(relation_list, relation);
+ }
+ else {
+ /* no matching relation found, add new one */
+ workspace_relation_add(relation_list, parent, data);
+ }
+}
+
+static void *workspace_relation_get_data_matching_parent(
+ const ListBase *relation_list, const void *parent)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ return relation->value;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/**
+ * Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple
+ * WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks.
+ * Hence, this should only be used as assert check before assigining a screen to a workspace.
+ */
+#ifndef NDEBUG
+static bool workspaces_is_screen_used(
+#else
+static bool UNUSED_FUNCTION(workspaces_is_screen_used)(
+#endif
+ const Main *bmain, bScreen *screen)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (workspace_layout_find_exec(workspace, screen)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* -------------------------------------------------------------------- */
+/* Create, delete, init */
+
+WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
+{
+ WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name);
+ return new_workspace;
+}
+
+void BKE_workspace_free(WorkSpace *workspace)
+{
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ relation;
+ relation = relation_next)
+ {
+ relation_next = relation->next;
+ workspace_relation_remove(&workspace->hook_layout_relations, relation);
+ }
+ BLI_freelistN(&workspace->layouts);
+}
+
+void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
+{
+ for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout; layout = layout_next) {
+ layout_next = layout->next;
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+
+ BKE_libblock_free(bmain, workspace);
+}
+
+WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
+{
+ WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__);
+
+ /* set an active screen-layout for each possible window/workspace combination */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
+ }
+
+ return hook;
+}
+void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook)
+{
+ /* workspaces should never be freed before wm (during which we call this function) */
+ BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces));
+
+ /* Free relations for this hook */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ relation;
+ relation = relation_next)
+ {
+ relation_next = relation->next;
+ if (relation->parent == hook) {
+ workspace_relation_remove(&workspace->hook_layout_relations, relation);
+ }
+ }
+ }
+
+ MEM_freeN(hook);
+}
+
+/**
+ * Add a new layout to \a workspace for \a screen.
+ */
+WorkSpaceLayout *BKE_workspace_layout_add(
+ WorkSpace *workspace,
+ bScreen *screen,
+ const char *name)
+{
+ WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
+
+ BLI_assert(!workspaces_is_screen_used(G.main, screen));
+ layout->screen = screen;
+ workspace_layout_name_set(workspace, layout, name);
+ BLI_addtail(&workspace->layouts, layout);
+
+ return layout;
+}
+
+void BKE_workspace_layout_remove(
+ Main *bmain,
+ WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ BKE_libblock_free(bmain, BKE_workspace_layout_screen_get(layout));
+ BLI_freelinkN(&workspace->layouts, layout);
+}
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+WorkSpaceLayout *BKE_workspace_layout_find(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen);
+ if (layout) {
+ return layout;
+ }
+
+ printf("%s: Couldn't find layout in this workspace: '%s' screen: '%s'. "
+ "This should not happen!\n",
+ __func__, workspace->id.name + 2, screen->id.name + 2);
+
+ return NULL;
+}
+
+/**
+ * Find the layout for \a screen without knowing which workspace to look in.
+ *
+ * \param r_workspace: Optionally return the workspace that contains the looked up layout (if found).
+ */
+WorkSpaceLayout *BKE_workspace_layout_find_global(
+ const Main *bmain, const bScreen *screen,
+ WorkSpace **r_workspace)
+{
+ WorkSpaceLayout *layout;
+
+ if (r_workspace) {
+ *r_workspace = NULL;
+ }
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if ((layout = workspace_layout_find_exec(workspace, screen))) {
+ if (r_workspace) {
+ *r_workspace = workspace;
+ }
+
+ return layout;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Circular workspace layout iterator.
+ *
+ * \param callback: Custom function which gets executed for each layout. Can return false to stop iterating.
+ * \param arg: Custom data passed to each \a callback call.
+ *
+ * \return the layout at which \a callback returned false.
+ */
+WorkSpaceLayout *BKE_workspace_layout_iter_circular(
+ const WorkSpace *workspace, WorkSpaceLayout *start,
+ bool (*callback)(const WorkSpaceLayout *layout, void *arg),
+ void *arg, const bool iter_backward)
+{
+ WorkSpaceLayout *iter_layout;
+
+ if (iter_backward) {
+ BLI_LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ BLI_LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start);
+ }
+ else {
+ BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ BLI_LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start)
+ }
+
+ return NULL;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Getters/Setters */
+
+WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook)
+{
+ return hook->active;
+}
+void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
+{
+ hook->active = workspace;
+ if (workspace) {
+ WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+ if (layout) {
+ hook->act_layout = layout;
+ }
+ }
+}
+
+WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout;
+}
+void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+}
+
+bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout->screen;
+}
+void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace, bScreen *screen)
+{
+ /* we need to find the WorkspaceLayout that wraps this screen */
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
+}
+
+#ifdef USE_WORKSPACE_MODE
+ObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace)
+{
+ return workspace->object_mode;
+}
+void BKE_workspace_object_mode_set(WorkSpace *workspace, const ObjectMode mode)
+{
+ workspace->object_mode = mode;
+}
+#endif
+
+SceneLayer *BKE_workspace_render_layer_get(const WorkSpace *workspace)
+{
+ return workspace->render_layer;
+}
+void BKE_workspace_render_layer_set(WorkSpace *workspace, SceneLayer *layer)
+{
+ workspace->render_layer = layer;
+}
+
+ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
+{
+ return &workspace->layouts;
+}
+
+
+const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout)
+{
+ return layout->name;
+}
+void BKE_workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ workspace_layout_name_set(workspace, layout, new_name);
+}
+
+bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout)
+{
+ return layout->screen;
+}
+void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen)
+{
+ layout->screen = screen;
+}
+
+WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+ const WorkSpaceInstanceHook *hook, const WorkSpace *workspace)
+{
+ return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+}
+void BKE_workspace_hook_layout_for_workspace_set(
+ WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+ workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
+}
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 0213a4ee997..fe38fc86c84 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -39,6 +39,7 @@ extern "C" {
struct BlendThumbnail;
struct bScreen;
struct LinkNode;
+struct ListBase;
struct Main;
struct MemFile;
struct ReportList;
@@ -49,6 +50,7 @@ struct View3D;
struct bContext;
struct BHead;
struct FileData;
+struct wmWindowManager;
typedef struct BlendHandle BlendHandle;
@@ -65,13 +67,20 @@ typedef struct BlendFileData {
int fileflags;
int globalf;
char filename[1024]; /* 1024 = FILE_MAX */
-
- struct bScreen *curscreen;
+
+ struct bScreen *curscreen; /* TODO think this isn't needed anymore? */
struct Scene *curscene;
-
+ struct SceneLayer *cur_render_layer; /* layer to activate in workspaces when reading without UI */
+
BlenFileType type;
} BlendFileData;
+typedef struct WorkspaceConfigFileData {
+ struct Main *main; /* has to be freed when done reading file data */
+
+ struct ListBase workspaces;
+} WorkspaceConfigFileData;
+
/* skip reading some data-block types (may want to skip screen data too). */
typedef enum eBLOReadSkip {
@@ -100,6 +109,7 @@ BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize);
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names);
struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev);
struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
+struct LinkNode *BLO_blendhandle_get_appendable_groups(BlendHandle *bh);
void BLO_blendhandle_close(BlendHandle *bh);
@@ -126,7 +136,9 @@ void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char
BlendFileData *blo_read_blendafterruntime(int file, const char *name, int actualsize, struct ReportList *reports);
/* internal function but we need to expose it */
-void blo_lib_link_screen_restore(struct Main *newmain, struct bScreen *curscreen, struct Scene *curscene);
+void blo_lib_link_restore(
+ struct Main *newmain, struct wmWindowManager *curwm,
+ struct Scene *curscene, struct SceneLayer *cur_render_layer);
typedef void (*BLOExpandDoitCallback) (void *fdhandle, struct Main *mainvar, void *idv);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index d22af275469..966cbce62db 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -53,6 +53,10 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+/* Allow using DNA struct members that are marked as private for read/write.
+ * Note: Each header that uses this needs to define its own way of handling
+ * it. There's no generic implementation, direct use does nothing. */
+#define DNA_PRIVATE_READ_WRITE_ALLOW
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -99,10 +103,13 @@
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
+#include "RNA_access.h"
+
#include "MEM_guardedalloc.h"
#include "BLI_endian_switch.h"
@@ -149,6 +156,7 @@
#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
#include "BKE_colortools.h"
+#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
@@ -2774,6 +2782,78 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
direct_link_animdata(fd, cache_file->adt);
}
+/* ************ READ WORKSPACES *************** */
+
+static void lib_link_workspaces(FileData *fd, Main *bmain)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+ ID *id = (ID *)workspace;
+
+ if ((id->tag & LIB_TAG_NEED_LINK) == 0) {
+ continue;
+ }
+ IDP_LibLinkProperty(id->properties, fd);
+ id_us_ensure_real(id);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ bScreen *screen = newlibadr(fd, id->lib, BKE_workspace_layout_screen_get(layout));
+
+ if (screen) {
+ BKE_workspace_layout_screen_set(layout, screen);
+
+ if (ID_IS_LINKED_DATABLOCK(id)) {
+ screen->winid = 0;
+ if (screen->temp) {
+ /* delete temp layouts when appending */
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+ }
+ }
+ }
+
+ id->tag &= ~LIB_TAG_NEED_LINK;
+ }
+}
+
+static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main *main)
+{
+ link_list(fd, BKE_workspace_layouts_get(workspace));
+ link_list(fd, &workspace->hook_layout_relations);
+
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first;
+ relation;
+ relation = relation->next)
+ {
+ relation->parent = newglobadr(fd, relation->parent); /* data from window - need to access through global oldnew-map */
+ relation->value = newdataadr(fd, relation->value);
+ }
+
+ if (ID_IS_LINKED_DATABLOCK(&workspace->id)) {
+ /* Appending workspace so render layer is likely from a different scene. Unset
+ * now, when activating workspace later we set a valid one from current scene. */
+ BKE_workspace_render_layer_set(workspace, NULL);
+ }
+
+ /* Same issue/fix as in direct_link_scene_update_screen_data: Can't read workspace data
+ * when reading windows, so have to update windows after/when reading workspaces. */
+ for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpaceLayout *act_layout = newdataadr(fd, BKE_workspace_active_layout_get(win->workspace_hook));
+ if (act_layout) {
+ BKE_workspace_active_layout_set(win->workspace_hook, act_layout);
+ }
+ }
+ }
+}
+
+static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id)
+{
+ WorkSpace *workspace = BKE_workspace_active_get(hook);
+ BKE_workspace_active_set(hook, newlibadr(fd, id->lib, workspace));
+}
+
+
/* ************ READ MOTION PATHS *************** */
/* direct data for cache */
@@ -5977,7 +6057,19 @@ static void direct_link_layer_collections(FileData *fd, ListBase *lb)
}
}
-static void direct_link_scene(FileData *fd, Scene *sce)
+static void direct_link_scene_update_screen_data(
+ FileData *fd, const Scene *scene, const ListBase *workspaces)
+{
+ for (WorkSpace *workspace = workspaces->first; workspace; workspace = workspace->id.next) {
+ SceneLayer *layer = newdataadr(fd, BKE_workspace_render_layer_get(workspace));
+ /* only set when layer is from the scene we read */
+ if (layer && (BLI_findindex(&scene->render_layers, layer) != -1)) {
+ BKE_workspace_render_layer_set(workspace, layer);
+ }
+ }
+}
+
+static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain)
{
Editing *ed;
Sequence *seq;
@@ -6250,7 +6342,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_scene_collection(fd, sce->collection);
}
- link_list(fd, &sce->render_layers);
+ /* insert into global old-new map for reading without UI (link_global accesses it again) */
+ link_glob_list(fd, &sce->render_layers);
for (sl = sce->render_layers.first; sl; sl = sl->next) {
sl->stats = NULL;
link_list(fd, &sl->object_bases);
@@ -6277,6 +6370,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
BKE_layer_collection_engine_settings_validate_scene(sce);
BKE_scene_layer_engine_settings_validate_scene(sce);
+
+ direct_link_scene_update_screen_data(fd, sce, &bmain->workspaces);
}
/* ************ READ WM ***************** */
@@ -6289,6 +6384,12 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
link_list(fd, &wm->windows);
for (win = wm->windows.first; win; win = win->next) {
+ WorkSpaceInstanceHook *hook = win->workspace_hook;
+
+ win->workspace_hook = newdataadr(fd, hook);
+ /* we need to restore a pointer to this later when reading workspaces, so store in global oldnew-map */
+ oldnewmap_insert(fd->globmap, hook, win->workspace_hook, 0);
+
win->ghostwin = NULL;
win->eventstate = NULL;
win->curswin = NULL;
@@ -6353,6 +6454,11 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
if (wm->id.tag & LIB_TAG_NEED_LINK) {
/* Note: WM IDProperties are never written to file, hence no need to read/link them here. */
for (win = wm->windows.first; win; win = win->next) {
+ if (win->workspace_hook) { /* NULL for old files */
+ lib_link_workspace_instance_hook(fd, win->workspace_hook, &wm->id);
+ }
+ win->scene = newlibadr(fd, wm->id.lib, win->scene);
+ /* deprecated, but needed for versioning (will be NULL'ed then) */
win->screen = newlibadr(fd, NULL, win->screen);
}
@@ -6438,13 +6544,9 @@ static void lib_link_screen(FileData *fd, Main *main)
IDP_LibLinkProperty(sc->id.properties, fd);
id_us_ensure_real(&sc->id);
+ /* deprecated, but needed for versioning (will be NULL'ed then) */
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
- /* this should not happen, but apparently it does somehow. Until we figure out the cause,
- * just assign first available scene */
- if (!sc->scene)
- sc->scene = main->scene.first;
-
sc->animtimer = NULL; /* saved in rare cases */
sc->scrubbing = false;
@@ -6752,56 +6854,59 @@ static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
-/* called from kernel/blender.c */
-/* used to link a file (without UI) to the current UI */
-/* note that it assumes the old pointers in UI are still valid, so old Main is not freed */
-void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene)
+static void lib_link_workspace_scene_data_restore(wmWindow *win, Scene *scene)
{
- wmWindow *win;
- wmWindowManager *wm;
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
- struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
- /* first windowmanager */
- for (wm = newmain->wm.first; wm; wm = wm->id.next) {
- for (win= wm->windows.first; win; win= win->next) {
- win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL);
-
- if (win->screen == NULL)
- win->screen = curscreen;
-
- win->screen->winid = win->winid;
+ if (v3d->camera == NULL || v3d->scenelock) {
+ v3d->camera = scene->camera;
+ }
+
+ if (v3d->localvd) {
+ /*Base *base;*/
+
+ v3d->localvd->camera = scene->camera;
+
+ /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
+#if 0 /* XXX regionlocalview ? */
+ for (base= sc->scene->base.first; base; base= base->next) {
+ if (base->lay & v3d->lay) break;
+ }
+ if (base==NULL) {
+ v3d->lay= v3d->localvd->lay;
+ v3d->layact= v3d->localvd->layact;
+ MEM_freeN(v3d->localvd);
+ v3d->localvd= NULL;
+ }
+#endif
+ }
+ else if (v3d->scenelock) {
+ v3d->lay = scene->lay;
+ }
+ }
}
}
-
-
- for (sc = newmain->screen.first; sc; sc = sc->id.next) {
- Scene *oldscene = sc->scene;
-
- sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL);
- if (sc->scene == NULL)
- sc->scene = curscene;
-
- /* keep cursor location through undo */
- copy_v3_v3(sc->scene->cursor, oldscene->cursor);
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+}
+
+static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, Main *newmain, WorkSpaceLayout *layout)
+{
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ /* avoid conflicts with 2.8x branch */
+ {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
BGpic *bgpic;
ARegion *ar;
- if (v3d->scenelock)
- v3d->camera = NULL; /* always get from scene */
- else
- v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
- if (v3d->camera == NULL)
- v3d->camera = sc->scene->camera;
+ v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
@@ -6812,27 +6917,6 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
id_us_plus((ID *)bgpic->clip);
}
}
- if (v3d->localvd) {
- /*Base *base;*/
-
- v3d->localvd->camera = sc->scene->camera;
-
- /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
-#if 0 /* XXX regionlocalview ? */
- for (base= sc->scene->base.first; base; base= base->next) {
- if (base->lay & v3d->lay) break;
- }
- if (base==NULL) {
- v3d->lay= v3d->localvd->lay;
- v3d->layact= v3d->localvd->layact;
- MEM_freeN(v3d->localvd);
- v3d->localvd= NULL;
- }
-#endif
- }
- else if (v3d->scenelock) {
- v3d->lay = sc->scene->lay;
- }
/* not very nice, but could help */
if ((v3d->layact & v3d->lay) == 0) v3d->layact = v3d->lay;
@@ -7035,6 +7119,44 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
}
}
+}
+
+/**
+ * Used to link a file (without UI) to the current UI.
+ * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
+ */
+void blo_lib_link_restore(Main *newmain, wmWindowManager *curwm, Scene *curscene, SceneLayer *cur_render_layer)
+{
+ struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+
+ for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ lib_link_workspace_layout_restore(id_map, newmain, layout);
+ }
+ BKE_workspace_render_layer_set(workspace, cur_render_layer);
+ }
+
+ for (wmWindow *win = curwm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ ID *workspace_id = (ID *)workspace;
+ Scene *oldscene = win->scene;
+
+ workspace = restore_pointer_by_name(id_map, workspace_id, USER_REAL);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ win->scene = restore_pointer_by_name(id_map, (ID *)win->scene, USER_REAL);
+ if (win->scene == NULL) {
+ win->scene = curscene;
+ }
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+
+ /* keep cursor location through undo */
+ copy_v3_v3(win->scene->cursor, oldscene->cursor);
+ lib_link_workspace_scene_data_restore(win, win->scene);
+
+ BLI_assert(win->screen == NULL);
+ }
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(id_map);
@@ -8146,6 +8268,7 @@ static const char *dataname(short id_code)
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
case ID_CF: return "Data from CF";
+ case ID_WS: return "Data from WS";
}
return "Data from Lib Block";
@@ -8309,7 +8432,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
wrong_id = direct_link_screen(fd, (bScreen *)id);
break;
case ID_SCE:
- direct_link_scene(fd, (Scene *)id);
+ direct_link_scene(fd, (Scene *)id, main);
break;
case ID_OB:
direct_link_object(fd, (Object *)id);
@@ -8404,6 +8527,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
case ID_CF:
direct_link_cachefile(fd, (CacheFile *)id);
break;
+ case ID_WS:
+ direct_link_workspace(fd, (WorkSpace *)id, main);
+ break;
}
oldnewmap_free_unused(fd->datamap);
@@ -8449,7 +8575,8 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->curscreen = fg->curscreen;
bfd->curscene = fg->curscene;
-
+ bfd->cur_render_layer = fg->cur_render_layer;
+
MEM_freeN(fg);
fd->globalf = bfd->globalf;
@@ -8461,6 +8588,7 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
/* note, this has to be kept for reading older files... */
static void link_global(FileData *fd, BlendFileData *bfd)
{
+ bfd->cur_render_layer = newglobadr(fd, bfd->cur_render_layer);
bfd->curscreen = newlibadr(fd, NULL, bfd->curscreen);
bfd->curscene = newlibadr(fd, NULL, bfd->curscene);
// this happens in files older than 2.35
@@ -8580,6 +8708,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
lib_link_cachefiles(fd, main);
+ lib_link_workspaces(fd, main);
lib_link_library(fd, main); /* only init users */
}
@@ -8966,6 +9095,11 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
}
}
else {
+ /* in 2.50+ file identifier for screens is patched, forward compatibility */
+ if (bhead->code == ID_SCRN) {
+ bhead->code = ID_SCR;
+ }
+
id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
read_libblock(fd, mainvar, bhead, LIB_TAG_TESTIND, NULL);
@@ -9817,6 +9951,15 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
expand_animdata(fd, mainvar, gpd->adt);
}
+static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace)
+{
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout));
+ }
+}
+
/**
* Set the callback func used over all ID data found by \a BLO_expand_main func.
*
@@ -9931,6 +10074,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_CF:
expand_cachefile(fd, mainvar, (CacheFile *)id);
break;
+ case ID_WS:
+ expand_workspace(fd, mainvar, (WorkSpace *)id);
+ break;
}
do_it = true;
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 3eeb0fc78e4..2d14238eb6f 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -45,6 +45,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
@@ -55,6 +56,83 @@
#include "MEM_guardedalloc.h"
+
+static bScreen *screen_parent_find(const bScreen *screen)
+{
+ /* can avoid lookup if screen state isn't maximized/full (parent and child store the same state) */
+ if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->full && sa->full != screen) {
+ BLI_assert(sa->full->state == screen->state);
+ return sa->full;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void do_version_workspaces_create_from_screens(Main *bmain)
+{
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ const bScreen *screen_parent = screen_parent_find(screen);
+ WorkSpace *workspace;
+
+ if (screen_parent) {
+ /* fullscreen with "Back to Previous" option, don't create
+ * a new workspace, add layout workspace containing parent */
+ workspace = BLI_findstring(
+ &bmain->workspaces, screen_parent->id.name + 2, offsetof(ID, name) + 2);
+ }
+ else {
+ workspace = BKE_workspace_add(bmain, screen->id.name + 2);
+ }
+ BKE_workspace_layout_add(workspace, screen, screen->id.name + 2);
+ BKE_workspace_render_layer_set(workspace, screen->scene->render_layers.first);
+ }
+}
+
+/**
+ * \brief After lib-link versioning for new workspace design.
+ *
+ * * Adds a workspace for (almost) each screen of the old file
+ * and adds the needed workspace-layout to wrap the screen.
+ * * Active screen isn't stored directly in window anymore, but in the active workspace.
+ * * Active scene isn't stored in screen anymore, but in window.
+ * * Create workspace instance hook for each window.
+ *
+ * \note Some of the created workspaces might be deleted again in case of reading the default startup.blend.
+ */
+static void do_version_workspaces_after_lib_link(Main *bmain)
+{
+ BLI_assert(BLI_listbase_is_empty(&bmain->workspaces));
+
+ do_version_workspaces_create_from_screens(bmain);
+
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen_parent = screen_parent_find(win->screen);
+ bScreen *screen = screen_parent ? screen_parent : win->screen;
+ WorkSpace *workspace = BLI_findstring(&bmain->workspaces, screen->id.name + 2, offsetof(ID, name) + 2);
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
+
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ BKE_workspace_active_layout_set(win->workspace_hook, layouts->first);
+
+ win->scene = screen->scene;
+ /* Deprecated from now on! */
+ win->screen = NULL;
+ }
+ }
+
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ /* Deprecated from now on! */
+ screen->scene = NULL;
+ }
+}
+
void do_versions_after_linking_280(Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
@@ -183,13 +261,18 @@ void do_versions_after_linking_280(Main *main)
scene->basact = NULL;
}
}
+ }
+ if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ /* same render-layer as do_version_workspaces_after_lib_link will activate,
+ * so same layer as BKE_scene_layer_context_active would return */
+ SceneLayer *layer = screen->scene->render_layers.first;
+
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *soutliner = (SpaceOops *)sl;
- SceneLayer *layer = BKE_scene_layer_context_active(screen->scene);
soutliner->outlinevis = SO_ACT_LAYER;
@@ -213,6 +296,11 @@ void do_versions_after_linking_280(Main *main)
}
}
}
+
+ /* New workspace design */
+ if (!MAIN_VERSION_ATLEAST(main, 280, 1)) {
+ do_version_workspaces_after_lib_link(main);
+ }
}
static void do_version_layer_collections_idproperties(ListBase *lb)
@@ -254,34 +342,35 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
-
}
- if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
- for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
- ca->gpu_dof.ratio = 1.0f;
+ if (!MAIN_VERSION_ATLEAST(main, 280, 1)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
+ for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
+ ca->gpu_dof.ratio = 1.0f;
+ }
}
- }
- if (!DNA_struct_elem_find(fd->filesdna, "SceneLayer", "IDProperty", "*properties")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
- for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
- IDPropertyTemplate val = {0};
- sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
- BKE_scene_layer_engine_settings_create(sl->properties);
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneLayer", "IDProperty", "*properties")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ IDPropertyTemplate val = {0};
+ sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_scene_layer_engine_settings_create(sl->properties);
+ }
}
}
- }
- /* MTexPoly now removed. */
- if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
- const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */
- for (Mesh *me = main->mesh.first; me; me = me->id.next) {
- /* If we have UV's, so this file will have MTexPoly layers too! */
- if (me->mloopuv != NULL) {
- CustomData_update_typemap(&me->pdata);
- CustomData_free_layers(&me->pdata, cd_mtexpoly, me->totpoly);
- BKE_mesh_update_customdata_pointers(me, false);
+ /* MTexPoly now removed. */
+ if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
+ const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */
+ for (Mesh *me = main->mesh.first; me; me = me->id.next) {
+ /* If we have UV's, so this file will have MTexPoly layers too! */
+ if (me->mloopuv != NULL) {
+ CustomData_update_typemap(&me->pdata);
+ CustomData_free_layers(&me->pdata, cd_mtexpoly, me->totpoly);
+ BKE_mesh_update_customdata_pointers(me, false);
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index a38f122ec56..002af20bc3a 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -40,10 +40,12 @@
#include "DNA_mesh_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_brush.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
@@ -84,6 +86,32 @@ void BLO_update_defaults_userpref_blend(void)
}
/**
+ * New workspace design: Remove all screens/workspaces except of "Default" one and rename the workspace to "General".
+ * For compatibility, a new workspace has been created for each screen of old files,
+ * we only want one workspace and one screen in the default startup file however.
+ */
+static void update_defaults_startup_workspaces(Main *bmain)
+{
+ WorkSpace *workspace_default = NULL;
+
+ for (WorkSpace *workspace = bmain->workspaces.first, *workspace_next; workspace; workspace = workspace_next) {
+ workspace_next = workspace->id.next;
+
+ if (STREQ(workspace->id.name + 2, "Default")) {
+ /* don't rename within iterator, renaming causes listbase to be re-sorted */
+ workspace_default = workspace;
+ }
+ else {
+ BKE_workspace_remove(bmain, workspace);
+ }
+ }
+
+ /* rename "Default" workspace to "General" */
+ BKE_libblock_rename(bmain, (ID *)workspace_default, "General");
+ BLI_assert(BLI_listbase_count(BKE_workspace_layouts_get(workspace_default)) == 1);
+}
+
+/**
* Update defaults in startup.blend, without having to save and embed the file.
* This function can be emptied each time the startup.blend is updated. */
void BLO_update_defaults_startup_blend(Main *bmain)
@@ -181,20 +209,18 @@ void BLO_update_defaults_startup_blend(Main *bmain)
linestyle->chain_count = 10;
}
- for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *area;
- for (area = screen->areabase.first; area; area = area->next) {
- SpaceLink *space_link;
- ARegion *ar;
+ update_defaults_startup_workspaces(bmain);
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *space_link = area->spacedata.first; space_link; space_link = space_link->next) {
if (space_link->spacetype == SPACE_CLIP) {
SpaceClip *space_clip = (SpaceClip *) space_link;
space_clip->flag &= ~SC_MANUAL_CALIBRATION;
}
}
- for (ar = area->regionbase.first; ar; ar = ar->next) {
+ for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
/* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
BLI_freelistN(&ar->panels);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 19f6b9f370d..82d2e37dce0 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -102,6 +102,10 @@
/* allow writefile to use deprecated functionality (for forward compatibility code) */
#define DNA_DEPRECATED_ALLOW
+/* Allow using DNA struct members that are marked as private for read/write.
+ * Note: Each header that uses this needs to define its own way of handling
+ * it. There's no generic implementation, direct use does nothing. */
+#define DNA_PRIVATE_READ_WRITE_ALLOW
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -147,6 +151,7 @@
#include "DNA_vfont_types.h"
#include "DNA_world_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
@@ -173,6 +178,7 @@
#include "BKE_fcurve.h"
#include "BKE_pointcache.h"
#include "BKE_mesh.h"
+#include "BKE_workspace.h"
#ifdef USE_NODE_COMPAT_CUSTOMNODES
#include "NOD_socket.h" /* for sock->default_value data */
@@ -1077,10 +1083,13 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
* Take care using 'use_active_win', since we wont want the currently active window
* to change which scene renders (currently only used for undo).
*/
-static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_active_win)
+static void current_screen_compat(
+ Main *mainvar, bool use_active_win,
+ bScreen **r_screen, Scene **r_scene, SceneLayer **r_render_layer)
{
wmWindowManager *wm;
wmWindow *window = NULL;
+ WorkSpace *workspace;
/* find a global current screen in the first open window, to have
* a reasonable default for reading in older versions */
@@ -1104,8 +1113,11 @@ static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_ac
window = wm->windows.first;
}
}
+ workspace = (window) ? BKE_workspace_active_get(window->workspace_hook) : NULL;
- *r_screen = (window) ? window->screen : NULL;
+ *r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL;
+ *r_scene = (window) ? window->scene : NULL;
+ *r_render_layer = (window) ? BKE_workspace_render_layer_get(workspace) : NULL;
}
typedef struct RenderInfo {
@@ -1121,13 +1133,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
{
bScreen *curscreen;
Scene *sce, *curscene = NULL;
+ SceneLayer *render_layer;
RenderInfo data;
/* XXX in future, handle multiple windows with multiple screens? */
- current_screen_compat(mainvar, &curscreen, false);
- if (curscreen) {
- curscene = curscreen->scene;
- }
+ current_screen_compat(mainvar, false, &curscreen, &curscene, &render_layer);
for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
@@ -2842,8 +2852,19 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
write_iddata(wd, &wm->id);
for (wmWindow *win = wm->windows.first; win; win = win->next) {
+
+ /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
+ win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ if (win->screen) {
+ BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
+ }
+
writestruct(wd, DATA, wmWindow, 1, win);
+ writestruct(wd, DATA, WorkSpaceInstanceHook, 1, win->workspace_hook);
writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
+
+ /* data is written, clear deprecated data again */
+ win->screen = NULL;
}
}
@@ -2984,6 +3005,7 @@ static void write_screen(WriteData *wd, bScreen *sc)
View3D *v3d = (View3D *)sl;
BGpic *bgpic;
writestruct(wd, DATA, View3D, 1, v3d);
+
for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
writestruct(wd, DATA, BGpic, 1, bgpic);
}
@@ -3729,6 +3751,15 @@ static void write_cachefile(WriteData *wd, CacheFile *cache_file)
}
}
+static void write_workspace(WriteData *wd, WorkSpace *workspace)
+{
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ writestruct(wd, ID_WS, WorkSpace, 1, workspace);
+ writelist(wd, DATA, WorkSpaceLayout, layouts);
+ writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations);
+}
+
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
@@ -3798,6 +3829,8 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
const bool is_undo = (wd->current != NULL);
FileGlobal fg;
bScreen *screen;
+ Scene *scene;
+ SceneLayer *render_layer;
char subvstr[8];
/* prevent mem checkers from complaining */
@@ -3805,11 +3838,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
memset(fg.filename, 0, sizeof(fg.filename));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
- current_screen_compat(mainvar, &screen, is_undo);
+ current_screen_compat(mainvar, is_undo, &screen, &scene, &render_layer);
/* XXX still remap G */
fg.curscreen = screen;
- fg.curscene = screen ? screen->scene : NULL;
+ fg.curscene = scene;
+ fg.cur_render_layer = render_layer;
/* prevent to save this, is not good convention, and feature with concerns... */
fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME);
@@ -3905,6 +3939,9 @@ static bool write_file_handle(
case ID_WM:
write_windowmanager(wd, (wmWindowManager *)id);
break;
+ case ID_WS:
+ write_workspace(wd, (WorkSpace *)id);
+ break;
case ID_SCR:
write_screen(wd, (bScreen *)id);
break;
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 1d76077c9f1..9a00df9a0d5 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -149,6 +149,7 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_TEXT "Text"
#define BLT_I18NCONTEXT_ID_VFONT "VFont"
#define BLT_I18NCONTEXT_ID_WORLD "World"
+#define BLT_I18NCONTEXT_ID_WORKSPACE "WorkSpace"
#define BLT_I18NCONTEXT_ID_WINDOWMANAGER "WindowManager"
#define BLT_I18NCONTEXT_ID_MOVIECLIP "MovieClip"
#define BLT_I18NCONTEXT_ID_MASK "Mask"
@@ -203,6 +204,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_TEXT, "id_text"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_VFONT, "id_vfont"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORLD, "id_world"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORKSPACE, "id_workspace"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "id_windowmanager"), \
{NULL, NULL, NULL} \
}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index c3d64dc05bd..16d1f39f47f 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -49,6 +49,7 @@ extern "C" {
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_workspace.h"
#define new new_
#include "BKE_screen.h"
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 1559512d713..f62db3c1ddb 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -35,7 +35,7 @@ if(WITH_BLENDER)
add_subdirectory(object)
add_subdirectory(physics)
add_subdirectory(render)
- add_subdirectory(screen)
+ add_subdirectory(scene)
add_subdirectory(sculpt_paint)
add_subdirectory(sound)
add_subdirectory(space_action)
@@ -60,6 +60,7 @@ if(WITH_BLENDER)
add_subdirectory(transform)
add_subdirectory(util)
add_subdirectory(uvedit)
+ add_subdirectory(screen)
endif()
add_subdirectory(datafiles)
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 7ec19d12fb6..ef67411a48d 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -859,7 +859,7 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
if (camera != scene->camera) {
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
}
#endif
@@ -1550,7 +1550,7 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
/* camera may have changes */
BKE_scene_camera_switch_update(scene);
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
new file mode 100644
index 00000000000..2f67f7befae
--- /dev/null
+++ b/source/blender/editors/include/ED_scene.h
@@ -0,0 +1,40 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_scene.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_SCENE_H__
+#define __ED_SCENE_H__
+
+#include "BLI_compiler_attrs.h"
+
+enum eSceneCopyMethod;
+
+struct Scene *ED_scene_add(struct Main *bmain, bContext *C, struct wmWindow *win, enum eSceneCopyMethod method) ATTR_NONNULL();
+bool ED_scene_delete(bContext *C, struct Main *bmain, struct wmWindow *win, struct Scene *scene) ATTR_NONNULL();
+void ED_scene_exit(bContext *C) ATTR_NONNULL();
+void ED_scene_changed_update(struct Main *bmain, bContext *C, struct Scene *scene_new,
+ const struct bScreen *active_screen) ATTR_NONNULL();
+
+void ED_operatortypes_scene(void);
+
+#endif /* __ED_SCENE_H__ */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 1208b1f31b6..dec8bf7d615 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -43,6 +43,8 @@ struct wmWindow;
struct wmNotifier;
struct wmEvent;
struct wmKeyConfig;
+struct WorkSpace;
+struct WorkSpaceInstanceHook;
struct bContext;
struct Scene;
struct bScreen;
@@ -107,12 +109,8 @@ void ED_screens_initialize(struct wmWindowManager *wm);
void ED_screen_draw(struct wmWindow *win);
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
-bScreen *ED_screen_duplicate(struct wmWindow *win, struct bScreen *sc);
-bScreen *ED_screen_add(struct wmWindow *win, struct Scene *scene, const char *name);
-bool ED_screen_set(struct bContext *C, struct bScreen *sc);
-bool ED_screen_delete(struct bContext *C, struct bScreen *sc);
-void ED_screen_set_scene(struct bContext *C, struct bScreen *screen, struct Scene *scene);
-bool ED_screen_delete_scene(struct bContext *C, struct Scene *scene);
+bool ED_screen_change(struct bContext *C, struct bScreen *sc);
+void ED_screen_update_after_scene_change(const struct bScreen *screen, struct Scene *scene_new);
void ED_screen_set_subwinactive(struct bContext *C, struct wmEvent *event);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable);
@@ -123,9 +121,42 @@ void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
-bool ED_screen_stereo3d_required(struct bScreen *screen);
+bool ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene);
+Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm);
void ED_screen_preview_render(const struct bScreen *screen, int size_x, int size_y, unsigned int *r_rect) ATTR_NONNULL();
+/* workspaces */
+struct WorkSpace *ED_workspace_add(
+ struct Main *bmain,
+ const char *name,
+ SceneLayer *act_render_layer) ATTR_NONNULL();
+bool ED_workspace_change(
+ struct WorkSpace *workspace_new,
+ struct bContext *C,
+ struct wmWindowManager *wm, struct wmWindow *win) ATTR_NONNULL();
+struct WorkSpace *ED_workspace_duplicate(
+ struct WorkSpace *workspace_old,
+ struct Main *bmain, struct wmWindow *win);
+bool ED_workspace_delete(
+ struct WorkSpace *workspace,
+ struct Main *bmain, struct bContext *C,
+ struct wmWindowManager *wm, struct wmWindow *win) ATTR_NONNULL();
+void ED_workspace_scene_data_sync(
+ struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL();
+struct WorkSpaceLayout *ED_workspace_layout_add(
+ struct WorkSpace *workspace,
+ struct wmWindow *win,
+ const char *name) ATTR_NONNULL();
+struct WorkSpaceLayout *ED_workspace_layout_duplicate(
+ struct WorkSpace *workspace, const struct WorkSpaceLayout *layout_old,
+ struct wmWindow *win) ATTR_NONNULL();
+bool ED_workspace_layout_delete(
+ struct WorkSpace *workspace, struct WorkSpaceLayout *layout_old,
+ struct bContext *C) ATTR_NONNULL();
+bool ED_workspace_layout_cycle(
+ struct WorkSpace *workspace, const short direction,
+ struct bContext *C) ATTR_NONNULL();
+
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);
@@ -137,6 +168,8 @@ bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
void ED_operatortypes_screen(void);
void ED_keymap_screen(struct wmKeyConfig *keyconf);
+/* workspace keymaps */
+void ED_operatortypes_workspace(void);
/* operators; context poll callbacks */
int ED_operator_screenactive(struct bContext *C);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 02243738d6c..667ca099305 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -262,8 +262,9 @@ void ED_view3d_calc_camera_border_size(
const struct Scene *scene, const struct ARegion *ar,
const struct View3D *v3d, const struct RegionView3D *rv3d,
float r_size[2]);
-bool ED_view3d_calc_render_border(struct Scene *scene, struct View3D *v3d,
- struct ARegion *ar, struct rcti *rect);
+bool ED_view3d_calc_render_border(
+ const struct Scene *scene, struct View3D *v3d,
+ struct ARegion *ar, struct rcti *rect);
void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip);
void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4],
@@ -388,7 +389,7 @@ char ED_view3d_axis_view_opposite(char view);
bool ED_view3d_lock(struct RegionView3D *rv3d);
uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d);
-uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);
+uint64_t ED_view3d_screen_datamask(const struct Scene *scene, const struct bScreen *screen);
bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 562a2f6e32c..be37ba46f7f 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2790,11 +2790,13 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
}
else {
+ const bScreen *screen = WM_window_get_active_screen(window);
+
/* no subwindow created yet, for menus for example, so we
* use the main window instead, since buttons are created
* there anyway */
- wm_subwindow_matrix_get(window, window->screen->mainwin, block->winmat);
- wm_subwindow_size_get(window, window->screen->mainwin, &getsizex, &getsizey);
+ wm_subwindow_matrix_get(window, screen->mainwin, block->winmat);
+ wm_subwindow_size_get(window, screen->mainwin, &getsizex, &getsizey);
block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
block->auto_open = true;
@@ -4628,7 +4630,10 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
if (ptr && prop) {
if (!item) {
int i;
-
+
+ /* so the context is passed to itemf functions */
+ WM_operator_properties_sanitize(ptr, false);
+
RNA_property_enum_items_gettexted(C, ptr, prop, &items, &totitems, &free_items);
for (i = 0, item = items; i < totitems; i++, item++) {
if (item->identifier[0] && item->value == value)
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index bad47512d12..858c21dfdda 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -169,8 +169,8 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
*/
static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, event->x, event->y);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
uiBut *but = ui_but_find_mouse_over(ar, event);
@@ -262,10 +262,9 @@ static void eyedropper_exit(bContext *C, wmOperator *op)
*/
static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3])
{
-
/* we could use some clever */
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
const char *display_device = CTX_data_scene(C)->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
@@ -586,8 +585,8 @@ static void datadropper_exit(bContext *C, wmOperator *op)
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
{
/* we could use some clever */
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, -1, mx, my);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
ScrArea *area_prev = CTX_wm_area(C);
ARegion *ar_prev = CTX_wm_region(C);
@@ -887,9 +886,9 @@ static void depthdropper_exit(bContext *C, wmOperator *op)
static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
{
/* we could use some clever */
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
- Scene *scene = win->screen->scene;
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ Scene *scene = CTX_data_scene(C);
UnitSettings *unit = &scene->unit;
const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index ed8c3a50875..fd6d056f7d4 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -117,6 +117,9 @@ static ARegion *ui_region_temp_add(bScreen *sc)
static void ui_region_temp_remove(bContext *C, bScreen *sc, ARegion *ar)
{
wmWindow *win = CTX_wm_window(C);
+
+ BLI_assert(ar->regiontype == RGN_TYPE_TEMPORARY);
+ BLI_assert(BLI_findindex(&sc->regionbase, ar) != -1);
if (win)
wm_draw_region_clear(win, ar);
@@ -3361,11 +3364,13 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
/* if loading new .blend while popup is open, window will be NULL */
if (block->handle) {
if (win) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
UI_popup_handlers_remove(&win->modalhandlers, block->handle);
ui_popup_block_free(C, block->handle);
/* In the case we have nested popups, closing one may need to redraw another, see: T48874 */
- for (ARegion *ar = win->screen->regionbase.first; ar; ar = ar->next) {
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
ED_region_tag_refresh_ui(ar);
}
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 266d8aacae3..dbef5b68a03 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -448,6 +448,7 @@ static const char *template_id_browse_tip(const StructRNA *type)
case ID_PAL: return N_("Browse Palette Data to be linked");
case ID_PC: return N_("Browse Paint Curve Data to be linked");
case ID_CF: return N_("Browse Cache Files to be linked");
+ case ID_WS: return N_("Browse Workspace to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -551,7 +552,7 @@ static void template_ID(
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
- if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
+ if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) {
uiDefButR(block, UI_BTYPE_TOGGLE, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
}
}
@@ -585,6 +586,7 @@ static void template_ID(
BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
BLT_I18NCONTEXT_ID_GPENCIL,
BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
+ BLT_I18NCONTEXT_ID_WORKSPACE,
);
if (newop) {
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index f383719a747..fd1569ae42e 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -298,8 +298,7 @@ void ui_rna_collection_search_cb(const struct bContext *C, void *arg, const char
}
-/***************************** ID Utilities *******************************/
-
+/***************************** ID Utilities *******************************/
int UI_icon_from_id(ID *id)
{
Object *ob;
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index e8eda567a4a..09ec08fe265 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -2899,13 +2899,7 @@ void init_userdef_do_versions(void)
btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255;
}
}
-
- /**
- * Include next version bump.
- *
- * (keep this block even if it becomes empty).
- */
- {
+ if (!USER_VERSION_ATLEAST(280, 1)) {
/* interface_widgets.c */
struct uiWidgetColors wcol_tab = {
{255, 255, 255, 255},
@@ -2925,6 +2919,15 @@ void init_userdef_do_versions(void)
}
}
+ /**
+ * Include next version bump.
+ *
+ * (keep this block even if it becomes empty).
+ */
+ {
+
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 177168aa3c3..068caee4e1a 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1210,8 +1210,8 @@ static int object_delete_exec(bContext *C, wmOperator *op)
/* delete has to handle all open scenes */
BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true);
for (win = wm->windows.first; win; win = win->next) {
- scene = win->screen->scene;
-
+ scene = WM_window_get_active_scene(win);
+
if (scene->id.tag & LIB_TAG_DOIT) {
scene->id.tag &= ~LIB_TAG_DOIT;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index abdbf3afd5a..fe232e37886 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -83,6 +83,7 @@
#include "BKE_modifier.h"
#include "BKE_editmesh.h"
#include "BKE_report.h"
+#include "BKE_workspace.h"
#include "ED_armature.h"
#include "ED_curve.h"
@@ -1499,8 +1500,15 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *re
{
bool ok;
if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) {
+ WorkSpace *workspace = CTX_wm_workspace(C);
const char *opstring = object_mode_op_string(ob->mode);
+
WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+#ifdef USE_WORKSPACE_MODE
+ BKE_workspace_object_mode_set(workspace, ob->mode);
+#else
+ UNUSED_VARS(workspace);
+#endif
ok = ELEM(ob->mode, mode, OB_MODE_OBJECT);
if (!ok) {
wmOperatorType *ot = WM_operatortype_find(opstring, false);
@@ -1610,13 +1618,23 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
}
-
void ED_object_toggle_modes(bContext *C, int mode)
{
if (mode != OB_MODE_OBJECT) {
const char *opstring = object_mode_op_string(mode);
+
if (opstring) {
+#ifdef USE_WORKSPACE_MODE
+ WorkSpace *workspace = CTX_wm_workspace(C);
+#endif
WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+
+#ifdef USE_WORKSPACE_MODE
+ Object *ob = CTX_data_active_object(C);
+ if (ob) {
+ BKE_workspace_object_mode_set(workspace, ob->mode);
+ }
+#endif
}
}
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 4bdd524f110..60c8fa6f28d 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -59,6 +59,7 @@
#include "BKE_property.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "BKE_library.h"
#include "BKE_deform.h"
@@ -110,7 +111,12 @@ void ED_base_object_activate(bContext *C, BaseLegacy *base)
BASACT = base;
if (base) {
-
+#ifdef USE_WORKSPACE_MODE
+ WorkSpace *workspace = CTX_wm_workspace(C);
+
+ BKE_workspace_object_mode_set(workspace, base->object->mode);
+#endif
+
/* XXX old signals, remember to handle notifiers now! */
// select_actionchannel_by_name(base->object->action, "Object", 1);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index d4e9956b189..bdfbac3dba7 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -491,8 +491,9 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
for (wm = rj->main->wm.first; wm && matched_sa == NULL; wm = wm->id.next) { /* only 1 wm */
wmWindow *win;
for (win = wm->windows.first; win && matched_sa == NULL; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
// sa->spacedata might be empty when toggling fullscreen mode.
@@ -618,8 +619,9 @@ static void render_image_restore_layer(RenderJob *rj)
for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa == rj->sa) {
if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index e019bc9f697..ce52b9af4b2 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -66,6 +66,8 @@
#include "ED_render.h"
#include "ED_view3d.h"
+#include "WM_api.h"
+
#include "render_intern.h" // own include
extern Material defmaterial;
@@ -104,7 +106,7 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
wm = bmain->wm.first;
for (win = wm->windows.first; win; win = win->next) {
- bScreen *sc = win->screen;
+ bScreen *sc = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index c4a9af79ec2..e4bae9d78ea 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -90,8 +90,10 @@ static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow *
/* find an imagewindow showing render result */
for (*win = wm->windows.first; *win; *win = (*win)->next) {
- if ((*win)->screen->scene == scene) {
- for (sa = (*win)->screen->areabase.first; sa; sa = sa->next) {
+ if (WM_window_get_active_scene(*win) == scene) {
+ const bScreen *screen = WM_window_get_active_screen(*win);
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_IMAGE) {
sima = sa->spacedata.first;
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT)
@@ -246,7 +248,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
}
/* test if we have a temp screen in front */
- if (win->screen->temp) {
+ if (WM_window_is_temp_screen(win)) {
wm_window_lower(win);
return OPERATOR_FINISHED;
}
@@ -292,7 +294,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
wmWindow *wincur = CTX_wm_window(C);
/* test if we have currently a temp screen active */
- if (wincur->screen->temp) {
+ if (WM_window_is_temp_screen(wincur)) {
wm_window_lower(wincur);
}
else {
@@ -301,8 +303,9 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* is there another window on current scene showing result? */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
- bScreen *sc = win->screen;
- if ((sc->temp && ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
+ const bScreen *sc = WM_window_get_active_screen(win);
+
+ if ((WM_window_is_temp_screen(win) && ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
(win == winshow && winshow != wincur))
{
wm_window_raise(win);
diff --git a/source/blender/editors/scene/CMakeLists.txt b/source/blender/editors/scene/CMakeLists.txt
new file mode 100644
index 00000000000..72199ca5c1f
--- /dev/null
+++ b/source/blender/editors/scene/CMakeLists.txt
@@ -0,0 +1,43 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ scene_edit.c
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+blender_add_lib(bf_editor_scene "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
new file mode 100644
index 00000000000..6956793435c
--- /dev/null
+++ b/source/blender/editors/scene/scene_edit.c
@@ -0,0 +1,202 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/scene/scene_edit.c
+ * \ingroup edscene
+ */
+
+#include <stdio.h>
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library_remap.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_listbase.h"
+
+#include "BLT_translation.h"
+
+#include "ED_object.h"
+#include "ED_render.h"
+#include "ED_scene.h"
+#include "ED_screen.h"
+#include "ED_util.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+
+Scene *ED_scene_add(Main *bmain, bContext *C, wmWindow *win, eSceneCopyMethod method)
+{
+ Scene *scene_new;
+
+ if (method == SCE_COPY_NEW) {
+ scene_new = BKE_scene_add(bmain, DATA_("Scene"));
+ }
+ else { /* different kinds of copying */
+ Scene *scene_old = WM_window_get_active_scene(win);
+
+ scene_new = BKE_scene_copy(bmain, scene_old, method);
+
+ /* these can't be handled in blenkernel currently, so do them here */
+ if (method == SCE_COPY_LINK_DATA) {
+ ED_object_single_users(bmain, scene_new, false, true);
+ }
+ else if (method == SCE_COPY_FULL) {
+ ED_editors_flush_edits(C, false);
+ ED_object_single_users(bmain, scene_new, true, true);
+ }
+ }
+
+ WM_window_change_active_scene(bmain, C, win, scene_new);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, scene_new);
+
+ return scene_new;
+}
+
+/**
+ * \note Only call outside of area/region loops
+ * \return true if successful
+ */
+bool ED_scene_delete(bContext *C, Main *bmain, wmWindow *win, Scene *scene)
+{
+ Scene *scene_new;
+
+ if (scene->id.prev)
+ scene_new = scene->id.prev;
+ else if (scene->id.next)
+ scene_new = scene->id.next;
+ else
+ return false;
+
+ WM_window_change_active_scene(bmain, C, win, scene_new);
+
+ BKE_libblock_remap(bmain, scene, scene_new, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ BKE_libblock_free(bmain, scene);
+
+ return true;
+}
+
+void ED_scene_exit(bContext *C)
+{
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
+}
+
+void ED_scene_changed_update(Main *bmain, bContext *C, Scene *scene_new, const bScreen *active_screen)
+{
+ /* XXX Just using active scene render-layer for workspace when switching,
+ * but workspace should remember the last one set. Could store render-layer
+ * per window-workspace combination (using WorkSpaceDataRelation) */
+ SceneLayer *layer_new = BLI_findlink(&scene_new->render_layers, scene_new->active_layer);
+
+ CTX_data_scene_set(C, scene_new);
+ BKE_workspace_render_layer_set(CTX_wm_workspace(C), layer_new);
+ BKE_scene_set_background(bmain, scene_new);
+ DAG_on_visible_update(bmain, false);
+
+ ED_screen_update_after_scene_change(active_screen, scene_new);
+ ED_render_engine_changed(bmain);
+ ED_update_for_newframe(bmain, scene_new, 1);
+
+ /* complete redraw */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+}
+
+static int scene_new_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ ED_scene_add(bmain, C, win, type);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCENE_OT_new(wmOperatorType *ot)
+{
+ static EnumPropertyItem type_items[] = {
+ {SCE_COPY_NEW, "NEW", 0, "New", "Add new scene"},
+ {SCE_COPY_EMPTY, "EMPTY", 0, "Copy Settings", "Make a copy without any objects"},
+ {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
+ {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
+ {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "New Scene";
+ ot->description = "Add new scene by type";
+ ot->idname = "SCENE_OT_new";
+
+ /* api callbacks */
+ ot->exec = scene_new_exec;
+ ot->invoke = WM_menu_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
+}
+
+static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (G.debug & G_DEBUG)
+ printf("scene delete %p\n", scene);
+
+ WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCENE_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Scene";
+ ot->description = "Delete active scene";
+ ot->idname = "SCENE_OT_delete";
+
+ /* api callbacks */
+ ot->exec = scene_delete_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void ED_operatortypes_scene(void)
+{
+ WM_operatortype_append(SCENE_OT_new);
+ WM_operatortype_append(SCENE_OT_delete);
+}
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index 43e044b613a..02584a4611b 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blenloader
../../blentranslation
../../bmesh
../../gpu
@@ -46,6 +47,8 @@ set(SRC
screen_edit.c
screen_ops.c
screendump.c
+ workspace_edit.c
+ workspace_layout_edit.c
screen_intern.h
)
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 3b933b0182a..9d3dde06925 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -581,9 +581,11 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
UI_blocklist_free_inactive(C, &ar->uiblocks);
if (sa) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
/* disable emboss when the area is full,
* unless we need to see division between regions (quad-split for eg) */
- if (((win->screen->state == SCREENFULL) && (ar->alignment == RGN_ALIGN_NONE)) == 0) {
+ if (((screen->state == SCREENFULL) && (ar->alignment == RGN_ALIGN_NONE)) == 0) {
region_draw_emboss(ar, &ar->winrct);
}
}
@@ -1353,7 +1355,9 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
* must be minimum '4' */
}
else {
- if (ELEM(win->screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ if (ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
region_azone_add(sa, ar, alignment, false);
}
else {
@@ -1477,6 +1481,7 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
/* called in screen_refresh, or screens_init, also area size changes */
void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
{
+ const bScreen *screen = WM_window_get_active_screen(win);
ARegion *ar;
rcti rect;
@@ -1495,7 +1500,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
area_calc_totrct(sa, WM_window_pixels_x(win), WM_window_pixels_y(win));
/* clear all azones, add the area triange widgets */
- area_azone_initialize(win, win->screen, sa);
+ area_azone_initialize(win, screen, sa);
/* region rect sizes */
rect = sa->totrct;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 0448fba78e6..d4e9609904e 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -50,6 +50,7 @@
#include "BKE_layer.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
@@ -81,10 +82,13 @@ const char *screen_context_dir[] = {
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
+ wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = sc->scene;
- SceneLayer *sl = CTX_data_scene_layer(C);
+ Scene *scene = WM_window_get_active_scene(win);
+ /* can't call BKE_scene_layer_context_active here, it uses G.main->wm which might be NULL on file read. */
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ SceneLayer *sl = BKE_workspace_render_layer_get(workspace);
Object *obedit = scene->obedit;
Object *obact = sl->basact ? sl->basact->object : NULL;
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 4e43a7f96e7..52c13871925 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -293,6 +293,7 @@ static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos
*/
void ED_screen_draw(wmWindow *win)
{
+ bScreen *screen = WM_window_get_active_screen(win);
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
@@ -301,7 +302,7 @@ void ED_screen_draw(wmWindow *win)
ScrArea *sa2 = NULL;
ScrArea *sa3 = NULL;
- wmSubWindowSet(win, win->screen->mainwin);
+ wmSubWindowSet(win, screen->mainwin);
unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -312,7 +313,7 @@ void ED_screen_draw(wmWindow *win)
glLineWidth((2.0f * U.pixelsize) - 1);
immUniformColor3ub(0x50, 0x50, 0x50);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
drawscredge_area(sa, winsize_x, winsize_y, pos);
}
}
@@ -320,7 +321,7 @@ void ED_screen_draw(wmWindow *win)
glLineWidth(1);
immUniformColor3ub(0, 0, 0);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
drawscredge_area(sa, winsize_x, winsize_y, pos);
/* gather area split/join info */
@@ -403,7 +404,7 @@ void ED_screen_draw(wmWindow *win)
immUnbindProgram();
- win->screen->do_draw = false;
+ screen->do_draw = false;
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index d59109a5baa..65b783463a9 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -51,6 +51,7 @@
#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -264,7 +265,7 @@ bool scredge_is_horizontal(ScrEdge *se)
}
/* need win size to make sure not to include edges along screen edge */
-ScrEdge *screen_find_active_scredge(bScreen *sc,
+ScrEdge *screen_find_active_scredge(const bScreen *sc,
const int winsize_x, const int winsize_y,
const int mx, const int my)
{
@@ -455,39 +456,35 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
return newa;
}
-/* empty screen, with 1 dummy area without spacedata */
-/* uses window size */
-bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name)
+/**
+ * Empty screen, with 1 dummy area without spacedata. Uses window size.
+ */
+bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
bScreen *sc;
ScrVert *sv1, *sv2, *sv3, *sv4;
-
+
sc = BKE_libblock_alloc(G.main, ID_SCR, name);
- sc->scene = scene;
sc->do_refresh = true;
sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
- sc->winid = win->winid;
sv1 = screen_addvert(sc, 0, 0);
sv2 = screen_addvert(sc, 0, winsize_y - 1);
sv3 = screen_addvert(sc, winsize_x - 1, winsize_y - 1);
sv4 = screen_addvert(sc, winsize_x - 1, 0);
-
+
screen_addedge(sc, sv1, sv2);
screen_addedge(sc, sv2, sv3);
screen_addedge(sc, sv3, sv4);
screen_addedge(sc, sv4, sv1);
-
+
/* dummy type, no spacedata */
screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_EMPTY);
-
+
return sc;
}
-static void screen_copy(bScreen *to, bScreen *from)
+void screen_data_copy(bScreen *to, bScreen *from)
{
ScrVert *s1, *s2;
ScrEdge *se;
@@ -530,7 +527,16 @@ static void screen_copy(bScreen *to, bScreen *from)
/* put at zero (needed?) */
for (s1 = from->vertbase.first; s1; s1 = s1->next)
s1->newv = NULL;
+}
+/**
+ * Prepare a newly created screen for initializing it as active screen.
+ */
+void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
+{
+ screen_new->winid = win->winid;
+ screen_new->do_refresh = true;
+ screen_new->do_draw = true;
}
@@ -841,24 +847,12 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
-bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
-{
- bScreen *newsc;
-
- if (sc->state != SCREENNORMAL) return NULL; /* XXX handle this case! */
-
- /* make new empty screen: */
- newsc = ED_screen_add(win, sc->scene, sc->id.name + 2);
- /* copy all data */
- screen_copy(newsc, sc);
-
- return newsc;
-}
-
/* screen sets cursor based on swinid */
static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
{
- for (ScrArea *sa = win->screen->areabase.first; sa; sa = sa->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid == swinid) {
if (swin_changed || (ar->type && ar->type->event_cursor)) {
@@ -876,19 +870,20 @@ static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
void ED_screen_do_listen(bContext *C, wmNotifier *note)
{
wmWindow *win = CTX_wm_window(C);
-
+ bScreen *screen = CTX_wm_screen(C);
+
/* generic notes */
switch (note->category) {
case NC_WM:
if (note->data == ND_FILEREAD)
- win->screen->do_draw = true;
+ screen->do_draw = true;
break;
case NC_WINDOW:
- win->screen->do_draw = true;
+ screen->do_draw = true;
break;
case NC_SCREEN:
if (note->action == NA_EDITED)
- win->screen->do_draw = win->screen->do_refresh = true;
+ screen->do_draw = screen->do_refresh = true;
break;
case NC_SCENE:
if (note->data == ND_MODE)
@@ -912,7 +907,9 @@ static void screen_refresh_headersizes(void)
/* make this screen usable */
/* for file read and first use, for scaling window, area moves */
void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
-{
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+
/* exception for bg mode, we only need the screen context */
if (!G.background) {
const int winsize_x = WM_window_pixels_x(win);
@@ -928,32 +925,34 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
/* header size depends on DPI, let's verify */
screen_refresh_headersizes();
- screen_test_scale(win->screen, winsize_x, winsize_y);
+ screen_test_scale(screen, winsize_x, winsize_y);
- if (win->screen->mainwin == 0) {
- win->screen->mainwin = wm_subwindow_open(win, &winrct, false);
+ if (screen->mainwin == 0) {
+ screen->mainwin = wm_subwindow_open(win, &winrct, false);
}
else {
- wm_subwindow_position(win, win->screen->mainwin, &winrct, false);
+ wm_subwindow_position(win, screen->mainwin, &winrct, false);
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
/* set spacetype and region callbacks, calls init() */
/* sets subwindows for regions, adds handlers */
ED_area_initialize(wm, win, sa);
}
/* wake up animtimer */
- if (win->screen->animtimer)
- WM_event_timer_sleep(wm, win, win->screen->animtimer, false);
+ if (screen->animtimer)
+ WM_event_timer_sleep(wm, win, screen->animtimer, false);
}
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set screen\n", __func__);
}
- win->screen->do_refresh = false;
+ screen->do_refresh = false;
+ /* prevent multiwin errors */
+ screen->winid = win->winid;
- win->screen->context = ed_screen_context;
+ screen->context = ed_screen_context;
}
/* file read, set all screens, ... */
@@ -962,10 +961,10 @@ void ED_screens_initialize(wmWindowManager *wm)
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
-
- if (win->screen == NULL)
- win->screen = G.main->screen.first;
-
+ if (WM_window_get_active_workspace(win) == NULL) {
+ WM_window_set_active_workspace(win, G.main->workspaces.first);
+ }
+
ED_screen_refresh(wm, win);
}
}
@@ -1053,7 +1052,7 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
/* mark it available for use for other windows */
screen->winid = 0;
- if (prevwin->screen->temp == 0) {
+ if (!WM_window_is_temp_screen(prevwin)) {
/* use previous window if possible */
CTX_wm_window_set(C, prevwin);
}
@@ -1069,13 +1068,14 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
/* case when on area-edge or in azones, or outside window */
static void screen_cursor_set(wmWindow *win, wmEvent *event)
{
+ const bScreen *screen = WM_window_get_active_screen(win);
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
AZone *az = NULL;
ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
+ for (sa = screen->areabase.first; sa; sa = sa->next)
if ((az = is_in_area_actionzone(sa, &event->x)))
break;
@@ -1090,7 +1090,7 @@ static void screen_cursor_set(wmWindow *win, wmEvent *event)
}
}
else {
- ScrEdge *actedge = screen_find_active_scredge(win->screen, winsize_x, winsize_y, event->x, event->y);
+ ScrEdge *actedge = screen_find_active_scredge(screen, winsize_x, winsize_y, event->x, event->y);
if (actedge) {
if (scredge_is_horizontal(actedge))
@@ -1109,9 +1109,9 @@ static void screen_cursor_set(wmWindow *win, wmEvent *event)
void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
-
- if (win->screen) {
- bScreen *scr = win->screen;
+ bScreen *scr = WM_window_get_active_screen(win);
+
+ if (scr) {
ScrArea *sa;
ARegion *ar;
int oldswin = scr->subwinactive;
@@ -1164,7 +1164,7 @@ void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
/* this used to be a notifier, but needs to be done immediate
* because it can undo setting the right button as active due
* to delayed notifier handling */
- UI_screen_free_active_but(C, win->screen);
+ UI_screen_free_active_but(C, scr);
}
else
region_cursor_set(win, scr->subwinactive, false);
@@ -1192,177 +1192,120 @@ int ED_screen_area_active(const bContext *C)
return 0;
}
+
+/* -------------------------------------------------------------------- */
+/* Screen changing */
+
+static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmain, bScreen *screen)
+{
+ for (bScreen *screen_iter = bmain->screen.first; screen_iter; screen_iter = screen_iter->id.next) {
+ ScrArea *sa = screen_iter->areabase.first;
+ if (sa->full == screen) {
+ return screen_iter;
+ }
+ }
+
+ return screen;
+}
+
/**
- * operator call, WM + Window + screen already existed before
- *
- * \warning Do NOT call in area/region queues!
- * \returns success.
+ * \return the screen to activate.
+ * \warning The returned screen may not always equal \a screen_new!
*/
-bool ED_screen_set(bContext *C, bScreen *sc)
+bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- bScreen *oldscreen = CTX_wm_screen(C);
-
/* validate screen, it's called with notifier reference */
- if (BLI_findindex(&bmain->screen, sc) == -1) {
- return true;
+ if (BLI_findindex(&bmain->screen, screen_new) == -1) {
+ return NULL;
}
- if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
- /* find associated full */
- bScreen *sc1;
- for (sc1 = bmain->screen.first; sc1; sc1 = sc1->id.next) {
- ScrArea *sa = sc1->areabase.first;
- if (sa->full == sc) {
- sc = sc1;
- break;
- }
- }
+ if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) {
+ screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new);
}
/* check for valid winid */
- if (sc->winid != 0 && sc->winid != win->winid) {
- return false;
+ if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) {
+ return NULL;
}
-
- if (oldscreen != sc) {
- wmTimer *wt = oldscreen->animtimer;
- ScrArea *sa;
- Scene *oldscene = oldscreen->scene;
+
+ if (screen_old != screen_new) {
+ wmTimer *wt = screen_old->animtimer;
/* remove handlers referencing areas in old screen */
- for (sa = oldscreen->areabase.first; sa; sa = sa->next) {
+ for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) {
WM_event_remove_area_handler(&win->modalhandlers, sa);
}
/* we put timer to sleep, so screen_exit has to think there's no timer */
- oldscreen->animtimer = NULL;
+ screen_old->animtimer = NULL;
if (wt) {
- WM_event_timer_sleep(wm, win, wt, true);
+ WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
}
-
- ED_screen_exit(C, win, oldscreen);
+ ED_screen_exit(C, win, screen_old);
/* Same scene, "transfer" playback to new screen. */
if (wt) {
- if (oldscene == sc->scene) {
- sc->animtimer = wt;
- }
- /* Else, stop playback. */
- else {
- oldscreen->animtimer = wt;
- ED_screen_animation_play(C, 0, 0);
- }
+ screen_new->animtimer = wt;
}
- win->screen = sc;
- CTX_wm_window_set(C, win); // stores C->wm.screen... hrmf
-
- /* prevent multiwin errors */
- sc->winid = win->winid;
-
- ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENSET, sc);
-
- /* makes button hilites work */
- WM_event_add_mousemove(C);
-
- /* Needed to make sure all the derivedMeshes are
- * up-to-date before viewport starts acquiring this.
- *
- * This is needed in cases when, for example, boolean
- * modifier uses operant from invisible layer.
- * Without this trick boolean wouldn't apply correct.
- *
- * Quite the same happens when setting screen's scene,
- * so perhaps this is in fact correct thing to do.
- */
- if (oldscene != sc->scene) {
- BKE_scene_set_background(bmain, sc->scene);
- }
-
- /* Always do visible update since it's possible new screen will
- * have different layers visible in 3D view-ports.
- * This is possible because of view3d.lock_camera_and_layers option.
- */
- DAG_on_visible_update(bmain, false);
+ return screen_new;
}
- return true;
+ return NULL;
}
-static bool ed_screen_used(wmWindowManager *wm, bScreen *sc)
+void screen_changed_update(bContext *C, wmWindow *win, bScreen *sc)
{
- wmWindow *win;
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen == sc) {
- return true;
- }
+ CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
- if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) {
- ScrArea *sa = win->screen->areabase.first;
- if (sa->full == sc) {
- return true;
- }
- }
- }
+ ED_screen_refresh(CTX_wm_manager(C), win);
- return false;
+ BKE_screen_view3d_scene_sync(sc, scene); /* sync new screen with scene data */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTSET, layout);
+
+ /* makes button hilites work */
+ WM_event_add_mousemove(C);
}
-/* only call outside of area/region loops */
-bool ED_screen_delete(bContext *C, bScreen *sc)
+
+/**
+ * \brief Change the active screen.
+ *
+ * Operator call, WM + Window + screen already existed before
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if screen changing was successful.
+ */
+bool ED_screen_change(bContext *C, bScreen *sc)
{
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- bScreen *newsc;
-
- /* don't allow deleting temp fullscreens for now */
- if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
- return false;
- }
+ bScreen *screen_old = CTX_wm_screen(C);
+ bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win);
- /* screen can only be in use by one window at a time, so as
- * long as we are able to find a screen that is unused, we
- * can safely assume ours is not in use anywhere an delete it */
+ if (screen_new) {
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WM_window_set_active_screen(win, workspace, sc);
+ screen_changed_update(C, win, screen_new);
- for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
-
- if (!newsc) {
- for (newsc = sc->id.next; newsc; newsc = newsc->id.next)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
- }
-
- if (!newsc) {
- return false;
- }
-
- ED_screen_set(C, newsc);
-
- if (win->screen != sc) {
- BKE_libblock_free(bmain, sc);
return true;
}
- else {
- return false;
- }
+
+ return false;
}
-static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa, View3D *v3d)
+static void screen_set_3dview_camera(Scene *scene, ScrArea *sa, View3D *v3d)
{
/* fix any cameras that are used in the 3d view but not in the scene */
BKE_screen_view3d_sync(v3d, scene);
if (!v3d->camera || !BKE_scene_base_find(scene, v3d->camera)) {
- v3d->camera = BKE_scene_camera_find(sc->scene);
+ v3d->camera = BKE_scene_camera_find(scene);
// XXX if (sc == curscreen) handle_view3d_lock();
if (!v3d->camera) {
ARegion *ar;
@@ -1386,90 +1329,16 @@ static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa,
}
}
-/* only call outside of area/region loops */
-void ED_screen_set_scene(bContext *C, bScreen *screen, Scene *scene)
+void ED_screen_update_after_scene_change(const bScreen *screen, Scene *scene_new)
{
- Main *bmain = CTX_data_main(C);
- bScreen *sc;
-
- if (screen == NULL)
- return;
-
- if (ed_screen_used(CTX_wm_manager(C), screen))
- ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
-
- if (scene != sc->scene) {
- /* all areas endlocalview */
- // XXX ScrArea *sa = sc->areabase.first;
- // while (sa) {
- // endlocalview(sa);
- // sa = sa->next;
- // }
- sc->scene = scene;
- }
-
- }
- }
-
- // copy_view3d_lock(0); /* space.c */
-
- /* are there cameras in the views that are not in the scene? */
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl = sa->spacedata.first;
- while (sl) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- ed_screen_set_3dview_camera(scene, sc, sa, v3d);
-
- }
- sl = sl->next;
- }
- sa = sa->next;
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ screen_set_3dview_camera(scene_new, sa, v3d);
}
}
}
-
- CTX_data_scene_set(C, scene);
- BKE_scene_set_background(bmain, scene);
- DAG_on_visible_update(bmain, false);
-
- ED_render_engine_changed(bmain);
- ED_update_for_newframe(bmain, scene, 1);
-
- /* complete redraw */
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
-}
-
-/**
- * \note Only call outside of area/region loops
- * \return true if successful
- */
-bool ED_screen_delete_scene(bContext *C, Scene *scene)
-{
- Main *bmain = CTX_data_main(C);
- Scene *newscene;
-
- if (scene->id.prev)
- newscene = scene->id.prev;
- else if (scene->id.next)
- newscene = scene->id.next;
- else
- return false;
-
- ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
-
- BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
-
- BKE_libblock_free(bmain, scene);
-
- return true;
}
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
@@ -1576,6 +1445,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
bScreen *sc, *oldscreen;
ARegion *ar;
@@ -1597,11 +1467,12 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
if (sa && sa->full) {
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
/* restoring back to SCREENNORMAL */
ScrArea *old;
sc = sa->full; /* the old screen to restore */
- oldscreen = win->screen; /* the one disappearing */
+ oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
sc->state = SCREENNORMAL;
@@ -1629,10 +1500,9 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
sc->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
- ED_screen_set(C, sc);
+ ED_screen_change(C, sc);
- BKE_screen_free(oldscreen);
- BKE_libblock_free(CTX_data_main(C), oldscreen);
+ BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
/* After we've restored back to SCREENNORMAL, we have to wait with
* screen handling as it uses the area coords which aren't updated yet.
@@ -1642,14 +1512,18 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
else {
/* change from SCREENNORMAL to new state */
+ WorkSpaceLayout *layout_new;
ScrArea *newa;
char newname[MAX_ID_NAME - 2];
- oldscreen = win->screen;
+ oldscreen = WM_window_get_active_screen(win);
oldscreen->state = state;
BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
- sc = ED_screen_add(win, oldscreen->scene, newname);
+
+ layout_new = ED_workspace_layout_add(workspace, win, newname);
+
+ sc = BKE_workspace_layout_screen_get(layout_new);
sc->state = state;
sc->redraws_flag = oldscreen->redraws_flag;
sc->temp = oldscreen->temp;
@@ -1704,7 +1578,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
BLI_assert(false);
}
- ED_screen_set(C, sc);
+ ED_screen_change(C, sc);
}
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
@@ -1850,7 +1724,7 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
scene->camera = camera;
/* are there cameras in the views that are not in the scene? */
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
}
}
#endif
@@ -1879,11 +1753,10 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
/*
* return true if any active area requires to see in 3D
*/
-bool ED_screen_stereo3d_required(bScreen *screen)
+bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
ScrArea *sa;
- Scene *sce = screen->scene;
- const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
for (sa = screen->areabase.first; sa; sa = sa->next) {
switch (sa->spacetype) {
@@ -1958,3 +1831,19 @@ bool ED_screen_stereo3d_required(bScreen *screen)
return false;
}
+
+/**
+ * Find the scene displayed in \a screen.
+ * \note Assumes \a screen to be visible/active!
+ */
+Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return WM_window_get_active_scene(win);
+ }
+ }
+
+ BLI_assert(0);
+ return NULL;
+}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 49c0869fcfb..4eb68d01df7 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -32,6 +32,7 @@
#define __SCREEN_INTERN_H__
struct bContextDataResult;
+struct Main;
/* internal exports only */
@@ -45,6 +46,11 @@ void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2);
void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade);
/* screen_edit.c */
+bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y);
+void screen_data_copy(bScreen *to, bScreen *from);
+void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
+void screen_changed_update(struct bContext *C, wmWindow *win, bScreen *sc);
+bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, struct Main *bmain, struct bContext *C, wmWindow *win);
ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2);
ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2);
@@ -56,7 +62,7 @@ void removedouble_scrverts(bScreen *sc);
void removedouble_scredges(bScreen *sc);
void removenotused_scredges(bScreen *sc);
bool scredge_is_horizontal(ScrEdge *se);
-ScrEdge *screen_find_active_scredge(bScreen *sc,
+ScrEdge *screen_find_active_scredge(const bScreen *sc,
const int winsize_x, const int winsize_y,
const int mx, const int my);
@@ -74,5 +80,8 @@ void SCREEN_OT_screencast(struct wmOperatorType *ot);
/* screen_ops.c */
void region_blend_start(struct bContext *C, struct ScrArea *sa, struct ARegion *ar);
+/* workspace_layout_edit.c */
+bool workspace_layout_set_poll(const struct WorkSpaceLayout *layout);
+
#endif /* __SCREEN_INTERN_H__ */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 69d13beee48..5cd68f5121c 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -62,6 +62,7 @@
#include "BKE_editmesh.h"
#include "BKE_sound.h"
#include "BKE_mask.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -978,13 +979,17 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot)
/* operator callback */
static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *newwin, *win;
- bScreen *newsc, *sc;
+ wmWindow *newwin, *win = CTX_wm_window(C);
+ Scene *scene;
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+ WorkSpaceLayout *layout_new;
+ bScreen *newsc;
ScrArea *sa;
rcti rect;
win = CTX_wm_window(C);
- sc = CTX_wm_screen(C);
+ scene = CTX_data_scene(C);
sa = CTX_wm_area(C);
/* XXX hrmf! */
@@ -1010,11 +1015,15 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
*newwin->stereo3d_format = *win->stereo3d_format;
-
+
+ newwin->scene = scene;
+
+ WM_window_set_active_workspace(newwin, workspace);
/* allocs new screen and adds to newly created window, using window size */
- newsc = ED_screen_add(newwin, CTX_data_scene(C), sc->id.name + 2);
- newwin->screen = newsc;
-
+ layout_new = ED_workspace_layout_add(workspace, newwin, BKE_workspace_layout_name_get(layout_old));
+ newsc = BKE_workspace_layout_screen_get(layout_new);
+ WM_window_set_active_layout(newwin, workspace, layout_new);
+
/* copy area to new screen */
ED_area_data_copy((ScrArea *)newsc->areabase.first, sa, true);
@@ -1714,7 +1723,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- CTX_wm_window(C)->screen->do_draw = true;
+ CTX_wm_screen(C)->do_draw = true;
}
@@ -2084,12 +2093,11 @@ static void areas_do_frame_follow(bContext *C, bool middle)
bScreen *scr = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *window;
- for (window = wm->windows.first; window; window = window->next) {
- ScrArea *sa;
- for (sa = window->screen->areabase.first; sa; sa = sa->next) {
- ARegion *ar;
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ for (wmWindow *window = wm->windows.first; window; window = window->next) {
+ const bScreen *screen = WM_window_get_active_screen(window);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
/* do follow here if editor type supports it */
if ((scr->redraws_flag & TIME_FOLLOW)) {
if ((ar->regiontype == RGN_TYPE_WINDOW &&
@@ -2385,64 +2393,16 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
/* ************** switch screen operator ***************************** */
-static bool screen_set_is_ok(bScreen *screen, bScreen *screen_prev)
-{
- return ((screen->winid == 0) &&
- /* in typical usage these should have a nonzero winid
- * (all temp screens should be used, or closed & freed). */
- (screen->temp == false) &&
- (screen->state == SCREENNORMAL) &&
- (screen != screen_prev) &&
- (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
-}
-
/* function to be called outside UI context, or for redo */
static int screen_set_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- bScreen *screen = CTX_wm_screen(C);
- bScreen *screen_prev = screen;
-
- ScrArea *sa = CTX_wm_area(C);
- int tot = BLI_listbase_count(&bmain->screen);
+ WorkSpace *workspace = CTX_wm_workspace(C);
int delta = RNA_int_get(op->ptr, "delta");
-
- /* temp screens are for userpref or render display */
- if (screen->temp || (sa && sa->full && sa->full->temp)) {
- return OPERATOR_CANCELLED;
- }
-
- if (delta == 1) {
- while (tot--) {
- screen = screen->id.next;
- if (screen == NULL) screen = bmain->screen.first;
- if (screen_set_is_ok(screen, screen_prev)) {
- break;
- }
- }
- }
- else if (delta == -1) {
- while (tot--) {
- screen = screen->id.prev;
- if (screen == NULL) screen = bmain->screen.last;
- if (screen_set_is_ok(screen, screen_prev)) {
- break;
- }
- }
- }
- else {
- screen = NULL;
- }
-
- if (screen && screen_prev != screen) {
- /* return to previous state before switching screens */
- if (sa && sa->full) {
- ED_screen_full_restore(C, sa); /* may free 'screen_prev' */
- }
-
- ED_screen_set(C, screen);
+
+ if (ED_workspace_layout_cycle(workspace, delta, C)) {
return OPERATOR_FINISHED;
}
+
return OPERATOR_CANCELLED;
}
@@ -3297,7 +3257,7 @@ static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op))
sa->flag = sa->flag ^ HEADER_NO_PULLDOWN;
ED_area_tag_redraw(sa);
- WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -3594,7 +3554,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
ED_update_for_newframe(bmain, scene, 1);
for (window = wm->windows.first; window; window = window->next) {
- for (sa = window->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *win_screen = WM_window_get_active_screen(window);
+
+ for (sa = win_screen->areabase.first; sa; sa = sa->next) {
ARegion *ar;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
bool redraw = false;
@@ -3668,11 +3630,11 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
- wmWindow *win;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->animtimer || win->screen->scrubbing) {
- return win->screen;
+ if (screen->animtimer || screen->scrubbing) {
+ return screen;
}
}
@@ -3681,11 +3643,11 @@ bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
{
- wmWindow *win;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->animtimer) {
- return win->screen;
+ if (screen->animtimer) {
+ return screen;
}
}
@@ -3919,11 +3881,13 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
-
- sc = ED_screen_duplicate(win, sc);
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, sc);
-
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout_old = BKE_workspace_active_layout_get(win->workspace_hook);
+ WorkSpaceLayout *layout_new;
+
+ layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
+
return OPERATOR_FINISHED;
}
@@ -3944,9 +3908,11 @@ static void SCREEN_OT_new(wmOperatorType *ot)
static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
bScreen *sc = CTX_wm_screen(C);
-
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENDELETE, sc);
-
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
+
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, layout);
+
return OPERATOR_FINISHED;
}
@@ -3961,95 +3927,6 @@ static void SCREEN_OT_delete(wmOperatorType *ot)
ot->exec = screen_delete_exec;
}
-/********************* new scene operator *********************/
-
-static int scene_new_exec(bContext *C, wmOperator *op)
-{
- Scene *newscene, *scene = CTX_data_scene(C);
- Main *bmain = CTX_data_main(C);
- int type = RNA_enum_get(op->ptr, "type");
-
- if (type == SCE_COPY_NEW) {
- newscene = BKE_scene_add(bmain, DATA_("Scene"));
- }
- else { /* different kinds of copying */
- newscene = BKE_scene_copy(bmain, scene, type);
-
- /* these can't be handled in blenkernel currently, so do them here */
- if (type == SCE_COPY_LINK_DATA) {
- ED_object_single_users(bmain, newscene, false, true);
- }
- else if (type == SCE_COPY_FULL) {
- ED_editors_flush_edits(C, false);
- ED_object_single_users(bmain, newscene, true, true);
- }
- }
-
- ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
-
- WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, newscene);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCENE_OT_new(wmOperatorType *ot)
-{
- static EnumPropertyItem type_items[] = {
- {SCE_COPY_NEW, "NEW", 0, "New", "Add new scene"},
- {SCE_COPY_EMPTY, "EMPTY", 0, "Copy Settings", "Make a copy without any objects"},
- {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
- {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
- {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name = "New Scene";
- ot->description = "Add new scene by type";
- ot->idname = "SCENE_OT_new";
-
- /* api callbacks */
- ot->exec = scene_new_exec;
- ot->invoke = WM_menu_invoke;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
-}
-
-/********************* delete scene operator *********************/
-
-static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
-
- if (ED_screen_delete_scene(C, scene) == false) {
- return OPERATOR_CANCELLED;
- }
-
- if (G.debug & G_DEBUG)
- printf("scene delete %p\n", scene);
-
- WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCENE_OT_delete(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Delete Scene";
- ot->description = "Delete active scene";
- ot->idname = "SCENE_OT_delete";
-
- /* api callbacks */
- ot->exec = scene_delete_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ***************** region alpha blending ***************** */
/* implementation note: a disappearing region needs at least 1 last draw with 100% backbuffer
@@ -4321,13 +4198,11 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_animation_step);
WM_operatortype_append(SCREEN_OT_animation_play);
WM_operatortype_append(SCREEN_OT_animation_cancel);
-
+
/* new/delete */
WM_operatortype_append(SCREEN_OT_new);
WM_operatortype_append(SCREEN_OT_delete);
- WM_operatortype_append(SCENE_OT_new);
- WM_operatortype_append(SCENE_OT_delete);
-
+
/* tools shared by more space types */
WM_operatortype_append(ED_OT_undo);
WM_operatortype_append(ED_OT_undo_push);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
new file mode 100644
index 00000000000..3782d583003
--- /dev/null
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -0,0 +1,426 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/workspace_edit.c
+ * \ingroup edscr
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_appdir.h"
+#include "BKE_blendfile.h"
+#include "BKE_context.h"
+#include "BKE_idcode.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
+
+#include "BLO_readfile.h"
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "screen_intern.h"
+
+
+/** \name Workspace API
+ *
+ * \brief API for managing workspaces and their data.
+ * \{ */
+
+WorkSpace *ED_workspace_add(
+ Main *bmain, const char *name, SceneLayer *act_render_layer)
+{
+ WorkSpace *workspace = BKE_workspace_add(bmain, name);
+
+#ifdef USE_WORKSPACE_MODE
+ BKE_workspace_object_mode_set(workspace, OB_MODE_OBJECT);
+#endif
+
+ BKE_workspace_render_layer_set(workspace, act_render_layer);
+
+ return workspace;
+}
+
+#ifdef USE_WORKSPACE_MODE
+/**
+ * Changes the object mode (if needed) to the one set in \a workspace_new.
+ * Object mode is still stored on object level. In future it should all be workspace level instead.
+ */
+static void workspace_change_update_mode(
+ const WorkSpace *workspace_old, const WorkSpace *workspace_new,
+ bContext *C, Object *ob_act, ReportList *reports)
+{
+ ObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old);
+ ObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new);
+
+ if (mode_old != mode_new) {
+ ED_object_mode_compat_set(C, ob_act, mode_new, reports);
+ ED_object_toggle_modes(C, mode_new);
+ }
+}
+#endif
+
+static void workspace_change_update_render_layer(
+ WorkSpace *workspace_new, const WorkSpace *workspace_old)
+{
+ if (!BKE_workspace_render_layer_get(workspace_new)) {
+ BKE_workspace_render_layer_set(workspace_new, BKE_workspace_render_layer_get(workspace_old));
+ }
+}
+
+static void workspace_change_update(
+ WorkSpace *workspace_new, const WorkSpace *workspace_old,
+ bContext *C, wmWindowManager *wm)
+{
+ /* needs to be done before changing mode! (to ensure right context) */
+ workspace_change_update_render_layer(workspace_new, workspace_old);
+#ifdef USE_WORKSPACE_MODE
+ workspace_change_update_mode(workspace_old, workspace_new, C, CTX_data_active_object(C), &wm->reports);
+#else
+ UNUSED_VARS(C, wm);
+#endif
+}
+
+static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
+{
+ /* return false to stop the iterator if we've found a layout that can be activated */
+ return workspace_layout_set_poll(layout) ? false : true;
+}
+
+static WorkSpaceLayout *workspace_change_get_new_layout(
+ WorkSpace *workspace_new, wmWindow *win)
+{
+ /* ED_workspace_duplicate may have stored a layout to activate once the workspace gets activated. */
+ WorkSpaceLayout *layout_new;
+ bScreen *screen_new;
+
+ if (win->workspace_hook->temp_workspace_store) {
+ layout_new = win->workspace_hook->temp_layout_store;
+ }
+ else {
+ layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new);
+ if (!layout_new) {
+ layout_new = BKE_workspace_layouts_get(workspace_new)->first;
+ }
+ }
+ screen_new = BKE_workspace_layout_screen_get(layout_new);
+
+ if (screen_new->winid) {
+ /* screen is already used, try to find a free one */
+ WorkSpaceLayout *layout_temp = BKE_workspace_layout_iter_circular(
+ workspace_new, layout_new, workspace_change_find_new_layout_cb,
+ NULL, false);
+ if (!layout_temp) {
+ /* fallback solution: duplicate layout */
+ layout_temp = ED_workspace_layout_duplicate(workspace_new, layout_new, win);
+ }
+ layout_new = layout_temp;
+ }
+
+ return layout_new;
+}
+
+/**
+ * \brief Change the active workspace.
+ *
+ * Operator call, WM + Window + screen already existed before
+ * Pretty similar to #ED_screen_change since changing workspace also changes screen.
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if workspace changing was successful.
+ */
+bool ED_workspace_change(
+ WorkSpace *workspace_new, bContext *C, wmWindowManager *wm, wmWindow *win)
+{
+ Main *bmain = CTX_data_main(C);
+ WorkSpace *workspace_old = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout_new = workspace_change_get_new_layout(workspace_new, win);
+ bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
+ bScreen *screen_old = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ win->workspace_hook->temp_layout_store = NULL;
+ if (workspace_old == workspace_new) {
+ /* Could also return true, everything that needs to be done was done (nothing :P), but nothing changed */
+ return false;
+ }
+
+ screen_new = screen_change_prepare(screen_old, screen_new, bmain, C, win);
+ BLI_assert(BKE_workspace_layout_screen_get(layout_new) == screen_new);
+
+ if (screen_new) {
+ WM_window_set_active_layout(win, workspace_new, layout_new);
+ WM_window_set_active_workspace(win, workspace_new);
+
+ /* update screen *after* changing workspace - which also causes the actual screen change */
+ screen_changed_update(C, win, screen_new);
+ workspace_change_update(workspace_new, workspace_old, C, wm);
+
+ BLI_assert(BKE_workspace_render_layer_get(workspace_new) != NULL);
+ BLI_assert(CTX_wm_workspace(C) == workspace_new);
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Duplicate a workspace including its layouts. Does not activate the workspace, but
+ * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
+ */
+WorkSpace *ED_workspace_duplicate(
+ WorkSpace *workspace_old, Main *bmain, wmWindow *win)
+{
+ WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
+ ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old);
+ WorkSpace *workspace_new = ED_workspace_add(
+ bmain, workspace_old->id.name + 2,
+ BKE_workspace_render_layer_get(workspace_old));
+
+#ifdef USE_WORKSPACE_MODE
+ BKE_workspace_object_mode_set(workspace_new, BKE_workspace_object_mode_get(workspace_old));
+#endif
+
+ for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) {
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace_new, layout_old, win);
+
+ if (layout_active_old == layout_old) {
+ win->workspace_hook->temp_layout_store = layout_new;
+ }
+ }
+
+ return workspace_new;
+}
+
+/**
+ * \return if succeeded.
+ */
+bool ED_workspace_delete(
+ WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm, wmWindow *win)
+{
+ ID *workspace_id = (ID *)workspace;
+
+ if (BLI_listbase_is_single(&bmain->workspaces)) {
+ return false;
+ }
+
+ if (WM_window_get_active_workspace(win) == workspace) {
+ WorkSpace *prev = workspace_id->prev;
+ WorkSpace *next = workspace_id->next;
+
+ ED_workspace_change((prev != NULL) ? prev : next, C, wm, win);
+ }
+ BKE_libblock_free(bmain, workspace_id);
+
+ return true;
+}
+
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in active layout of \a workspace.
+ */
+void ED_workspace_scene_data_sync(
+ WorkSpaceInstanceHook *hook, Scene *scene)
+{
+ bScreen *screen = BKE_workspace_active_screen_get(hook);
+ BKE_screen_view3d_scene_sync(screen, scene);
+}
+
+/** \} Workspace API */
+
+
+/** \name Workspace Operators
+ *
+ * \{ */
+
+static int workspace_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = ED_workspace_duplicate(WM_window_get_active_workspace(win), bmain, win);
+
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_workspace_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Workspace";
+ ot->description = "Add a new workspace";
+ ot->idname = "WORKSPACE_OT_workspace_duplicate";
+
+ /* api callbacks */
+ ot->exec = workspace_new_exec;
+ ot->poll = WM_operator_winactive;
+}
+
+static int workspace_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
+ ED_workspace_delete(WM_window_get_active_workspace(win), bmain, C, wm, win);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_workspace_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Workspace";
+ ot->description = "Delete the active workspace";
+ ot->idname = "WORKSPACE_OT_workspace_delete";
+
+ /* api callbacks */
+ ot->exec = workspace_delete_exec;
+}
+
+static void workspace_config_file_path_from_folder_id(
+ const Main *bmain, int folder_id, char *r_path)
+{
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id(folder_id, app_template);
+
+ if (cfgdir) {
+ BLI_make_file_string(bmain->name, r_path, cfgdir, BLENDER_WORKSPACES_FILE);
+ }
+ else {
+ r_path[0] = '\0';
+ }
+}
+
+ATTR_NONNULL(1)
+static WorkspaceConfigFileData *workspace_config_file_read(
+ const Main *bmain, ReportList *reports)
+{
+ char workspace_config_path[FILE_MAX];
+ bool has_path = false;
+
+ workspace_config_file_path_from_folder_id(bmain, BLENDER_USER_CONFIG, workspace_config_path);
+ if (BLI_exists(workspace_config_path)) {
+ has_path = true;
+ }
+ else {
+ workspace_config_file_path_from_folder_id(bmain, BLENDER_DATAFILES, workspace_config_path);
+ if (BLI_exists(workspace_config_path)) {
+ has_path = true;
+ }
+ }
+
+ return has_path ? BKE_blendfile_workspace_config_read(workspace_config_path, reports) : NULL;
+}
+
+static void workspace_append_button(
+ uiLayout *layout, wmOperatorType *ot_append, const WorkSpace *workspace, const Main *from_main)
+{
+ const ID *id = (ID *)workspace;
+ PointerRNA opptr;
+ char lib_path[FILE_MAX_LIBEXTRA];
+
+ BLI_path_join(
+ lib_path, sizeof(lib_path), from_main->name, BKE_idcode_to_name(GS(id->name)), NULL);
+
+ BLI_assert(STREQ(ot_append->idname, "WM_OT_append"));
+ opptr = uiItemFullO_ptr(
+ layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL,
+ WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_string_set(&opptr, "directory", lib_path);
+ RNA_string_set(&opptr, "filename", id->name + 2);
+}
+
+ATTR_NONNULL(1, 2)
+static void workspace_config_file_append_buttons(
+ uiLayout *layout, const Main *bmain, ReportList *reports)
+{
+ WorkspaceConfigFileData *workspace_config = workspace_config_file_read(bmain, reports);
+
+ if (workspace_config) {
+ wmOperatorType *ot_append = WM_operatortype_find("WM_OT_append", true);
+
+ for (WorkSpace *workspace = workspace_config->workspaces.first; workspace; workspace = workspace->id.next) {
+ workspace_append_button(layout, ot_append, workspace, workspace_config->main);
+ }
+
+ BKE_blendfile_workspace_config_data_free(workspace_config);
+ }
+}
+
+static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const Main *bmain = CTX_data_main(C);
+
+ uiPopupMenu *pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ uiItemO(layout, "Duplicate Current", ICON_NONE, "WORKSPACE_OT_workspace_duplicate");
+ uiItemS(layout);
+ workspace_config_file_append_buttons(layout, bmain, op->reports);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+static void WORKSPACE_OT_workspace_add_menu(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Workspace";
+ ot->description = "Add a new workspace by duplicating the current one or appending one "
+ "from the user configuration";
+ ot->idname = "WORKSPACE_OT_workspace_add_menu";
+
+ /* api callbacks */
+ ot->invoke = workspace_add_invoke;
+}
+
+void ED_operatortypes_workspace(void)
+{
+ WM_operatortype_append(WORKSPACE_OT_workspace_duplicate);
+ WM_operatortype_append(WORKSPACE_OT_workspace_delete);
+ WM_operatortype_append(WORKSPACE_OT_workspace_add_menu);
+}
+
+/** \} Workspace Operators */
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
new file mode 100644
index 00000000000..e4dd841f833
--- /dev/null
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -0,0 +1,198 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/workspace_layout_edit.c
+ * \ingroup edscr
+ */
+
+#include <stdlib.h>
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+
+#include "screen_intern.h"
+
+
+/**
+ * Empty screen, with 1 dummy area without spacedata. Uses window size.
+ */
+WorkSpaceLayout *ED_workspace_layout_add(
+ WorkSpace *workspace,
+ wmWindow *win,
+ const char *name)
+{
+ const int winsize_x = WM_window_pixels_x(win);
+ const int winsize_y = WM_window_pixels_y(win);
+
+ bScreen *screen = screen_add(name, winsize_x, winsize_y);
+ WorkSpaceLayout *layout = BKE_workspace_layout_add(workspace, screen, name);
+
+ return layout;
+}
+
+WorkSpaceLayout *ED_workspace_layout_duplicate(
+ WorkSpace *workspace, const WorkSpaceLayout *layout_old,
+ wmWindow *win)
+{
+ bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
+ const char *name = BKE_workspace_layout_name_get(layout_old);
+ bScreen *screen_new;
+ WorkSpaceLayout *layout_new;
+
+ if (BKE_screen_is_fullscreen_area(screen_old)) {
+ return NULL; /* XXX handle this case! */
+ }
+
+ layout_new = ED_workspace_layout_add(workspace, win, name);
+ screen_new = BKE_workspace_layout_screen_get(layout_new);
+ screen_data_copy(screen_new, screen_old);
+
+ return layout_new;
+}
+
+static bool workspace_layout_delete_doit(
+ WorkSpace *workspace, WorkSpaceLayout *layout_old, WorkSpaceLayout *layout_new,
+ bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
+
+ ED_screen_change(C, screen_new);
+
+ if (BKE_workspace_active_layout_get(win->workspace_hook) != layout_old) {
+ BKE_workspace_layout_remove(bmain, workspace, layout_old);
+ return true;
+ }
+
+ return false;
+}
+
+bool workspace_layout_set_poll(const WorkSpaceLayout *layout)
+{
+ const bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ return ((BKE_screen_is_used(screen) == false) &&
+ /* in typical usage temp screens should have a nonzero winid
+ * (all temp screens should be used, or closed & freed). */
+ (screen->temp == false) &&
+ (BKE_screen_is_fullscreen_area(screen) == false) &&
+ (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
+}
+
+static WorkSpaceLayout *workspace_layout_delete_find_new(const WorkSpaceLayout *layout_old)
+{
+ for (WorkSpaceLayout *layout_new = layout_old->prev; layout_new; layout_new = layout_new->next) {
+ if (workspace_layout_set_poll(layout_new)) {
+ return layout_new;
+ }
+ }
+
+ for (WorkSpaceLayout *layout_new = layout_old->next; layout_new; layout_new = layout_new->next) {
+ if (workspace_layout_set_poll(layout_new)) {
+ return layout_new;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * \warning Only call outside of area/region loops!
+ * \return true if succeeded.
+ */
+bool ED_workspace_layout_delete(
+ WorkSpace *workspace, WorkSpaceLayout *layout_old,
+ bContext *C)
+{
+ const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
+ WorkSpaceLayout *layout_new;
+
+ BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1);
+
+ /* don't allow deleting temp fullscreens for now */
+ if (BKE_screen_is_fullscreen_area(screen_old)) {
+ return false;
+ }
+
+ /* A layout/screen can only be in use by one window at a time, so as
+ * long as we are able to find a layout/screen that is unused, we
+ * can safely assume ours is not in use anywhere an delete it. */
+
+ layout_new = workspace_layout_delete_find_new(layout_old);
+
+ if (layout_new) {
+ return workspace_layout_delete_doit(workspace, layout_old, layout_new, C);
+ }
+
+ return false;
+}
+
+static bool workspace_layout_cycle_iter_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
+{
+ /* return false to stop iterator when we have found a layout to activate */
+ return !workspace_layout_set_poll(layout);
+}
+
+bool ED_workspace_layout_cycle(
+ WorkSpace *workspace, const short direction, bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpaceLayout *old_layout = BKE_workspace_active_layout_get(win->workspace_hook);
+ WorkSpaceLayout *new_layout;
+ const bScreen *old_screen = BKE_workspace_layout_screen_get(old_layout);
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (old_screen->temp || (sa && sa->full && sa->full->temp)) {
+ return false;
+ }
+
+ BLI_assert(ELEM(direction, 1, -1));
+ new_layout = BKE_workspace_layout_iter_circular(workspace, old_layout, workspace_layout_cycle_iter_cb,
+ NULL, (direction == -1) ? true : false);
+
+ if (new_layout && (old_layout != new_layout)) {
+ bScreen *new_screen = BKE_workspace_layout_screen_get(new_layout);
+
+ if (sa && sa->full) {
+ /* return to previous state before switching screens */
+ ED_screen_full_restore(C, sa); /* may free screen of old_layout */
+ }
+
+ ED_screen_change(C, new_screen);
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 1b18dd4e41c..64bd866c0db 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -1056,16 +1056,20 @@ static void toggle_paint_cursor(bContext *C, int enable)
void ED_space_image_paint_update(wmWindowManager *wm, Scene *scene)
{
ToolSettings *settings = scene->toolsettings;
- wmWindow *win;
- ScrArea *sa;
ImagePaintSettings *imapaint = &settings->imapaint;
bool enabled = false;
- for (win = wm->windows.first; win; win = win->next)
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
- if (sa->spacetype == SPACE_IMAGE)
- if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT)
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT) {
enabled = true;
+ }
+ }
+ }
+ }
if (enabled) {
BKE_paint_init(scene, ePaintTexture2D, PAINT_CURSOR_TEXTURE_PAINT);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index e76d83715a2..fca54b282f8 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -395,7 +395,11 @@ static void action_main_region_listener(
if (wmn->action == NA_RENAME)
ED_region_tag_redraw(ar);
break;
-
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
default:
if (wmn->data == ND_KEYS)
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 4d601a31251..3a431eb82df 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -55,6 +55,7 @@
#include "ED_paint.h"
#include "ED_physics.h"
#include "ED_render.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_space_api.h"
@@ -99,6 +100,8 @@ void ED_spacetypes_init(void)
// ...
/* register operator types for screen and all spaces */
+ ED_operatortypes_workspace();
+ ED_operatortypes_scene();
ED_operatortypes_screen();
ED_operatortypes_anim();
ED_operatortypes_animchannels();
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 47297e84242..299ab7171d6 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -178,6 +178,20 @@ static void buttons_main_region_draw(const bContext *C, ARegion *ar)
sbuts->mainbo = sbuts->mainb;
}
+static void buttons_main_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn,
+ const Scene *UNUSED(scene))
+{
+ /* context changes */
+ switch (wmn->category) {
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
+ }
+}
+
static void buttons_operatortypes(void)
{
WM_operatortype_append(BUTTONS_OT_toolbox);
@@ -471,6 +485,7 @@ void ED_spacetype_buttons(void)
art->regionid = RGN_TYPE_WINDOW;
art->init = buttons_main_region_init;
art->draw = buttons_main_region_draw;
+ art->listener = buttons_main_region_listener;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 59dd755173f..942bc2661c3 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -305,15 +305,12 @@ bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r
void ED_clip_update_frame(const Main *mainp, int cfra)
{
- wmWindowManager *wm;
- wmWindow *win;
-
/* image window, compo node users */
- for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
- for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
+ for (wmWindowManager *wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_CLIP) {
SpaceClip *sc = sa->spacedata.first;
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index c1caf5ae8ac..fc870399696 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -26,6 +26,7 @@
#include "BLI_rect.h"
#include "BLI_fileops.h"
+#include "BLI_listbase.h"
#include "BLO_readfile.h"
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index c2700233cf5..c03be5782be 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -215,7 +215,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA |
FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB |
FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO |
- FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF;
+ FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS;
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 980ee5aeffe..c17b60badae 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -461,6 +461,11 @@ static void graph_region_listener(
if (wmn->action == NA_RENAME)
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
default:
if (wmn->data == ND_KEYS)
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index baa1dcdffd9..56afdce7bb1 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -443,7 +443,6 @@ static void image_refresh(const bContext *C, ScrArea *sa)
static void image_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *scene)
{
- SceneLayer *sl = BKE_scene_layer_context_active(scene);
SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
/* context changes */
@@ -536,6 +535,7 @@ static void image_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, co
case ND_TRANSFORM:
case ND_MODIFIER:
{
+ SceneLayer *sl = BKE_scene_layer_context_active(scene);
Object *ob = OBACT_NEW;
if (ob && (ob == wmn->reference) && (ob->mode & OB_MODE_EDIT)) {
if (sima->lock && (sima->flag & SI_DRAWSHADOW)) {
@@ -828,6 +828,11 @@ static void image_main_region_listener(
ED_region_tag_redraw(ar);
}
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index ab08b288470..4f042364c63 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -260,8 +260,9 @@ static void info_header_listener(
/* context changes */
switch (wmn->category) {
case NC_SCREEN:
- if (ELEM(wmn->data, ND_SCREENCAST, ND_ANIMPLAY))
+ if (ELEM(wmn->data, ND_LAYER, ND_SCREENCAST, ND_ANIMPLAY)) {
ED_region_tag_redraw(ar);
+ }
break;
case NC_WM:
if (wmn->data == ND_JOB)
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index a71f2f20a3f..ab7a913ce62 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -428,6 +428,11 @@ static void nla_main_region_listener(
if (wmn->action == NA_RENAME)
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
default:
if (wmn->data == ND_KEYS)
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 3cb5fd94ea9..8568b0a676d 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -123,7 +123,7 @@ static int compo_get_recalc_flags(const bContext *C)
int recalc_flags = 0;
for (win = wm->windows.first; win; win = win->next) {
- bScreen *sc = win->screen;
+ const bScreen *sc = WM_window_get_active_screen(win);
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 4eeb4d02d8c..665808c500f 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -766,12 +766,13 @@ static void node_region_listener(
}
break;
case NC_SCREEN:
- if (wmn->data == ND_SCREENSET || wmn->action == NA_EDITED) {
+ if (wmn->data == ND_LAYOUTSET || wmn->action == NA_EDITED) {
WM_manipulatormap_tag_refresh(mmap);
}
switch (wmn->data) {
case ND_SCREENCAST:
case ND_ANIMPLAY:
+ case ND_LAYER:
ED_region_tag_redraw(ar);
break;
}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 06b37377535..722bec1fa46 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -109,7 +109,7 @@ typedef struct TreeElement {
#define TREESTORE_ID_TYPE(_id) \
(ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
- ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF, ID_PAL)) /* Only in 'blendfile' mode ... :/ */
+ ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF, ID_PAL, ID_WS)) /* Only in 'blendfile' mode ... :/ */
/* TreeElement->flag */
enum {
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 931af08c717..400a01a2908 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -160,7 +160,7 @@ static eOLDrawState tree_element_set_active_object(
sce = (Scene *)outliner_search_back(soops, te, ID_SCE);
if (sce && scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce);
scene = sce;
}
@@ -392,7 +392,7 @@ static eOLDrawState tree_element_active_world(
if (set != OL_SETSEL_NONE) {
/* make new scene active */
if (sce && scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce);
}
}
@@ -891,7 +891,7 @@ static void outliner_item_activate(
/* editmode? */
if (te->idcode == ID_SCE) {
if (scene != (Scene *)tselem->id) {
- ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id);
+ WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id);
}
}
else if (te->idcode == ID_GR) {
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 0591a8674d3..159a00ae0ed 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -67,6 +67,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_util.h"
@@ -310,7 +311,7 @@ static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNU
Scene *scene = (Scene *)tselem->id;
if (event == OL_SCENE_OP_DELETE) {
- if (ED_screen_delete_scene(C, scene)) {
+ if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene)) {
WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
}
else {
@@ -571,7 +572,7 @@ void outliner_do_object_operation_ex(
// when objects selected in other scenes... dunno if that should be allowed
Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE);
if (scene_owner && scene_act != scene_owner) {
- ED_screen_set_scene(C, CTX_wm_screen(C), scene_owner);
+ WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner);
}
/* important to use 'scene_owner' not scene_act else deleting objects can crash.
* only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
@@ -994,6 +995,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
int event;
const char *str = NULL;
@@ -1008,7 +1010,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
Scene *sce = scene; // to be able to delete, scenes are set...
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb);
if (scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ WM_window_change_active_scene(bmain, C, win, sce);
}
str = "Select Objects";
@@ -1018,8 +1020,8 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
Scene *sce = scene; // to be able to delete, scenes are set...
outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
if (scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
- }
+ WM_window_change_active_scene(bmain, C, win, sce);
+ }
str = "Select Object Hierarchy";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index b632db48caa..346e567dd8d 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -403,6 +403,11 @@ static void outliner_main_region_listener(
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 9a3ae2dcd70..283cd6c0e24 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -640,6 +640,11 @@ static void time_main_region_listener(
if (wmn->data == ND_DATA)
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 9c55e99b151..1dc9b169714 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -53,6 +53,7 @@
#include "BKE_object.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -804,7 +805,6 @@ static void *view3d_main_region_duplicate(void *poin)
static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, const Scene *scene)
{
wmWindow *win = wmn->wm->winactive;
- ScrArea *sa;
unsigned int lay_used = 0;
BaseLegacy *base;
@@ -820,7 +820,8 @@ static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, const Scene
base = base->next;
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_VIEW3D) {
if (BLI_findindex(&sa->regionbase, ar) != -1) {
View3D *v3d = sa->spacedata.first;
@@ -865,18 +866,24 @@ static void view3d_main_region_listener(
break;
case NC_SCENE:
switch (wmn->data) {
+ case ND_SCENEBROWSE:
case ND_LAYER_CONTENT:
if (wmn->reference)
view3d_recalc_used_layers(ar, wmn, wmn->reference);
ED_region_tag_redraw(ar);
WM_manipulatormap_tag_refresh(mmap);
break;
+ case ND_LAYER:
+ if (wmn->reference) {
+ BKE_screen_view3d_sync(v3d, wmn->reference);
+ }
+ ED_region_tag_redraw(ar);
+ break;
case ND_FRAME:
case ND_TRANSFORM:
case ND_OB_ACTIVE:
case ND_OB_SELECT:
case ND_OB_VISIBLE:
- case ND_LAYER:
case ND_RENDER_OPTIONS:
case ND_MARKERS:
case ND_MODE:
@@ -1056,18 +1063,15 @@ static void view3d_main_region_listener(
case ND_SKETCH:
ED_region_tag_redraw(ar);
break;
- case ND_SCREENBROWSE:
- case ND_SCREENDELETE:
- case ND_SCREENSET:
- /* screen was changed, need to update used layers due to NC_SCENE|ND_LAYER_CONTENT */
- /* updates used layers only for View3D in active screen */
- if (wmn->reference) {
- bScreen *sc_ref = wmn->reference;
- view3d_recalc_used_layers(ar, wmn, sc_ref->scene);
- }
+ case ND_LAYOUTBROWSE:
+ case ND_LAYOUTDELETE:
+ case ND_LAYOUTSET:
WM_manipulatormap_tag_refresh(mmap);
ED_region_tag_redraw(ar);
break;
+ case ND_LAYER:
+ ED_region_tag_redraw(ar);
+ break;
}
break;
@@ -1082,7 +1086,7 @@ static void view3d_main_region_listener(
/* concept is to retrieve cursor type context-less */
static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar))
{
- Scene *scene = win->screen->scene;
+ const Scene *scene = WM_window_get_active_scene(win);
if (scene->obedit) {
WM_cursor_set(win, CURSOR_EDIT);
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index bc74475e8cc..a27c5df9128 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -1473,9 +1473,8 @@ CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
}
/* goes over all modes and view3d settings */
-CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
+CustomDataMask ED_view3d_screen_datamask(const Scene *scene, const bScreen *screen)
{
- const Scene *scene = screen->scene;
CustomDataMask mask = CD_MASK_BAREMESH;
/* check if we need tfaces & mcols due to view mode */
@@ -1767,14 +1766,14 @@ void ED_scene_draw_fps(Scene *scene, const rcti *rect)
#endif
}
-static bool view3d_main_region_do_render_draw(Scene *scene)
+static bool view3d_main_region_do_render_draw(const Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->view_update && type->render_to_view);
}
-bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *rect)
+bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar, rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
bool use_border;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 6d1393a2905..31677e08207 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -71,11 +71,10 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event);
/* XXX quickly ported across */
static void handle_view3d_lock(bContext *C)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = CTX_wm_view3d(C);
-
+
if (v3d != NULL && sa != NULL) {
if (v3d->localvd == NULL && v3d->scenelock && sa->spacetype == SPACE_VIEW3D) {
/* copy to scene */
@@ -83,10 +82,6 @@ static void handle_view3d_lock(bContext *C)
scene->layact = v3d->layact;
scene->camera = v3d->camera;
- /* not through notifier, listener don't have context
- * and non-open screens or spaces need to be updated too */
- BKE_screen_view3d_main_sync(&bmain->screen, scene);
-
/* notifiers for scene update */
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
}
@@ -292,8 +287,8 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
bGPdata *gpd = CTX_data_gpencil_data(C);
uiBlock *block;
uiLayout *row;
- bool is_paint = false;
- int modeselect;
+ bool is_paint = ob && !(gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
+ ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
RNA_pointer_create(&screen->id, &RNA_SpaceView3D, v3d, &v3dptr);
RNA_pointer_create(&scene->id, &RNA_ToolSettings, ts, &toolsptr);
@@ -304,36 +299,6 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
/* other buttons: */
UI_block_emboss_set(block, UI_EMBOSS);
-
- /* mode */
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
- modeselect = OB_MODE_GPENCIL;
- }
- else if (ob) {
- modeselect = ob->mode;
- is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
- }
- else {
- modeselect = OB_MODE_OBJECT;
- }
-
- row = uiLayoutRow(layout, false);
- {
- EnumPropertyItem *item = rna_enum_object_mode_items;
- const char *name = "";
- int icon = ICON_OBJECT_DATAMODE;
-
- while (item->identifier) {
- if (item->value == modeselect && item->identifier[0]) {
- name = IFACE_(item->name);
- icon = item->icon;
- break;
- }
- item++;
- }
-
- uiItemMenuEnumO(row, C, "OBJECT_OT_mode_set", "mode", name, icon);
- }
row = uiLayoutRow(layout, true);
uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 93554c374d9..53f343ed071 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -1358,19 +1358,21 @@ static void game_set_commmandline_options(GameData *gm)
static int game_engine_poll(bContext *C)
{
- bScreen *screen;
+ const wmWindow *win = CTX_wm_window(C);
+ const Scene *scene = WM_window_get_active_scene(win);
+
/* we need a context and area to launch BGE
* it's a temporary solution to avoid crash at load time
* if we try to auto run the BGE. Ideally we want the
* context to be set as soon as we load the file. */
- if (CTX_wm_window(C) == NULL) return 0;
- if ((screen = CTX_wm_screen(C)) == NULL) return 0;
+ if (win == NULL) return 0;
+ if (CTX_wm_screen(C) == NULL) return 0;
if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)
return 0;
- if (!BKE_scene_uses_blender_game(screen->scene))
+ if (!BKE_scene_uses_blender_game(scene))
return 0;
return 1;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 2a97384cf7d..a2a5307c707 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -229,11 +229,11 @@ static int delete_orientation_poll(bContext *C)
if (ED_operator_areaactive(C) == 0)
return 0;
-
+
if (v3d) {
selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
}
-
+
return selected_index >= 0;
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index c9e40865164..2ba640500c7 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -381,8 +381,10 @@ void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target)
void BIF_selectTransformOrientationValue(bContext *C, int orientation)
{
View3D *v3d = CTX_wm_view3d(C);
- if (v3d) /* currently using generic poll */
+
+ if (v3d) { /* currently using generic poll */
v3d->twmode = orientation;
+ }
}
int BIF_countTransformOrientation(const bContext *C)
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index c0b30f93939..766f70d025c 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -75,6 +75,7 @@ set(SRC
../include/ED_particle.h
../include/ED_physics.h
../include/ED_render.h
+ ../include/ED_scene.h
../include/ED_screen.h
../include/ED_screen_types.h
../include/ED_sculpt.h
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index b5c6deb6b01..00fb1a44dff 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -32,6 +32,7 @@
#include "BLI_endian_switch.h"
#include "BLI_fileops.h"
#include "BLI_linklist.h"
+#include "BLI_listbase.h" /* Needed due to import of BLO_readfile.h */
#include "BLO_blend_defs.h"
#include "BLO_readfile.h"
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 4f22d873a30..9a89bf859c7 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -265,6 +265,7 @@ typedef enum ID_Type {
ID_PAL = MAKE_ID2('P', 'L'), /* Palette */
ID_PC = MAKE_ID2('P', 'C'), /* PaintCurve */
ID_CF = MAKE_ID2('C', 'F'), /* CacheFile */
+ ID_WS = MAKE_ID2('W', 'S'), /* WorkSpace */
} ID_Type;
/* Only used as 'placeholder' in .blend files for directly linked datablocks. */
@@ -288,7 +289,7 @@ typedef enum ID_Type {
#define ID_REAL_USERS(id) (((ID *)id)->us - ID_FAKE_USERS(id))
#define ID_EXTRA_USERS(id) (((ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0)
-#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM))
+#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM) && (GS((id)->name) != ID_WS))
#define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : (_bmain)->name)
@@ -398,6 +399,7 @@ enum {
FILTER_ID_WO = (1 << 26),
FILTER_ID_PA = (1 << 27),
FILTER_ID_CF = (1 << 28),
+ FILTER_ID_WS = (1 << 29),
};
/* IMPORTANT: this enum matches the order currently use in set_lisbasepointers,
@@ -435,6 +437,7 @@ enum {
INDEX_ID_OB,
INDEX_ID_LS,
INDEX_ID_SCE,
+ INDEX_ID_WS,
INDEX_ID_WM,
INDEX_ID_MSK,
INDEX_ID_NULL,
diff --git a/source/blender/makesdna/DNA_defs.h b/source/blender/makesdna/DNA_defs.h
index fc9dd8f06a9..bfa8da02707 100644
--- a/source/blender/makesdna/DNA_defs.h
+++ b/source/blender/makesdna/DNA_defs.h
@@ -44,6 +44,12 @@
# endif
#endif
+#ifdef __GNUC__
+# define DNA_PRIVATE_ATTR __attribute__ ((deprecated))
+#else
+# define DNA_PRIVATE_ATTR
+#endif
+
/* poison pragma */
#ifdef DNA_DEPRECATED_ALLOW
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index b2ab0d2a08d..6a01878a9ef 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -32,9 +32,6 @@
#ifndef __DNA_FILEGLOBAL_TYPES_H__
#define __DNA_FILEGLOBAL_TYPES_H__
-struct bScreen;
-struct Scene;
-
/**
* FileGlobal stores a part of the current user-interface settings at
* the moment of saving, and the file-specific settings.
@@ -46,6 +43,9 @@ typedef struct FileGlobal {
char pad[6];
struct bScreen *curscreen;
struct Scene *curscene;
+ struct SceneLayer *cur_render_layer;
+ void *pad1;
+
int fileflags;
int globalf;
uint64_t build_commit_timestamp; /* commit timestamp from buildinfo */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index ce1f8d1a7d4..2524bad7c0f 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -30,6 +30,7 @@
#ifndef __DNA_SCREEN_TYPES_H__
#define __DNA_SCREEN_TYPES_H__
+#include "DNA_defs.h"
#include "DNA_listBase.h"
#include "DNA_view2d_types.h"
#include "DNA_vec_types.h"
@@ -52,10 +53,9 @@ typedef struct bScreen {
ListBase edgebase;
ListBase areabase;
ListBase regionbase; /* screen level regions (menus), runtime only */
-
- struct Scene *scene;
- struct Scene *newscene; /* temporary when switching */
-
+
+ struct Scene *scene DNA_DEPRECATED;
+
short winid; /* winid from WM, starts with 1 */
short redraws_flag; /* user-setting for which editors get redrawn during anim playback (used to be time->redraws) */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 256d53eed0b..9f5d33531f6 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -601,7 +601,7 @@ typedef enum eUserPref_Flag {
/* USER_AUTOGRABGRID = (1 << 1), deprecated */
/* USER_AUTOROTGRID = (1 << 2), deprecated */
/* USER_AUTOSIZEGRID = (1 << 3), deprecated */
- USER_SCENEGLOBAL = (1 << 4),
+/* USER_SCENEGLOBAL = (1 << 4), deprecated */
USER_TRACKBALL = (1 << 5),
/* USER_DUPLILINK = (1 << 6), deprecated */
/* USER_FSCOLLUM = (1 << 7), deprecated */
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 14400c84b69..8558e3b5a08 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -177,9 +177,13 @@ typedef struct wmWindow {
void *ghostwin; /* don't want to include ghost.h stuff */
- struct bScreen *screen; /* active screen */
- struct bScreen *newscreen; /* temporary when switching */
- char screenname[64]; /* MAX_ID_NAME for matching window with active screen after file read */
+ struct Scene *scene; /* The scene displayed in this window. */
+ struct Scene *new_scene; /* temporary when switching */
+
+ struct WorkSpaceInstanceHook *workspace_hook;
+
+ struct bScreen *screen DNA_DEPRECATED;
+ char screenname[64]; /* MAX_ID_NAME for matching window with active screen after file read */
short posx, posy, sizex, sizey; /* window coords */
short windowstate; /* borderless, full */
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
new file mode 100644
index 00000000000..56221242fbf
--- /dev/null
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -0,0 +1,132 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_workspace_types.h
+ * \ingroup DNA
+ *
+ * Use API in BKE_workspace.h!
+ * Struct members marked with DNA_PRIVATE_WORKSPACE will throw a
+ * warning saying it's deprecated when used outside of workspace.c.
+ */
+
+#ifndef __DNA_WORKSPACE_TYPES_H__
+#define __DNA_WORKSPACE_TYPES_H__
+
+
+/* Same logic as DNA_DEPRECATED_ALLOW, but throws 'deprecated'
+ * warnings if DNA_PRIVATE_WORKSPACE_ALLOW is not defined */
+#ifdef DNA_PRIVATE_WORKSPACE_ALLOW
+ /* allow use of private items */
+# define DNA_PRIVATE_WORKSPACE
+#else
+# ifndef DNA_PRIVATE_WORKSPACE
+# define DNA_PRIVATE_WORKSPACE DNA_PRIVATE_ATTR
+# endif
+#endif
+
+#ifdef DNA_PRIVATE_READ_WRITE_ALLOW
+# define DNA_PRIVATE_WORKSPACE_READ_WRITE
+#else
+# ifndef DNA_PRIVATE_WORKSPACE_READ_WRITE
+# define DNA_PRIVATE_WORKSPACE_READ_WRITE DNA_PRIVATE_WORKSPACE
+# endif
+#endif
+
+
+/**
+ * \brief Wrapper for bScreen.
+ *
+ * bScreens are IDs and thus stored in a main list-base. We also want to store a list-base of them within the
+ * workspace (so each workspace can have its own set of screen-layouts) which would mess with the next/prev pointers.
+ * So we use this struct to wrap a bScreen pointer with another pair of next/prev pointers.
+ */
+typedef struct WorkSpaceLayout {
+ struct WorkSpaceLayout *next, *prev;
+
+ struct bScreen *screen DNA_PRIVATE_WORKSPACE;
+ /* The name of this layout, we override the RNA name of the screen with this (but not ID name itself) */
+ char name[64] DNA_PRIVATE_WORKSPACE; /* MAX_NAME */
+} WorkSpaceLayout;
+
+typedef struct WorkSpace {
+ ID id;
+
+ ListBase layouts DNA_PRIVATE_WORKSPACE; /* WorkSpaceLayout */
+ /* Store for each hook (so for each window) which layout has
+ * been activated the last time this workspace was visible. */
+ ListBase hook_layout_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */
+
+ int object_mode DNA_PRIVATE_WORKSPACE; /* enum ObjectMode */
+ int pad;
+
+ struct SceneLayer *render_layer DNA_PRIVATE_WORKSPACE;
+} WorkSpace;
+
+/* internal struct, but exported for read/write */
+#if defined(DNA_PRIVATE_READ_WRITE_ALLOW) || defined(DNA_PRIVATE_WORKSPACE_ALLOW)
+
+/**
+ * Generic (and simple/primitive) struct for storing a history of assignments/relations
+ * of workspace data to non-workspace data in a listbase inside the workspace.
+ *
+ * Using this we can restore the old state of a workspace if the user switches back to it.
+ *
+ * Usage
+ * =====
+ * When activating a workspace, it should activate the screen-layout that was active in that
+ * workspace before *in this window*.
+ * More concretely:
+ * * There are two windows, win1 and win2.
+ * * Both show workspace ws1, but both also had workspace ws2 activated at some point before.
+ * * Last time ws2 was active in win1, screen-layout sl1 was activated.
+ * * Last time ws2 was active in win2, screen-layout sl2 was activated.
+ * * When changing from ws1 to ws2 in win1, screen-layout sl1 should be activated again.
+ * * When changing from ws1 to ws2 in win2, screen-layout sl2 should be activated again.
+ * So that means we have to store the active screen-layout in a per workspace, per window
+ * relation. This struct is used to store an active screen-layout for each window within the
+ * workspace.
+ * To find the screen-layout to activate for this window-workspace combination, simply lookup
+ * the WorkSpaceDataRelation with the workspace-hook of the window set as parent.
+ */
+typedef struct WorkSpaceDataRelation {
+ struct WorkSpaceDataRelation *next, *prev;
+
+ /* the data used to identify the relation (e.g. to find screen-layout (= value) from/for a hook) */
+ void *parent;
+ /* The value for this parent-data/workspace relation */
+ void *value;
+} WorkSpaceDataRelation;
+
+#endif /* DNA_PRIVATE_WORKSPACE_READ_WRITE */
+
+/**
+ * Little wrapper to store data that is going to be per window, but comming from the workspace.
+ * It allows us to keep workspace and window data completely separate.
+ */
+typedef struct WorkSpaceInstanceHook {
+ WorkSpace *active DNA_PRIVATE_WORKSPACE;
+ struct WorkSpaceLayout *act_layout DNA_PRIVATE_WORKSPACE;
+
+ /* Needed because we can't change workspaces/layouts in running handler loop, it would break context. */
+ WorkSpace *temp_workspace_store;
+ struct WorkSpaceLayout *temp_layout_store;
+} WorkSpaceInstanceHook;
+
+#endif /* __DNA_WORKSPACE_TYPES_H__ */
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index e761d68ca64..ad9a03703b4 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -56,6 +56,9 @@
#include "../blenlib/BLI_sys_types.h" // for intptr_t support
+/* Allow includinsg DNA files for specially guarded namespaces */
+#define DNA_NAMESPACE
+
#define SDNA_MAX_FILENAME_LENGTH 255
@@ -132,6 +135,8 @@ static const char *includefiles[] = {
"DNA_linestyle_types.h",
"DNA_cachefile_types.h",
"DNA_layer_types.h",
+ "DNA_workspace_types.h",
+
/* see comment above before editing! */
/* empty string to indicate end of includefiles */
@@ -506,6 +511,17 @@ static int preprocess_include(char *maindata, int len)
a -= 13;
cp += 13;
}
+ else if (strncmp("DNA_PRIVATE_WORKSPACE", cp, 21) == 0) {
+ /* Check for DNA_PRIVATE_WORKSPACE_READ_WRITE */
+ if (strncmp("_READ_WRITE", cp + 21, 11) == 0) {
+ a -= 31;
+ cp += 31;
+ }
+ else {
+ a -= 20;
+ cp += 20;
+ }
+ }
else {
md[0] = cp[0];
md++;
@@ -1346,4 +1362,6 @@ int main(int argc, char **argv)
#include "DNA_linestyle_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_layer_types.h"
+#include "DNA_workspace_types.h"
+
/* end of list */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 127977c23bb..2982c459169 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -707,6 +707,7 @@ extern StructRNA RNA_WindowManager;
extern StructRNA RNA_WipeSequence;
extern StructRNA RNA_WireframeModifier;
extern StructRNA RNA_WoodTexture;
+extern StructRNA RNA_WorkSpace;
extern StructRNA RNA_World;
extern StructRNA RNA_WorldAmbientOcclusion;
extern StructRNA RNA_WorldLighting;
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 020c3a755c1..899c9bf77a9 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -94,6 +94,7 @@ set(DEFSRC
rna_userdef.c
rna_vfont.c
rna_wm.c
+ rna_workspace.c
rna_world.c
)
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index de436172bfd..bac221f96ab 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3364,6 +3364,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_userdef.c", NULL, RNA_def_userdef},
{"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont},
{"rna_wm.c", "rna_wm_api.c", RNA_def_wm},
+ {"rna_workspace.c", NULL, RNA_def_workspace},
{"rna_world.c", NULL, RNA_def_world},
{"rna_movieclip.c", NULL, RNA_def_movieclip},
{"rna_tracking.c", NULL, RNA_def_tracking},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 4291e5b63ae..f36c8d0cc0d 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -82,6 +82,7 @@ EnumPropertyItem rna_enum_id_type_items[] = {
{ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""},
{ID_WM, "WINDOWMANAGER", ICON_FULLSCREEN, "Window Manager", ""},
{ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
+ {ID_WS, "WORKSPACE", ICON_NONE, "Workspace", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -169,6 +170,7 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (RNA_struct_is_a(type, &RNA_Texture)) return ID_TE;
if (RNA_struct_is_a(type, &RNA_Text)) return ID_TXT;
if (RNA_struct_is_a(type, &RNA_VectorFont)) return ID_VF;
+ if (RNA_struct_is_a(type, &RNA_WorkSpace)) return ID_WS;
if (RNA_struct_is_a(type, &RNA_World)) return ID_WO;
if (RNA_struct_is_a(type, &RNA_WindowManager)) return ID_WM;
@@ -211,6 +213,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_VF: return &RNA_VectorFont;
case ID_WM: return &RNA_WindowManager;
case ID_WO: return &RNA_World;
+ case ID_WS: return &RNA_WorkSpace;
default: return &RNA_ID;
}
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index 360bd5691cd..a0b46a447ae 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -51,6 +51,12 @@ static PointerRNA rna_Context_window_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_Window, CTX_wm_window(C));
}
+static PointerRNA rna_Context_workspace_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_WorkSpace, CTX_wm_workspace(C));
+}
+
static PointerRNA rna_Context_screen_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
@@ -193,6 +199,11 @@ void RNA_def_context(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Window");
RNA_def_property_pointer_funcs(prop, "rna_Context_window_get", NULL, NULL, NULL);
+ prop = RNA_def_property(srna, "workspace", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "WorkSpace");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_workspace_get", NULL, NULL, NULL);
+
prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "Screen");
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 75fc9a17b07..878ee722c2d 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -186,6 +186,7 @@ void RNA_def_ui(struct BlenderRNA *brna);
void RNA_def_userdef(struct BlenderRNA *brna);
void RNA_def_vfont(struct BlenderRNA *brna);
void RNA_def_wm(struct BlenderRNA *brna);
+void RNA_def_workspace(struct BlenderRNA *brna);
void RNA_def_world(struct BlenderRNA *brna);
void RNA_def_movieclip(struct BlenderRNA *brna);
void RNA_def_tracking(struct BlenderRNA *brna);
@@ -335,6 +336,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_workspaces(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 94687b6fd46..4f52ac97961 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -293,6 +293,12 @@ static void rna_Main_paintcurves_begin(CollectionPropertyIterator *iter, Pointer
rna_iterator_listbase_begin(iter, &bmain->paintcurves, NULL);
}
+static void rna_Main_workspaces_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->workspaces, NULL);
+}
+
static void rna_Main_version_get(PointerRNA *ptr, int *value)
{
Main *bmain = (Main *)ptr->data;
@@ -368,6 +374,7 @@ void RNA_def_main(BlenderRNA *brna)
{"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style data-blocks", RNA_def_main_linestyles},
{"cache_files", "CacheFile", "rna_Main_cachefiles_begin", "Cache Files", "Cache Files data-blocks", RNA_def_main_cachefiles},
{"paint_curves", "PaintCurve", "rna_Main_paintcurves_begin", "Paint Curves", "Paint Curves data-blocks", RNA_def_main_paintcurves},
+ {"workspaces", "WorkSpace", "rna_Main_workspaces_begin", "Workspaces", "Workspace data-blocks", RNA_def_main_workspaces},
{NULL, NULL, NULL, NULL, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 244820f5a49..cd0fe461428 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -84,6 +84,7 @@
#include "BKE_mask.h"
#include "BKE_gpencil.h"
#include "BKE_linestyle.h"
+#include "BKE_workspace.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -115,6 +116,8 @@
# include "BPY_extern.h"
#endif
+#include "WM_api.h"
+
static void rna_idname_validate(const char *name, char *r_name)
{
@@ -169,14 +172,15 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
(scene_new = scene->id.next))
{
if (do_unlink) {
- bScreen *sc = CTX_wm_screen(C);
- if (sc->scene == scene) {
+ wmWindow *win = CTX_wm_window(C);
+
+ if (WM_window_get_active_scene(win) == scene) {
#ifdef WITH_PYTHON
BPy_BEGIN_ALLOW_THREADS;
#endif
- ED_screen_set_scene(C, sc, scene_new);
+ WM_window_change_active_scene(bmain, C, win, scene_new);
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -610,6 +614,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(masks, mask, ID_MSK)
RNA_MAIN_ID_TAG_FUNCS_DEF(linestyle, linestyle, ID_LS)
RNA_MAIN_ID_TAG_FUNCS_DEF(cachefiles, cachefiles, ID_CF)
RNA_MAIN_ID_TAG_FUNCS_DEF(paintcurves, paintcurves, ID_PC)
+RNA_MAIN_ID_TAG_FUNCS_DEF(workspaces, workspaces, ID_WS)
#undef RNA_MAIN_ID_TAG_FUNCS_DEF
@@ -1819,4 +1824,25 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_boolean_funcs(prop, "rna_Main_linestyle_is_updated_get", NULL);
}
+void RNA_def_main_workspaces(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "BlendDataWorkSpaces");
+ srna = RNA_def_struct(brna, "BlendDataWorkSpaces", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Workspaces", "Collection of workspaces");
+
+ func = RNA_def_function(srna, "tag", "rna_Main_workspaces_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_workspaces_is_updated_get", NULL);
+}
+
#endif
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 4ff2e03ef9c..266838153e9 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -763,19 +763,21 @@ static int rna_Scene_active_layer_get(PointerRNA *ptr)
static void rna_Scene_view3d_update(Main *bmain, Scene *UNUSED(scene_unused), PointerRNA *ptr)
{
+ wmWindowManager *wm = bmain->wm.first;
Scene *scene = (Scene *)ptr->data;
- BKE_screen_view3d_main_sync(&bmain->screen, scene);
+ WM_windows_scene_data_sync(&wm->windows, scene);
}
-static void rna_Scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Scene_layer_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
- rna_Scene_view3d_update(bmain, scene, ptr);
/* XXX We would need do_time=true here, else we can have update issues like [#36289]...
* However, this has too much drawbacks (like slower layer switch, undesired updates...).
* That's TODO for future DAG updates.
*/
DAG_on_visible_update(bmain, false);
+
+ /* No need to sync scene data here (WM_windows_scene_data_sync), handled through notifier. */
}
static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index b44e404c364..a145ac95d6b 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -57,6 +57,7 @@ EnumPropertyItem rna_enum_region_type_items[] = {
#include "BKE_global.h"
#include "BKE_depsgraph.h"
+#include "BKE_workspace.h"
#include "UI_view2d.h"
@@ -64,55 +65,58 @@ EnumPropertyItem rna_enum_region_type_items[] = {
# include "BPY_extern.h"
#endif
-static void rna_Screen_scene_set(PointerRNA *ptr, PointerRNA value)
-{
- bScreen *sc = (bScreen *)ptr->data;
- if (value.data == NULL)
- return;
+static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ bScreen *screen = (bScreen *)ptr->data;
- sc->newscene = value.data;
+ /* the settings for this are currently only available from a menu in the TimeLine, hence refresh=SPACE_TIME */
+ ED_screen_animation_timer_update(screen, screen->redraws_flag, SPACE_TIME);
}
-static void rna_Screen_scene_update(bContext *C, PointerRNA *ptr)
+static int rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr))
{
- bScreen *sc = (bScreen *)ptr->data;
-
- /* exception: must use context so notifier gets to the right window */
- if (sc->newscene) {
-#ifdef WITH_PYTHON
- BPy_BEGIN_ALLOW_THREADS;
-#endif
-
- ED_screen_set_scene(C, sc, sc->newscene);
-
-#ifdef WITH_PYTHON
- BPy_END_ALLOW_THREADS;
-#endif
-
- WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, sc->newscene);
+ /* can be NULL on file load, T42619 */
+ wmWindowManager *wm = G.main->wm.first;
+ return wm ? (ED_screen_animation_playing(wm) != NULL) : 0;
+}
- if (G.debug & G_DEBUG)
- printf("scene set %p\n", sc->newscene);
+static void rna_Screen_layout_name_get(PointerRNA *ptr, char *value)
+{
+ const bScreen *screen = ptr->data;
+ const WorkSpaceLayout *layout = BKE_workspace_layout_find_global(G.main, screen, NULL);
- sc->newscene = NULL;
+ if (layout) {
+ const char *name = BKE_workspace_layout_name_get(layout);
+ strcpy(value, name);
+ }
+ else {
+ value[0] = '\0';
}
}
-static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static int rna_Screen_layout_name_length(PointerRNA *ptr)
{
- bScreen *screen = (bScreen *)ptr->data;
+ const bScreen *screen = ptr->data;
+ const WorkSpaceLayout *layout = BKE_workspace_layout_find_global(G.main, screen, NULL);
- /* the settings for this are currently only available from a menu in the TimeLine, hence refresh=SPACE_TIME */
- ED_screen_animation_timer_update(screen, screen->redraws_flag, SPACE_TIME);
-}
+ if (layout) {
+ const char *name = BKE_workspace_layout_name_get(layout);
+ return strlen(name);
+ }
+ return 0;
+}
-static int rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr))
+static void rna_Screen_layout_name_set(PointerRNA *ptr, const char *value)
{
- /* can be NULL on file load, T42619 */
- wmWindowManager *wm = G.main->wm.first;
- return wm ? (ED_screen_animation_playing(wm) != NULL) : 0;
+ bScreen *screen = ptr->data;
+ WorkSpace *workspace;
+ WorkSpaceLayout *layout = BKE_workspace_layout_find_global(G.main, screen, &workspace);
+
+ if (layout) {
+ BKE_workspace_layout_name_set(workspace, layout, value);
+ }
}
static int rna_Screen_fullscreen_get(PointerRNA *ptr)
@@ -152,7 +156,7 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
/* XXX this call still use context, so we trick it to work in the right context */
for (win = wm->windows.first; win; win = win->next) {
- if (sc == win->screen) {
+ if (sc == WM_window_get_active_screen(win)) {
wmWindow *prevwin = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *prevar = CTX_wm_region(C);
@@ -377,13 +381,11 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Screen", "Screen data-block, defining the layout of areas in a window");
RNA_def_struct_ui_icon(srna, ICON_SPLITSCREEN);
- /* pointers */
- prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Screen_scene_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Scene", "Active scene to be edited in the screen");
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, 0, "rna_Screen_scene_update");
+ prop = RNA_def_property(srna, "layout_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_Screen_layout_name_get", "rna_Screen_layout_name_length",
+ "rna_Screen_layout_name_set");
+ RNA_def_property_ui_text(prop, "Layout Name", "The name of the layout that refers to the screen");
+ RNA_def_struct_name_property(srna, prop);
/* collections */
prop = RNA_def_property(srna, "areas", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 0eedcb25b4c..0e16b410dc7 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -256,6 +256,7 @@ EnumPropertyItem rna_enum_file_sort_items[] = {
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_layer.h"
+#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
@@ -407,7 +408,7 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain), Scene *UNUSED(scen
static PointerRNA rna_CurrentOrientation_get(PointerRNA *ptr)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ Scene *scene = WM_windows_scene_get_from_screen(G.main->wm.first, ptr->id.data);
View3D *v3d = (View3D *)ptr->data;
if (v3d->twmode < V3D_MANIP_CUSTOM)
@@ -429,7 +430,7 @@ EnumPropertyItem *rna_TransformOrientation_itemf(bContext *C, PointerRNA *ptr, P
RNA_enum_items_add(&item, &totitem, transform_orientation_items);
if (ptr->type == &RNA_SpaceView3D)
- scene = ((bScreen *)ptr->id.data)->scene;
+ scene = WM_windows_scene_get_from_screen(G.main->wm.first, ptr->id.data);
else
scene = CTX_data_scene(C); /* can't use scene from ptr->id.data because that enum is also used by operators */
@@ -460,8 +461,10 @@ static void rna_SpaceView3D_camera_update(Main *bmain, Scene *scene, PointerRNA
{
View3D *v3d = (View3D *)(ptr->data);
if (v3d->scenelock) {
+ wmWindowManager *wm = bmain->wm.first;
+
scene->camera = v3d->camera;
- BKE_screen_view3d_main_sync(&bmain->screen, scene);
+ WM_windows_scene_data_sync(&wm->windows, scene);
}
}
@@ -473,8 +476,10 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int valu
v3d->scenelock = value;
if (value) {
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
int bit;
- v3d->lay = sc->scene->lay;
+
+ v3d->lay = scene->lay;
/* seek for layact */
bit = 0;
while (bit < 32) {
@@ -484,15 +489,15 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int valu
}
bit++;
}
- v3d->camera = sc->scene->camera;
+ v3d->camera = scene->camera;
}
}
static void rna_View3D_CursorLocation_get(PointerRNA *ptr, float *values)
{
View3D *v3d = (View3D *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->id.data;
- Scene *scene = (Scene *)sc->scene;
+ bScreen *screen = ptr->id.data;
+ Scene *scene = ED_screen_scene_find(screen, G.main->wm.first);
const float *loc = ED_view3d_cursor3d_get(scene, v3d);
copy_v3_v3(values, loc);
@@ -501,8 +506,8 @@ static void rna_View3D_CursorLocation_get(PointerRNA *ptr, float *values)
static void rna_View3D_CursorLocation_set(PointerRNA *ptr, const float *values)
{
View3D *v3d = (View3D *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->id.data;
- Scene *scene = (Scene *)sc->scene;
+ bScreen *screen = ptr->id.data;
+ Scene *scene = ED_screen_scene_find(screen, G.main->wm.first);
float *cursor = ED_view3d_cursor3d_get(scene, v3d);
copy_v3_v3(cursor, values);
@@ -511,8 +516,8 @@ static void rna_View3D_CursorLocation_set(PointerRNA *ptr, const float *values)
static float rna_View3D_GridScaleUnit_get(PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->id.data;
- Scene *scene = (Scene *)sc->scene;
+ bScreen *screen = ptr->id.data;
+ Scene *scene = ED_screen_scene_find(screen, G.main->wm.first);
return ED_view3d_grid_scale(scene, v3d, NULL);
}
@@ -696,7 +701,7 @@ static void rna_RegionView3D_view_matrix_set(PointerRNA *ptr, const float *value
static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ Scene *scene = WM_windows_scene_get_from_screen(G.main->wm.first, ptr->id.data);
RenderEngineType *type = RE_engines_find(scene->r.engine);
View3D *v3d = (View3D *)ptr->data;
int drawtype = v3d->drawtype;
@@ -716,10 +721,11 @@ static void rna_SpaceView3D_viewport_shade_set(PointerRNA *ptr, int value)
v3d->drawtype = value;
}
-static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *C, PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *r_free)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = WM_window_get_active_scene(win);
RenderEngineType *type = RE_engines_find(scene->r.engine);
EnumPropertyItem *item = NULL;
@@ -740,10 +746,10 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
return item;
}
-static EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+static EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *C, PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ Scene *scene = CTX_data_scene(C);
if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
return multiview_camera_items;
@@ -811,16 +817,17 @@ static int rna_SpaceImageEditor_show_uvedit_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
bScreen *sc = (bScreen *)ptr->id.data;
- return ED_space_image_show_uvedit(sima, sc->scene->obedit);
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
+
+ return ED_space_image_show_uvedit(sima, scene->obedit);
}
static int rna_SpaceImageEditor_show_maskedit_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
bScreen *sc = (bScreen *)ptr->id.data;
-
- TODO_LAYER_CONTEXT; /* get SceneLayer from context/window/workspace instead */
- SceneLayer *sl = BKE_scene_layer_context_active(sc->scene);
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
+ SceneLayer *sl = BKE_scene_layer_context_active(scene);
return ED_space_image_check_show_maskedit(sl, sima);
}
@@ -829,8 +836,9 @@ static void rna_SpaceImageEditor_image_set(PointerRNA *ptr, PointerRNA value)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
bScreen *sc = (bScreen *)ptr->id.data;
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
- ED_space_image_set(sima, sc->scene, sc->scene->obedit, (Image *)value.data);
+ ED_space_image_set(sima, scene, scene->obedit, (Image *)value.data);
}
static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, PointerRNA value)
@@ -3880,6 +3888,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{FILTER_ID_TXT, "TEXT", ICON_TEXT, "Texts", "Show/hide Text data-blocks"},
{FILTER_ID_VF, "FONT", ICON_FONT_DATA, "Fonts", "Show/hide Font data-blocks"},
{FILTER_ID_WO, "WORLD", ICON_WORLD_DATA, "Worlds", "Show/hide World data-blocks"},
+ {FILTER_ID_WS, "WORK_SPACE", ICON_NONE, "Workspaces", "Show/hide workspace data-blocks"},
{0, NULL, 0, NULL, NULL}
};
@@ -3897,7 +3906,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
"Show/hide materials, nodetrees, textures and Freestyle's linestyles"},
{FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO,
"IMAGE", ICON_IMAGE_DATA, "Images & Sounds", "Show/hide images, movie clips, sounds and masks"},
- {FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_SPK | FILTER_ID_WO,
+ {FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_SPK | FILTER_ID_WO | FILTER_ID_WS,
"ENVIRONMENT", ICON_WORLD_DATA, "Environment", "Show/hide worlds, lamps, cameras and speakers"},
{FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_CF,
"MISC", ICON_GREASEPENCIL, "Miscellaneous", "Show/hide other data types"},
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 8f771eda99d..aabe421b872 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -31,6 +31,9 @@
#ifdef RNA_RUNTIME
+#include "BKE_global.h"
+
+#include "ED_screen.h"
#include "ED_text.h"
static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d)
@@ -43,11 +46,10 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d)
area_region_from_regiondata(sc, rv3d, &sa, &ar);
if (sa && ar && sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d;
-
- v3d = (View3D *)sa->spacedata.first;
+ View3D *v3d = sa->spacedata.first;
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
- ED_view3d_update_viewmat(sc->scene, v3d, ar, NULL, NULL, NULL);
+ ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL, NULL);
}
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index d1e89ea18d0..a0fb398ee3a 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -3335,11 +3335,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Object Info", "Display objects name and frame number in 3D view");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "use_global_scene", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SCENEGLOBAL);
- RNA_def_property_ui_text(prop, "Global Scene", "Force the current Scene to be displayed in all Screens");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
prop = RNA_def_property(srna, "show_large_cursors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "curssize", 0);
RNA_def_property_ui_text(prop, "Large Cursors", "Use large mouse cursors when available");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index b458b2e69d5..f6e67d5f765 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -461,12 +461,23 @@ EnumPropertyItem rna_enum_wm_report_items[] = {
#include "WM_api.h"
+#include "DNA_workspace_types.h"
+
+#include "ED_screen.h"
+
#include "UI_interface.h"
+#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_workspace.h"
#include "MEM_guardedalloc.h"
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+
static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr)
{
wmWindowManager *wm = ptr->id.data;
@@ -621,39 +632,120 @@ static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr)
return rptr;
}
-static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
+static void rna_Window_scene_set(PointerRNA *ptr, PointerRNA value)
+{
+ wmWindow *win = ptr->data;
+
+ if (value.data == NULL) {
+ return;
+ }
+
+ win->new_scene = value.data;
+}
+
+static void rna_Window_scene_update(bContext *C, PointerRNA *ptr)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = ptr->data;
+
+ /* exception: must use context so notifier gets to the right window */
+ if (win->new_scene) {
+#ifdef WITH_PYTHON
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ WM_window_change_active_scene(bmain, C, win, win->new_scene);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, win->new_scene);
+
+ if (G.debug & G_DEBUG)
+ printf("scene set %p\n", win->new_scene);
+
+ win->new_scene = NULL;
+ }
+}
+
+static PointerRNA rna_Window_workspace_get(PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_WorkSpace, BKE_workspace_active_get(win->workspace_hook));
+}
+
+static void rna_Window_workspace_set(PointerRNA *ptr, PointerRNA value)
{
wmWindow *win = (wmWindow *)ptr->data;
/* disallow ID-browsing away from temp screens */
- if (win->screen->temp) {
+ if (WM_window_is_temp_screen(win)) {
return;
}
+ if (value.data == NULL) {
+ return;
+ }
+
+ /* exception: can't set workspaces inside of area/region handlers */
+ win->workspace_hook->temp_workspace_store = value.data;
+}
+
+static void rna_Window_workspace_update(bContext *C, PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ WorkSpace *new_workspace = win->workspace_hook->temp_workspace_store;
+
+ /* exception: can't set screens inside of area/region handlers,
+ * and must use context so notifier gets to the right window */
+ if (new_workspace) {
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, new_workspace);
+ win->workspace_hook->temp_workspace_store = NULL;
+ }
+}
+
+PointerRNA rna_Window_screen_get(PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Screen, BKE_workspace_active_screen_get(win->workspace_hook));
+}
- if (value.data == NULL)
+static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
+{
+ wmWindow *win = ptr->data;
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout_new;
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ /* disallow ID-browsing away from temp screens */
+ if (screen->temp) {
+ return;
+ }
+ if (value.data == NULL) {
return;
+ }
/* exception: can't set screens inside of area/region handlers */
- win->newscreen = value.data;
+ layout_new = BKE_workspace_layout_find(workspace, value.data);
+ win->workspace_hook->temp_layout_store = layout_new;
}
static int rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
- bScreen *screen = (bScreen *)value.id.data;
-
+ bScreen *screen = value.id.data;
return !screen->temp;
}
-
-static void rna_Window_screen_update(bContext *C, PointerRNA *ptr)
+static void rna_workspace_screen_update(bContext *C, PointerRNA *ptr)
{
- wmWindow *win = (wmWindow *)ptr->data;
+ wmWindow *win = ptr->data;
+ WorkSpaceLayout *layout_new = win->workspace_hook->temp_layout_store;
/* exception: can't set screens inside of area/region handlers,
* and must use context so notifier gets to the right window */
- if (win->newscreen) {
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, win->newscreen);
- win->newscreen = NULL;
+ if (layout_new) {
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
+ win->workspace_hook->temp_layout_store = NULL;
}
}
@@ -1910,14 +2002,28 @@ static void rna_def_window(BlenderRNA *brna)
rna_def_window_stereo3d(brna);
- prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Window_scene_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Scene", "Active scene to be edited in the window");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_Window_scene_update");
+
+ prop = RNA_def_property(srna, "workspace", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "WorkSpace");
+ RNA_def_property_ui_text(prop, "Workspace", "Active workspace showing in the window");
+ RNA_def_property_pointer_funcs(prop, "rna_Window_workspace_get", "rna_Window_workspace_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_Window_workspace_update");
+
+ prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Screen");
- RNA_def_property_ui_text(prop, "Screen", "Active screen showing in the window");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Window_screen_set", NULL, "rna_Window_screen_assign_poll");
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, 0, "rna_Window_screen_update");
+ RNA_def_property_ui_text(prop, "Screen", "Active workspace screen showing in the window");
+ RNA_def_property_pointer_funcs(prop, "rna_Window_screen_get", "rna_Window_screen_set", NULL,
+ "rna_Window_screen_assign_poll");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL | PROP_EDITABLE | PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_workspace_screen_update");
prop = RNA_def_property(srna, "x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "posx");
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
new file mode 100644
index 00000000000..29fe5bae0e4
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -0,0 +1,144 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_workspace.c
+ * \ingroup RNA
+ */
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+#include "RNA_types.h"
+
+#include "BKE_workspace.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "rna_internal.h"
+
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_global.h"
+
+#include "BLI_listbase.h"
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+
+#include "RNA_access.h"
+
+
+void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ WorkSpace *workspace = ptr->id.data;
+ rna_iterator_listbase_begin(iter, BKE_workspace_layouts_get(workspace), NULL);
+}
+
+static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *iter)
+{
+ WorkSpaceLayout *layout = rna_iterator_listbase_get(iter);
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Screen, screen);
+}
+
+#ifdef USE_WORKSPACE_MODE
+
+static int rna_workspace_object_mode_get(PointerRNA *ptr)
+{
+ WorkSpace *workspace = ptr->data;
+ return (int)BKE_workspace_object_mode_get(workspace);
+}
+
+static void rna_workspace_object_mode_set(PointerRNA *ptr, int value)
+{
+ WorkSpace *workspace = ptr->data;
+ BKE_workspace_object_mode_set(workspace, value);
+}
+
+#endif /* USE_WORKSPACE_MODE */
+
+static PointerRNA rna_workspace_render_layer_get(PointerRNA *ptr)
+{
+ WorkSpace *workspace = ptr->data;
+ SceneLayer *render_layer = BKE_workspace_render_layer_get(workspace);
+
+ /* XXX hmrf... lookup in getter... but how could we avoid it? */
+ for (Scene *scene = G.main->scene.first; scene; scene = scene->id.next) {
+ if (BLI_findindex(&scene->render_layers, render_layer) != -1) {
+ PointerRNA scene_ptr;
+
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+ return rna_pointer_inherit_refine(&scene_ptr, &RNA_SceneLayer, render_layer);
+ }
+ }
+
+ return PointerRNA_NULL;
+}
+
+static void rna_workspace_render_layer_set(PointerRNA *ptr, PointerRNA value)
+{
+ WorkSpace *workspace = ptr->data;
+ BKE_workspace_render_layer_set(workspace, value.data);
+}
+
+#else /* RNA_RUNTIME */
+
+static void rna_def_workspace(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WorkSpace", "ID");
+ RNA_def_struct_sdna(srna, "WorkSpace");
+ RNA_def_struct_ui_text(srna, "Workspace", "Workspace data-block, defining the working environment for the user");
+ /* TODO: real icon, just to show something */
+ RNA_def_struct_ui_icon(srna, ICON_RENDER_RESULT);
+
+ prop = RNA_def_property(srna, "screens", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "layouts", NULL);
+ RNA_def_property_struct_type(prop, "Screen");
+ RNA_def_property_collection_funcs(prop, "rna_workspace_screens_begin", NULL, NULL,
+ "rna_workspace_screens_item_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Screens", "Screen layouts of a workspace");
+
+#ifdef USE_WORKSPACE_MODE
+ prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_object_mode_items);
+ RNA_def_property_enum_funcs(prop, "rna_workspace_object_mode_get", "rna_workspace_object_mode_set", NULL);
+ RNA_def_property_ui_text(prop, "Mode", "Object interaction mode");
+#endif
+
+ prop = RNA_def_property(srna, "render_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_workspace_render_layer_get", "rna_workspace_render_layer_set",
+ NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Render Layer", "The active render layer used in this workspace");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL);
+}
+
+void RNA_def_workspace(BlenderRNA *brna)
+{
+ rna_def_workspace(brna);
+}
+
+#endif /* RNA_RUNTIME */
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 15f3c665fcf..73265d28a93 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -332,6 +332,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
Main *bmain = CTX_data_main(BPy_GetContext());
Main *mainl = NULL;
int err = 0;
+ const bool do_append = ((self->flag & FILE_LINK) == 0);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
@@ -341,7 +342,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
int idcode_step = 0, idcode;
while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
- if (BKE_idcode_is_linkable(idcode)) {
+ if (BKE_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
const char *name_plural = BKE_idcode_to_name_plural(idcode);
PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
// printf("lib: %s\n", name_plural);
@@ -414,7 +415,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
BKE_main_lib_objects_recalc_all(bmain);
/* append, rather than linking */
- if ((self->flag & FILE_LINK) == 0) {
+ if (do_append) {
BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
}
}
@@ -427,7 +428,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
int idcode_step = 0, idcode;
while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
- if (BKE_idcode_is_linkable(idcode)) {
+ if (BKE_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
const char *name_plural = BKE_idcode_to_name_plural(idcode);
PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
if (ls && PyList_Check(ls)) {
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index a0b76bd67ee..3a6d5c9f972 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -310,7 +310,7 @@ static bool rna_id_write_error(PointerRNA *ptr, PyObject *key)
ID *id = ptr->id.data;
if (id) {
const short idcode = GS(id->name);
- if (!ELEM(idcode, ID_WM, ID_SCR)) { /* may need more added here */
+ if (!ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { /* may need more added here */
const char *idtype = BKE_idcode_to_name(idcode);
const char *pyname;
if (key && PyUnicode_Check(key)) pyname = _PyUnicode_AsString(key);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 80170d70dbd..6fa9429d04f 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -102,6 +102,21 @@ int WM_window_pixels_x (struct wmWindow *win);
int WM_window_pixels_y (struct wmWindow *win);
bool WM_window_is_fullscreen (struct wmWindow *win);
+void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATTR_NONNULL();
+struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+
+struct Scene *WM_window_get_active_scene(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_change_active_scene(struct Main *bmain, struct bContext *C, struct wmWindow *win,
+ struct Scene *scene_new) ATTR_NONNULL();
+struct WorkSpace *WM_window_get_active_workspace(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_workspace(struct wmWindow *win, struct WorkSpace *workspace) ATTR_NONNULL(1);
+struct WorkSpaceLayout *WM_window_get_active_layout(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_layout(
+ struct wmWindow *win, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL(1);
+struct bScreen *WM_window_get_active_screen(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_screen(struct wmWindow *win, struct WorkSpace *workspace, struct bScreen *screen) ATTR_NONNULL(1);
+bool WM_window_is_temp_screen(const struct wmWindow *win) ATTR_WARN_UNUSED_RESULT;
+
/* defines for 'type' WM_window_open_temp */
enum {
WM_WINDOW_RENDER = 1,
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 84209a0e3c8..756a9d6a1d1 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -224,7 +224,7 @@ typedef struct wmNotifier {
#define NOTE_CATEGORY 0xFF000000
#define NC_WM (1<<24)
#define NC_WINDOW (2<<24)
-#define NC_SCREEN (3<<24)
+#define NC_SCREEN (3<<24)
#define NC_SCENE (4<<24)
#define NC_OBJECT (5<<24)
#define NC_MATERIAL (6<<24)
@@ -258,15 +258,16 @@ typedef struct wmNotifier {
#define ND_JOB (5<<16)
#define ND_UNDO (6<<16)
- /* NC_SCREEN screen */
-#define ND_SCREENBROWSE (1<<16)
-#define ND_SCREENDELETE (2<<16)
+ /* NC_SCREEN */
+#define ND_LAYOUTBROWSE (1<<16)
+#define ND_LAYOUTDELETE (2<<16)
#define ND_SCREENCAST (3<<16)
#define ND_ANIMPLAY (4<<16)
#define ND_GPENCIL (5<<16)
#define ND_EDITOR_CHANGED (6<<16) /*sent to new editors after switching to them*/
-#define ND_SCREENSET (7<<16)
+#define ND_LAYOUTSET (7<<16)
#define ND_SKETCH (8<<16)
+#define ND_WORKSPACE_SET (9<<16)
/* NC_SCENE Scene */
#define ND_SCENEBROWSE (1<<16)
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index d0522fdd7d4..af275394fcb 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -433,10 +433,12 @@ void wm_add_default(bContext *C)
wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan");
wmWindow *win;
bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
-
+ struct WorkSpace *workspace = G.main->workspaces.last;
+
CTX_wm_manager_set(C, wm);
win = wm_window_new(C);
- win->screen = screen;
+ WM_window_set_active_workspace(win, workspace);
+ WM_window_set_active_screen(win, workspace, screen);
screen->winid = win->winid;
BLI_strncpy(win->screenname, screen->id.name + 2, sizeof(win->screenname));
@@ -457,7 +459,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
wm_autosave_timer_ended(wm);
while ((win = BLI_pophead(&wm->windows))) {
- win->screen = NULL; /* prevent draw clear to use screen */
+ WM_window_set_active_workspace(win, NULL); /* prevent draw clear to use screen */
wm_draw_window_clear(win);
wm_window_free(C, wm, win);
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 3c176912409..5be3429f2de 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -87,7 +87,7 @@ static void wm_paintcursor_draw(bContext *C, ARegion *ar)
if (wm->paintcursors.first) {
wmWindow *win = CTX_wm_window(C);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
wmPaintCursor *pc;
if (ar->swinid && screen->subwinactive == ar->swinid) {
@@ -130,7 +130,7 @@ static bool wm_area_test_invalid_backbuf(ScrArea *sa)
return true;
}
-static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion *ar)
+static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegion *ar)
{
/* tag region for redraw from render engine preview running inside of it */
if (sa->spacetype == SPACE_VIEW3D) {
@@ -138,7 +138,6 @@ static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion
RenderEngine *engine = (rv3d) ? rv3d->render_engine : NULL;
if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
- Scene *scene = screen->scene;
View3D *v3d = sa->spacedata.first;
rcti border_rect;
@@ -158,7 +157,7 @@ static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion
static void wm_method_draw_full(bContext *C, wmWindow *win)
{
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
@@ -181,7 +180,7 @@ static void wm_method_draw_full(bContext *C, wmWindow *win)
}
ED_screen_draw(win);
- win->screen->do_draw = false;
+ screen->do_draw = false;
/* draw overlapping regions */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -237,7 +236,7 @@ static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
{
wmWindowManager *wm = CTX_wm_manager(C);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
static rcti rect = {0, 0, 0, 0};
@@ -318,7 +317,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
/* after area regions so we can do area 'overlay' drawing */
if (screen->do_draw) {
ED_screen_draw(win);
- win->screen->do_draw = false;
+ screen->do_draw = false;
if (exchange)
screen->swap = WIN_FRONT_OK;
@@ -326,7 +325,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
else if (exchange) {
if (screen->swap == WIN_FRONT_OK) {
ED_screen_draw(win);
- win->screen->do_draw = false;
+ screen->do_draw = false;
screen->swap = WIN_BOTH_OK;
}
else if (screen->swap == WIN_BACK_OK)
@@ -500,7 +499,9 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl
/* region blend always is 1, except when blend timer is running */
if (fac < 1.0f) {
- wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ wmSubWindowScissorSet(win, screen->mainwin, &ar->winrct, true);
glEnable(GL_BLEND);
wm_triple_draw_textures(win, triple, 1.0f - fac);
@@ -512,7 +513,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first;
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
bool copytex = false;
@@ -620,7 +621,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* after area regions so we can do area 'overlay' drawing */
ED_screen_draw(win);
- win->screen->do_draw = false;
+ WM_window_get_active_screen(win)->do_draw = false;
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -647,7 +648,7 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
wmWindowManager *wm = CTX_wm_manager(C);
wmDrawData *drawdata;
wmDrawTriple *triple_data, *triple_all;
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
int copytex = false;
@@ -793,7 +794,7 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
/* after area regions so we can do area 'overlay' drawing */
ED_screen_draw(win);
if (sview == STEREO_RIGHT_ID)
- win->screen->do_draw = false;
+ screen->do_draw = false;
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -825,11 +826,13 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
/* quick test to prevent changing window drawable */
static bool wm_draw_update_test_window(wmWindow *win)
{
+ const Scene *scene = WM_window_get_active_scene(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
bool do_draw = false;
- for (ar = win->screen->regionbase.first; ar; ar = ar->next) {
+ for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->do_draw_overlay) {
wm_tag_redraw_overlay(win, ar);
ar->do_draw_overlay = false;
@@ -838,9 +841,9 @@ static bool wm_draw_update_test_window(wmWindow *win)
do_draw = true;
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- wm_region_test_render_do_draw(win->screen, sa, ar);
+ wm_region_test_render_do_draw(scene, sa, ar);
if (ar->swinid && ar->do_draw)
do_draw = true;
@@ -850,15 +853,15 @@ static bool wm_draw_update_test_window(wmWindow *win)
if (do_draw)
return true;
- if (win->screen->do_refresh)
+ if (screen->do_refresh)
return true;
- if (win->screen->do_draw)
+ if (screen->do_draw)
return true;
- if (win->screen->do_draw_gesture)
+ if (screen->do_draw_gesture)
return true;
- if (win->screen->do_draw_paintcursor)
+ if (screen->do_draw_paintcursor)
return true;
- if (win->screen->do_draw_drag)
+ if (screen->do_draw_drag)
return true;
return false;
@@ -899,15 +902,18 @@ void wm_tag_redraw_overlay(wmWindow *win, ARegion *ar)
{
/* for draw triple gestures, paint cursors don't need region redraw */
if (ar && win) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
if (wm_automatic_draw_method(win) != USER_DRAW_TRIPLE)
ED_region_tag_redraw(ar);
- win->screen->do_draw_paintcursor = true;
+ screen->do_draw_paintcursor = true;
}
}
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *ar)
{
- win->screen->do_draw_paintcursor = true;
+ bScreen *screen = WM_window_get_active_screen(win);
+ screen->do_draw_paintcursor = true;
wm_tag_redraw_overlay(win, ar);
}
@@ -941,13 +947,15 @@ void wm_draw_update(bContext *C)
}
if (wm_draw_update_test_window(win)) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
CTX_wm_window_set(C, win);
/* sets context window+screen */
wm_window_make_drawable(wm, win);
/* notifiers for screen redraw */
- if (win->screen->do_refresh)
+ if (screen->do_refresh)
ED_screen_refresh(wm, win);
int drawmethod = wm_automatic_draw_method(win);
@@ -971,9 +979,9 @@ void wm_draw_update(bContext *C)
}
}
- win->screen->do_draw_gesture = false;
- win->screen->do_draw_paintcursor = false;
- win->screen->do_draw_drag = false;
+ screen->do_draw_gesture = false;
+ screen->do_draw_paintcursor = false;
+ screen->do_draw_drag = false;
wm_window_swap_buffers(win);
@@ -994,7 +1002,7 @@ void wm_draw_data_free(wmWindow *win)
void wm_draw_window_clear(wmWindow *win)
{
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
@@ -1012,12 +1020,13 @@ void wm_draw_window_clear(wmWindow *win)
void wm_draw_region_clear(wmWindow *win, ARegion *ar)
{
+ bScreen *screen = WM_window_get_active_screen(win);
int drawmethod = wm_automatic_draw_method(win);
if (ELEM(drawmethod, USER_DRAW_OVERLAP, USER_DRAW_OVERLAP_FLIP))
- wm_flush_regions_down(win->screen, &ar->winrct);
+ wm_flush_regions_down(screen, &ar->winrct);
- win->screen->do_draw = true;
+ screen->do_draw = true;
}
void WM_redraw_windows(bContext *C)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 5d4b7a68d42..c4776f53f42 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -59,6 +59,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BKE_sound.h"
@@ -276,6 +277,7 @@ void wm_event_do_notifiers(bContext *C)
/* cache & catch WM level notifiers, such as frame change, scene/screen set */
for (win = wm->windows.first; win; win = win->next) {
+ Scene *scene = WM_window_get_active_scene(win);
bool do_anim = false;
CTX_wm_window_set(C, win);
@@ -293,17 +295,31 @@ void wm_event_do_notifiers(bContext *C)
}
if (note->window == win) {
if (note->category == NC_SCREEN) {
- if (note->data == ND_SCREENBROWSE) {
+ if (note->data == ND_WORKSPACE_SET) {
+ WorkSpace *ref_ws = note->reference;
+
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
+
+ ED_workspace_change(ref_ws, C, wm, win);
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: Workspace set %p\n", __func__, note->reference);
+ }
+ else if (note->data == ND_LAYOUTBROWSE) {
+ bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
+
/* free popup handlers only [#35434] */
UI_popup_handlers_remove_all(C, &win->modalhandlers);
- ED_screen_set(C, note->reference); // XXX hrms, think this over!
+ ED_screen_change(C, ref_screen); /* XXX hrms, think this over! */
if (G.debug & G_DEBUG_EVENTS)
printf("%s: screen set %p\n", __func__, note->reference);
}
- else if (note->data == ND_SCREENDELETE) {
- ED_screen_delete(C, note->reference); // XXX hrms, think this over!
+ else if (note->data == ND_LAYOUTDELETE) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = note->reference;
+
+ ED_workspace_layout_delete(workspace, layout, C); // XXX hrms, think this over!
if (G.debug & G_DEBUG_EVENTS)
printf("%s: screen delete %p\n", __func__, note->reference);
}
@@ -311,7 +327,7 @@ void wm_event_do_notifiers(bContext *C)
}
if (note->window == win ||
- (note->window == NULL && (note->reference == NULL || note->reference == win->screen->scene)))
+ (note->window == NULL && (note->reference == NULL || note->reference == scene)))
{
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME)
@@ -319,7 +335,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
- SceneLayer *sl = BKE_scene_layer_context_active(win->screen->scene);
+ SceneLayer *sl = BKE_scene_layer_context_active(scene);
ED_info_stats_clear(sl);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
@@ -332,7 +348,7 @@ void wm_event_do_notifiers(bContext *C)
if (G.is_rendering == false) {
/* depsgraph gets called, might send more notifiers */
- ED_update_for_newframe(CTX_data_main(C), win->screen->scene, 1);
+ ED_update_for_newframe(CTX_data_main(C), scene, 1);
}
}
}
@@ -340,10 +356,16 @@ void wm_event_do_notifiers(bContext *C)
/* the notifiers are sent without context, to keep it clean */
while ((note = BLI_pophead(&wm->queue))) {
for (win = wm->windows.first; win; win = win->next) {
- Scene *scene = win->screen->scene;
-
+ Scene *scene = WM_window_get_active_scene(win);
+ bScreen *screen = WM_window_get_active_screen(win);
+
/* filter out notifiers */
- if (note->category == NC_SCREEN && note->reference && note->reference != win->screen) {
+ if (note->category == NC_SCREEN &&
+ note->reference &&
+ note->reference != screen &&
+ note->reference != WM_window_get_active_workspace(win) &&
+ note->reference != WM_window_get_active_layout(win))
+ {
/* pass */
}
else if (note->category == NC_SCENE && note->reference && note->reference != scene) {
@@ -359,14 +381,14 @@ void wm_event_do_notifiers(bContext *C)
/* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name + 2, note->category); */
ED_screen_do_listen(C, note);
- for (ar = win->screen->regionbase.first; ar; ar = ar->next) {
- ED_region_do_listen(win->screen, NULL, ar, note, scene);
+ for (ar = screen->regionbase.first; ar; ar = ar->next) {
+ ED_region_do_listen(screen, NULL, ar, note, scene);
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- ED_area_do_listen(win->screen, sa, note, scene);
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ED_area_do_listen(screen, sa, note, scene);
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- ED_region_do_listen(win->screen, sa, ar, note, scene);
+ ED_region_do_listen(screen, sa, ar, note, scene);
}
}
}
@@ -374,18 +396,23 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
-
+
/* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
for (win = wm->windows.first; win; win = win->next) {
- win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
+ const Scene *scene = WM_window_get_active_scene(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
}
/* cached: editor refresh callbacks now, they get context */
for (win = wm->windows.first; win; win = win->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+ Scene *scene = WM_window_get_active_scene(win);
ScrArea *sa;
CTX_wm_window_set(C, win);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->do_refresh) {
CTX_wm_area_set(C, sa);
ED_area_do_refresh(C, sa);
@@ -398,12 +425,12 @@ void wm_event_do_notifiers(bContext *C)
Main *bmain = CTX_data_main(C);
/* copied to set's in scene_update_tagged_recursive() */
- win->screen->scene->customdata_mask = win_combine_v3d_datamask;
+ scene->customdata_mask = win_combine_v3d_datamask;
/* XXX, hack so operators can enforce datamasks [#26482], gl render */
- win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
+ scene->customdata_mask |= scene->customdata_mask_modal;
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
}
}
@@ -2362,17 +2389,19 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
+ bScreen *screen = WM_window_get_active_screen(win);
+
if (BLI_listbase_is_empty(&wm->drags)) {
return;
}
if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
}
else if (event->type == ESCKEY) {
WM_drag_free_list(&wm->drags);
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
}
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
event->type = EVT_DROP;
@@ -2388,16 +2417,16 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
event->customdatafree = 1;
/* clear drop icon */
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
/* restore cursor (disabled, see wm_dragdrop.c) */
// WM_cursor_modal_restore(win);
}
/* overlap fails otherwise */
- if (win->screen->do_draw_drag)
+ if (screen->do_draw_drag)
if (win->drawmethod == USER_DRAW_OVERLAP)
- win->screen->do_draw = true;
+ screen->do_draw = true;
}
@@ -2429,20 +2458,25 @@ void wm_event_do_handlers(bContext *C)
WM_keyconfig_update(wm);
for (win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
wmEvent *event;
-
- if (win->screen == NULL)
+
+ /* some safty checks - these should always be set! */
+ BLI_assert(WM_window_get_active_scene(win));
+ BLI_assert(WM_window_get_active_screen(win));
+ BLI_assert(WM_window_get_active_workspace(win));
+
+ if (screen == NULL)
wm_event_free_all(win);
else {
- Scene *scene = win->screen->scene;
+ Scene *scene = WM_window_get_active_scene(win);
if (scene) {
- int is_playing_sound = BKE_sound_scene_playing(win->screen->scene);
+ int is_playing_sound = BKE_sound_scene_playing(scene);
if (is_playing_sound != -1) {
bool is_playing_screen;
CTX_wm_window_set(C, win);
- CTX_wm_screen_set(C, win->screen);
CTX_data_scene_set(C, scene);
is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
@@ -2475,6 +2509,9 @@ void wm_event_do_handlers(bContext *C)
while ( (event = win->queue.first) ) {
int action = WM_HANDLER_CONTINUE;
+ /* active screen might change during handlers, update pointer */
+ screen = WM_window_get_active_screen(win);
+
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
printf("\n%s: Handling event\n", __func__);
WM_event_print(event);
@@ -2532,12 +2569,12 @@ void wm_event_do_handlers(bContext *C)
}
#endif
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
/* after restoring a screen from SCREENMAXIMIZED we have to wait
* with the screen handling till the region coordinates are updated */
- if (win->screen->skip_handling == true) {
+ if (screen->skip_handling == true) {
/* restore for the next iteration of wm_event_do_handlers */
- win->screen->skip_handling = false;
+ screen->skip_handling = false;
break;
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 99e0e28ab1b..8d442a2ed25 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -85,6 +85,7 @@
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -160,7 +161,7 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+ ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
}
@@ -249,16 +250,23 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
/* match oldwm to new dbase, only old files */
for (wm = oldwmlist->first; wm; wm = wm->id.next) {
-
for (win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+
/* all windows get active screen from file */
- if (screen->winid == 0)
- win->screen = screen;
- else
- win->screen = ED_screen_duplicate(win, screen);
-
- BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
- win->screen->winid = win->winid;
+ if (screen->winid == 0) {
+ WM_window_set_active_screen(win, workspace, screen);
+ }
+ else {
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win);
+
+ WM_window_set_active_layout(win, workspace, layout_new);
+ }
+
+ bScreen *win_screen = WM_window_get_active_screen(win);
+ BLI_strncpy(win->screenname, win_screen->id.name + 2, sizeof(win->screenname));
+ win_screen->winid = win->winid;
}
}
}
@@ -317,10 +325,8 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
}
/* in case UserDef was read, we re-initialize all, and do versioning */
-static void wm_init_userdef(bContext *C, const bool use_factory_settings)
+static void wm_init_userdef(Main *bmain, const bool use_factory_settings)
{
- Main *bmain = CTX_data_main(C);
-
/* versioning is here */
UI_init_userdef();
@@ -582,7 +588,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
/* in case a userdef is read from regular .blend */
- wm_init_userdef(C, false);
+ wm_init_userdef(G.main, false);
}
if (retval != BKE_BLENDFILE_READ_FAIL) {
@@ -828,7 +834,7 @@ int wm_homefile_read(
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
/* check userdef before open window, keymaps etc */
- wm_init_userdef(C, read_userdef_from_memory);
+ wm_init_userdef(CTX_data_main(C), read_userdef_from_memory);
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase);
@@ -1370,7 +1376,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
- if (win && win->screen->temp)
+ if (win && WM_window_is_temp_screen(win))
wm_window_close(C, wm, win);
/* update keymaps in user preferences */
@@ -1505,6 +1511,42 @@ void WM_OT_save_userpref(wmOperatorType *ot)
ot->exec = wm_userpref_write_exec;
}
+static int wm_workspace_configuration_file_write_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+ if (cfgdir == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create workspace configuration file path");
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_WORKSPACES_FILE, NULL);
+ printf("trying to save workspace configuration file at %s ", filepath);
+
+ if (BKE_blendfile_workspace_config_write(bmain, filepath, op->reports) != 0) {
+ printf("ok\n");
+ return OPERATOR_FINISHED;
+ }
+ else {
+ printf("fail\n");
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void WM_OT_save_workspace_file(wmOperatorType *ot)
+{
+ ot->name = "Save Workspace Configuration";
+ ot->idname = "WM_OT_save_workspace_file";
+ ot->description = "Save workspaces of the current file as part of the user configuration";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_workspace_configuration_file_write_exec;
+}
+
static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
ED_file_read_bookmarks();
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 82e9be3970f..3c7a48662f8 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -278,6 +278,40 @@ static void wm_link_do(
}
}
+/**
+ * Check if an item defined by \a name and \a group can be appended/linked.
+ *
+ * \param reports: Optionally report an error when an item can't be appended/linked.
+ */
+static bool wm_link_append_item_poll(
+ ReportList *reports, const char *path, const char *group, const char *name, const bool do_append)
+{
+ short idcode;
+
+ if (!group || !name) {
+ printf("skipping %s\n", path);
+ return false;
+ }
+
+ idcode = BKE_idcode_from_name(group);
+
+ /* XXX For now, we do a nasty exception for workspace, forbid linking them.
+ * Not nice, ultimately should be solved! */
+ if (!BKE_idcode_is_linkable(idcode) && (do_append || idcode != ID_WS)) {
+ if (reports) {
+ if (do_append) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't append data-block '%s' of type '%s'", name, group);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't link data-block '%s' of type '%s'", name, group);
+ }
+ }
+ return false;
+ }
+
+ return true;
+}
+
static int wm_link_append_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -289,6 +323,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
char *group, *name;
int totfiles = 0;
short flag;
+ bool has_item = false;
+ bool do_append;
RNA_string_get(op->ptr, "filename", relname);
RNA_string_get(op->ptr, "directory", root);
@@ -326,6 +362,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
}
flag = wm_link_append_flag(op);
+ do_append = (flag & FILE_LINK) == 0;
/* sanity checks for flag */
if (scene && scene->id.lib) {
@@ -361,7 +398,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_join_dirfile(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
- if (!group || !name) {
+ if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) {
continue;
}
@@ -369,6 +406,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx));
lib_idx++;
wm_link_append_data_library_add(lapp_data, libname);
+ has_item = true;
}
}
}
@@ -382,8 +420,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (BLO_library_path_explode(path, libname, &group, &name)) {
WMLinkAppendDataItem *item;
- if (!group || !name) {
- printf("skipping %s\n", path);
+
+ if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) {
continue;
}
@@ -391,6 +429,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ has_item = true;
}
}
RNA_END;
@@ -403,6 +442,12 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
wm_link_append_data_library_add(lapp_data, libname);
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
BLI_BITMAP_ENABLE(item->libraries, 0);
+ has_item = true;
+ }
+
+ if (!has_item) {
+ wm_link_append_data_free(lapp_data);
+ return OPERATOR_CANCELLED;
}
/* XXX We'd need re-entrant locking on Main for this to work... */
@@ -417,7 +462,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
IMB_colormanagement_check_file_config(bmain);
/* append, rather than linking */
- if ((flag & FILE_LINK) == 0) {
+ if (do_append) {
const bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive");
@@ -572,6 +617,7 @@ static void lib_relocate_do(
LinkNode *itemlink;
int item_idx;
+ bool has_item = false;
/* Remove all IDs to be reloaded from Main. */
lba_idx = set_listbasepointers(bmain, lbarray);
@@ -593,6 +639,7 @@ static void lib_relocate_do(
BLI_remlink(lbarray[lba_idx], id);
item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
+ has_item = true;
#ifdef PRINT_DEBUG
printf("\tdatablock to seek for: %s\n", id->name);
@@ -601,6 +648,11 @@ static void lib_relocate_do(
}
}
+ if (!has_item) {
+ /* nothing to relocate */
+ return;
+ }
+
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* We do not want any instanciation here! */
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index ce4a65b854a..022502c9935 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -478,7 +478,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+ ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 00fc75eb282..3665b6f2c12 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -2101,8 +2101,11 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
static int wm_operator_winactive_normal(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
+ bScreen *screen;
- if (win == NULL || win->screen == NULL || win->screen->state != SCREENNORMAL)
+ if (win == NULL)
+ return 0;
+ if (!((screen = WM_window_get_active_screen(win)) && (screen->state == SCREENNORMAL)))
return 0;
return 1;
@@ -3830,11 +3833,12 @@ static void redraw_timer_step(
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
}
else if (type == eRTDrawWindow) {
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa_iter;
CTX_wm_menu_set(C, NULL);
- for (sa_iter = win->screen->areabase.first; sa_iter; sa_iter = sa_iter->next) {
+ for (sa_iter = screen->areabase.first; sa_iter; sa_iter = sa_iter->next) {
ARegion *ar_iter;
CTX_wm_area_set(C, sa_iter);
@@ -4209,6 +4213,7 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_read_factory_settings);
WM_operatortype_append(WM_OT_save_homefile);
WM_operatortype_append(WM_OT_save_userpref);
+ WM_operatortype_append(WM_OT_save_workspace_file);
WM_operatortype_append(WM_OT_userpref_autoexec_path_add);
WM_operatortype_append(WM_OT_userpref_autoexec_path_remove);
WM_operatortype_append(WM_OT_window_fullscreen_toggle);
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 94e4e85026f..f8c4639c1b1 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -373,7 +373,8 @@ static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
{
- bScreen *screen = win->screen;
+ const bScreen *screen = WM_window_get_active_screen(win);
+ const Scene *scene = WM_window_get_active_scene(win);
/* some 3d methods change the window arrangement, thus they shouldn't
* toggle on/off just because there is no 3d elements being drawn */
@@ -381,7 +382,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return GHOST_GetWindowState(win->ghostwin) == GHOST_kWindowStateFullScreen;
}
- if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen) == false)) {
+ if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen, scene) == false)) {
return false;
}
@@ -508,7 +509,7 @@ int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
prev_display_mode != win_src->stereo3d_format->display_mode)
{
/* in case the hardward supports pageflip but not the display */
- if ((win_dst = wm_window_copy_test(C, win_src))) {
+ if ((win_dst = wm_window_copy_test(C, win_src, false))) {
/* pass */
}
else {
@@ -518,14 +519,16 @@ int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
}
}
else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
- /* ED_screen_duplicate() can't handle other cases yet T44688 */
- if (win_src->screen->state != SCREENNORMAL) {
+ const bScreen *screen = WM_window_get_active_screen(win_src);
+
+ /* ED_workspace_layout_duplicate() can't handle other cases yet T44688 */
+ if (screen->state != SCREENNORMAL) {
BKE_report(op->reports, RPT_ERROR,
"Failed to switch to Time Sequential mode when in fullscreen");
ok = false;
}
/* pageflip requires a new window to be created with the proper OS flags */
- else if ((win_dst = wm_window_copy_test(C, win_src))) {
+ else if ((win_dst = wm_window_copy_test(C, win_src, false))) {
if (wm_stereo3d_quadbuffer_supported()) {
BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created");
}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 7613479aacd..1a8f71891c0 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -141,8 +141,10 @@ void wm_subwindow_origin_get(wmWindow *win, int swinid, int *x, int *y)
static void wm_swin_matrix_get(wmWindow *win, wmSubWindow *swin, float mat[4][4])
{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
/* used by UI, should find a better way to get the matrix there */
- if (swin->swinid == win->screen->mainwin) {
+ if (swin->swinid == screen->mainwin) {
int width, height;
wm_swin_size_get(swin, &width, &height);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 3ff323862b3..66df41e5b84 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -38,6 +38,7 @@
#include "DNA_listBase.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
@@ -55,6 +56,8 @@
#include "BKE_library.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
@@ -68,6 +71,7 @@
#include "wm_subwindow.h"
#include "wm_event_system.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_fileselect.h"
@@ -218,6 +222,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
wm_ghostwindow_destroy(win);
+ BKE_workspace_instance_hook_free(G.main, win->workspace_hook);
MEM_freeN(win->stereo3d_format);
MEM_freeN(win);
@@ -238,13 +243,15 @@ static int find_free_winid(wmWindowManager *wm)
/* don't change context itself */
wmWindow *wm_window_new(bContext *C)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
-
+
BLI_addtail(&wm->windows, win);
win->winid = find_free_winid(wm);
win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
return win;
}
@@ -270,22 +277,26 @@ static wmWindow *wm_window_new_test(bContext *C)
}
/* part of wm_window.c api */
-wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
+wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout)
{
wmWindow *win_dst = wm_window_new(C);
-
+ WorkSpace *workspace = WM_window_get_active_workspace(win_src);
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
+ Scene *scene = WM_window_get_active_scene(win_src);
+ WorkSpaceLayout *layout_new;
+ bScreen *new_screen;
+
win_dst->posx = win_src->posx + 10;
win_dst->posy = win_src->posy;
win_dst->sizex = win_src->sizex;
win_dst->sizey = win_src->sizey;
-
- /* duplicate assigns to window */
- win_dst->screen = ED_screen_duplicate(win_dst, win_src->screen);
- BLI_strncpy(win_dst->screenname, win_dst->screen->id.name + 2, sizeof(win_dst->screenname));
- win_dst->screen->winid = win_dst->winid;
- win_dst->screen->do_refresh = true;
- win_dst->screen->do_draw = true;
+ win_dst->scene = scene;
+ WM_window_set_active_workspace(win_dst, workspace);
+ layout_new = duplicate_layout ? ED_workspace_layout_duplicate(workspace, layout_old, win_dst) : layout_old;
+ WM_window_set_active_layout(win_dst, workspace, layout_new);
+ new_screen = WM_window_get_active_screen(win_dst);
+ BLI_strncpy(win_dst->screenname, new_screen->id.name + 2, sizeof(win_dst->screenname));
win_dst->drawmethod = U.wmdrawmethod;
@@ -300,12 +311,12 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
* A higher level version of copy that tests the new window can be added.
* (called from the operator directly)
*/
-wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src)
+wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win_dst;
- win_dst = wm_window_copy(C, win_src);
+ win_dst = wm_window_copy(C, win_src, duplicate_layout);
WM_check(C);
@@ -329,7 +340,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
if (tmpwin == win)
continue;
- if (tmpwin->screen->temp == 0)
+ if (WM_window_is_temp_screen(tmpwin) == false)
break;
}
@@ -348,8 +359,10 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
WM_exit(C);
}
else {
- bScreen *screen = win->screen;
-
+ bScreen *screen = WM_window_get_active_screen(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook);
+
BLI_remlink(&wm->windows, win);
wm_draw_window_clear(win);
@@ -360,8 +373,8 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
/* for regular use this will _never_ be NULL,
* however we may be freeing an improperly initialized window. */
- if (win->screen) {
- ED_screen_exit(C, win, win->screen);
+ if (screen) {
+ ED_screen_exit(C, win, screen);
}
wm_window_free(C, wm, win);
@@ -369,14 +382,16 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
/* if temp screen, delete it after window free (it stops jobs that can access it) */
if (screen && screen->temp) {
Main *bmain = CTX_data_main(C);
- BKE_libblock_free(bmain, screen);
+
+ BLI_assert(BKE_workspace_layout_screen_get(layout) == screen);
+ BKE_workspace_layout_remove(bmain, workspace, layout);
}
- }
+ }
}
void wm_window_title(wmWindowManager *wm, wmWindow *win)
{
- if (win->screen && win->screen->temp) {
+ if (WM_window_is_temp_screen(win)) {
/* nothing to do for 'temp' windows,
* because WM_window_open_temp always sets window title */
}
@@ -668,8 +683,10 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
*/
wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
{
+ Main *bmain = CTX_data_main(C);
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
+ bScreen *screen;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
const char *title;
@@ -693,7 +710,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
/* test if we have a temp screen already */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
- if (win->screen->temp)
+ if (WM_window_is_temp_screen(win))
break;
/* add new window? */
@@ -704,6 +721,8 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
win->posy = rect.ymin;
}
+ screen = WM_window_get_active_screen(win);
+
win->sizex = BLI_rcti_size_x(&rect);
win->sizey = BLI_rcti_size_y(&rect);
@@ -711,19 +730,27 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
wm_window_set_size(win, win->sizex, win->sizey);
wm_window_raise(win);
}
-
- if (win->screen == NULL) {
- /* add new screen */
- win->screen = ED_screen_add(win, scene, "temp");
+
+ if (WM_window_get_active_workspace(win) == NULL) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
+ WM_window_set_active_workspace(win, workspace);
}
- else {
- /* switch scene for rendering */
- if (win->screen->scene != scene)
- ED_screen_set_scene(C, win->screen, scene);
+
+ if (screen == NULL) {
+ /* add new screen layout */
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = ED_workspace_layout_add(workspace, win, "temp");
+
+ screen = BKE_workspace_layout_screen_get(layout);
+ WM_window_set_active_layout(win, workspace, layout);
}
- win->screen->temp = 1;
-
+ if (WM_window_get_active_scene(win) != scene) {
+ WM_window_change_active_scene(bmain, C, win, scene);
+ }
+
+ screen->temp = 1;
+
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
WM_check(C);
@@ -735,7 +762,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
*/
/* ensure it shows the right spacetype editor */
- sa = win->screen->areabase.first;
+ sa = screen->areabase.first;
CTX_wm_area_set(C, sa);
if (type == WM_WINDOW_RENDER) {
@@ -745,7 +772,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
ED_area_newspace(C, sa, SPACE_USERPREF, false);
}
- ED_screen_set(C, win->screen);
+ ED_screen_change(C, screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
if (sa->spacetype == SPACE_IMAGE)
@@ -781,23 +808,42 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+static WorkSpaceLayout *wm_window_new_find_layout(wmOperator *op, WorkSpace *workspace)
+{
+ ListBase *listbase = BKE_workspace_layouts_get(workspace);
+ const int layout_id = RNA_enum_get(op->ptr, "screen");
+ int i = 0;
+
+ for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
+ if (i++ == layout_id) {
+ return layout;
+ }
+ }
+
+ BLI_assert(0);
+ return NULL;
+}
+
/* new window operator callback */
int wm_window_new_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
wmWindow *win_src = CTX_wm_window(C);
- const int screen_id = RNA_enum_get(op->ptr, "screen");
- bScreen *screen = BLI_findlink(&bmain->screen, screen_id);
+ WorkSpace *workspace = WM_window_get_active_workspace(win_src);
+ WorkSpaceLayout *layout_new = wm_window_new_find_layout(op, workspace);
+ bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
wmWindow *win_dst;
- if (screen->winid) {
- /* Screen is already used, duplicate window and screen */
- win_dst = wm_window_copy_test(C, win_src);
- }
- else if ((win_dst = wm_window_new_test(C))) {
- /* New window with a different screen */
- win_dst->screen = screen;
- screen->winid = win_dst->winid;
+ if ((win_dst = wm_window_new_test(C))) {
+ if (screen_new->winid) {
+ /* layout/screen is already used, duplicate it */
+ layout_new = ED_workspace_layout_duplicate(workspace, layout_new, win_dst);
+ screen_new = BKE_workspace_layout_screen_get(layout_new);
+ }
+ /* New window with a different screen but same workspace */
+ WM_window_set_active_workspace(win_dst, workspace);
+ WM_window_set_active_screen(win_dst, workspace, screen_new);
+ win_dst->scene = win_src->scene;
+ screen_new->winid = win_dst->winid;
CTX_wm_window_set(C, win_dst);
ED_screen_refresh(CTX_wm_manager(C), win_dst);
}
@@ -807,9 +853,11 @@ int wm_window_new_exec(bContext *C, wmOperator *op)
int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ ListBase *listbase = BKE_workspace_layouts_get(workspace);
- if (BLI_listbase_count_ex(&bmain->screen, 2) == 1) {
+ if (BLI_listbase_count_ex(listbase, 2) == 1) {
RNA_enum_set(op->ptr, "screen", 0);
return wm_window_new_exec(C, op);
}
@@ -821,7 +869,9 @@ int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(even
struct EnumPropertyItem *wm_window_new_screen_itemf(
bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free)
{
- Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ ListBase *listbase = BKE_workspace_layouts_get(workspace);
EnumPropertyItem *item = NULL;
EnumPropertyItem tmp = {0, "", 0, "", ""};
int value = 0, totitem = 0;
@@ -830,18 +880,20 @@ struct EnumPropertyItem *wm_window_new_screen_itemf(
* for dynamic strings in EnumPropertyItem.name to avoid this. */
static char active_screens[20][MAX_NAME + 12];
- for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+ const char *layout_name = BKE_workspace_layout_name_get(layout);
+
if (screen->winid) {
- BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)",
- screen->id.name + 2);
+ BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)", layout_name);
tmp.name = active_screens[count_act_screens++];
}
else {
- tmp.name = screen->id.name + 2;
+ tmp.name = layout_name;
}
tmp.value = value;
- tmp.identifier = screen->id.name;
+ tmp.identifier = layout_name;
UI_id_icon_render(C, CTX_data_scene(C), &screen->id, true, false);
tmp.icon = BKE_icon_id_ensure(&screen->id);
@@ -1156,7 +1208,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* stop screencast if resize */
if (type == GHOST_kEventWindowSize) {
- WM_jobs_stop(wm, win->screen, NULL);
+ WM_jobs_stop(wm, WM_window_get_active_screen(win), NULL);
}
wm_window_set_dpi(win);
@@ -1191,6 +1243,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
win->posx != posx ||
win->posy != posy)
{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
win->sizex = sizex;
win->sizey = sizey;
win->posx = posx;
@@ -1227,7 +1281,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wm_window_make_drawable(wm, win);
wm_draw_window_clear(win);
- BKE_icon_changed(win->screen->id.icon_id);
+ BKE_icon_changed(screen->id.icon_id);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
@@ -1340,7 +1394,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wm_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
- BKE_icon_changed(win->screen->id.icon_id);
+ BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id);
// close all popups since they are positioned with the pixel
// size baked in and it's difficult to correct them
@@ -1847,6 +1901,86 @@ bool WM_window_is_fullscreen(wmWindow *win)
return win->windowstate == GHOST_kWindowStateFullScreen;
}
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in visible workspaces and their visible layouts.
+ */
+void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
+{
+ for (wmWindow *win = win_lb->first; win; win = win->next) {
+ if (WM_window_get_active_scene(win) == scene) {
+ ED_workspace_scene_data_sync(win->workspace_hook, scene);
+ }
+ }
+}
+
+Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return WM_window_get_active_scene(win);
+ }
+ }
+
+ return NULL;
+}
+
+Scene *WM_window_get_active_scene(const wmWindow *win)
+{
+ return win->scene;
+}
+
+/**
+ * \warning Only call outside of area/region loops
+ */
+void WM_window_change_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene_new)
+{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ ED_scene_exit(C);
+ win->scene = scene_new;
+ ED_scene_changed_update(bmain, C, scene_new, screen);
+}
+
+WorkSpace *WM_window_get_active_workspace(const wmWindow *win)
+{
+ return BKE_workspace_active_get(win->workspace_hook);
+}
+void WM_window_set_active_workspace(wmWindow *win, WorkSpace *workspace)
+{
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+}
+
+WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win)
+{
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook): NULL);
+}
+void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
+}
+
+/**
+ * Get the active screen of the active workspace in \a win.
+ */
+bScreen *WM_window_get_active_screen(const wmWindow *win)
+{
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ /* May be NULL in rare cases like closing Blender */
+ return (LIKELY(workspace != NULL) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL);
+}
+void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
+{
+ BKE_workspace_active_screen_set(win->workspace_hook, workspace, screen);
+}
+
+bool WM_window_is_temp_screen(const wmWindow *win)
+{
+ const bScreen *screen = WM_window_get_active_screen(win);
+ return (screen && screen->temp != 0);
+}
+
#ifdef WITH_INPUT_IME
/* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 9a1518e15b0..4fbbe3d2879 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -45,6 +45,7 @@ void WM_OT_save_homefile(struct wmOperatorType *ot);
void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot);
void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot);
void WM_OT_save_userpref(struct wmOperatorType *ot);
+void WM_OT_save_workspace_file(struct wmOperatorType *ot);
void WM_OT_read_history(struct wmOperatorType *ot);
void WM_OT_read_homefile(struct wmOperatorType *ot);
void WM_OT_read_factory_settings(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 089e2994d3d..c8f89a5bf62 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -46,8 +46,8 @@ void wm_get_screensize(int *r_width, int *r_height);
void wm_get_desktopsize(int *r_width, int *r_height);
wmWindow *wm_window_new (bContext *C);
-wmWindow *wm_window_copy (bContext *C, wmWindow *win_src);
-wmWindow *wm_window_copy_test (bContext *C, wmWindow *win_src);
+wmWindow *wm_window_copy (bContext *C, wmWindow *win_src, const bool duplicate_layout);
+wmWindow *wm_window_copy_test (bContext *C, wmWindow *win_src, const bool duplicate_layout);
void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win);
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index d06777e792c..9d5d4d37a13 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -316,6 +316,12 @@ struct MenuType *WM_menutype_find(const char *idname, bool quiet) RET_NULL
void WM_operator_stack_clear(struct wmWindowManager *wm) RET_NONE
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot) RET_NONE
bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op) RET_ZERO;
+void WM_windows_scene_data_sync(const struct ListBase *win_lb, struct Scene *scene) RET_NONE
+struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm, const struct bScreen *screen) RET_NULL
+struct bScreen *WM_window_get_active_screen(const struct wmWindow *win) RET_NULL
+struct Scene *WM_window_get_active_scene(const struct wmWindow *win) RET_NULL
+void WM_window_change_active_scene(struct Main *bmain, struct bContext *C, struct wmWindow *win, struct Scene *scene_new) RET_NONE
+bool WM_window_is_temp_screen(const struct wmWindow *win) RET_ZERO
void WM_autosave_init(wmWindowManager *wm) RET_NONE
void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner) RET_NONE
@@ -400,7 +406,6 @@ void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *s
void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy) RET_NONE
-void ED_screen_set_scene(struct bContext *C, struct bScreen *screen, struct Scene *scene) RET_NONE
struct MovieClip *ED_space_clip_get_clip(struct SpaceClip *sc) RET_NULL
void ED_space_clip_set_clip(struct bContext *C, struct bScreen *screen, struct SpaceClip *sc, struct MovieClip *clip) RET_NONE
void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask) RET_NONE
@@ -495,6 +500,7 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View
void ED_node_shader_default(const struct bContext *C, struct ID *id) RET_NONE
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh) RET_NONE
struct bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm) RET_NULL
+struct Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm) RET_NULL
void ED_base_object_select(struct BaseLegacy *base, short mode) RET_NONE
void ED_object_base_select(struct Base *base, short mode) RET_NONE
bool ED_object_modifier_remove(struct ReportList *reports, struct Main *bmain, struct Object *ob, struct ModifierData *md) RET_ZERO
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 8f26e248424..11e22fffa4d 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -412,6 +412,12 @@ if(WITH_OPENCOLORIO)
)
endif()
+# Add default workspaces.blend to build (under [version]/datafiles
+install(
+ FILES ${CMAKE_SOURCE_DIR}/release/datafiles/workspaces.blend
+ DESTINATION ${TARGETDIR_VER}/datafiles
+)
+
# helpful tip when using make
if("${CMAKE_GENERATOR}" MATCHES ".*Makefiles.*")
# message after building.
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index a6b2340d7b4..6fdc823ba1a 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -324,7 +324,6 @@ static unsigned int *screenshot(ScrArea *curarea, int *dumpsx, int *dumpsy)
void KX_BlenderCanvas::MakeScreenShot(const char *filename)
{
ScrArea area_dummy= {0};
- bScreen *screen = m_win->screen;
unsigned int *dumprect;
int dumpsx, dumpsy;
@@ -340,7 +339,7 @@ void KX_BlenderCanvas::MakeScreenShot(const char *filename)
}
/* initialize image file format data */
- Scene *scene = (screen)? screen->scene: NULL;
+ Scene *scene = WM_window_get_active_scene(m_win);
ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format");
if (scene)