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