36#define BPY_MSGBUS_RNA_MSGKEY_DOC \
37 " :arg key: Represents the type of data being subscribed to\n" \
39 " Arguments include\n" \
40 " - A property instance.\n" \
41 " - A struct type.\n" \
42 " - A tuple representing a (struct, property name) pair.\n" \
43 " :type key: :class:`bpy.types.Property` | " \
44 ":class:`bpy.types.Struct` | " \
45 "tuple[:class:`bpy.types.Struct`, str]\n"
59 const char *error_prefix)
65 if (py_sub_math->cb_user ==
nullptr) {
66 PyErr_Format(PyExc_TypeError,
"%s: math argument has no owner", error_prefix);
69 py_sub = py_sub_math->cb_user;
76 msg_key_params->
ptr = data_prop->
ptr;
77 msg_key_params->
prop = data_prop->
prop;
83 msg_key_params->
ptr = data_srna->
ptr;
86 else if (PyType_Check(py_sub)) {
88 if (data_type ==
nullptr) {
91 msg_key_params->
ptr.
type = data_type;
93 else if (PyTuple_CheckExact(py_sub)) {
94 if (PyTuple_GET_SIZE(py_sub) == 2) {
95 PyObject *data_type_py = PyTuple_GET_ITEM(py_sub, 0);
96 PyObject *data_prop_py = PyTuple_GET_ITEM(py_sub, 1);
98 if (data_type ==
nullptr) {
101 if (!PyUnicode_CheckExact(data_prop_py)) {
102 PyErr_Format(PyExc_TypeError,
"%s: expected property to be a string", error_prefix);
106 data_type_ptr.
type = data_type;
108 const char *data_prop_str = PyUnicode_AsUTF8(data_prop_py);
111 if (data_prop ==
nullptr) {
112 PyErr_Format(PyExc_TypeError,
113 "%s: struct %.200s does not contain property %.200s",
120 msg_key_params->
ptr.
type = data_type;
121 msg_key_params->
prop = data_prop;
124 PyErr_Format(PyExc_ValueError,
"%s: Expected a pair (type, property_id)", error_prefix);
137#define BPY_MSGBUS_USER_DATA_LEN 2
144 PyGILState_STATE gilstate;
147 PyObject *user_data =
static_cast<PyObject *
>(msg_val->
user_data);
150 PyObject *callback_args = PyTuple_GET_ITEM(user_data, 0);
151 PyObject *callback_notify = PyTuple_GET_ITEM(user_data, 1);
158 PyObject *
ret = PyObject_CallObject(callback_notify, callback_args);
160 if (
ret ==
nullptr) {
164 if (
ret != Py_None) {
165 PyErr_SetString(PyExc_ValueError,
"the return value must be None");
182 const PyGILState_STATE gilstate = PyGILState_Ensure();
183 Py_DECREF(msg_val->
owner);
185 PyGILState_Release(gilstate);
196 bpy_msgbus_subscribe_rna_doc,
197 ".. function:: subscribe_rna(key, owner, args, notify, options=set())\n"
199 " Register a message bus subscription. It will be cleared when another blend file is\n"
200 " loaded, or can be cleared explicitly via :func:`bpy.msgbus.clear_by_owner`.\n"
202 " :arg owner: Handle for this subscription (compared by identity).\n"
203 " :type owner: Any\n"
204 " :arg options: Change the behavior of the subscriber.\n"
206 " - ``PERSISTENT`` when set, the subscriber will be kept when remapping ID data.\n"
208 " :type options: set[str]\n"
212 " All subscribers will be cleared on file-load. Subscribers can be re-registered on load,\n"
213 " see :mod:`bpy.app.handlers.load_post`.\n");
216 const char *error_prefix =
"subscribe_rna";
217 PyObject *py_sub =
nullptr;
218 PyObject *py_owner =
nullptr;
219 PyObject *callback_args =
nullptr;
220 PyObject *callback_notify =
nullptr;
223 IS_PERSISTENT = (1 << 0),
225 PyObject *py_options =
nullptr;
227 {IS_PERSISTENT,
"PERSISTENT", 0,
""},
228 {0,
nullptr, 0,
nullptr,
nullptr},
232 if (PyTuple_GET_SIZE(args) != 0) {
233 PyErr_Format(PyExc_TypeError,
"%s: only keyword arguments are supported", error_prefix);
236 static const char *_keywords[] = {
244 static _PyArg_Parser _parser = {
256 if (!_PyArg_ParseTupleAndKeywordsFast(args,
287 if (!PyFunction_Check(callback_notify)) {
288 PyErr_Format(PyExc_TypeError,
289 "notify expects a function, found %.200s",
290 Py_TYPE(callback_notify)->tp_name);
302 msg_val_params.
owner = py_owner;
307 PyObject *user_data = PyTuple_New(2);
308 PyTuple_SET_ITEMS(user_data, Py_NewRef(callback_args), Py_NewRef(callback_notify));
326 bpy_msgbus_publish_rna_doc,
327 ".. function:: publish_rna(key)\n"
330 " Notify subscribers of changes to this property\n"
331 " (this typically doesn't need to be called explicitly since changes will automatically "
332 "publish updates).\n"
333 " In some cases it may be useful to publish changes explicitly using more general keys.\n");
336 const char *error_prefix =
"publish_rna";
337 PyObject *py_sub =
nullptr;
339 if (PyTuple_GET_SIZE(args) != 0) {
340 PyErr_Format(PyExc_TypeError,
"%s: only keyword arguments are supported", error_prefix);
343 static const char *_keywords[] = {
347 static _PyArg_Parser _parser = {
354 if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &py_sub)) {
374 bpy_msgbus_clear_by_owner_doc,
375 ".. function:: clear_by_owner(owner)\n"
377 " Clear all subscribers using this owner.\n");
386#if (defined(__GNUC__) && !defined(__clang__))
387# pragma GCC diagnostic push
388# pragma GCC diagnostic ignored "-Wcast-function-type"
394 METH_VARARGS | METH_KEYWORDS,
395 bpy_msgbus_subscribe_rna_doc},
398 METH_VARARGS | METH_KEYWORDS,
399 bpy_msgbus_publish_rna_doc},
403 bpy_msgbus_clear_by_owner_doc},
404 {
nullptr,
nullptr, 0,
nullptr},
407#if (defined(__GNUC__) && !defined(__clang__))
408# pragma GCC diagnostic pop
412 PyModuleDef_HEAD_INIT,
wmMsgBus * CTX_wm_message_bus(const bContext *C)
void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate)
void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate)
struct bContext * BPY_context_get(void)
static void bpy_msgbus_notify(bContext *C, wmMsgSubscribeKey *, wmMsgSubscribeValue *msg_val)
static void bpy_msgbus_subscribe_value_free_data(wmMsgSubscribeKey *, wmMsgSubscribeValue *msg_val)
static PyModuleDef _bpy_msgbus_def
#define BPY_MSGBUS_USER_DATA_LEN
static int py_msgbus_rna_key_from_py(PyObject *py_sub, wmMsgParams_RNA *msg_key_params, const char *error_prefix)
static PyObject * bpy_msgbus_subscribe_rna(PyObject *, PyObject *args, PyObject *kw)
PyObject * BPY_msgbus_module()
static PyMethodDef BPy_msgbus_methods[]
PyDoc_STRVAR(bpy_msgbus_subscribe_rna_doc, ".. function:: subscribe_rna(key, owner, args, notify, options=set())\n" "\n" " Register a message bus subscription. It will be cleared when another blend file is\n" " loaded, or can be cleared explicitly via :func:`bpy.msgbus.clear_by_owner`.\n" "\n" BPY_MSGBUS_RNA_MSGKEY_DOC " :arg owner: Handle for this subscription (compared by identity).\n" " :type owner: Any\n" " :arg options: Change the behavior of the subscriber.\n" "\n" " - ``PERSISTENT`` when set, the subscriber will be kept when remapping ID data.\n" "\n" " :type options: set[str]\n" "\n" ".. note::\n" "\n" " All subscribers will be cleared on file-load. Subscribers can be re-registered on load,\n" " see :mod:`bpy.app.handlers.load_post`.\n")
#define BPY_MSGBUS_RNA_MSGKEY_DOC
static PyObject * bpy_msgbus_clear_by_owner(PyObject *, PyObject *py_owner)
static PyObject * bpy_msgbus_publish_rna(PyObject *, PyObject *args, PyObject *kw)
StructRNA * pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix)
void pyrna_write_set(bool val)
#define PYRNA_STRUCT_CHECK_INT(obj)
#define PYRNA_PROP_CHECK_INT(obj)
#define BPy_StructRNA_Check(v)
#define BPy_PropertyRNA_Check(v)
CCL_NAMESPACE_BEGIN struct Options options
#define BaseMathObject_CheckExact(v)
int pyrna_enum_bitfield_from_set(const EnumPropertyItem *items, PyObject *value, int *r_value, const char *error_prefix)
void PyC_Err_PrintWithFunc(PyObject *py_func)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
#define PyTuple_SET_ITEMS(op_arg,...)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
const char * RNA_struct_identifier(const StructRNA *type)
PyObject_HEAD PointerRNA ptr
PyObject_HEAD PointerRNA ptr
wmMsgSubscribeValueFreeDataFn free_data
void WM_msgbus_clear_by_owner(wmMsgBus *mbus, void *owner)
void WM_msg_dump(wmMsgBus *mbus, const char *info_str)
void WM_msg_subscribe_rna_params(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
void WM_msg_publish_rna_params(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)