利用者:Mneilly

提供: wiki
2013年1月17日 (木) 17:19時点におけるwiki>Mneillyによる版
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
移動先: 案内検索
Work In Progress
I am writing this tutorial as I learn to work with Blender Areas/Spaces/Editors. Hopefully, this will make it easier for others to learn the same material. Since this is new to me there may be comments/questions embedded related to things for which I have no answers.


Adding a New Space (Editor) to Blender

Getting Started

I recommend taking a look at Area Manager implementation before starting this tutorial. It'll give you a good base from which to start.

For the purposes of using terminology that matches the code base please note the following:

  • Area or Editor is also referred to as a Space. Ie - the boxes labeled as Area in the diagram can be referred to equally as Area, Editor or Space.
  • Region is implemented as ARegion.
  • RegionType is implemented as ARegionType.

Spaces and Regions

Blender starts with a single window which is divided into multiple spaces/editors/areas. Each of those spaces contains one or more regions.

In the following image, each of the orange boxes outlines a space (or editor) in the Blender window. The box at the top is the info space, the large box in the middle is the 3D View space, on the right are the outliner and properties spaces and at the bottom is the timeline space. Each of these boxes represents a space and has a specific space type defined in the source code.

Blender Spaces

The next image shows orange boxes around each of the regions within the 3D View space. To the left is the tools region, in the middle is the 3D View region and on the bottom is the header region.

Blender Regions

Looking at the Source

Every space has an associated type defined by the SpaceType structure. The basic information contained within the SpaceType structure is a name, an ID, a list of region types and pointers to a set of callback functions. The SpaceType structure is defined in blender/source/blender/makesdna/DNA_space_types.h.

typedef struct SpaceType {
	struct SpaceType *next, *prev;
	
	char name[BKE_ST_MAXNAME];                  /* for menus */
	int spaceid;                                /* unique space identifier */
	int iconid;                                 /* icon lookup for menus */
	
	/* initial allocation, after this WM will call init() too */
	struct SpaceLink    *(*new)(const struct bContext *C);

	...
		
	/* region type definitions */
	ListBase regiontypes;

        ...
    
} SpaceType;

A unique ID for each space type is defined in the eSpace_Type enumeration. When a new SpaceType instance is created it's spaceid is set to one of these values. eSpace_Type is defined in blender/source/blender/makesdna/DNA_space_types.h.

/* space types, moved from DNA_screen_types.h */
/* Do NOT change order, append on end. types are hardcoded needed */
typedef enum eSpace_Type {
	SPACE_EMPTY    = 0,
	SPACE_VIEW3D   = 1,
	SPACE_IPO      = 2,
	SPACE_OUTLINER = 3,
	SPACE_BUTS     = 4,
	SPACE_FILE     = 5,
	SPACE_IMAGE    = 6,
	SPACE_INFO     = 7,
	SPACE_SEQ      = 8,
	SPACE_TEXT     = 9,
	SPACE_IMASEL   = 10, /* deprecated */
	SPACE_SOUND    = 11, /* Deprecated */
	SPACE_ACTION   = 12,
	SPACE_NLA      = 13,
	SPACE_SCRIPT   = 14, /* Deprecated */
	SPACE_TIME     = 15,
	SPACE_NODE     = 16,
	SPACE_LOGIC    = 17,
	SPACE_CONSOLE  = 18,
	SPACE_USERPREF = 19,
	SPACE_CLIP     = 20,
	
	SPACEICONMAX = SPACE_CLIP
} eSpace_Type;

When Blender's window manager is initialized it calls the ED_spacetypes_init() function in blender/source/blender/editors/space_api/spacetypes.c which in turn calls each ED_spacetype_*() function to initialize each space type.

/* only call once on startup, storage is global in BKE kernel listbase */
void ED_spacetypes_init(void)
{
	const ListBase *spacetypes;
	SpaceType *type;

	/* UI_UNIT_X is now a variable, is used in some spacetype inits? */
	U.widget_unit = 20;
	
	/* create space types */
	ED_spacetype_outliner();
	ED_spacetype_time();
	ED_spacetype_view3d();
	ED_spacetype_ipo();
	ED_spacetype_image();
	ED_spacetype_node();
	ED_spacetype_buttons();
	ED_spacetype_info();
	ED_spacetype_file();
	ED_spacetype_action();
	ED_spacetype_nla();
	ED_spacetype_script();
	ED_spacetype_text();
	ED_spacetype_sequencer();
	ED_spacetype_logic();
	ED_spacetype_console();
	ED_spacetype_userpref();
	ED_spacetype_clip();
        ...

The declaration for each spacetype initialization function is put in blender/source/blender/editors/include/ED_space_api.h.

/* the pluginnable API for export to editors */

/* calls for registering default spaces */
void ED_spacetype_outliner(void);
void ED_spacetype_time(void);
void ED_spacetype_view3d(void);
void ED_spacetype_ipo(void);
void ED_spacetype_image(void);
void ED_spacetype_node(void);
void ED_spacetype_buttons(void);
void ED_spacetype_info(void);
void ED_spacetype_file(void);
void ED_spacetype_action(void);
void ED_spacetype_nla(void);
void ED_spacetype_script(void);
void ED_spacetype_text(void);
void ED_spacetype_tutorial(void);
void ED_spacetype_sequencer(void);
void ED_spacetype_logic(void);
void ED_spacetype_console(void);
void ED_spacetype_userpref(void);
void ED_spacetype_clip(void);

Each space type is implemented in a set of source files under blender/source/blender/editors. The following image highlights the directories associated with the various space types (editors).

Editor source directories

Examining the logic space type contained in space_logic/space_logic.c reveals the definition of the ED_spacetype_logic function which is called by ED_spacetypes_init() as indicated above.

/* only called once, from space/spacetypes.c */
void ED_spacetype_logic(void)
{
	SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype logic");
	ARegionType *art;
	
	st->spaceid = SPACE_LOGIC;
	strncpy(st->name, "Logic", BKE_ST_MAXNAME);
	
	st->new = logic_new;
	st->free = logic_free;
	st->init = logic_init;
	st->duplicate = logic_duplicate;
	st->operatortypes = logic_operatortypes;
	st->keymap = logic_keymap;
	st->refresh = logic_refresh;
	st->context = logic_context;
	
	/* regions: main window */
	art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
	art->regionid = RGN_TYPE_WINDOW;
	art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_VIEW2D;
	art->init = logic_main_area_init;
	art->draw = logic_main_area_draw;
	art->listener = logic_listener;

	BLI_addhead(&st->regiontypes, art);
	
	/* regions: listview/buttons */
	art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
	art->regionid = RGN_TYPE_UI;
	art->prefsizex= 220; // XXX
	art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
	art->listener = logic_listener;
	art->init = logic_buttons_area_init;
	art->draw = logic_buttons_area_draw;
	BLI_addhead(&st->regiontypes, art);

	/* regions: header */
	art= MEM_callocN(sizeof(ARegionType), "spacetype logic region");
	art->regionid = RGN_TYPE_HEADER;
	art->prefsizey = HEADERY;
	art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
	art->init = logic_header_area_init;
	art->draw = logic_header_area_draw;
	
	BLI_addhead(&st->regiontypes, art);
	
	BKE_spacetype_register(st);
}

The top portion of this function allocates a new SpaceType structure and a new RegionType structure. The st SpaceType structure is updated with it's spaceid set to SPACE_LOGIC, a name and function pointers for each callback.

Region types are allocated for the main logic area, the header and the properties list. Each region type is added to the regiontypes linked list in the st SpaceType structure by calling BLI_add_head() which adds the region type to the head of the linked list.

Finally, the space type is registered with Blender with a call to BKE_spacetype_register(st) which essentially is a wrapper around BLI_add_tail() which first checks to make sure that the space type has not already been assigned.

The first time the user selects an editor from the Editor Type menu for a given space the new callback for the space type is called. The function returns a SpaceLink type which is a generic pointer for all of the specific space types.

Search for the logic_new() function in blender/source/blender/editors/space_logic/space_logic.c.

static SpaceLink *logic_new(const bContext *C)
{
	ScrArea *sa= CTX_wm_area(C);
	ARegion *ar;
	SpaceLogic *slogic;
	
	slogic= MEM_callocN(sizeof(SpaceLogic), "initlogic");
	slogic->spacetype= SPACE_LOGIC;
	
	/* default options */
	slogic->scaflag = ((BUTS_SENS_SEL|BUTS_SENS_ACT|BUTS_SENS_LINK) |
	                   (BUTS_CONT_SEL|BUTS_CONT_ACT|BUTS_CONT_LINK) |
	                   (BUTS_ACT_SEL|BUTS_ACT_ACT|BUTS_ACT_LINK)    |
	                   (BUTS_SENS_STATE|BUTS_ACT_STATE));
	
	
	/* header */
	ar= MEM_callocN(sizeof(ARegion), "header for logic");
	
	BLI_addtail(&slogic->regionbase, ar);
	ar->regiontype= RGN_TYPE_HEADER;
	ar->alignment= RGN_ALIGN_BOTTOM;
	
	/* buttons/list view */
	ar= MEM_callocN(sizeof(ARegion), "buttons for logic");
	
	BLI_addtail(&slogic->regionbase, ar);
	ar->regiontype= RGN_TYPE_UI;
	ar->alignment= RGN_ALIGN_LEFT;
	
	/* main area */
	ar= MEM_callocN(sizeof(ARegion), "main area for logic");
	
	BLI_addtail(&slogic->regionbase, ar);
	ar->regiontype= RGN_TYPE_WINDOW;

	ar->v2d.tot.xmin =  0.0f;
	ar->v2d.tot.ymax =  0.0f;
	ar->v2d.tot.xmax = 1150.0f;
	ar->v2d.tot.ymin = ( 1150.0f/(float)sa->winx ) * (float)-sa->winy;
	
	ar->v2d.cur = ar->v2d.tot;
	
	ar->v2d.min[0] = 1.0f;
	ar->v2d.min[1] = 1.0f;
	
	ar->v2d.max[0] = 32000.0f;
	ar->v2d.max[1] = 32000.0f;
	
	ar->v2d.minzoom = 0.5f;
	ar->v2d.maxzoom = 1.5f;
	
	ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
	ar->v2d.keepzoom = V2D_KEEPZOOM | V2D_LIMITZOOM | V2D_KEEPASPECT;
	ar->v2d.keeptot = V2D_KEEPTOT_BOUNDS;
	ar->v2d.align = V2D_ALIGN_NO_POS_Y | V2D_ALIGN_NO_NEG_X;
	ar->v2d.keepofs = V2D_KEEPOFS_Y;
	
	return (SpaceLink *)slogic;
}

logic_new() allocates a new SpaceLogic structure and sets its spaceid to SPACE_LOGIC. Then it proceeds to create 3 regions for the main logic region, the header region and the properties region and adding these regions to the regionbase linked list within the space. Finally, the pointer to the SpaceLogic structure is returned as a SpaceLink pointer.

In order to select the Logic Editor from the Editor Type menu it must first be added to the menu. This is done in blender/source/blender/editors/screen/area.c.

static const char *editortype_pup(void)
{
	const char *types = N_(
	    "Editor type: %t"
	    "|3D View %x1"

	    "|%l"

	    "|Timeline %x15"
	    "|Graph Editor %x2"
	    "|DopeSheet %x12"
	    "|NLA Editor %x13"

	    "|%l"

	    "|UV/Image Editor %x6"

	    "|Video Sequence Editor %x8"
	    "|Movie Clip Editor %x20"
	    "|Text Editor %x9"
	    "|Node Editor %x16"
	    "|Logic Editor %x17"

	    "|%l"

	    "|Properties %x4"
	    "|Outliner %x3"
	    "|User Preferences %x19"
	    "|Info %x7"

	    "|%l"

	    "|File Browser %x5"

	    "|%l"

	    "|Python Console %x18"

	    );

	return IFACE_(types);
}

editortype_pup (editor type popup) defines the entries in the Editor Type menu. Notice that the Logic Editor is followed by %x17. This number corresponds to the value of SPACE_LOGIC as defined in the eSpace_Type enumerated list discussed above.

While there is much more going on in regard to initialization, keymaps etc in most of the files discussed so far we now have enough information to create a new space with minimal functionality.


Create a New Space (Editor)

First, edit blender/source/blender/makesdna/DNA_space_types.h and modify the eSpace_Type enumeration to contain a new ID. Then add a new structure for the space.

Add the new ID:

typedef enum eSpace_Type {
	SPACE_EMPTY    = 0,
	SPACE_VIEW3D   = 1,
	SPACE_IPO      = 2,
	SPACE_OUTLINER = 3,
	...
	SPACE_CLIP     = 20,
	SPACE_TUTORIAL = 21,
	
	SPACEICONMAX
} eSpace_Type;

Add the new SpaceLink structure:

/* Tutorial Editor */
typedef struct SpaceTutorial {
  SpaceLink *next, *prev;
  ListBase regionbase;
  int spacetype;
  char pad[4];
} SpaceTutorial;

Next, edit blender/source/blender/editors/space_api/spacetypes.c and modify the ED_spacetypes_init() function to include a call to ED_spacetype_tutorial().

void ED_spacetypes_init(void)
{
	const ListBase *spacetypes;
	SpaceType *type;

	/* UI_UNIT_X is now a variable, is used in some spacetype inits? */
	U.widget_unit = 20;
	
	/* create space types */
	ED_spacetype_outliner();
	ED_spacetype_time();
	ED_spacetype_view3d();
	ED_spacetype_ipo();
	ED_spacetype_image();
	ED_spacetype_node();
	ED_spacetype_buttons();
	ED_spacetype_info();
	ED_spacetype_file();
	ED_spacetype_action();
	ED_spacetype_nla();
	ED_spacetype_script();
	ED_spacetype_text();
	ED_spacetype_sequencer();
	ED_spacetype_logic();
	ED_spacetype_console();
	ED_spacetype_userpref();
	ED_spacetype_clip();
        ED_spacetype_tutorial();        /* Our new space/editor */
        ...

Edit blender/source/blender/editors/include/ED_space_api.h to add a declaration for the new space type initialization function.

/* the pluginnable API for export to editors */

/* calls for registering default spaces */
void ED_spacetype_outliner(void);
void ED_spacetype_time(void);
void ED_spacetype_view3d(void);
void ED_spacetype_ipo(void);
void ED_spacetype_image(void);
void ED_spacetype_node(void);
void ED_spacetype_buttons(void);
void ED_spacetype_info(void);
void ED_spacetype_file(void);
void ED_spacetype_action(void);
void ED_spacetype_nla(void);
void ED_spacetype_script(void);
void ED_spacetype_text(void);
void ED_spacetype_tutorial(void);
void ED_spacetype_sequencer(void);
void ED_spacetype_logic(void);
void ED_spacetype_console(void);
void ED_spacetype_userpref(void);
void ED_spacetype_clip(void);
void ED_spacetype_tutorial(void);        /* Our new space/editor */

Create a new folder in blender/source/blender/editors called space_tutorial and edit a new file named space_tutorial.c.

The content of that file should be as follows:

/*
 * ***** 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.
 *
 * The Original Code is Copyright (C) 2008 Blender Foundation.
 * All rights reserved.
 *
 *
 * Contributor(s): Michael Neilly
 *
 * ***** END GPL LICENSE BLOCK *****
 */

/** \file blender/editors/space_tutorial/space_tutorial.c
 *  \ingroup sptutorial
 */

#include <string.h>

#include "DNA_text_types.h"

#include "MEM_guardedalloc.h"

#include "BLI_blenlib.h"

#include "BKE_context.h"
#include "BKE_screen.h"

#include "ED_space_api.h"
#include "ED_screen.h"

#include "BIF_gl.h"

#include "WM_api.h"
#include "WM_types.h"

#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"

static SpaceLink *tutorial_new(const bContext *C)
{
	ScrArea *sa= CTX_wm_area(C);
	ARegion *ar;
	SpaceTutorial *stutorial;

	stutorial = MEM_callocN(sizeof(SpaceTutorial), "inittutorial");
	stutorial->spacetype = SPACE_TUTORIAL;

	/* header */
	ar = MEM_callocN(sizeof(ARegion), "header for tutorial");

	BLI_addtail(&stutorial->regionbase, ar);
	ar->regiontype = RGN_TYPE_HEADER;
	ar->alignment = RGN_ALIGN_BOTTOM;

	/* main area */
	ar = MEM_callocN(sizeof(ARegion), "main area for tutorial");

	BLI_addtail(&stutorial->regionbase, ar);
	ar->regiontype = RGN_TYPE_WINDOW;

	return (SpaceLink *)stutorial;
}

/* add handlers, stuff you only do once or on area/region changes */
static void tutorial_main_area_init(wmWindowManager *wm, ARegion *ar)
{
	UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
}

static void tutorial_main_area_draw(const bContext *C, ARegion *ar)
{
	/* draw entirely, view changes should be handled here */
	SpaceTutorial *stutorial = CTX_wm_space_tutorial(C);
	View2D *v2d = &ar->v2d;
	View2DScrollers *scrollers;

	/* clear and setup matrix */
	UI_ThemeClearColor(TH_BACK);
	glClear(GL_COLOR_BUFFER_BIT);

	/* works best with no view2d matrix set */
	UI_view2d_view_ortho(v2d);

	/* reset view matrix */
	UI_view2d_view_restore(C);

	/* scrollers */
	scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_GRID_CLAMP);
	UI_view2d_scrollers_draw(C, v2d, scrollers);
	UI_view2d_scrollers_free(scrollers);
}

static void tutorial_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
	ED_region_header_init(ar);
}

static void tutorial_header_area_draw(const bContext *C, ARegion *ar)
{
	ED_region_header(C, ar);
}

/********************* registration ********************/

/* only called once, from space/spacetypes.c */
void ED_spacetype_tutorial(void)
{
	SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype tutorial");
	ARegionType *art;

	st->spaceid = SPACE_TUTORIAL;
	strncpy(st->name, "Tutorial", BKE_ST_MAXNAME);

	st->new = tutorial_new;

	/* regions: main window */
	art = MEM_callocN(sizeof(ARegionType), "spacetype tutorial region");
	art->regionid = RGN_TYPE_WINDOW;

	art->init = tutorial_main_area_init;
	art->draw = tutorial_main_area_draw;

	BLI_addhead(&st->regiontypes, art);

	/* regions: header */
	art = MEM_callocN(sizeof(ARegionType), "spacetype tutorial region");
	art->regionid = RGN_TYPE_HEADER;
	art->prefsizey = HEADERY;
	art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
	art->init = tutorial_header_area_init;
	art->draw = tutorial_header_area_draw;
	
	BLI_addhead(&st->regiontypes, art);

	BKE_spacetype_register(st);
}

Edit editortype_pup() function to add the new space/editor to the Editor Type menu. This is done in blender/source/blender/editors/screen/area.c.

static const char *editortype_pup(void)
{
	const char *types = N_(
	    "Editor type: %t"
	    "|3D View %x1"

	    "|%l"

	    "|Timeline %x15"
	    "|Graph Editor %x2"
	    "|DopeSheet %x12"
	    "|NLA Editor %x13"

	    "|%l"

	    "|UV/Image Editor %x6"

	    "|Video Sequence Editor %x8"
	    "|Movie Clip Editor %x20"
	    "|Text Editor %x9"
	    "|Node Editor %x16"
	    "|Logic Editor %x17"

	    "|%l"

	    "|Properties %x4"
	    "|Outliner %x3"
	    "|User Preferences %x19"
	    "|Info %x7"

	    "|%l"

	    "|File Browser %x5"

	    "|%l"

	    "|Python Console %x18"

	    "|%l"

	    "|Tutorial %x21"

	    );

	return IFACE_(types);
}

What's missing

The above discussion touches on key areas but is not a complete picture of all the changes need to create a new space. The diff below contains the full set of changes that compile and run successfully in my tree as of 01/16/2013. I plan to update this page as I learn more myself but wanted to get it put in place in the hope that it will be useful even in its current limited state.

diff --git a/blender/source/blender/blenkernel/BKE_context.h b/blender/source/blender/blenkernel/BKE_context.h
index 285077f..cc5d21e 100644
--- a/blender/source/blender/blenkernel/BKE_context.h
+++ b/blender/source/blender/blenkernel/BKE_context.h
@@ -145,6 +145,7 @@ struct ReportList *CTX_wm_reports(const bContext *C);
 struct View3D *CTX_wm_view3d(const bContext *C);
 struct RegionView3D *CTX_wm_region_view3d(const bContext *C);
 struct SpaceText *CTX_wm_space_text(const bContext *C);
+struct SpaceTutorial *CTX_wm_space_tutorial(const bContext *C);
 struct SpaceImage *CTX_wm_space_image(const bContext *C);
 struct SpaceConsole *CTX_wm_space_console(const bContext *C);
 struct SpaceButs *CTX_wm_space_buts(const bContext *C);
diff --git a/blender/source/blender/blenkernel/intern/context.c b/blender/source/blender/blenkernel/intern/context.c
index a45afa5..2c55e1a 100644
--- a/blender/source/blender/blenkernel/intern/context.c
+++ b/blender/source/blender/blenkernel/intern/context.c
@@ -680,6 +680,14 @@ struct SpaceText *CTX_wm_space_text(const bContext *C)
 	return NULL;
 }
 
+struct SpaceTutorial *CTX_wm_space_tutorial(const bContext *C)
+{
+	ScrArea *sa = CTX_wm_area(C);
+	if (sa && sa->spacetype == SPACE_TUTORIAL)
+		return sa->spacedata.first;
+	return NULL;
+}
+
 struct SpaceConsole *CTX_wm_space_console(const bContext *C)
 {
 	ScrArea *sa = CTX_wm_area(C);
diff --git a/blender/source/blender/editors/CMakeLists.txt b/blender/source/blender/editors/CMakeLists.txt
index 084006c..5e3c5d3 100644
--- a/blender/source/blender/editors/CMakeLists.txt
+++ b/blender/source/blender/editors/CMakeLists.txt
@@ -50,6 +50,7 @@ if(WITH_BLENDER)
 	add_subdirectory(space_script)
 	add_subdirectory(space_sequencer)
 	add_subdirectory(space_text)
+	add_subdirectory(space_tutorial)
 	add_subdirectory(space_time)
 	add_subdirectory(space_userpref)
 	add_subdirectory(space_view3d)
diff --git a/blender/source/blender/editors/include/ED_space_api.h b/blender/source/blender/editors/include/ED_space_api.h
index c8521cb..517edf1 100644
--- a/blender/source/blender/editors/include/ED_space_api.h
+++ b/blender/source/blender/editors/include/ED_space_api.h
@@ -50,6 +50,7 @@ void ED_spacetype_action(void);
 void ED_spacetype_nla(void);
 void ED_spacetype_script(void);
 void ED_spacetype_text(void);
+void ED_spacetype_tutorial(void);
 void ED_spacetype_sequencer(void);
 void ED_spacetype_logic(void);
 void ED_spacetype_console(void);
diff --git a/blender/source/blender/editors/screen/area.c b/blender/source/blender/editors/screen/area.c
index cea7b12..7412ffe 100644
--- a/blender/source/blender/editors/screen/area.c
+++ b/blender/source/blender/editors/screen/area.c
@@ -1539,6 +1539,11 @@ static const char *editortype_pup(void)
 	    "|%l"
 
 	    "|Python Console %x18"
+
+	    "|%l"
+
+	    "|Tutorial %x21"
+
 	    );
 
 	return IFACE_(types);
diff --git a/blender/source/blender/editors/space_api/spacetypes.c b/blender/source/blender/editors/space_api/spacetypes.c
index 35344f2..e67e411 100644
--- a/blender/source/blender/editors/space_api/spacetypes.c
+++ b/blender/source/blender/editors/space_api/spacetypes.c
@@ -90,6 +90,7 @@ void ED_spacetypes_init(void)
 	ED_spacetype_nla();
 	ED_spacetype_script();
 	ED_spacetype_text();
+	ED_spacetype_tutorial();
 	ED_spacetype_sequencer();
 	ED_spacetype_logic();
 	ED_spacetype_console();
diff --git a/blender/source/blender/makesdna/DNA_space_types.h b/blender/source/blender/makesdna/DNA_space_types.h
index d632a88..4d33637 100644
--- a/blender/source/blender/makesdna/DNA_space_types.h
+++ b/blender/source/blender/makesdna/DNA_space_types.h
@@ -782,6 +782,16 @@ typedef enum eSpaceImage_Flag {
 	SI_COLOR_CORRECTION   = (1 << 24),
 } eSpaceImage_Flag;
 
+/* Tutorial Editor ============================================ */
+
+/* Tutorial Editor */
+typedef struct SpaceTutorial {
+	SpaceLink *next, *prev;
+	ListBase regionbase;        /* storage of regions for inactive spaces */
+	int spacetype;
+	char pad[4];
+} SpaceTutorial;
+
 /* Text Editor ============================================ */
 
 /* Text Editor */
@@ -1124,8 +1134,9 @@ typedef enum eSpace_Type {
 	SPACE_CONSOLE  = 18,
 	SPACE_USERPREF = 19,
 	SPACE_CLIP     = 20,
+	SPACE_TUTORIAL = 21,
 	
-	SPACEICONMAX = SPACE_CLIP
+	SPACEICONMAX
 } eSpace_Type;
 
 #define IMG_SIZE_FALLBACK 256
diff --git a/blender/source/blender/makesrna/RNA_access.h b/blender/source/blender/makesrna/RNA_access.h
index 29adb8f..46309f4 100644
--- a/blender/source/blender/makesrna/RNA_access.h
+++ b/blender/source/blender/makesrna/RNA_access.h
@@ -504,6 +504,7 @@ extern StructRNA RNA_SpaceOutliner;
 extern StructRNA RNA_SpaceProperties;
 extern StructRNA RNA_SpaceSequenceEditor;
 extern StructRNA RNA_SpaceTextEditor;
+extern StructRNA RNA_SpaceTutorialEditor;
 extern StructRNA RNA_SpaceTimeline;
 extern StructRNA RNA_SpaceUVEditor;
 extern StructRNA RNA_SpaceUserPreferences;
diff --git a/blender/source/blender/makesrna/intern/rna_space.c b/blender/source/blender/makesrna/intern/rna_space.c
index 926b141..a240dff 100644
--- a/blender/source/blender/makesrna/intern/rna_space.c
+++ b/blender/source/blender/makesrna/intern/rna_space.c
@@ -67,6 +67,7 @@ EnumPropertyItem space_type_items[] = {
 	{SPACE_INFO, "INFO", 0, "Info", ""},
 	{SPACE_SEQ, "SEQUENCE_EDITOR", 0, "Sequence Editor", ""},
 	{SPACE_TEXT, "TEXT_EDITOR", 0, "Text Editor", ""},
+	{SPACE_TUTORIAL, "TUTORIAL_EDITOR", 0, "Tutorial Editor", ""},
 	{SPACE_ACTION, "DOPESHEET_EDITOR", 0, "DopeSheet Editor", ""},
 	{SPACE_NLA, "NLA_EDITOR", 0, "NLA Editor", ""},
 	{SPACE_TIME, "TIMELINE", 0, "Timeline", ""},
@@ -177,6 +178,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
 			return &RNA_SpaceSequenceEditor;
 		case SPACE_TEXT:
 			return &RNA_SpaceTextEditor;
+		case SPACE_TUTORIAL:
+			return &RNA_SpaceTutorialEditor;
 		case SPACE_ACTION:
 			return &RNA_SpaceDopeSheetEditor;
 		case SPACE_NLA:
@@ -2367,6 +2370,17 @@ static void rna_def_space_text(BlenderRNA *brna)
 	RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
 }
 
+static void rna_def_space_tutorial(BlenderRNA *brna)
+{
+	StructRNA *srna;
+	PropertyRNA *prop;
+
+	srna = RNA_def_struct(brna, "SpaceTutorialEditor", "Space");
+	RNA_def_struct_sdna(srna, "SpaceTutorial");
+	RNA_def_struct_ui_text(srna, "Space Tutorial Editor", "Tutorial editor space data");
+
+}
+
 static void rna_def_space_dopesheet(BlenderRNA *brna)
 {
 	StructRNA *srna;
@@ -3426,6 +3440,7 @@ void RNA_def_space(BlenderRNA *brna)
 	rna_def_space_image(brna);
 	rna_def_space_sequencer(brna);
 	rna_def_space_text(brna);
+	rna_def_space_tutorial(brna);
 	rna_def_fileselect_params(brna);
 	rna_def_space_filebrowser(brna);
 	rna_def_space_outliner(brna);
diff --git a/blender/source/creator/CMakeLists.txt b/blender/source/creator/CMakeLists.txt
index 72f1132..7b0e6bd 100644
--- a/blender/source/creator/CMakeLists.txt
+++ b/blender/source/creator/CMakeLists.txt
@@ -824,6 +824,7 @@ endif()
 		bf_editor_space_userpref
 		bf_editor_space_view3d
 		bf_editor_space_clip
+		bf_editor_space_tutorial
 
 		bf_editor_text
 		bf_editor_transform

The follow images show the new Tutorial space in the Editor Type menu, after creation and after being split into three spaces.

Tutorialspace.png

Tutorialspace2.png

Tutorialspace3.png