整理
わかったこと/わからないことを整理するところ
いつか調べる
-
RNA_id_pointer_create
とRNA_pointer_create
が処理の中心
→ 具体的になにをやっているのか? 2つの違いは? -
コールバック関数の処理は、結局どのような意味を持つのか?
取得した情報は result に代入される → operator などは、context じゃなくて result を利用している?
StructRNA の作成について
-
RNA_Image
などの RNA_xx 系は、StructRNA
として定義はされているが、具体的な設定を行うコードは見つからない - Code Doc. やらの記述を見ると、preprocessing において自動的に作成されるように見える
→RNA_def_xx()
のなかでは、様々なrna_def_yy()
を実行し、プロパティが設定される - 確認のためには自分でビルドしてみる?
問題は、ビルド結果に対して「何を調べればいいのか」がわからないこと
Code Doc. の記述
RNA の説明のとこ
Structs and their properties are defined in rna_*.c files in the makesrna module, and the definitions are generated as part of the build system. Errors will be printed during build and will help debugging.
...
Next in the RNA_def_* function the struct must be defined. RNA_def_struct defines the struct itself. We must define an identifier which is a unique name and used for identifying the struct in code, and a name which is a human readable name.
The system will automatically try to find a corresponding DNA struct with the same name as the identifier. If there is a corresponding DNA struct but it has a different name, RNA_def_struct_sdna can be used to pass the right name, this is important for defining properties more automatic later.
いま:
- コールバックを呼んだ側が、結果をどのように処理して最終的な context を作っているのか?
→ctx_data_get
のなかで各階層のコールバックが呼ばれているっぽい
CTX_data_dir_get_ex
の中では 空文字列でコールバックを呼んでいる? - ID is 何? dna とどう違うの?
→ 識別符号がついたデータ(データブロック:最初単位のデータ?)があって、その構造というか、関連情報の持ち方が DNA って感じに見える
any data-block that has an ID (data that can be linked in and accessed from bpy.data)
コメントとか
疑問
-
UI context とは 何か? どうやって要素を取得しているのか?
予想:Buttons の context / set_context_pointer による 一時的・局所的なもの (通常は無)
確認:実際に取得しているコードを見つける・・・どこ? -
member が空文字列かどうかによって、context の要素が
None
になるのはおかしい
予想:? 微妙な理由しか思いつかない
確認:member を与えてコールバックを呼んでいるとこを見る・・・ bContext ?
その他
- User Pref. や Main の context ってなに?
- wm の一番上は、screen なのか window なのか この2つの関係は?
基本情報
StructRNA の定義 コメント削除版
struct StructRNA {
ContainerRNA cont;
const char *identifier;
void *py_type;
void *blender_type;
int flag;
const EnumPropertyItem *prop_tag_defines;
const char *name;
const char *description;
const char *translation_context;
int icon;
PropertyRNA *nameproperty;
PropertyRNA *iteratorproperty;
struct StructRNA *base;
struct StructRNA *nested;
StructRefineFunc refine;
StructPathFunc path;
StructRegisterFunc reg;
StructUnregisterFunc unreg;
StructInstanceFunc instance;
IDPropertiesFunc idproperties;
ListBase functions;
};
PointerRNA の定義
typedef struct PointerRNA {
struct ID *owner_id;
struct StructRNA *type;
void *data;
} PointerRNA;
ID の定義 コメント削除版
typedef struct ID {
void *next, *prev;
struct ID *newid;
struct Library *lib;
struct AssetMetaData *asset_data;
char name[66];
short flag;
int tag;
int us;
int icon_id;
int recalc;
int recalc_up_to_undo_push;
int recalc_after_undo_push;
unsigned int session_uuid;
IDProperty *properties;
IDOverrideLibrary *override_library;
struct ID *orig_id;
void *py_instance;
void *_pad1;
} ID;
bContextDataResult の定義
struct bContextDataResult {
PointerRNA ptr;
ListBase list;
const char **dir;
short type; /* 0: normal, 1: seq */
};
画像/UVエディタのコールバック関数 image_context のコード
const char *image_context_dir[] = {"edit_image", "edit_mask", NULL};
static int /*eContextResult*/ image_context(const bContext *C,
const char *member,
bContextDataResult *result)
{
SpaceImage *sima = CTX_wm_space_image(C);
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, image_context_dir);
}
else if (CTX_data_equals(member, "edit_image")) {
CTX_data_id_pointer_set(result, (ID *)ED_space_image(sima));
return CTX_RESULT_OK;
}
else if (CTX_data_equals(member, "edit_mask")) {
Mask *mask = ED_space_image_get_mask(sima);
if (mask) {
CTX_data_id_pointer_set(result, &mask->id);
}
return CTX_RESULT_OK;
}
return CTX_RESULT_MEMBER_NOT_FOUND;
}
image_context() に関連する関数の関係図っぽいもの
結局、処理の中心的なポイントは2つ
-
CTX_wm_space_image
で SpaceImageEditor を bContext から取得する
→ SpaceImageEditor が手に入れば、image や mask はそのメンバなのでデータの取得は簡単 -
RNA_id_pointer_create
で必要な情報をresult.ptr
以下に代入する
→ 調べた結果
CTX_wm_space_image() に関連する関数の関係図っぽいもの
処理の中心的なポイント
-
BPY_context_member_get
で bContext から Area の RNAポインタを取得する (result に代入) - Area の space が SpaceImageEditor であるかどうかを確認する
BPY_context_member_get() に関連する関数の関係図っぽいもの
処理の中心的なポイント
-
RNA_pointer_create
で必要な情報をresult.ptr
以下に代入する
→RNA_id_pointer_create
ではなくRNA_pointer_create
であることの意味は?
CTX_data_id_pointer_set
とりあえずこのコードを追ってみた
SpaceImage *sima = CTX_wm_space_image(C);
...
else if (CTX_data_equals(member, "edit_image")) {
CTX_data_id_pointer_set(result, (ID *)ED_space_image(sima));
return CTX_RESULT_OK;
}
-
CTX_data_equals(member, "edit_image")
:member
と"edit_image"
の一致判定 -
ED_space_image(sima)
:Space からメンバのimage
を取得 (型はstruct Image *
) -
(ID *) image
:image へのポインタ値を ID へのポインタ値にキャスト -
CTX_data_id_pointer_set(result, &ID)
:RNA_id_pointer_create(&ID, &result->ptr)
-
RNA_id_pointer_create(&ID, &result->ptr)
:情報がいい感じに result に代入される -
return CTX_RESULT_OK
:1 を返す
わからないこと:結局なんの意味があったのか
"edit_image" は、一致判定のあとは一切使われない(= result には代入されない)
→ コールバックを呼んだ側が result の中身と "edit_image" を 組み合わせて context に設定?
CTX_data_equals の定義
STREQ
は文字列比較らしい
bool CTX_data_equals(const char *member, const char *str)
{
return (STREQ(member, str));
}
ED_space_image の定義
Image *ED_space_image(SpaceImage *sima)
{
return sima->image;
}
CTX_data_id_pointer_set の定義
void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
{
RNA_id_pointer_create(id, &result->ptr);
}
RNA_id_pointer_create の定義
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
{
StructRNA *type, *idtype = NULL;
if (id) {
PointerRNA tmp = {NULL};
tmp.data = id;
idtype = rna_ID_refine(&tmp);
while (idtype->refine) {
type = idtype->refine(&tmp);
if (type == idtype) {
break;
}
idtype = type;
}
}
r_ptr->owner_id = id;
r_ptr->type = idtype;
r_ptr->data = id;
}
RNA_id_pointer_create(&ID, &result->ptr)
について考える
- 基本情報:StructRNA / PointerRNA / ID / bContextDataResult の定義
状態確認 その1
-
id
(&ID
): Space から取得した Image へのポインタ値 (ID へのポインタ値に変換されている) -
r_ptr
(&result -> ptr
): bContextDataResult の メンバで PointerRNA 構造体
開始 ~ idtype = rna_ID_refine ...
- &StructRNA として
type
とidtype
を定義し、NULL を代入 -
id
(つまり&ID) はあるので判定を通過 - PointerRNA として
tmp
を定義し、先頭要素に NULL を代入して全体を初期化(たぶん) -
temp.data
(汎用ポインタ型)にid
を代入 -
idtype
にrna_ID_refine(&tmp)
の返り値である RNA_Image (StructRNA型) のアドレス値が代入される
状態確認 その2
-
id
(&ID
):Space から取得した Image へのポインタ値 (ID へのポインタ値に変換されている) -
r_ptr
(&result->ptr
):bContextDataResult の メンバで PointerRNA 構造体 -
temp
:temp.data
に &IDが代入され、それ以外は(たぶん)初期化された PointerRNA -
type
:StructRNA へのポインタ値で、値は NULL -
idtype
:StructRNA へのポインタ値で、値は &RNA_Image -
RNA_Image:(Build 時において作成されると予想している) Image 用の初期設定の StructRNA
- while ループ:
RNA_Image.refine
は NULL のはずなので、ループは実行されない
最後の3行
-
result.ptr
のowner_id
に、Space から取得した Image へのポインタ値を代入する -
result.ptr
のtype
に、StructRNA へのポインタ値&RNA_Image
を代入する -
result.ptr
のdata
に、Space から取得した Image へのポインタ値を代入する
結果として実現する状態
- Space (
sima
) から取得したimage
に基づいて - 3つのメンバ
owner_id
,type
,data
の値が設定された PointerRNA へのポインタ値が -
result
のメンバptr
に代入されている
rna_ID_refine(&tmp) について考える
5行目:rna_ID_refine(&tmp) の中での処理
- &ID:Space から取得した Image 構造体へのポインタ値 (構造体 ID へのポインタ値に変換されている)
-
temp
:temp.data
に &IDが代入され、それ以外は(たぶん)初期化された PointerRNA
-
&tmp ->data
経由で IDへの?ポインタ値を取得し、IDへのポインタ値に再キャストしてid
に代入 -
id->name)
でImage.name
を取得し、GS() によって*(&short name)
と2回型変換することでname
を short 型にする
→ この変換で、Image.name
の最初の2文字(たぶん) "IM" を取り出している (下部参照) - 取りだした2文字(
name
)を ID_Type にキャストし、ID_code_to_RNA_type(name)
を実行して2文字を列挙型ID_Type
の各要素と比較する - "IM" は
ID_IM
と一致するので、&RNA_Image (StructRNA型のアドレス値)が返される
データの名前とタイプの判定
Code Doc. の ID Datablocks のページの説明
The name of the datablock (
pointer->id.name
) encodes the type of the datablock. For example, a mesh that is presented in the Blender user interface with the name "Suzanne" is actually named "MESuzanne" in the datablock. This can be used to cast anID *id
to the correct type. A functionGS(name)
is available to take such a name and return a constant that indicates the ID data type:if (GS(id->name) == ID_SC) …
can be used to test whether the ID datablock is a Scene.(訳) データブロックの名前(
pointer->id.name
)は、データブロックのタイプに変換される。たとえば、Blender の UI に「Suzanne」という名前で表示されるメッシュは、データブロックでは "MESuzanne" という名前になっている。このデータ名の性質は、ID *id
として提供されるデータを適切な type にキャストするために利用できる。その手段である関数GS(name)
は、上記のような名前を引数に取り ID データの type を示す定数を返す関数であり、例えば、 ("SC"のようなものであるID_SC
を利用して)if (GS(id->name) == ID_SC)
という処理を行うことで、ID データの type が Scene であるかどうかを判定できる。
ID_Type の定義部分にも、以下のようなコメントがある
ID from database.
Written to #BHead.code (for file IO)
and the first 2 bytes of #ID.name (for runtime checks, see #GS macro).
na_ID_refine の定義
StructRNA *rna_ID_refine(PointerRNA *ptr)
{
ID *id = (ID *)ptr->data;
return ID_code_to_RNA_type(GS(id->name));
}
ID_code_to_RNA_typeの定義 省略あり
StructRNA *ID_code_to_RNA_type(short idcode)
{
switch ((ID_Type)idcode) {
case ID_AC:
return &RNA_Action;
...
case ID_IM:
return &RNA_Image;
...
}
return &RNA_ID;
}
GS() の定義
#define GS(a) \
(CHECK_TYPE_ANY(a, char *, const char *, char[66], const char[66]), \
(ID_Type)(*((const short *)(a))))
refine
と、デフォルトとしての StructRNA の作成 (未整理)
メンバとしての RNA_def_image の定義
void RNA_def_image(BlenderRNA *brna)
{
rna_def_render_slot(brna);
rna_def_udim_tile(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
rna_def_image_packed_files(brna);
}
RNA_def_space の定義 (一部省略)
void RNA_def_space(BlenderRNA *brna)
{
rna_def_space(brna);
rna_def_space_image(brna);
rna_def_space_sequencer(brna);
...
}
rna_def_space の定義 (一部省略)
static void rna_def_space(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Space", NULL);
RNA_def_struct_sdna(srna, "SpaceLink");
RNA_def_struct_ui_text(srna, "Space", "Space data for a screen area");
RNA_def_struct_refine_func(srna, "rna_Space_refine");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacetype");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "Space data type");
...
}
BlenderRNA の定義
struct BlenderRNA {
ListBase structs;
/* A map of structs: {StructRNA.identifier -> StructRNA}
* These are ensured to have unique names (with STRUCT_PUBLIC_NAMESPACE enabled). */
struct GHash *structs_map;
/* Needed because types with an empty identifier aren't included in 'structs_map'. */
unsigned int structs_len;
};
RNA_def_struct の定義
StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *from)
{
StructRNA *srnafrom = NULL;
/* only use RNA_def_struct() while pre-processing, otherwise use RNA_def_struct_ptr() */
BLI_assert(DefRNA.preprocess);
if (from) {
/* find struct to derive from */
/* Inline RNA_struct_find(...) because it wont link from here. */
srnafrom = BLI_ghash_lookup(brna->structs_map, from);
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found to define %s.", from, identifier);
DefRNA.error = true;
}
}
return RNA_def_struct_ptr(brna, identifier, srnafrom);
}
RNA_def_struct_ptr
の定義:srnafrom = NULL
の場合は、identifier
を設定しつつデフォルトのプロパティを設定した StructRNA を返すっぽい
RNA_def_struct_refine_func
void RNA_def_struct_refine_func(StructRNA *srna, const char *refine)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (refine) {
srna->refine = (StructRefineFunc)refine;
}
}
StructRefineFunc の定義
typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
PointerRNA へのポインタ値を引数にとって StructRNA へのポインタへの値を返す関数ポインタ
rna_Space_refine の定義 (一部省略)
static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
{
SpaceLink *space = (SpaceLink *)ptr->data;
switch ((eSpace_Type)space->spacetype) {
case SPACE_VIEW3D:
return &RNA_SpaceView3D;
case SPACE_GRAPH:
return &RNA_SpaceGraphEditor;
case SPACE_OUTLINER:
return &RNA_SpaceOutliner;
...
/* Currently no type info. */
case SPACE_SCRIPT:
case SPACE_EMPTY:
case SPACE_TOPBAR:
case SPACE_STATUSBAR:
break;
}
return &RNA_Space;
}
Build において、RNA_def_space()
によってRNA_Space
が作成されるとする
-
RNA_def_space(&BlenderRNA)
の中で、rna_def_space(&BlenderRNA)
などが実行される -
rna_def_space(&BlenderRNA)
の中で、Space 用の StrcutRNA が BlenderRNA から作成される - この StrcutRNA に対し、
RNA_def_struct_refine_func(StrcutRNA, "rna_Space_refine")
が実行される -
RNA_def_struct_refine_func
の中で、文字列が StructRefineFunc 型(の関数ポインタ型?)にキャストされ、StrcutRNA.refine = rna_Space_refine
として代入される
(ほんとに? 型変換だけでこんなことできるの?) - その他のあれこれが行われる
↓
もし、idtype = rna_ID_refine(&tmp)
によって idtype に &RNA_Space が代入された場合
-
idtype->refine
が存在するので判定を通過 -
idtype->refine(&tmp)
が実行されると、type = rna_Space_refine(&PointerRNA)
が実行される -
SpaceLink *space = (SpaceLink *)ptr->data
によって、PointerRNA の data メンバである ID が SpaceLink へのポインタにキャストされる
→ (この場合は)結局、引っ張ってきた Space のデータの SpaceLink を取得することになる - SpaceLink のメンバ
spacetype
を使って判定を行い、該当するサブタイプの Space の PointerRNA&RNA_SpaceView3D
が返されることになり、これにidtype
を更新する - 一致する case がない場合はベースのタイプが返されるので、
idtype->refine
が存在する場合、最終的に必ずtype == idtype
となり、 while ループが終わる
要するに:refine
はサブタイプを持つ構造体において、ベースからサブタイプを絞るためのもの[1]
- rna_ID_refine:データ名の接頭辞を使って StructRNA を取ってきて、ベースタイプを規定
- refine:データのタイプを使って StructRNA を取ってきて、サブタイプを規定
↓
サブタイプがなければrefine
は必要がないので、idtype->refine
は False になりうる
↓
Image:サブタイプがないのでidtype->refine
は初期値 NULL のまま設定されない
-
Struct 定義での
refine
部分のコメント:"function to give the more specific type" ↩︎
CTX_wm_space_image の定義
struct SpaceImage *CTX_wm_space_image(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
if (area && area->spacetype == SPACE_IMAGE) {
return area->spacedata.first;
}
return NULL;
}
CTX_wm_area の定義
ScrArea *CTX_wm_area(const bContext *C)
{
return ctx_wm_python_context_get(C, "area", &RNA_Area, C->wm.area);
}
ctx_wm_python_context_get の定義
static void *ctx_wm_python_context_get(const bContext *C,
const char *member,
const StructRNA *member_type,
void *fall_through)
{
#ifdef WITH_PYTHON
if (UNLIKELY(C && CTX_py_dict_get(C))) {
bContextDataResult result;
memset(&result, 0, sizeof(bContextDataResult));
BPY_context_member_get((bContext *)C, member, &result);
if (result.ptr.data) {
if (RNA_struct_is_a(result.ptr.type, member_type)) {
return result.ptr.data;
}
CLOG_WARN(&LOG,
"PyContext '%s' is a '%s', expected a '%s'",
member,
RNA_struct_identifier(result.ptr.type),
RNA_struct_identifier(member_type));
}
}
#else
UNUSED_VARS(C, member, member_type);
#endif
/* don't allow UI context access from non-main threads */
if (!BLI_thread_is_main()) {
return NULL;
}
return fall_through;
}
BPY_context_member_get の定義 一部省略
int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result)
{
PyObject *pyctx;
PyObject *item;
PointerRNA *ptr = NULL;
bool done = false;
pyctx = (PyObject *)CTX_py_dict_get(C);
item = PyDict_GetItemString(pyctx, member);
if (item == NULL) {
/* pass */
}
else if (item == Py_None) {
done = true;
}
else if (BPy_StructRNA_Check(item)) {
ptr = &(((BPy_StructRNA *)item)->ptr);
CTX_data_pointer_set(result, ptr->owner_id, ptr->type, ptr->data);
CTX_data_type_set(result, CTX_DATA_TYPE_POINTER);
done = true;
}
else if (PySequence_Check(item)) {
PyObject *seq_fast = PySequence_Fast(item, "bpy_context_get sequence conversion");
if (seq_fast == NULL) {
PyErr_Print();
PyErr_Clear();
}
else {
const int len = PySequence_Fast_GET_SIZE(seq_fast);
PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
int i;
for (i = 0; i < len; i++) {
PyObject *list_item = seq_fast_items[i];
if (BPy_StructRNA_Check(list_item)) {
ptr = &(((BPy_StructRNA *)list_item)->ptr);
CTX_data_list_add(result, ptr->owner_id, ptr->type, ptr->data);
}
else {
CLOG_INFO(BPY_LOG_CONTEXT,
1,
"'%s' list item not a valid type in sequence type '%s'",
member,
Py_TYPE(item)->tp_name);
}
}
Py_DECREF(seq_fast);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
done = true;
}
}
ctx_wm_python_context_get(C, "area", &RNA_Area, C->wm.area)
-
CTX_py_dict_get(C)
:C->data.py_context
の有無の判定
(UNLIKELY なので普通は NULL ではないらしい) - bContextDataResult 型の
result
を作成し、memset で初期化 -
BPY_context_member_get((bContext *)C, member, &result)
:? -
result.ptr.data
の有無を判定・・・通過した場合を考える -
RNA_struct_is_a(result.ptr.type, member_type)
:result.ptr.type
が &RNA_Area と一致するか判定 - 判定を通過すれば、
result.ptr.data
を返して終了 - もし、いろいろな判定に失敗した場合は、
C->wm.area
を返して終了
CTX_py_dict_get の定義
void *CTX_py_dict_get(const bContext *C)
{
return C->data.py_context;
}
RNA_struct_is_a の定義
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
{
const StructRNA *base;
if (srna == &RNA_AnyType) {
return true;
}
if (!type) {
return false;
}
/* ptr->type is always maximally refined */
for (base = type; base; base = base->base) {
if (base == srna) {
return true;
}
}
return false;
}
BPY_context_member_get の定義
int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result)
{
PyGILState_STATE gilstate;
const bool use_gil = !PyC_IsInterpreterActive();
PyObject *pyctx;
PyObject *item;
PointerRNA *ptr = NULL;
bool done = false;
if (use_gil) {
gilstate = PyGILState_Ensure();
}
pyctx = (PyObject *)CTX_py_dict_get(C);
item = PyDict_GetItemString(pyctx, member);
if (item == NULL) {
/* pass */
}
else if (item == Py_None) {
done = true;
}
else if (BPy_StructRNA_Check(item)) {
ptr = &(((BPy_StructRNA *)item)->ptr);
// result->ptr = ((BPy_StructRNA *)item)->ptr;
CTX_data_pointer_set(result, ptr->owner_id, ptr->type, ptr->data);
CTX_data_type_set(result, CTX_DATA_TYPE_POINTER);
done = true;
}
else if (PySequence_Check(item)) {
PyObject *seq_fast = PySequence_Fast(item, "bpy_context_get sequence conversion");
if (seq_fast == NULL) {
PyErr_Print();
PyErr_Clear();
}
else {
const int len = PySequence_Fast_GET_SIZE(seq_fast);
PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
int i;
for (i = 0; i < len; i++) {
PyObject *list_item = seq_fast_items[i];
if (BPy_StructRNA_Check(list_item)) {
#if 0
CollectionPointerLink *link = MEM_callocN(sizeof(CollectionPointerLink),
"bpy_context_get");
link->ptr = ((BPy_StructRNA *)item)->ptr;
BLI_addtail(&result->list, link);
#endif
ptr = &(((BPy_StructRNA *)list_item)->ptr);
CTX_data_list_add(result, ptr->owner_id, ptr->type, ptr->data);
}
else {
CLOG_INFO(BPY_LOG_CONTEXT,
1,
"'%s' list item not a valid type in sequence type '%s'",
member,
Py_TYPE(item)->tp_name);
}
}
Py_DECREF(seq_fast);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
done = true;
}
}
if (done == false) {
if (item) {
CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not a valid type", member);
}
else {
CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not found\n", member);
}
}
else {
CLOG_INFO(BPY_LOG_CONTEXT, 2, "'%s' found", member);
}
if (use_gil) {
PyGILState_Release(gilstate);
}
return done;
}
BPY_context_member_get((bContext *)C, member, &result) を考える
-
C
:コールバック呼び出し側から与えられた bContext 構造体へのポインタ値 -
member
:"area" -
result
:ctx_wm_python_context_get
が作成した、初期状態の bContextDataResult
-
pyctx
にC->data.py_context
(PyObject へのポインタ型)を代入 - PyDict_GetItemString:
pyctx
から、キー"area"で値を取り出し、item
(PyObject へのポインタ型)に代入 -
item
のチェック:NULL やPy_None
ならば、メッセージを出すなりして終了 -
BPy_StructRNA_Check(item)
のチェック:pyrna_struct_Type
の type/subtype であるかどうかをチェック
なにもわからないが、適切な対象で非リストなものがチェックを通過するっぽい
通過した場合
- あれこれ変換しているが、結局
item.ptr
のアドレス値を、ptr
(PointerRNA へのポインタ型)に代入する -
CTX_data_pointer_set
:RNA_pointer_create(ptr->owner_id, ptr->type, ptr->data, &result->ptr)
- 結局のところ、
item.ptr
のowner_id
、type
、data
を、そのままresult->ptr
に代入している - さらに
result->ptr->type->refine
が NULL でないか、つまりサブタイプがあるかを確認し、サブタイプがあるものならrefine(ptr)
を実行してptr->type
をサブタイプに変更
RNA_id_pointer_create との差異:rna_ID_refine() するかどうか
つまり、データ名からベースのタイプの情報を規定するための StructRNA が必要かどうか
↓
「元データ」が、ID、つまり StructRNA でないならrna_ID_refine()
が必要だが、「元データ」が StructRNA ならそのまま流用でき、サブタイプのチェックのみが必要ってこと?
細かい定義の情報
-
PyObject
:Python の type -
PyDict_GetItemString
:Python の関数、辞書内で キーconst char
に対応する value を返す -
PySequence_Check
:Python の関数、こことかによると、__getitem__
と__len__
を持ちx[i]
が可能な dict ではないオブジェクトならTrue
となるらしい -
PyObject_TypeCheck
:Python の関数、v
が第2引数の type/subtype ならTrue
を返す pyrna_struct_Type
の定義-
BPy_StructRNA_Check
の定義
#define BPy_StructRNA_Check(v) (PyObject_TypeCheck(v, &pyrna_struct_Type))
CTX_data_pointer_set の定義 と RNA_pointer_createの定義(コメント省略)
void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
{
RNA_pointer_create(id, type, data, &result->ptr);
}
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
{
r_ptr->owner_id = id;
r_ptr->type = type;
r_ptr->data = data;
if (data) {
while (r_ptr->type && r_ptr->type->refine) {
StructRNA *rtype = r_ptr->type->refine(r_ptr);
if (rtype == r_ptr->type) {
break;
}
r_ptr->type = rtype;
}
}
}
◇ コールバックが呼ばれるまで
なにか → CTX_data_active_object
とか → ctx_data_pointer_get
→
→ member で指定して ctx_data_get
→ 指定した member で各階層のコールバックが呼ばれる