Main Workspace Integration
authorJulian Eisel <eiseljulian@gmail.com>
Thu, 1 Jun 2017 17:56:58 +0000 (19:56 +0200)
committerJulian Eisel <eiseljulian@gmail.com>
Thu, 1 Jun 2017 17:59:37 +0000 (19:59 +0200)
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

131 files changed:
build_files/cmake/macros.cmake
doc/doxygen/doxygen.source.h
release/datafiles/workspaces.blend [new file with mode: 0644]
release/scripts/startup/bl_ui/space_info.py
release/scripts/startup/bl_ui/space_userpref.py
source/blender/CMakeLists.txt
source/blender/blenkernel/BKE_appdir.h
source/blender/blenkernel/BKE_blender_version.h
source/blender/blenkernel/BKE_blendfile.h
source/blender/blenkernel/BKE_context.h
source/blender/blenkernel/BKE_layer.h
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/BKE_scene.h
source/blender/blenkernel/BKE_screen.h
source/blender/blenkernel/BKE_workspace.h [new file with mode: 0644]
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/blendfile.c
source/blender/blenkernel/intern/context.c
source/blender/blenkernel/intern/idcode.c
source/blender/blenkernel/intern/image.c
source/blender/blenkernel/intern/layer.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/library_query.c
source/blender/blenkernel/intern/library_remap.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/screen.c
source/blender/blenkernel/intern/workspace.c [new file with mode: 0644]
source/blender/blenloader/BLO_readfile.h
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/versioning_280.c
source/blender/blenloader/intern/versioning_defaults.c
source/blender/blenloader/intern/writefile.c
source/blender/blentranslation/BLT_translation.h
source/blender/depsgraph/intern/depsgraph_tag.cc
source/blender/editors/CMakeLists.txt
source/blender/editors/animation/anim_markers.c
source/blender/editors/include/ED_scene.h [new file with mode: 0644]
source/blender/editors/include/ED_screen.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_eyedropper.c
source/blender/editors/interface/interface_regions.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/interface/interface_utils.c
source/blender/editors/interface/resources.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_edit.c
source/blender/editors/object/object_select.c
source/blender/editors/render/render_internal.c
source/blender/editors/render/render_update.c
source/blender/editors/render/render_view.c
source/blender/editors/scene/CMakeLists.txt [new file with mode: 0644]
source/blender/editors/scene/scene_edit.c [new file with mode: 0644]
source/blender/editors/screen/CMakeLists.txt
source/blender/editors/screen/area.c
source/blender/editors/screen/screen_context.c
source/blender/editors/screen/screen_draw.c
source/blender/editors/screen/screen_edit.c
source/blender/editors/screen/screen_intern.h
source/blender/editors/screen/screen_ops.c
source/blender/editors/screen/workspace_edit.c [new file with mode: 0644]
source/blender/editors/screen/workspace_layout_edit.c [new file with mode: 0644]
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/space_action/space_action.c
source/blender/editors/space_api/spacetypes.c
source/blender/editors/space_buttons/space_buttons.c
source/blender/editors/space_clip/clip_editor.c
source/blender/editors/space_file/file_utils.c
source/blender/editors/space_file/filesel.c
source/blender/editors/space_graph/space_graph.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_info/space_info.c
source/blender/editors/space_nla/space_nla.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/space_node.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/editors/space_outliner/outliner_select.c
source/blender/editors/space_outliner/outliner_tools.c
source/blender/editors/space_outliner/space_outliner.c
source/blender/editors/space_time/space_time.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_draw_legacy.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform_ops.c
source/blender/editors/transform/transform_orientations.c
source/blender/editors/util/CMakeLists.txt
source/blender/imbuf/intern/thumbs_blend.c
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_defs.h
source/blender/makesdna/DNA_fileglobal_types.h
source/blender/makesdna/DNA_screen_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesdna/DNA_workspace_types.h [new file with mode: 0644]
source/blender/makesdna/intern/makesdna.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_context.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_main.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_screen.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_space_api.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/makesrna/intern/rna_wm.c
source/blender/makesrna/intern/rna_workspace.c [new file with mode: 0644]
source/blender/python/intern/bpy_library_load.c
source/blender/python/intern/bpy_rna.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm.c
source/blender/windowmanager/intern/wm_draw.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_files.c
source/blender/windowmanager/intern/wm_files_link.c
source/blender/windowmanager/intern/wm_init_exit.c
source/blender/windowmanager/intern/wm_operators.c
source/blender/windowmanager/intern/wm_stereo.c
source/blender/windowmanager/intern/wm_subwindow.c
source/blender/windowmanager/intern/wm_window.c
source/blender/windowmanager/wm_files.h
source/blender/windowmanager/wm_window.h
source/blenderplayer/bad_level_call_stubs/stubs.c
source/creator/CMakeLists.txt
source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp

index bb356f51ab96d9bb6ce5b5e94a372658bb3329d0..92342d580c37d580619500e10f6083751ffd1c73 100644 (file)
@@ -585,6 +585,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
                bf_editor_armature
                bf_editor_physics
                bf_editor_render
+               bf_editor_scene
                bf_editor_screen
                bf_editor_sculpt_paint
                bf_editor_sound
index 3ef2046666443c5bdd771156ee9a7e5051c2d01f..6f12991fb4477db4bc180bed9296bd13cb68a563 100644 (file)
  *  \ingroup editors
  */
 
+/** \defgroup edscene scene
+ *  \ingroup editors
+ */
+
 /** \defgroup edsculpt sculpt and paint
  *  \ingroup editors
  */
diff --git a/release/datafiles/workspaces.blend b/release/datafiles/workspaces.blend
new file mode 100644 (file)
index 0000000..4e5e964
Binary files /dev/null and b/release/datafiles/workspaces.blend differ
index 901684297245a9c2ad99e6a58fa26681ed9ee249..f05808c7a2c66e5bc0bc7f019e1b092e07bf65a0 100644 (file)
@@ -28,7 +28,10 @@ class INFO_HT_header(Header):
         layout = self.layout
 
         window = context.window
+        workspace = context.workspace
+        screen = context.screen
         scene = context.scene
+        layer = context.render_layer
         rd = scene.render
 
         row = layout.row(align=True)
@@ -36,15 +39,27 @@ class INFO_HT_header(Header):
 
         INFO_MT_editor_menus.draw_collapsible(context, layout)
 
-        if window.screen.show_fullscreen:
+        layout.separator()
+
+        if screen.show_fullscreen:
             layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous")
             layout.separator()
         else:
-            layout.template_ID_preview(context.window, "screen", new="screen.new", unlink="screen.delete", rows=2, cols=6)
-            layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete")
+            layout.template_ID(window, "workspace", new="workspace.workspace_add_menu", unlink="workspace.workspace_delete")
+            layout.template_search_preview(window, "screen", workspace, "screens", new="screen.new", unlink="screen.delete", rows=2, cols=6)
+
+        if hasattr(workspace, 'object_mode'):
+            act_mode_item = bpy.types.Object.bl_rna.properties['mode'].enum_items[workspace.object_mode]
+        else:
+            act_mode_item = bpy.types.Object.bl_rna.properties['mode'].enum_items[layer.objects.active.mode]
+        layout.operator_menu_enum("object.mode_set", "mode", text=act_mode_item.name, icon=act_mode_item.icon)
+
+        layout.template_search(workspace, "render_layer", scene, "render_layers")
 
         layout.separator()
 
+        layout.template_ID(window, "scene", new="scene.new", unlink="scene.delete")
+
         if rd.has_multiple_engines:
             layout.prop(rd, "engine", text="")
 
index dad8ca73dce0c504bc3d1303d58d03e8c96abe97..0250f4a8ce81d847c80a8801fb0e630c9d081e02 100644 (file)
@@ -57,7 +57,9 @@ class USERPREF_HT_header(Header):
 
         layout.operator_context = 'INVOKE_DEFAULT'
 
-        if userpref.active_section == 'INPUT':
+        if userpref.active_section == 'INTERFACE':
+            layout.operator("wm.save_workspace_file")
+        elif userpref.active_section == 'INPUT':
             layout.operator("wm.keyconfig_import")
             layout.operator("wm.keyconfig_export")
         elif userpref.active_section == 'ADDONS':
@@ -224,7 +226,6 @@ class USERPREF_PT_interface(Panel):
         col.prop(view, "show_large_cursors")
         col.prop(view, "show_view_name", text="View Name")
         col.prop(view, "show_playback_fps", text="Playback FPS")
-        col.prop(view, "use_global_scene")
         col.prop(view, "object_origin_size")
 
         col.separator()
index 448e66ec5409110adc2825ed6b41156305223948..1788c8897192f6a569840db44cefd528de5b5aaa 100644 (file)
@@ -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
index ac8f861fa561584827a5b0453962123173b9a855..ffbdc6972f4b1efb3f3873fd4dc2ca9fc452b1d9 100644 (file)
@@ -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"
index bc3db11f34b5ab968d88f4be5ba4996e13db0f2b..ae87f1097d13cd3646b6d37b186b37e2c30e53bb 100644 (file)
@@ -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
index ac58451e412ed2988d02909c5961e95398ace547..d9fff5343b0a3ed59339b53ddb98857528d885d2 100644 (file)
@@ -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);
index c911d9ec9525207805b6552cf286be84f85a7176..b71f5a4aa8e54109131c26445d30bebb6cc78d95 100644 (file)
@@ -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);
index c6ec7e9df25cd583cafd33bb0e973b9e1f078517..17ab0bf0d2b9d36f213eebfcabf11137ce98841e 100644 (file)
@@ -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);
 
index 6649cfbb5858b97fccea76da1d73c41a50b6c003..dcc15c66c3e1e58a883fd547add482a8428ff118 100644 (file)
@@ -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 */
index 387045878f3e2d94c8da44eba740dcd17772d3bf..a616429fa95348fea18bde94dd73df77e19d6a2a 100644 (file)
@@ -123,6 +123,7 @@ typedef struct Main {
        ListBase mask;
        ListBase linestyle;
        ListBase cachefiles;
+       ListBase workspaces;
 
        char id_tag_update[MAX_LIBARRAY];
 
index 454fba0126e3266e3475fc7225351362573d8cc9..cd59ef98903d19936cc06f788c14ec3f749db626 100644 (file)
@@ -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)                               \
index 7def41d0540461bf2359c99fbca24d6c7b5ba62d..645a99d592f4adcdbe3c2d2af95d42ff427e1087 100644 (file)
@@ -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 (file)
index 0000000..e7eaf72
--- /dev/null
@@ -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__ */
index 1ddc6fce8182b1b17b0fb5fd3a5337b5450ed639..71aeb393c974cbf08c29c6e0a70b47903c9ea313 100644 (file)
@@ -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
index a521d671ea424dc8dea7eeacd37f468f53f08403..9e244246e16055d062295f095b25407c1d3370c1 100644 (file)
@@ -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"
 #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);
+}
+
 /** \} */
 
 
index ec0e14d814f9abb512ee4071cc70c7e8dfbaf962..7f24f1c2e5e8e28012bbb6d51f7f3dc9f1ae665a 100644 (file)
@@ -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;
 }
index 70d037d85f35d8caddda767ded429bc1092f19f3..e905eaeed768ddfc4a368eb11379a36f5f8f1ec4 100644 (file)
@@ -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);
index 9b28d9732e5521bd97e2e8c02de1f3ed9c5da30c..7ee4afd052dfdf6b137bd8467d27f41f6b3e7c3b 100644 (file)
@@ -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;
index d2fa09fa9e9811858b6ed1767a90b19d26dbc4b9..b088c7b4745eb72cf67249e830da7d4c650f3740 100644 (file)
 #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);
 }
 
 /**
index 4da2108b9d052febc1169c086cdcd8f56c8a2509..b81465a1b1d3c498db779619ec55f50048aa197a 100644 (file)
@@ -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;
 }
index 0c89a5bea4261895a9154158f296708a6d516e0a..d2ee11cc3976c9345da838a388f8b727d5772085 100644 (file)
@@ -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:
index 02128ae9c3a6912d093be24499a67a7a739a932b..235b10dd1da78e54aed437bf61f57e96fe0a59a6 100644 (file)
 #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 */
index 9de3ab5a93b5949f1dde5f099d1d4bbeb94688bb..92f5dade0a5f7d1bf19fa9b2228047d96bc73870 100644 (file)
@@ -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;
index c5d00d63b6dedc673a6239029c0fc9a38f4b47eb..b1f8f574b7ed08f76f55db127bf5a394335c61f2 100644 (file)
@@ -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 (file)
index 0000000..8afad31
--- /dev/null
@@ -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);
+}
index 0213a4ee997404eb46ebe09b33be9bb066633c25..fe38fc86c843d64171bb33dbe77302a41261fb5a 100644 (file)
@@ -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);
 
index d22af275469562974f15b0ca03730c26450741c0..966cbce62db5bc346a0c314344c71dccffd1eaee 100644 (file)
 
 /* 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"
 #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"
 #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;
index 3eeb0fc78e493af8f6dd1f7b3187fc218f351573..2d14238eb6f5bef0bd80c77ea608f84710436043 100644 (file)
@@ -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"
 
 #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);
+                               }
                        }
                }
        }
index a38f122ec56931a3c73af45a8b05ea3c3b63f2bf..002af20bc3a63cc22aed3926b87db4ee28eaab94 100644 (file)
 #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"
 
@@ -83,6 +85,32 @@ void BLO_update_defaults_userpref_blend(void)
 #endif
 }
 
+/**
+ * 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. */
@@ -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);
 
index 19f6b9f370d88842f5cec852220cf12beb657517..82d2e37dce0fbbe2b389840998fe211c51ace28f 100644 (file)
 
 /* 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"
 #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"
 
 #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;
index 1d76077c9f1e6fcfaa341d668b5234c42b1fbf46..9a00df9a0d5ec438cfe308e02c665c82c68fff1d 100644 (file)
@@ -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}                                                                                                 \
 }
index c3d64dc05bde877858485760e307f49fe65c064c..16d1f39f47ffa1f02545e56ee067fd0180d068f5 100644 (file)
@@ -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"
index 1559512d713f2108fe09a56e254f769610a4316f..f62db3c1ddbe2d7a152ce161baa296bb8e08b3f7 100644 (file)
@@ -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)
index 7ec19d12fb6954a35ff7c125d4c958e2cc0b573a..ef67411a48dcbd5b8dff2bfc948866990bc73dc4 100644 (file)
@@ -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 (file)
index 0000000..2f67f7b
--- /dev/null
@@ -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__ */
index 1208b1f31b6f814505f29023866b6ac948b25ad2..dec8bf7d615d688d717aa8e83443812a0cdc76a6 100644 (file)
@@ -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);
index 02243738d6ccc0d86e54386e2e7e5c705896d9a9..667ca09930508c9072e4a3c1e55b98134e819865 100644 (file)
@@ -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);
 
index 562a2f6e32c9e3dcf2b0c202c11d1f10ae53b912..be37ba46f7f6ac29cb2d87a1dcafd30bd16ff9cc 100644 (file)
@@ -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)
index bad47512d1263c8981c8178b9feb882571de9d09..858c21dfdda44139620583253cfaa191a89792c4 100644 (file)
@@ -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;
 
index ed8c3a5087514319a8fe34dcf76656992ba7f4d0..fd6d056f7d4074891754a24e5a2ecd8dd48a86ff 100644 (file)
@@ -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);
                        }
                }
index 266d8aacae35ee66d01496ebeb0854da80a34c6e..dbef5b68a03eedcd1bf900d0bec86359289cf173 100644 (file)
@@ -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) {
index f383719a7475e0decc2f5a9f6fda24ac4939cb06..fd1569ae42e91ba441edc43d39dbaf33f0ddd6fe 100644 (file)
@@ -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;
index e8eda567a4a35c55e46ab9a4ce328b201fdba3db..09ec08fe26571fd3cec50413838ea52f195e7f6a 100644 (file)
@@ -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;
        
index 177168aa3c3806c8cb49ee80b7cae230e78e6ede..068caee4e1ae04a669c552b52ac7753775fabe8f 100644 (file)
@@ -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;
                        
index abdbf3afd5acabfb315acf48dcaf8109e66bb1e5..fe232e378869e377acdbab4b78e47143525d4e39 100644 (file)
@@ -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
                }
        }
 }
index 4bdd524f11061e798c8cbfe3dd227232bdf07cdd..60c8fa6f28d726399bc998d69aba8b9197d6f2f3 100644 (file)
@@ -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);
                
index d4e9956b1890eae27007f04c365377793e79c6ab..bdfbac3dba7b480216c5d199b8159e623c376a99 100644 (file)
@@ -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;
index e019bc9f697c31a8dae0af630ede379494d2395e..ce52b9af4b2576ccee32cd89481e5b727a412b08 100644 (file)
@@ -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;
                
index c4a9af79ec28fba82f987e400bd4c0381ce70c6d..e4bae9d78ea9e5fa73fb6296ac7602d753482d0b 100644 (file)
@@ -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 (file)
index 0000000..72199ca
--- /dev/null
@@ -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 (file)
index 0000000..6956793
--- /dev/null
@@ -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);
+}
index 43e044b613ab9fb4cd9908a37c57f7f5e4652c53..02584a4611b2912ffeaf04c664ce7ecc3acafefe 100644 (file)
@@ -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
 )
index 3b933b0182a8f3aa8a3348117c5da93348cd1ebc..9d3dde06925e0b7e4633a3625c00e2ca66587465 100644 (file)
@@ -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;
index 0448fba78e61b86c18c3aa602121b8295ca34bae..d4e9609904ed1a75c1d39095d0587ec3e5536f47 100644 (file)
@@ -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;
 
index 4e43a7f96e77d086dfdc09bcc28e9b98c5f50363..52c138719254ffa8e3a84279bc95e50b6b557f2b 100644 (file)
@@ -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;
 }
 
 
index d59109a5baa2369fe852a4f2386c61b41a7e9be1..65b783463a95fde72d1aead744dc3422b9cf66af 100644 (file)
@@ -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;
+}
index 49c0869fcfb121e46aa7a335d57c2939d6c246fa..4eb68d01df7f0916f5ea31f39874ed73eabc6f07 100644 (file)
@@ -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__ */
index 69d13beee48af28ab8c1df0eac189d5aa877c6a2..5cd68f5121ccdf1135b3a79de5266ec1cab82aeb 100644 (file)
@@ -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 (file)
index 0000000..3782d58
--- /dev/null
@@ -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 (file)
index 0000000..e4dd841
--- /dev/null
@@ -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;
+}
index 1b18dd4e41c911b680dd6b0db5d4d1b4da05add7..64bd866c0db4b69a72e93354a0daaff6e5567753 100644 (file)
@@ -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);
index e76d83715a2eda9f1206e36757eae71ba9f991b4..fca54b282f888523e95885d15ff0c201c456c402 100644 (file)
@@ -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);
index 4d601a31251f6f7732d8bf88df4d8c98fb94aecf..3a431eb82dfe83b14728e031cd596051cb30a490 100644 (file)
@@ -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();
index 47297e8424232391781ffa0b6d0f41998c8ea2c1..299ab7171d697204b3b7cdb94314ba1a282ec982 100644 (file)
@@ -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);
 
index 59dd755173f8f0c4fb1bfae1fa768f0e78551641..942bc2661c356bf7972d4effe0f44bbe8d9a5c88 100644 (file)
@@ -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;
 
index c1caf5ae8ac5682de01d4dd71e524492966bc7e7..fc8703996966a3bdda5f512e459e07c91a752bfd 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "BLI_rect.h"
 #include "BLI_fileops.h"
+#include "BLI_listbase.h"
 
 #include "BLO_readfile.h"
 
index c2700233cf57ee38f3cbee62ed50a7be367b14e5..c03be5782be1c4f51789b989fce1fb08042fa71c 100644 (file)
@@ -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;
index 980ee5aeffe886b2eb256385e08334c851821af5..c17b60badaef619ed93dd7d93fbc83e9aabcfb11 100644 (file)
@@ -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);
index baa1dcdffd99ea7488e0385409142ef50d65c43e..56afdce7bb11c30c299501af415456eefd8cd743 100644 (file)
@@ -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;
        }
 }
 
index ab08b2884706ba23faf014f9d7e41c9761f9558e..4f042364c6354385857ec2bede093cf33feef8a5 100644 (file)
@@ -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)
index a71f2f20a3f3f303a4efa07bc72bf2c86592ec61..ab7a913ce6262a5be0e2da1cee445f3a476ec4f7 100644 (file)
@@ -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);
index 3cb5fd94ea98ceac5a96a303e2a147bffda6c936..8568b0a676d41202080fb041b08a3844148c0075 100644 (file)
@@ -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) {
index 4eeb4d02d8cbd145191065c933b2b95b31a8584e..665808c500fb120298b3894a83816200cb892fdb 100644 (file)
@@ -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;
                        }
index 06b3737753590c900172df22140bab5bd7c0cf9e..722bec1fa4627ebd9303b5d3b5f3e36aa0fdd07f 100644 (file)
@@ -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 {
index 931af08c717e31fa8ab6ecfb3b4f4e09a8b50a9d..400a01a2908e335b228acf1f8d4da3bdf74bf243 100644 (file)
@@ -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) {
index 0591a8674d3393c4b1d60185eb3e5d85ace3040d..159a00ae0ed0da11e2914496217a833c4010f6f4 100644 (file)
@@ -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);
        }
index b632db48caa7205fb98c9835cdd64b9bababd8ca..346e567dd8d1d2a7618d9d5f7e49742333469c44 100644 (file)
@@ -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;
        }
        
 }
index 9a3ae2dcd70a155194266a97a03d8d87548d0a3b..283cd6c0e24817070bc5927ed4a76642be106f83 100644 (file)
@@ -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;
        }
 }
 
index 9c55e99b151b37bee4b1ed54897b082795ece680..1dc9b1697148964322a3ae3c422b1c95a71d3eef 100644 (file)
@@ -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);
index bc74475e8cc34cc392d97fe19b6845d0a8417ff2..a27c5df9128e3e2f81371958599e427b5cd80cfa 100644 (file)
@@ -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;
index 6d1393a29053e25d8ef5723f680156440151976d..31677e082071888d40c3a74a4677c4abee14c5c6 100644 (file)
@@ -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);
index 93554c374d981283cd4e596875c9de39a53f4d7d..53f343ed071f55f0504288e02729bc0b70456639 100644 (file)
@@ -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;
index 2a97384cf7d21212c1a9ba3f9ffee1221bc9305b..a2a5307c70786c2c46b3a3d84f130b187ed04474 100644 (file)
@@ -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;
 }
 
index c9e40865164b1d07ee55ff486fb394eaeb956c06..2ba640500c7b129848d3540a9db92b89e62f697f 100644 (file)
@@ -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)
index c0b30f93939b410c40b52053e357de2e83f727f9..766f70d025c1d8b0f2b3a9ced58918f33749f09d 100644 (file)
@@ -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
index b5c6deb6b01e1693d6945c5b3f1d49a58fb27971..00fb1a44dff4007f0ea27f7cccf1339a2d193027 100644 (file)
@@ -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"
index 4f22d873a30dbbd6e0bbea46dab23825714fa605..9a89bf859c7ac7fb2311793f0327c89078f2ff5e 100644 (file)
@@ -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,
index fc9dd8f06a99f9fa725894f793cdb02a2d25aaca..bfa8da02707fba400c1404b51ad0ef74e42f1ac8 100644 (file)
 #  endif
 #endif
 
+#ifdef __GNUC__
+#  define DNA_PRIVATE_ATTR __attribute__ ((deprecated))
+#else
+#  define DNA_PRIVATE_ATTR
+#endif
+
 
 /* poison pragma */
 #ifdef DNA_DEPRECATED_ALLOW
index b2ab0d2a08d875777e36f85bd28a4d20268cfaed..6a01878a9ef078870cb44dfe809b96b18bf80652 100644 (file)
@@ -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 */
index ce1f8d1a7d4355b6e98eafadfca38f9717a833fb..2524bad7c0fba894eaad7aeafe1ff8bc7784f372 100644 (file)
@@ -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) */
 
index 256d53eed0ba182b4d73fbc987decdbfe1bdd238..9f5d33531f6089ad776f2f3379864bfb00f4283c 100644 (file)
@@ -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 */