Blender  V2.93
bpy_app_timers.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 
21 #include "BLI_timer.h"
22 #include "BLI_utildefines.h"
23 #include "PIL_time.h"
24 #include <Python.h>
25 
26 #include "BPY_extern.h"
27 #include "bpy_app_timers.h"
28 
29 #include "../generic/py_capi_utils.h"
30 #include "../generic/python_utildefines.h"
31 
32 static double handle_returned_value(PyObject *function, PyObject *ret)
33 {
34  if (ret == NULL) {
35  PyErr_PrintEx(0);
36  PyErr_Clear();
37  return -1;
38  }
39 
40  if (ret == Py_None) {
41  return -1;
42  }
43 
44  double value = PyFloat_AsDouble(ret);
45  if (value == -1.0f && PyErr_Occurred()) {
46  PyErr_Clear();
47  printf("Error: 'bpy.app.timers' callback ");
48  PyObject_Print(function, stdout, Py_PRINT_RAW);
49  printf(" did not return None or float.\n");
50  return -1;
51  }
52 
53  if (value < 0.0) {
54  value = 0.0;
55  }
56 
57  return value;
58 }
59 
60 static double py_timer_execute(uintptr_t UNUSED(uuid), void *user_data)
61 {
62  PyObject *function = user_data;
63 
64  PyGILState_STATE gilstate;
65  gilstate = PyGILState_Ensure();
66 
67  PyObject *py_ret = PyObject_CallObject(function, NULL);
68  const double ret = handle_returned_value(function, py_ret);
69 
70  PyGILState_Release(gilstate);
71 
72  return ret;
73 }
74 
75 static void py_timer_free(uintptr_t UNUSED(uuid), void *user_data)
76 {
77  PyObject *function = user_data;
78 
79  PyGILState_STATE gilstate;
80  gilstate = PyGILState_Ensure();
81 
82  Py_DECREF(function);
83 
84  PyGILState_Release(gilstate);
85 }
86 
88  bpy_app_timers_register_doc,
89  ".. function:: register(function, first_interval=0, persistent=False)\n"
90  "\n"
91  " Add a new function that will be called after the specified amount of seconds.\n"
92  " The function gets no arguments and is expected to return either None or a float.\n"
93  " If ``None`` is returned, the timer will be unregistered.\n"
94  " A returned number specifies the delay until the function is called again.\n"
95  " ``functools.partial`` can be used to assign some parameters.\n"
96  "\n"
97  " :arg function: The function that should called.\n"
98  " :type function: Callable[[], Union[float, None]]\n"
99  " :arg first_interval: Seconds until the callback should be called the first time.\n"
100  " :type first_interval: float\n"
101  " :arg persistent: Don't remove timer when a new file is loaded.\n"
102  " :type persistent: bool\n");
103 static PyObject *bpy_app_timers_register(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
104 {
105  PyObject *function;
106  double first_interval = 0;
107  int persistent = false;
108 
109  static const char *_keywords[] = {"function", "first_interval", "persistent", NULL};
110  static _PyArg_Parser _parser = {"O|$dp:register", _keywords, 0};
111  if (!_PyArg_ParseTupleAndKeywordsFast(
112  args, kw, &_parser, &function, &first_interval, &persistent)) {
113  return NULL;
114  }
115 
116  if (!PyCallable_Check(function)) {
117  PyErr_SetString(PyExc_TypeError, "function is not callable");
118  return NULL;
119  }
120 
121  Py_INCREF(function);
123  (intptr_t)function, py_timer_execute, function, py_timer_free, first_interval, persistent);
124  Py_RETURN_NONE;
125 }
126 
127 PyDoc_STRVAR(bpy_app_timers_unregister_doc,
128  ".. function:: unregister(function)\n"
129  "\n"
130  " Unregister timer.\n"
131  "\n"
132  " :arg function: Function to unregister.\n"
133  " :type function: function\n");
134 static PyObject *bpy_app_timers_unregister(PyObject *UNUSED(self), PyObject *function)
135 {
136  if (!BLI_timer_unregister((intptr_t)function)) {
137  PyErr_SetString(PyExc_ValueError, "Error: function is not registered");
138  return NULL;
139  }
140  Py_RETURN_NONE;
141 }
142 
143 PyDoc_STRVAR(bpy_app_timers_is_registered_doc,
144  ".. function:: is_registered(function)\n"
145  "\n"
146  " Check if this function is registered as a timer.\n"
147  "\n"
148  " :arg function: Function to check.\n"
149  " :type function: int\n"
150  " :return: True when this function is registered, otherwise False.\n"
151  " :rtype: bool\n");
152 static PyObject *bpy_app_timers_is_registered(PyObject *UNUSED(self), PyObject *function)
153 {
154  const bool ret = BLI_timer_is_registered((intptr_t)function);
155  return PyBool_FromLong(ret);
156 }
157 
158 static struct PyMethodDef M_AppTimers_methods[] = {
159  {"register",
160  (PyCFunction)bpy_app_timers_register,
161  METH_VARARGS | METH_KEYWORDS,
162  bpy_app_timers_register_doc},
163  {"unregister", (PyCFunction)bpy_app_timers_unregister, METH_O, bpy_app_timers_unregister_doc},
164  {"is_registered",
165  (PyCFunction)bpy_app_timers_is_registered,
166  METH_O,
167  bpy_app_timers_is_registered_doc},
168  {NULL, NULL, 0, NULL},
169 };
170 
171 static struct PyModuleDef M_AppTimers_module_def = {
172  PyModuleDef_HEAD_INIT,
173  "bpy.app.timers", /* m_name */
174  NULL, /* m_doc */
175  0, /* m_size */
176  M_AppTimers_methods, /* m_methods */
177  NULL, /* m_reload */
178  NULL, /* m_traverse */
179  NULL, /* m_clear */
180  NULL, /* m_free */
181 };
182 
183 PyObject *BPY_app_timers_module(void)
184 {
185  PyObject *sys_modules = PyImport_GetModuleDict();
186  PyObject *mod = PyModule_Create(&M_AppTimers_module_def);
187  PyDict_SetItem(sys_modules, PyModule_GetNameObject(mod), mod);
188  return mod;
189 }
bool BLI_timer_is_registered(uintptr_t uuid)
Definition: BLI_timer.c:88
void BLI_timer_register(uintptr_t uuid, BLI_timer_func func, void *user_data, BLI_timer_data_free user_data_free, double first_interval, bool persistent)
Definition: BLI_timer.c:49
bool BLI_timer_unregister(uintptr_t uuid)
Definition: BLI_timer.c:76
#define UNUSED(x)
Platform independent time functions.
static struct PyMethodDef M_AppTimers_methods[]
static struct PyModuleDef M_AppTimers_module_def
PyDoc_STRVAR(bpy_app_timers_register_doc, ".. function:: register(function, first_interval=0, persistent=False)\n" "\n" " Add a new function that will be called after the specified amount of seconds.\n" " The function gets no arguments and is expected to return either None or a float.\n" " If ``None`` is returned, the timer will be unregistered.\n" " A returned number specifies the delay until the function is called again.\n" " ``functools.partial`` can be used to assign some parameters.\n" "\n" " :arg function: The function that should called.\n" " :type function: Callable[[], Union[float, None]]\n" " :arg first_interval: Seconds until the callback should be called the first time.\n" " :type first_interval: float\n" " :arg persistent: Don't remove timer when a new file is loaded.\n" " :type persistent: bool\n")
static double handle_returned_value(PyObject *function, PyObject *ret)
static PyObject * bpy_app_timers_is_registered(PyObject *UNUSED(self), PyObject *function)
static PyObject * bpy_app_timers_unregister(PyObject *UNUSED(self), PyObject *function)
PyObject * BPY_app_timers_module(void)
static PyObject * bpy_app_timers_register(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
static void py_timer_free(uintptr_t UNUSED(uuid), void *user_data)
static double py_timer_execute(uintptr_t UNUSED(uuid), void *user_data)
void * user_data
return ret
_W64 unsigned int uintptr_t
Definition: stdint.h:122
_W64 int intptr_t
Definition: stdint.h:121
ccl_device_inline int mod(int x, int m)
Definition: util_math.h:405