34#define BPY_MSGBUS_RNA_MSGKEY_DOC \
35 " :arg key: Represents the type of data being subscribed to\n" \
37 " Arguments include\n" \
38 " - A property instance.\n" \
39 " - A struct type.\n" \
40 " - A tuple representing a (struct, property name) pair.\n" \
41 " :type key: :class:`bpy.types.Property` | " \
42 ":class:`bpy.types.Struct` | " \
43 "tuple[:class:`bpy.types.Struct`, str]\n"
57 const char *error_prefix)
63 if (py_sub_math->cb_user ==
nullptr) {
64 PyErr_Format(PyExc_TypeError,
"%s: math argument has no owner", error_prefix);
67 py_sub = py_sub_math->cb_user;
74 msg_key_params->
ptr = *data_prop->
ptr;
75 msg_key_params->
prop = data_prop->
prop;
81 msg_key_params->
ptr = *data_srna->
ptr;
84 else if (PyType_Check(py_sub)) {
86 if (data_type ==
nullptr) {
89 msg_key_params->
ptr.
type = data_type;
91 else if (PyTuple_CheckExact(py_sub)) {
92 if (PyTuple_GET_SIZE(py_sub) == 2) {
93 PyObject *data_type_py = PyTuple_GET_ITEM(py_sub, 0);
94 PyObject *data_prop_py = PyTuple_GET_ITEM(py_sub, 1);
96 if (data_type ==
nullptr) {
99 if (!PyUnicode_CheckExact(data_prop_py)) {
100 PyErr_Format(PyExc_TypeError,
"%s: expected property to be a string", error_prefix);
104 data_type_ptr.
type = data_type;
106 const char *data_prop_str = PyUnicode_AsUTF8(data_prop_py);
109 if (data_prop ==
nullptr) {
110 PyErr_Format(PyExc_TypeError,
111 "%s: struct %.200s does not contain property %.200s",
118 msg_key_params->
ptr.
type = data_type;
119 msg_key_params->
prop = data_prop;
122 PyErr_Format(PyExc_ValueError,
"%s: Expected a pair (type, property_id)", error_prefix);
135#define BPY_MSGBUS_USER_DATA_LEN 2
142 PyGILState_STATE gilstate;
149 PyObject *user_data =
static_cast<PyObject *
>(msg_val->
user_data);
152 PyObject *callback_args = PyTuple_GET_ITEM(user_data, 0);
153 PyObject *callback_notify = PyTuple_GET_ITEM(user_data, 1);
155 PyObject *
ret = PyObject_CallObject(callback_notify, callback_args);
157 if (
ret ==
nullptr) {
161 if (
ret != Py_None) {
162 PyErr_SetString(PyExc_ValueError,
"the return value must be None");
178 const PyGILState_STATE gilstate = PyGILState_Ensure();
181 PyGILState_Release(gilstate);
192 bpy_msgbus_subscribe_rna_doc,
193 ".. function:: subscribe_rna(key, owner, args, notify, *, options=set())\n"
195 " Register a message bus subscription. It will be cleared when another blend file is\n"
196 " loaded, or can be cleared explicitly via :func:`bpy.msgbus.clear_by_owner`.\n"
198 " :arg owner: Handle for this subscription (compared by identity).\n"
199 " :type owner: Any\n"
200 " :arg options: Change the behavior of the subscriber.\n"
202 " - ``PERSISTENT`` when set, the subscriber will be kept when remapping ID data.\n"
204 " :type options: set[str]\n"
208 " All subscribers will be cleared on file-load. Subscribers can be re-registered on load,\n"
209 " see :mod:`bpy.app.handlers.load_post`.\n");
212 const char *error_prefix =
"subscribe_rna";
213 PyObject *py_sub =
nullptr;
214 PyObject *py_owner =
nullptr;
215 PyObject *callback_args =
nullptr;
216 PyObject *callback_notify =
nullptr;
219 IS_PERSISTENT = (1 << 0),
221 PyObject *py_options =
nullptr;
223 {IS_PERSISTENT,
"PERSISTENT", 0,
""},
224 {0,
nullptr, 0,
nullptr,
nullptr},
228 if (PyTuple_GET_SIZE(args) != 0) {
229 PyErr_Format(PyExc_TypeError,
"%s: only keyword arguments are supported", error_prefix);
232 static const char *_keywords[] = {
240 static _PyArg_Parser _parser = {
252 if (!_PyArg_ParseTupleAndKeywordsFast(args,
283 if (!PyFunction_Check(callback_notify)) {
284 PyErr_Format(PyExc_TypeError,
285 "notify expects a function, found %.200s",
286 Py_TYPE(callback_notify)->tp_name);
298 msg_val_params.
owner = py_owner;
303 PyObject *user_data = PyTuple_New(2);
304 PyTuple_SET_ITEMS(user_data, Py_NewRef(callback_args), Py_NewRef(callback_notify));
322 bpy_msgbus_publish_rna_doc,
323 ".. function:: publish_rna(key)\n"
326 " Notify subscribers of changes to this property\n"
327 " (this typically doesn't need to be called explicitly since changes will automatically "
328 "publish updates).\n"
329 " In some cases it may be useful to publish changes explicitly using more general keys.\n");
332 const char *error_prefix =
"publish_rna";
333 PyObject *py_sub =
nullptr;
335 if (PyTuple_GET_SIZE(args) != 0) {
336 PyErr_Format(PyExc_TypeError,
"%s: only keyword arguments are supported", error_prefix);
339 static const char *_keywords[] = {
343 static _PyArg_Parser _parser = {
350 if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &py_sub)) {
370 bpy_msgbus_clear_by_owner_doc,
371 ".. function:: clear_by_owner(owner)\n"
373 " Clear all subscribers using this owner.\n");
384# pragma clang diagnostic push
385# pragma clang diagnostic ignored "-Wcast-function-type"
387# pragma GCC diagnostic push
388# pragma GCC diagnostic ignored "-Wcast-function-type"
395 METH_VARARGS | METH_KEYWORDS,
396 bpy_msgbus_subscribe_rna_doc},
399 METH_VARARGS | METH_KEYWORDS,
400 bpy_msgbus_publish_rna_doc},
404 bpy_msgbus_clear_by_owner_doc},
405 {
nullptr,
nullptr, 0,
nullptr},
410# pragma clang diagnostic pop
412# pragma GCC diagnostic pop
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()
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
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")
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[]
#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 std::optional< PointerRNA > ptr
PyObject_HEAD std::optional< 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)