Blender  V2.93
bpy_interface_atexit.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 
25 #include <Python.h>
26 
27 #include "BLI_utildefines.h"
28 
29 #include "bpy.h" /* own include */
30 #include "bpy_capi_utils.h"
31 
32 #include "WM_api.h"
33 
34 static PyObject *bpy_atexit(PyObject *UNUSED(self), PyObject *UNUSED(args), PyObject *UNUSED(kw))
35 {
36  /* close down enough of blender at least not to crash */
37  struct bContext *C = BPY_context_get();
38 
39  WM_exit_ex(C, false);
40 
41  Py_RETURN_NONE;
42 }
43 
44 static PyMethodDef meth_bpy_atexit = {"bpy_atexit", (PyCFunction)bpy_atexit, METH_NOARGS, NULL};
45 static PyObject *func_bpy_atregister = NULL; /* borrowed reference, `atexit` holds. */
46 
47 static void atexit_func_call(const char *func_name, PyObject *atexit_func_arg)
48 {
49  /* note - no error checking, if any of these fail we'll get a crash
50  * this is intended, but if its problematic it could be changed
51  * - campbell */
52 
53  PyObject *atexit_mod = PyImport_ImportModuleLevel("atexit", NULL, NULL, NULL, 0);
54  PyObject *atexit_func = PyObject_GetAttrString(atexit_mod, func_name);
55  PyObject *args = PyTuple_New(1);
56  PyObject *ret;
57 
58  PyTuple_SET_ITEM(args, 0, atexit_func_arg);
59  Py_INCREF(atexit_func_arg); /* only incref so we don't dec'ref along with 'args' */
60 
61  ret = PyObject_CallObject(atexit_func, args);
62 
63  Py_DECREF(atexit_mod);
64  Py_DECREF(atexit_func);
65  Py_DECREF(args);
66 
67  if (ret) {
68  Py_DECREF(ret);
69  }
70  else { /* should never happen */
71  PyErr_Print();
72  }
73 }
74 
76 {
77  /* atexit module owns this new function reference */
79 
80  func_bpy_atregister = (PyObject *)PyCFunction_New(&meth_bpy_atexit, NULL);
82 }
83 
85 {
87 
89  func_bpy_atregister = NULL; /* don't really need to set but just in case */
90 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define UNUSED(x)
#define C
Definition: RandGen.cpp:39
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:473