Include SDL information in system info text.
[blender.git] / source / blender / python / intern / bpy_app.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  * Contributor(s): Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/python/intern/bpy_app.c
24  *  \ingroup pythonintern
25  *
26  * This file defines a 'PyStructSequence' accessed via 'bpy.app', mostly
27  * exposing static applications variables such as version and buildinfo
28  * however some writable variables have been added such as 'debug' and 'tempdir'
29  */
30
31
32 #include <Python.h>
33
34 #include "bpy_app.h"
35
36 #include "bpy_app_ffmpeg.h"
37 #include "bpy_app_ocio.h"
38 #include "bpy_app_oiio.h"
39 #include "bpy_app_sdl.h"
40 #include "bpy_app_build_options.h"
41
42 #include "bpy_app_translations.h"
43
44 #include "bpy_app_handlers.h"
45 #include "bpy_driver.h"
46
47 #include "BLI_utildefines.h"
48
49 #include "BKE_appdir.h"
50 #include "BKE_blender.h"
51 #include "BKE_global.h"
52
53 #include "../generic/py_capi_utils.h"
54 #include "../generic/python_utildefines.h"
55
56 #ifdef BUILD_DATE
57 extern char build_date[];
58 extern char build_time[];
59 extern unsigned long build_commit_timestamp;
60 extern char build_commit_date[];
61 extern char build_commit_time[];
62 extern char build_hash[];
63 extern char build_branch[];
64 extern char build_platform[];
65 extern char build_type[];
66 extern char build_cflags[];
67 extern char build_cxxflags[];
68 extern char build_linkflags[];
69 extern char build_system[];
70 #endif
71
72 static PyTypeObject BlenderAppType;
73
74 static PyStructSequence_Field app_info_fields[] = {
75         {(char *)"version", (char *)"The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"},
76         {(char *)"version_string", (char *)"The Blender version formatted as a string"},
77         {(char *)"version_char", (char *)"The Blender version character (for minor releases)"},
78         {(char *)"version_cycle", (char *)"The release status of this build alpha/beta/rc/release"},
79         {(char *)"binary_path", (char *)"The location of blenders executable, useful for utilities that spawn new instances"},
80         {(char *)"background", (char *)"Boolean, True when blender is running without a user interface (started with -b)"},
81
82         /* buildinfo */
83         {(char *)"build_date", (char *)"The date this blender instance was built"},
84         {(char *)"build_time", (char *)"The time this blender instance was built"},
85         {(char *)"build_commit_timestamp", (char *)"The unix timestamp of commit this blender instance was built"},
86         {(char *)"build_commit_date", (char *)"The date of commit this blender instance was built"},
87         {(char *)"build_commit_time", (char *)"The time of commit this blender instance was built"},
88         {(char *)"build_hash", (char *)"The commit hash this blender instance was built with"},
89         {(char *)"build_branch", (char *)"The branch this blender instance was built from"},
90         {(char *)"build_platform", (char *)"The platform this blender instance was built for"},
91         {(char *)"build_type", (char *)"The type of build (Release, Debug)"},
92         {(char *)"build_cflags", (char *)"C compiler flags"},
93         {(char *)"build_cxxflags", (char *)"C++ compiler flags"},
94         {(char *)"build_linkflags", (char *)"Binary linking flags"},
95         {(char *)"build_system", (char *)"Build system used"},
96
97         /* submodules */
98         {(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
99         {(char *)"ocio", (char *)"OpenColorIO library information backend"},
100         {(char *)"oiio", (char *)"OpenImageIO library information backend"},
101         {(char *)"sdl", (char *)"SDL library information backend"},
102         {(char *)"build_options", (char *)"A set containing most important enabled optional build features"},
103         {(char *)"handlers", (char *)"Application handler callbacks"},
104         {(char *)"translations", (char *)"Application and addons internationalization API"},
105         {NULL},
106 };
107
108 static PyStructSequence_Desc app_info_desc = {
109         (char *)"bpy.app",     /* name */
110         (char *)"This module contains application values that remain unchanged during runtime.",    /* doc */
111         app_info_fields,    /* fields */
112         ARRAY_SIZE(app_info_fields) - 1
113 };
114
115 static PyObject *make_app_info(void)
116 {
117         PyObject *app_info;
118         int pos = 0;
119
120         app_info = PyStructSequence_New(&BlenderAppType);
121         if (app_info == NULL) {
122                 return NULL;
123         }
124 #define SetIntItem(flag) \
125         PyStructSequence_SET_ITEM(app_info, pos++, PyLong_FromLong(flag))
126 #define SetStrItem(str) \
127         PyStructSequence_SET_ITEM(app_info, pos++, PyUnicode_FromString(str))
128 #define SetBytesItem(str) \
129         PyStructSequence_SET_ITEM(app_info, pos++, PyBytes_FromString(str))
130 #define SetObjItem(obj) \
131         PyStructSequence_SET_ITEM(app_info, pos++, obj)
132
133         SetObjItem(Py_BuildValue("(iii)",
134                                  BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION));
135         SetObjItem(PyUnicode_FromFormat("%d.%02d (sub %d)",
136                                         BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION));
137
138         SetStrItem(STRINGIFY(BLENDER_VERSION_CHAR));
139         SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE));
140         SetStrItem(BKE_appdir_program_path());
141         SetObjItem(PyBool_FromLong(G.background));
142
143         /* build info, use bytes since we can't assume _any_ encoding:
144          * see patch [#30154] for issue */
145 #ifdef BUILD_DATE
146         SetBytesItem(build_date);
147         SetBytesItem(build_time);
148         SetIntItem(build_commit_timestamp);
149         SetBytesItem(build_commit_date);
150         SetBytesItem(build_commit_time);
151         SetBytesItem(build_hash);
152         SetBytesItem(build_branch);
153         SetBytesItem(build_platform);
154         SetBytesItem(build_type);
155         SetBytesItem(build_cflags);
156         SetBytesItem(build_cxxflags);
157         SetBytesItem(build_linkflags);
158         SetBytesItem(build_system);
159 #else
160         SetBytesItem("Unknown");
161         SetBytesItem("Unknown");
162         SetIntItem(0);
163         SetBytesItem("Unknown");
164         SetBytesItem("Unknown");
165         SetBytesItem("Unknown");
166         SetBytesItem("Unknown");
167         SetBytesItem("Unknown");
168         SetBytesItem("Unknown");
169         SetBytesItem("Unknown");
170         SetBytesItem("Unknown");
171         SetBytesItem("Unknown");
172         SetBytesItem("Unknown");
173 #endif
174
175         SetObjItem(BPY_app_ffmpeg_struct());
176         SetObjItem(BPY_app_ocio_struct());
177         SetObjItem(BPY_app_oiio_struct());
178         SetObjItem(BPY_app_sdl_struct());
179         SetObjItem(BPY_app_build_options_struct());
180         SetObjItem(BPY_app_handlers_struct());
181         SetObjItem(BPY_app_translations_struct());
182
183 #undef SetIntItem
184 #undef SetStrItem
185 #undef SetBytesItem
186 #undef SetObjItem
187
188         if (PyErr_Occurred()) {
189                 Py_CLEAR(app_info);
190                 return NULL;
191         }
192         return app_info;
193 }
194
195 /* a few getsets because it makes sense for them to be in bpy.app even though
196  * they are not static */
197
198 PyDoc_STRVAR(bpy_app_debug_doc,
199 "Boolean, for debug info (started with --debug / --debug_* matching this attribute name)"
200 );
201 static PyObject *bpy_app_debug_get(PyObject *UNUSED(self), void *closure)
202 {
203         const int flag = GET_INT_FROM_POINTER(closure);
204         return PyBool_FromLong(G.debug & flag);
205 }
206
207 static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *closure)
208 {
209         const int flag = GET_INT_FROM_POINTER(closure);
210         const int param = PyObject_IsTrue(value);
211
212         if (param == -1) {
213                 PyErr_SetString(PyExc_TypeError, "bpy.app.debug can only be True/False");
214                 return -1;
215         }
216         
217         if (param)  G.debug |=  flag;
218         else        G.debug &= ~flag;
219         
220         return 0;
221 }
222
223 PyDoc_STRVAR(bpy_app_debug_value_doc,
224 "Int, number which can be set to non-zero values for testing purposes"
225 );
226 static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(closure))
227 {
228         return PyLong_FromLong(G.debug_value);
229 }
230
231 static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure))
232 {
233         int param = PyLong_AsLong(value);
234
235         if (param == -1 && PyErr_Occurred()) {
236                 PyErr_SetString(PyExc_TypeError, "bpy.app.debug_value can only be set to a whole number");
237                 return -1;
238         }
239         
240         G.debug_value = param;
241
242         return 0;
243 }
244
245 static PyObject *bpy_app_global_flag_get(PyObject *UNUSED(self), void *closure)
246 {
247         const int flag = GET_INT_FROM_POINTER(closure);
248         return PyBool_FromLong(G.f & flag);
249 }
250
251 PyDoc_STRVAR(bpy_app_tempdir_doc,
252 "String, the temp directory used by blender (read-only)"
253 );
254 static PyObject *bpy_app_tempdir_get(PyObject *UNUSED(self), void *UNUSED(closure))
255 {
256         return PyC_UnicodeFromByte(BKE_tempdir_session());
257 }
258
259 PyDoc_STRVAR(bpy_app_driver_dict_doc,
260 "Dictionary for drivers namespace, editable in-place, reset on file load (read-only)"
261 );
262 static PyObject *bpy_app_driver_dict_get(PyObject *UNUSED(self), void *UNUSED(closure))
263 {
264         if (bpy_pydriver_Dict == NULL) {
265                 if (bpy_pydriver_create_dict() != 0) {
266                         PyErr_SetString(PyExc_RuntimeError, "bpy.app.driver_namespace failed to create dictionary");
267                         return NULL;
268                 }
269         }
270
271         return Py_INCREF_RET(bpy_pydriver_Dict);
272 }
273
274 static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void *UNUSED(closure))
275 {
276         return PyC_UnicodeFromByte(G.autoexec_fail);
277 }
278
279
280 static PyGetSetDef bpy_app_getsets[] = {
281         {(char *)"debug",           bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG},
282         {(char *)"debug_ffmpeg",    bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_FFMPEG},
283         {(char *)"debug_freestyle", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_FREESTYLE},
284         {(char *)"debug_python",    bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_PYTHON},
285         {(char *)"debug_events",    bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_EVENTS},
286         {(char *)"debug_handlers",  bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_HANDLERS},
287         {(char *)"debug_wm",        bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_WM},
288         {(char *)"debug_depsgraph", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH},
289         {(char *)"debug_simdata",   bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_SIMDATA},
290
291         {(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)bpy_app_debug_value_doc, NULL},
292         {(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)bpy_app_tempdir_doc, NULL},
293         {(char *)"driver_namespace", bpy_app_driver_dict_get, NULL, (char *)bpy_app_driver_dict_doc, NULL},
294
295         /* security */
296         {(char *)"autoexec_fail", bpy_app_global_flag_get, NULL, NULL, (void *)G_SCRIPT_AUTOEXEC_FAIL},
297         {(char *)"autoexec_fail_quiet", bpy_app_global_flag_get, NULL, NULL, (void *)G_SCRIPT_AUTOEXEC_FAIL_QUIET},
298         {(char *)"autoexec_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
299         {NULL, NULL, NULL, NULL, NULL}
300 };
301
302 static void py_struct_seq_getset_init(void)
303 {
304         /* tricky dynamic members, not to py-spec! */
305         PyGetSetDef *getset;
306
307         for (getset = bpy_app_getsets; getset->name; getset++) {
308                 PyDict_SetItemString(BlenderAppType.tp_dict, getset->name, PyDescr_NewGetSet(&BlenderAppType, getset));
309         }
310 }
311 /* end dynamic bpy.app */
312
313
314 PyObject *BPY_app_struct(void)
315 {
316         PyObject *ret;
317         
318         PyStructSequence_InitType(&BlenderAppType, &app_info_desc);
319
320         ret = make_app_info();
321
322         /* prevent user from creating new instances */
323         BlenderAppType.tp_init = NULL;
324         BlenderAppType.tp_new = NULL;
325         BlenderAppType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
326
327         /* kindof a hack ontop of PyStructSequence */
328         py_struct_seq_getset_init();
329
330         return ret;
331 }