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.hh
. 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.
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.
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 data-blocks and data-blocks 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.
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.
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.
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).
In python it is easiest, there context members appear as properties.
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.cc
.
In python, it's easy to look at what's in the context at runtime:
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.
API¶
For more specific information, look at these files: