Blender  V3.3
bpy_interface_atexit.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
11 #include <Python.h>
12 
13 #include "BLI_utildefines.h"
14 
15 #include "bpy.h" /* own include */
16 #include "bpy_capi_utils.h"
17 
18 #include "WM_api.h"
19 
20 static PyObject *bpy_atexit(PyObject *UNUSED(self), PyObject *UNUSED(args), PyObject *UNUSED(kw))
21 {
22  /* close down enough of blender at least not to crash */
23  struct bContext *C = BPY_context_get();
24 
25  WM_exit_ex(C, false);
26 
27  Py_RETURN_NONE;
28 }
29 
30 static PyMethodDef meth_bpy_atexit = {"bpy_atexit", (PyCFunction)bpy_atexit, METH_NOARGS, NULL};
31 static PyObject *func_bpy_atregister = NULL; /* borrowed reference, `atexit` holds. */
32 
33 static void atexit_func_call(const char *func_name, PyObject *atexit_func_arg)
34 {
35  /* NOTE(campbell): no error checking, if any of these fail we'll get a crash
36  * this is intended, but if its problematic it could be changed. */
37 
38  PyObject *atexit_mod = PyImport_ImportModuleLevel("atexit", NULL, NULL, NULL, 0);
39  PyObject *atexit_func = PyObject_GetAttrString(atexit_mod, func_name);
40  PyObject *args = PyTuple_New(1);
41  PyObject *ret;
42 
43  PyTuple_SET_ITEM(args, 0, atexit_func_arg);
44  Py_INCREF(atexit_func_arg); /* only incref so we don't dec'ref along with 'args' */
45 
46  ret = PyObject_CallObject(atexit_func, args);
47 
48  Py_DECREF(atexit_mod);
49  Py_DECREF(atexit_func);
50  Py_DECREF(args);
51 
52  if (ret) {
53  Py_DECREF(ret);
54  }
55  else { /* should never happen */
56  PyErr_Print();
57  }
58 }
59 
61 {
62  /* atexit module owns this new function reference */
64 
65  func_bpy_atregister = (PyObject *)PyCFunction_New(&meth_bpy_atexit, NULL);
67 }
68 
70 {
72 
74  func_bpy_atregister = NULL; /* don't really need to set but just in case */
75 }
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
#define C
Definition: RandGen.cpp:25
struct bContext * BPY_context_get(void)
static PyObject * func_bpy_atregister
void BPY_atexit_register(void)
static void atexit_func_call(const char *func_name, PyObject *atexit_func_arg)
static PyObject * bpy_atexit(PyObject *UNUSED(self), PyObject *UNUSED(args), PyObject *UNUSED(kw))
void BPY_atexit_unregister(void)
static PyMethodDef meth_bpy_atexit
return ret
void WM_exit_ex(bContext *C, const bool do_python)
Definition: wm_init_exit.c:434