From BlenderWiki

Jump to: navigation, search

Context

In 2.5 the bContext struct was added to make context more explicit and replace global variables. For example operators, python scripts, drawing code, then can always work within a well defined context.

Context is represented by the bContext struct, for which the the API is defined in BKE_context.h. Getting context information mostly involves calling CTX_data_* and CTX_wm_* functions with bContext as the argument, while setting context is done lazily through callbacks that can be defined in screens, areas and regions.

-- Brecht 23:57, 4 December 2008 (UTC)

What's in the context?

Important to note in this diagram is that it is not about who's calling who, but rather about which data different types of code can assume to be in the context.

align=center

All code has access to User Preferences, which is a global and not something that is really context. Further there is Main, which is a .blend file with its own datablocks and datablocks linked from other .blend files. We should assume as much as possible there may be multiple such files open, even though this is not implemented yet.

Next there is a split. Drawing and interactive editing code can assume to be running under a Window Manager. The drawing and operator code running under the window manager always works at a certain level, in a Screen, Area or Region. Along with that level comes certain data, the screen has an active Scene, and areas and regions can additionally put other Data into the context, what that is exactly depends on the area and region types.

Besides that we have code that cannot be assumed to be running under a window manager. It does not mean that this code may not be called from the window manager, it means that such code should never assume there is a window manager and access it. This code can then run in background mode without a window option, typically for rendering. Evaluation (modifiers, constraints, ..) and rendering will typically get passed along a Scene and some other data, but should not have access to the bContext struct.

File reading and writing, various kernel functions, the window manager code, etc are not covered by this diagram. In general these will work with very little context or no context pointer at all.

Setting Context

Important to understand is that the context is not persistent. That is, if you want to change the active object, that is not done by setting it in the context. Rather the appropriate property in the Scene should be set, which will then be used in context lookups. Context is a temporary, local state when running an operator or drawing.

Callbacks

Context is mainly defined by callbacks. The Screen, space types and region types have a context() callback function. This function gets the name of a context member, then checks if it knows about this member, and if so, returns and RNA pointer or collection. Additionally, each context callback should also provide a list of context members it provides.

An example of such a callback for the image window space type:

static int image_context(const bContext *C, const char *member, bContextDataResult *result)
{
    SpaceImage *sima= CTX_wm_space_image(C);
 
    if(CTX_data_dir(member)) {
        static const char *dir[] = {"edit_image", NULL};
        CTX_data_dir_set(result, dir);
    }
    else if(CTX_data_equals(member, "edit_image")) {
        CTX_data_id_pointer_set(result, (ID*)ED_space_image(sima));
        return 1;
    }
 
    return 0;
}

UI Layouts

Additionally, it is possible to specify a more specific context for UI layouts. This is intended for things like modifiers or constraints. Within each modifier UI layout box, "modifier" is set in the context, and all operators called from buttons in that box will receive this in their context.

box.set_context_pointer("group", group)

Lookups

When a member is requested from the context, UI layout context will be looked at first, then the region callback, area callback and screen callback. As soon as it is found, the result is returned. If it is not found, a NULL pointer or an empty collection will be returned.

Context 2.5 setting.png

Getting Context

Window Manager

Window manager context is easiest, these are just pointers to the screen, area, space data, region and region data. Mainly you have to ensure that those things will actually be in the context. For drawing functions it's quite clear when they are, for operators it's important to check this in either the poll() function or verify it on the fly as the operator runs. Not doing this can lead to crashes when the user configures keymaps in ways that were not intended originally.

Data

Data context is more complicated, important to understand is that it is based on RNA pointers and collections. This makes the context automatically usable by Python scripts too.

In C there are two types of functions to call to get data from the context. For some things an accessor function is already defined. Note that internally this will still use a "edit_object" string to get the value, it is mostly for convenience.

Object *obedit= CTX_data_edit_object(C);

For others it may not be defined, and in such cases it is possible to use a string to query the context member. This however does not give a guarantee that the data type is right, so it's good practice to also specify the required type. The value returned is a PointerRNA (note the .data at the end of the line).

Object *obedit= CTX_data_pointer_get_type(C, "edit_object", &RNA_Object).data;

In python it is easiest, there context members appear as properties.

obedit = context.object_edit

Collections are also available, for this it is most convenient to use the provided macro:

CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
    printf("object: %s\n", base->object->id.name);
}
CTX_DATA_END;

Where to Look

There is no central place that lists all context members. To find out which context members are available, it is best to look at the relevant callback. I.e. if you're working in the image window, look at the context callback function defined in space_image.c.

In python, it's easy to look at what's in the context at runtime:

print(dir(context))

Always Available

Some context members can be assumed to be always set (with the exception of some file loading code). These do not need to be checked for in operator poll() functions, everything else should be checked for.

CTX_wm_manager
CTX_wm_window
CTX_wm_screen
 
CTX_data_main
CTX_data_scene
CTX_data_tool_settings

API

For more specific information, look at these files:

source/blender/blenkernel/BKE_context.h
source/blender/blenkernel/intern/context.c