Merge branch 'blender2.7'
[blender.git] / source / blender / python / intern / bpy_msgbus.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file \ingroup pythonintern
18  * This file defines '_bpy_msgbus' module, exposed as 'bpy.msgbus'.
19  */
20
21 #include <Python.h>
22
23 #include "../generic/python_utildefines.h"
24 #include "../generic/py_capi_utils.h"
25 #include "../mathutils/mathutils.h"
26
27 #include "BLI_utildefines.h"
28
29 #include "BKE_context.h"
30
31 #include "WM_api.h"
32 #include "WM_types.h"
33 #include "WM_message.h"
34
35 #include "RNA_access.h"
36 #include "RNA_define.h"
37 #include "RNA_enum_types.h"
38
39 #include "bpy_capi_utils.h"
40 #include "bpy_rna.h"
41 #include "bpy_intern_string.h"
42 #include "bpy_gizmo_wrap.h"  /* own include */
43
44
45 #include "bpy_msgbus.h"  /* own include */
46
47
48 /* -------------------------------------------------------------------- */
49 /** \name Internal Utils
50  * \{ */
51
52 #define BPY_MSGBUS_RNA_MSGKEY_DOC \
53 "   :arg key: Represents the type of data being subscribed to\n" \
54 "\n" \
55 "      Arguments include\n" \
56 "      - :class:`bpy.types.Property` instance.\n" \
57 "      - :class:`bpy.types.Struct` type.\n" \
58 "      - (:class:`bpy.types.Struct`, str) type and property name.\n" \
59 "   :type key: Muliple\n"
60
61 /**
62  * There are multiple ways we can get RNA from Python,
63  * it's also possible to register a type instead of an instance.
64  *
65  * This function handles converting Python to RNA subscription information.
66  *
67  * \param py_sub: See #BPY_MSGBUS_RNA_MSGKEY_DOC for description.
68  * \param msg_key_params: Message key with all members zeroed out.
69  * \return -1 on failure, 0 on success.
70  */
71 static int py_msgbus_rna_key_from_py(
72         PyObject *py_sub,
73         wmMsgParams_RNA *msg_key_params,
74         const char *error_prefix)
75 {
76
77         /* Allow common case, object rotation, location - etc. */
78         if (BaseMathObject_CheckExact(py_sub)) {
79                 BaseMathObject *py_sub_math = (BaseMathObject *)py_sub;
80                 if (py_sub_math->cb_user == NULL) {
81                         PyErr_Format(
82                                 PyExc_TypeError,
83                                 "%s: math argument has no owner",
84                                 error_prefix);
85                         return -1;
86                 }
87                 py_sub = py_sub_math->cb_user;
88                 /* Common case will use BPy_PropertyRNA_Check below. */
89         }
90
91         if (BPy_PropertyRNA_Check(py_sub)) {
92                 BPy_PropertyRNA *data_prop = (BPy_PropertyRNA *)py_sub;
93                 PYRNA_PROP_CHECK_INT(data_prop);
94                 msg_key_params->ptr = data_prop->ptr;
95                 msg_key_params->prop = data_prop->prop;
96         }
97         else if (BPy_StructRNA_Check(py_sub)) {
98                 /* note, this isn't typically used since we don't edit structs directly. */
99                 BPy_StructRNA *data_srna = (BPy_StructRNA *)py_sub;
100                 PYRNA_STRUCT_CHECK_INT(data_srna);
101                 msg_key_params->ptr = data_srna->ptr;
102         }
103         /* TODO - property / type, not instance. */
104         else if (PyType_Check(py_sub)) {
105                 StructRNA *data_type = pyrna_struct_as_srna(py_sub, false, error_prefix);
106                 if (data_type == NULL) {
107                         return -1;
108                 }
109                 msg_key_params->ptr.type = data_type;
110         }
111         else if (PyTuple_CheckExact(py_sub)) {
112                 if (PyTuple_GET_SIZE(py_sub) == 2) {
113                         PyObject *data_type_py = PyTuple_GET_ITEM(py_sub, 0);
114                         PyObject *data_prop_py = PyTuple_GET_ITEM(py_sub, 1);
115                         StructRNA *data_type = pyrna_struct_as_srna(data_type_py, false, error_prefix);
116                         if (data_type == NULL) {
117                                 return -1;
118                         }
119                         if (!PyUnicode_CheckExact(data_prop_py)) {
120                                 PyErr_Format(
121                                         PyExc_TypeError,
122                                         "%s: expected property to be a string",
123                                         error_prefix);
124                                 return -1;
125                         }
126                         PointerRNA data_type_ptr = { .type = data_type, };
127                         const char *data_prop_str = _PyUnicode_AsString(data_prop_py);
128                         PropertyRNA *data_prop = RNA_struct_find_property(&data_type_ptr, data_prop_str);
129
130                         if (data_prop == NULL) {
131                                 PyErr_Format(
132                                         PyExc_TypeError,
133                                         "%s: struct %.200s does not contain property %.200s",
134                                         error_prefix,
135                                         RNA_struct_identifier(data_type),
136                                         data_prop_str);
137                                 return -1;
138                         }
139
140                         msg_key_params->ptr.type = data_type;
141                         msg_key_params->prop = data_prop;
142                 }
143                 else {
144                         PyErr_Format(
145                                 PyExc_ValueError,
146                                 "%s: Expected a pair (type, property_id)",
147                                 error_prefix);
148                         return -1;
149                 }
150         }
151         return 0;
152 }
153
154 /** \} */
155
156 /* -------------------------------------------------------------------- */
157 /** \name Internal Callbacks
158  * \{ */
159
160 #define BPY_MSGBUS_USER_DATA_LEN 2
161
162 /* Follow wmMsgNotifyFn spec */
163 static void bpy_msgbus_notify(
164         bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
165 {
166         PyGILState_STATE gilstate;
167         bpy_context_set(C, &gilstate);
168
169         PyObject *user_data = msg_val->user_data;
170         BLI_assert(PyTuple_GET_SIZE(user_data) == BPY_MSGBUS_USER_DATA_LEN);
171
172         PyObject *callback_args = PyTuple_GET_ITEM(user_data, 0);
173         PyObject *callback_notify = PyTuple_GET_ITEM(user_data, 1);
174
175         const bool is_write_ok = pyrna_write_check();
176         if (!is_write_ok) {
177                 pyrna_write_set(true);
178         }
179
180         PyObject *ret = PyObject_CallObject(callback_notify, callback_args);
181
182         if (ret == NULL) {
183                 PyC_Err_PrintWithFunc(callback_notify);
184         }
185         else {
186                 if (ret != Py_None) {
187                         PyErr_SetString(PyExc_ValueError, "the return value must be None");
188                         PyC_Err_PrintWithFunc(callback_notify);
189                 }
190                 Py_DECREF(ret);
191         }
192
193         bpy_context_clear(C, &gilstate);
194
195         if (!is_write_ok) {
196                 pyrna_write_set(false);
197         }
198 }
199
200 /* Follow wmMsgSubscribeValueFreeDataFn spec */
201 static void bpy_msgbus_subscribe_value_free_data(
202         struct wmMsgSubscribeKey *UNUSED(msg_key), struct wmMsgSubscribeValue *msg_val)
203 {
204         PyGILState_STATE gilstate = PyGILState_Ensure();
205         Py_DECREF(msg_val->owner);
206         Py_DECREF(msg_val->user_data);
207         PyGILState_Release(gilstate);
208 }
209
210 /** \} */
211
212 /* -------------------------------------------------------------------- */
213 /** \name Public Message Bus API
214  * \{ */
215
216 PyDoc_STRVAR(bpy_msgbus_subscribe_rna_doc,
217 ".. function:: subscribe_rna(data, owner, args, notify)\n"
218 "\n"
219 BPY_MSGBUS_RNA_MSGKEY_DOC
220 "   :arg owner: Handle for this subscription (compared by identity).\n"
221 "   :type owner: Any type.\n"
222 "\n"
223 "   Returns a new vector int property definition.\n"
224 );
225 static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
226 {
227         const char *error_prefix = "subscribe_rna";
228         PyObject *py_sub = NULL;
229         PyObject *py_owner = NULL;
230         PyObject *callback_args = NULL;
231         PyObject *callback_notify = NULL;
232
233         enum {
234                 IS_PERSISTENT = (1 << 0),
235         };
236         PyObject *py_options = NULL;
237         EnumPropertyItem py_options_enum[] = {
238                 {IS_PERSISTENT, "PERSISTENT", 0, ""},
239                 {0, NULL, 0, NULL, NULL},
240         };
241         int options = 0;
242
243         static const char *_keywords[] = {
244                 "key",
245                 "owner",
246                 "args",
247                 "notify",
248                 "options",
249                 NULL,
250         };
251         static _PyArg_Parser _parser = {"$OOO!O|O!:subscribe_rna", _keywords, 0};
252         if (!_PyArg_ParseTupleAndKeywordsFast(
253                 args, kw, &_parser,
254                 &py_sub, &py_owner,
255                 &PyTuple_Type, &callback_args,
256                 &callback_notify,
257                 &PySet_Type, &py_options))
258         {
259                 return NULL;
260         }
261
262         if (py_options &&
263             (pyrna_set_to_enum_bitfield(py_options_enum, py_options, &options, error_prefix)) == -1)
264         {
265                 return NULL;
266         }
267
268         /* Note: we may want to have a way to pass this in. */
269         bContext *C = (bContext *)BPy_GetContext();
270         struct wmMsgBus *mbus = CTX_wm_message_bus(C);
271         wmMsgParams_RNA msg_key_params = {{{0}}};
272
273         wmMsgSubscribeValue msg_val_params = {0};
274
275         if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) {
276                 return NULL;
277         }
278
279         if (!PyFunction_Check(callback_notify)) {
280                 PyErr_Format(
281                         PyExc_TypeError,
282                         "notify expects a function, found %.200s",
283                         Py_TYPE(callback_notify)->tp_name);
284                 return NULL;
285         }
286
287         if (options != 0) {
288                 if (options & IS_PERSISTENT) {
289                         msg_val_params.is_persistent = true;
290                 }
291         }
292
293         /* owner can be anything. */
294         {
295                 msg_val_params.owner = py_owner;
296                 Py_INCREF(py_owner);
297         }
298
299         {
300                 PyObject *user_data = PyTuple_New(2);
301                 PyTuple_SET_ITEMS(
302                         user_data,
303                         Py_INCREF_RET(callback_args),
304                         Py_INCREF_RET(callback_notify));
305                 msg_val_params.user_data = user_data;
306         }
307
308         msg_val_params.notify = bpy_msgbus_notify;
309         msg_val_params.free_data = bpy_msgbus_subscribe_value_free_data;
310
311         WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_val_params, __func__);
312
313         WM_msg_dump(mbus, __func__);
314
315         Py_RETURN_NONE;
316 }
317
318 PyDoc_STRVAR(bpy_msgbus_publish_rna_doc,
319 ".. function:: publish_rna(data, owner, args, notify)\n"
320 "\n"
321 BPY_MSGBUS_RNA_MSGKEY_DOC
322 "\n"
323 "   Notify subscribers of changes to this property\n"
324 "   (this typically doesn't need to be called explicitly since changes will automatically publish updates).\n"
325 "   In some cases it may be useful to publish changes explicitly using more general keys.\n"
326 );
327 static PyObject *bpy_msgbus_publish_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
328 {
329         const char *error_prefix = "publish_rna";
330         PyObject *py_sub = NULL;
331
332         static const char *_keywords[] = {
333                 "key",
334                 NULL,
335         };
336         static _PyArg_Parser _parser = {"$O:publish_rna", _keywords, 0};
337         if (!_PyArg_ParseTupleAndKeywordsFast(
338                 args, kw, &_parser,
339                 &py_sub))
340         {
341                 return NULL;
342         }
343
344         /* Note: we may want to have a way to pass this in. */
345         bContext *C = (bContext *)BPy_GetContext();
346         struct wmMsgBus *mbus = CTX_wm_message_bus(C);
347         wmMsgParams_RNA msg_key_params = {{{0}}};
348
349         if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) {
350                 return NULL;
351         }
352
353         WM_msg_publish_rna_params(mbus, &msg_key_params);
354
355         Py_RETURN_NONE;
356 }
357
358 PyDoc_STRVAR(bpy_msgbus_clear_by_owner_doc,
359 ".. function:: clear_by_owner(owner)\n"
360 "\n"
361 "   Clear all subscribers using this owner.\n"
362 );
363 static PyObject *bpy_msgbus_clear_by_owner(PyObject *UNUSED(self), PyObject *py_owner)
364 {
365         bContext *C = (bContext *)BPy_GetContext();
366         struct wmMsgBus *mbus = CTX_wm_message_bus(C);
367         WM_msgbus_clear_by_owner(mbus, py_owner);
368         Py_RETURN_NONE;
369 }
370
371 static struct PyMethodDef BPy_msgbus_methods[] = {
372         {"subscribe_rna", (PyCFunction)bpy_msgbus_subscribe_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_subscribe_rna_doc},
373         {"publish_rna", (PyCFunction)bpy_msgbus_publish_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_publish_rna_doc},
374         {"clear_by_owner", (PyCFunction)bpy_msgbus_clear_by_owner, METH_O, bpy_msgbus_clear_by_owner_doc},
375         {NULL, NULL, 0, NULL},
376 };
377
378 static struct PyModuleDef _bpy_msgbus_def = {
379         PyModuleDef_HEAD_INIT,
380         .m_name = "msgbus",
381         .m_methods = BPy_msgbus_methods,
382 };
383
384
385 PyObject *BPY_msgbus_module(void)
386 {
387         PyObject *submodule;
388
389         submodule = PyModule_Create(&_bpy_msgbus_def);
390
391         return submodule;
392 }
393
394 /** \} */