Blender  V2.93
bpy_rna_callback.c
Go to the documentation of this file.
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 
24 #include <Python.h>
25 
26 #include "../generic/python_utildefines.h"
27 
28 #include "DNA_space_types.h"
29 
30 #include "RNA_access.h"
31 #include "RNA_enum_types.h"
32 
33 #include "BKE_screen.h"
34 
35 #include "WM_api.h"
36 
37 #include "ED_space_api.h"
38 
39 #include "BPY_extern.h" /* For public API. */
40 
41 #include "bpy_capi_utils.h"
42 #include "bpy_rna.h"
43 #include "bpy_rna_callback.h" /* Own include. */
44 
45 /* Use this to stop other capsules from being mis-used. */
46 static const char *rna_capsual_id = "RNA_HANDLE";
47 static const char *rna_capsual_id_invalid = "RNA_HANDLE_REMOVED";
48 
50  {REGION_DRAW_POST_PIXEL, "POST_PIXEL", 0, "Post Pixel", ""},
51  {REGION_DRAW_POST_VIEW, "POST_VIEW", 0, "Post View", ""},
52  {REGION_DRAW_PRE_VIEW, "PRE_VIEW", 0, "Pre View", ""},
53  {REGION_DRAW_BACKDROP, "BACKDROP", 0, "Backdrop", ""},
54  {0, NULL, 0, NULL, NULL},
55 };
56 
57 static void cb_region_draw(const bContext *C, ARegion *UNUSED(region), void *customdata)
58 {
59  PyObject *cb_func, *cb_args, *result;
60  PyGILState_STATE gilstate;
61 
62  bpy_context_set((bContext *)C, &gilstate);
63 
64  cb_func = PyTuple_GET_ITEM((PyObject *)customdata, 1);
65  cb_args = PyTuple_GET_ITEM((PyObject *)customdata, 2);
66  result = PyObject_CallObject(cb_func, cb_args);
67 
68  if (result) {
69  Py_DECREF(result);
70  }
71  else {
72  PyErr_Print();
73  PyErr_Clear();
74  }
75 
76  bpy_context_clear((bContext *)C, &gilstate);
77 }
78 
79 /* We could make generic utility */
80 static PyObject *PyC_Tuple_CopySized(PyObject *src, int len_dst)
81 {
82  PyObject *dst = PyTuple_New(len_dst);
83  const int len_src = PyTuple_GET_SIZE(src);
84  BLI_assert(len_src <= len_dst);
85  for (int i = 0; i < len_src; i++) {
86  PyObject *item = PyTuple_GET_ITEM(src, i);
87  PyTuple_SET_ITEM(dst, i, item);
88  Py_INCREF(item);
89  }
90  return dst;
91 }
92 
93 static void cb_wm_cursor_draw(bContext *C, int x, int y, void *customdata)
94 {
95  PyObject *cb_func, *cb_args, *result;
96  PyGILState_STATE gilstate;
97 
98  bpy_context_set((bContext *)C, &gilstate);
99 
100  cb_func = PyTuple_GET_ITEM((PyObject *)customdata, 1);
101  cb_args = PyTuple_GET_ITEM((PyObject *)customdata, 2);
102 
103  const int cb_args_len = PyTuple_GET_SIZE(cb_args);
104 
105  PyObject *cb_args_xy = PyTuple_New(2);
106  PyTuple_SET_ITEMS(cb_args_xy, PyLong_FromLong(x), PyLong_FromLong(y));
107 
108  PyObject *cb_args_with_xy = PyC_Tuple_CopySized(cb_args, cb_args_len + 1);
109  PyTuple_SET_ITEM(cb_args_with_xy, cb_args_len, cb_args_xy);
110 
111  result = PyObject_CallObject(cb_func, cb_args_with_xy);
112 
113  Py_DECREF(cb_args_with_xy);
114 
115  if (result) {
116  Py_DECREF(result);
117  }
118  else {
119  PyErr_Print();
120  PyErr_Clear();
121  }
122 
123  bpy_context_clear((bContext *)C, &gilstate);
124 }
125 
126 #if 0
127 PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args)
128 {
129  void *handle;
130 
131  PyObject *cb_func, *cb_args;
132  char *cb_event_str = NULL;
133  int cb_event;
134 
135  if (!PyArg_ParseTuple(args,
136  "OO!|s:bpy_struct.callback_add",
137  &cb_func,
138  &PyTuple_Type,
139  &cb_args,
140  &cb_event_str)) {
141  return NULL;
142  }
143 
144  if (!PyCallable_Check(cb_func)) {
145  PyErr_SetString(PyExc_TypeError, "callback_add(): first argument isn't callable");
146  return NULL;
147  }
148 
149  if (RNA_struct_is_a(self->ptr.type, &RNA_Region)) {
150  if (cb_event_str) {
152  region_draw_mode_items, cb_event_str, &cb_event, "bpy_struct.callback_add()") ==
153  -1) {
154  return NULL;
155  }
156  }
157  else {
158  cb_event = REGION_DRAW_POST_PIXEL;
159  }
160 
162  ((ARegion *)self->ptr.data)->type, cb_region_draw, (void *)args, cb_event);
163  Py_INCREF(args);
164  }
165  else {
166  PyErr_SetString(PyExc_TypeError, "callback_add(): type does not support callbacks");
167  return NULL;
168  }
169 
170  return PyCapsule_New((void *)handle, rna_capsual_id, NULL);
171 }
172 
173 PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args)
174 {
175  PyObject *py_handle;
176  void *handle;
177  void *customdata;
178 
179  if (!PyArg_ParseTuple(args, "O!:callback_remove", &PyCapsule_Type, &py_handle)) {
180  return NULL;
181  }
182 
183  handle = PyCapsule_GetPointer(py_handle, rna_capsual_id);
184 
185  if (handle == NULL) {
186  PyErr_SetString(PyExc_ValueError,
187  "callback_remove(handle): NULL handle given, invalid or already removed");
188  return NULL;
189  }
190 
191  if (RNA_struct_is_a(self->ptr.type, &RNA_Region)) {
192  customdata = ED_region_draw_cb_customdata(handle);
193  Py_DECREF((PyObject *)customdata);
194 
195  ED_region_draw_cb_exit(((ARegion *)self->ptr.data)->type, handle);
196  }
197  else {
198  PyErr_SetString(PyExc_TypeError, "callback_remove(): type does not support callbacks");
199  return NULL;
200  }
201 
202  /* don't allow reuse */
203  PyCapsule_SetName(py_handle, rna_capsual_id_invalid);
204 
205  Py_RETURN_NONE;
206 }
207 #endif
208 
209 /* reverse of rna_Space_refine() */
211 {
212  if (srna == &RNA_SpaceView3D) {
213  return SPACE_VIEW3D;
214  }
215  if (srna == &RNA_SpaceGraphEditor) {
216  return SPACE_GRAPH;
217  }
218  if (srna == &RNA_SpaceOutliner) {
219  return SPACE_OUTLINER;
220  }
221  if (srna == &RNA_SpaceProperties) {
222  return SPACE_PROPERTIES;
223  }
224  if (srna == &RNA_SpaceFileBrowser) {
225  return SPACE_FILE;
226  }
227  if (srna == &RNA_SpaceImageEditor) {
228  return SPACE_IMAGE;
229  }
230  if (srna == &RNA_SpaceInfo) {
231  return SPACE_INFO;
232  }
233  if (srna == &RNA_SpaceSequenceEditor) {
234  return SPACE_SEQ;
235  }
236  if (srna == &RNA_SpaceTextEditor) {
237  return SPACE_TEXT;
238  }
239  if (srna == &RNA_SpaceDopeSheetEditor) {
240  return SPACE_ACTION;
241  }
242  if (srna == &RNA_SpaceNLA) {
243  return SPACE_NLA;
244  }
245  if (srna == &RNA_SpaceNodeEditor) {
246  return SPACE_NODE;
247  }
248  if (srna == &RNA_SpaceConsole) {
249  return SPACE_CONSOLE;
250  }
251  if (srna == &RNA_SpacePreferences) {
252  return SPACE_USERPREF;
253  }
254  if (srna == &RNA_SpaceClipEditor) {
255  return SPACE_CLIP;
256  }
257  if (srna == &RNA_SpaceSpreadsheet) {
258  return SPACE_SPREADSHEET;
259  }
260  return SPACE_EMPTY;
261 }
262 
263 static void cb_rna_capsule_destructor(PyObject *capsule)
264 {
265  PyObject *args = PyCapsule_GetContext(capsule);
266  Py_DECREF(args);
267 }
268 
269 PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
270 {
271  void *handle;
272  PyObject *cls;
273  PyObject *cb_func, *cb_args;
274  StructRNA *srna;
275 
276  if (PyTuple_GET_SIZE(args) < 2) {
277  PyErr_SetString(PyExc_ValueError, "handler_add(handler): expected at least 2 args");
278  return NULL;
279  }
280 
281  cls = PyTuple_GET_ITEM(args, 0);
282  if (!(srna = pyrna_struct_as_srna(cls, false, "handler_add"))) {
283  return NULL;
284  }
285  cb_func = PyTuple_GET_ITEM(args, 1);
286  if (!PyCallable_Check(cb_func)) {
287  PyErr_SetString(PyExc_TypeError, "first argument isn't callable");
288  return NULL;
289  }
290 
291  /* class specific callbacks */
292 
293  if (srna == &RNA_WindowManager) {
294  const char *error_prefix = "WindowManager.draw_cursor_add";
295  struct {
296  const char *space_type_str;
297  const char *region_type_str;
298 
299  int space_type;
300  int region_type;
301  } params = {
302  .space_type_str = NULL,
303  .region_type_str = NULL,
304  .space_type = SPACE_TYPE_ANY,
305  .region_type = RGN_TYPE_ANY,
306  };
307 
308  if (!PyArg_ParseTuple(args,
309  "OOO!|ss:WindowManager.draw_cursor_add",
310  &cls,
311  &cb_func, /* already assigned, no matter */
312  &PyTuple_Type,
313  &cb_args,
314  &params.space_type_str,
315  &params.region_type_str)) {
316  return NULL;
317  }
318 
320  params.space_type_str,
321  &params.space_type,
322  error_prefix) == -1) {
323  return NULL;
324  }
326  params.region_type_str,
327  &params.region_type,
328  error_prefix) == -1) {
329  return NULL;
330  }
331 
332  handle = WM_paint_cursor_activate(
333  params.space_type, params.region_type, NULL, cb_wm_cursor_draw, (void *)args);
334  }
335  else if (RNA_struct_is_a(srna, &RNA_Space)) {
336  const char *error_prefix = "Space.draw_handler_add";
337  struct {
338  const char *region_type_str;
339  const char *event_str;
340 
341  int region_type;
342  int event;
343  } params;
344 
345  if (!PyArg_ParseTuple(args,
346  "OOO!ss:Space.draw_handler_add",
347  &cls,
348  &cb_func, /* already assigned, no matter */
349  &PyTuple_Type,
350  &cb_args,
351  &params.region_type_str,
352  &params.event_str)) {
353  return NULL;
354  }
355 
357  region_draw_mode_items, params.event_str, &params.event, error_prefix) == -1) {
358  return NULL;
359  }
361  params.region_type_str,
362  &params.region_type,
363  error_prefix) == -1) {
364  return NULL;
365  }
366 
367  const eSpace_Type spaceid = rna_Space_refine_reverse(srna);
368  if (spaceid == SPACE_EMPTY) {
369  PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna));
370  return NULL;
371  }
372 
373  SpaceType *st = BKE_spacetype_from_id(spaceid);
374  ARegionType *art = BKE_regiontype_from_id(st, params.region_type);
375  if (art == NULL) {
376  PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", params.region_type_str);
377  return NULL;
378  }
379  handle = ED_region_draw_cb_activate(art, cb_region_draw, (void *)args, params.event);
380  }
381  else {
382  PyErr_SetString(PyExc_TypeError, "callback_add(): type does not support callbacks");
383  return NULL;
384  }
385 
386  /* Keep the 'args' reference as long as the callback exists.
387  * This reference is decremented in #BPY_callback_screen_free and #BPY_callback_wm_free. */
388  Py_INCREF(args);
389 
390  PyObject *ret = PyCapsule_New((void *)handle, rna_capsual_id, NULL);
391 
392  /* Store 'args' in context as well for simple access. */
393  PyCapsule_SetDestructor(ret, cb_rna_capsule_destructor);
394  PyCapsule_SetContext(ret, args);
395  Py_INCREF(args);
396 
397  return ret;
398 }
399 
400 PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *args)
401 {
402  PyObject *cls;
403  PyObject *py_handle;
404  void *handle;
405  StructRNA *srna;
406  bool capsule_clear = false;
407 
408  if (PyTuple_GET_SIZE(args) < 2) {
409  PyErr_SetString(PyExc_ValueError, "callback_remove(handler): expected at least 2 args");
410  return NULL;
411  }
412 
413  cls = PyTuple_GET_ITEM(args, 0);
414  if (!(srna = pyrna_struct_as_srna(cls, false, "callback_remove"))) {
415  return NULL;
416  }
417  py_handle = PyTuple_GET_ITEM(args, 1);
418  handle = PyCapsule_GetPointer(py_handle, rna_capsual_id);
419  if (handle == NULL) {
420  PyErr_SetString(PyExc_ValueError,
421  "callback_remove(handler): NULL handler given, invalid or already removed");
422  return NULL;
423  }
424 
425  if (srna == &RNA_WindowManager) {
426  if (!PyArg_ParseTuple(
427  args, "OO!:WindowManager.draw_cursor_remove", &cls, &PyCapsule_Type, &py_handle)) {
428  return NULL;
429  }
430  WM_paint_cursor_end(handle);
431  capsule_clear = true;
432  }
433  else if (RNA_struct_is_a(srna, &RNA_Space)) {
434  const char *error_prefix = "Space.draw_handler_remove";
435  struct {
436  const char *region_type_str;
437 
438  int region_type;
439  } params;
440 
441  if (!PyArg_ParseTuple(args,
442  "OO!s:Space.draw_handler_remove",
443  &cls,
444  &PyCapsule_Type,
445  &py_handle, /* already assigned, no matter */
446  &params.region_type_str)) {
447  return NULL;
448  }
449 
451  params.region_type_str,
452  &params.region_type,
453  error_prefix) == -1) {
454  return NULL;
455  }
456 
457  const eSpace_Type spaceid = rna_Space_refine_reverse(srna);
458  if (spaceid == SPACE_EMPTY) {
459  PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna));
460  return NULL;
461  }
462 
463  SpaceType *st = BKE_spacetype_from_id(spaceid);
464  ARegionType *art = BKE_regiontype_from_id(st, params.region_type);
465  if (art == NULL) {
466  PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", params.region_type_str);
467  return NULL;
468  }
469  ED_region_draw_cb_exit(art, handle);
470  capsule_clear = true;
471  }
472  else {
473  PyErr_SetString(PyExc_TypeError, "callback_remove(): type does not support callbacks");
474  return NULL;
475  }
476 
477  /* The handle has been removed, so decrement its customdata. */
478  PyObject *handle_args = PyCapsule_GetContext(py_handle);
479  Py_DECREF(handle_args);
480 
481  /* don't allow reuse */
482  if (capsule_clear) {
483  PyCapsule_Destructor destructor_fn = PyCapsule_GetDestructor(py_handle);
484  if (destructor_fn) {
485  destructor_fn(py_handle);
486  PyCapsule_SetDestructor(py_handle, NULL);
487  }
488  PyCapsule_SetName(py_handle, rna_capsual_id_invalid);
489  }
490 
491  Py_RETURN_NONE;
492 }
493 
494 /* -------------------------------------------------------------------- */
498 static void cb_customdata_free(void *customdata)
499 {
500  PyObject *tuple = customdata;
501  bool use_gil = true; /* !PyC_IsInterpreterActive(); */
502 
503  PyGILState_STATE gilstate;
504  if (use_gil) {
505  gilstate = PyGILState_Ensure();
506  }
507 
508  Py_DECREF(tuple);
509 
510  if (use_gil) {
511  PyGILState_Release(gilstate);
512  }
513 }
514 
516 {
518 }
519 
521 {
523 }
524 
struct SpaceType * BKE_spacetype_from_id(int spaceid)
Definition: screen.c:382
struct ARegionType * BKE_regiontype_from_id(const struct SpaceType *st, int regionid)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define UNUSED(x)
#define RGN_TYPE_ANY
eSpace_Type
@ SPACE_TEXT
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_CONSOLE
@ SPACE_OUTLINER
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_USERPREF
@ SPACE_FILE
@ SPACE_PROPERTIES
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_EMPTY
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SPACE_INFO
#define SPACE_TYPE_ANY
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:66
#define REGION_DRAW_BACKDROP
Definition: ED_space_api.h:69
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:238
void ED_region_draw_cb_remove_by_type(struct ARegionType *art, void *draw_fn, void(*free)(void *))
Definition: spacetypes.c:276
#define REGION_DRAW_POST_PIXEL
Definition: ED_space_api.h:67
void ED_region_draw_cb_exit(struct ARegionType *, void *)
Definition: spacetypes.c:253
#define REGION_DRAW_PRE_VIEW
Definition: ED_space_api.h:68
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
StructRNA RNA_Region
StructRNA RNA_SpacePreferences
StructRNA RNA_SpaceView3D
StructRNA RNA_SpaceInfo
StructRNA RNA_SpaceProperties
StructRNA RNA_SpaceImageEditor
StructRNA RNA_Space
StructRNA RNA_SpaceNLA
StructRNA RNA_SpaceTextEditor
StructRNA RNA_WindowManager
StructRNA RNA_SpaceNodeEditor
StructRNA RNA_SpaceSequenceEditor
StructRNA RNA_SpaceOutliner
StructRNA RNA_SpaceClipEditor
StructRNA RNA_SpaceSpreadsheet
StructRNA RNA_SpaceDopeSheetEditor
StructRNA RNA_SpaceFileBrowser
StructRNA RNA_SpaceConsole
StructRNA RNA_SpaceGraphEditor
#define C
Definition: RandGen.cpp:39
void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate)
void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate)
PyObject * self
Definition: bpy_driver.c:185
int pyrna_enum_value_from_id(const EnumPropertyItem *item, const char *identifier, int *r_value, const char *error_prefix)
Definition: bpy_rna.c:804
StructRNA * pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix)
Definition: bpy_rna.c:7849
static eSpace_Type rna_Space_refine_reverse(StructRNA *srna)
static const char * rna_capsual_id_invalid
PyObject * pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *args)
static PyObject * PyC_Tuple_CopySized(PyObject *src, int len_dst)
static void cb_customdata_free(void *customdata)
static void cb_region_draw(const bContext *C, ARegion *UNUSED(region), void *customdata)
static void cb_rna_capsule_destructor(PyObject *capsule)
static void cb_wm_cursor_draw(bContext *C, int x, int y, void *customdata)
void BPY_callback_screen_free(struct ARegionType *art)
PyObject * pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
static const EnumPropertyItem region_draw_mode_items[]
static const char * rna_capsual_id
void BPY_callback_wm_free(struct wmWindowManager *wm)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
const char * RNA_struct_identifier(const StructRNA *type)
Definition: rna_access.c:723
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
Definition: rna_access.c:844
const EnumPropertyItem rna_enum_region_type_items[]
Definition: rna_screen.c:35
const EnumPropertyItem rna_enum_space_type_items[]
Definition: rna_space.c:72
bool WM_paint_cursor_end(wmPaintCursor *handle)
void WM_paint_cursor_remove_by_type(wmWindowManager *wm, void *draw_fn, void(*free)(void *))
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)