|
Blender
V2.59
|
00001 00002 /* 00003 * $Id: bpy_operator.c 39293 2011-08-11 06:06:17Z campbellbarton $ 00004 * 00005 * ***** BEGIN GPL LICENSE BLOCK ***** 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License 00009 * as published by the Free Software Foundation; either version 2 00010 * of the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software Foundation, 00019 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00020 * 00021 * Contributor(s): Campbell Barton 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 /* Note, this module is not to be used directly by the user. 00032 * Internally its exposed as '_bpy.ops', which provides functions for 'bpy.ops', a python package. 00033 * */ 00034 00035 #include <Python.h> 00036 00037 #include "RNA_types.h" 00038 00039 #include "BPY_extern.h" 00040 #include "bpy_operator.h" 00041 #include "bpy_operator_wrap.h" 00042 #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */ 00043 #include "bpy_util.h" 00044 #include "../generic/bpy_internal_import.h" 00045 00046 #include "BLI_utildefines.h" 00047 00048 #include "RNA_access.h" 00049 #include "RNA_enum_types.h" 00050 00051 #include "WM_api.h" 00052 #include "WM_types.h" 00053 00054 #include "MEM_guardedalloc.h" 00055 00056 #include "BLI_ghash.h" 00057 00058 #include "BKE_report.h" 00059 #include "BKE_context.h" 00060 00061 /* so operators called can spawn threads which aquire the GIL */ 00062 #define BPY_RELEASE_GIL 00063 00064 00065 static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) 00066 { 00067 wmOperatorType *ot; 00068 char *opname; 00069 PyObject *context_dict= NULL; /* optional args */ 00070 PyObject *context_dict_back; 00071 char *context_str= NULL; 00072 PyObject *ret; 00073 00074 int context= WM_OP_EXEC_DEFAULT; 00075 00076 // XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it... 00077 bContext *C= (bContext *)BPy_GetContext(); 00078 00079 if(C==NULL) { 00080 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators"); 00081 return NULL; 00082 } 00083 00084 if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str)) 00085 return NULL; 00086 00087 ot= WM_operatortype_find(opname, TRUE); 00088 00089 if (ot == NULL) { 00090 PyErr_Format(PyExc_AttributeError, 00091 "Polling operator \"bpy.ops.%s\" error, " 00092 "could not be found", opname); 00093 return NULL; 00094 } 00095 00096 if(context_str) { 00097 if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) { 00098 char *enum_str= BPy_enum_as_string(operator_context_items); 00099 PyErr_Format(PyExc_TypeError, 00100 "Calling operator \"bpy.ops.%s.poll\" error, " 00101 "expected a string enum in (%.200s)", 00102 opname, enum_str); 00103 MEM_freeN(enum_str); 00104 return NULL; 00105 } 00106 } 00107 00108 if(context_dict==NULL || context_dict==Py_None) { 00109 context_dict= NULL; 00110 } 00111 else if (!PyDict_Check(context_dict)) { 00112 PyErr_Format(PyExc_TypeError, 00113 "Calling operator \"bpy.ops.%s.poll\" error, " 00114 "custom context expected a dict or None, got a %.200s", 00115 opname, Py_TYPE(context_dict)->tp_name); 00116 return NULL; 00117 } 00118 00119 context_dict_back= CTX_py_dict_get(C); 00120 00121 CTX_py_dict_set(C, (void *)context_dict); 00122 Py_XINCREF(context_dict); /* so we done loose it */ 00123 00124 /* main purpose of thsi function */ 00125 ret= WM_operator_poll_context((bContext*)C, ot, context) ? Py_True : Py_False; 00126 00127 /* restore with original context dict, probably NULL but need this for nested operator calls */ 00128 Py_XDECREF(context_dict); 00129 CTX_py_dict_set(C, (void *)context_dict_back); 00130 00131 Py_INCREF(ret); 00132 return ret; 00133 } 00134 00135 static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) 00136 { 00137 wmOperatorType *ot; 00138 int error_val= 0; 00139 PointerRNA ptr; 00140 int operator_ret= OPERATOR_CANCELLED; 00141 00142 char *opname; 00143 char *context_str= NULL; 00144 PyObject *kw= NULL; /* optional args */ 00145 PyObject *context_dict= NULL; /* optional args */ 00146 PyObject *context_dict_back; 00147 00148 /* note that context is an int, python does the conversion in this case */ 00149 int context= WM_OP_EXEC_DEFAULT; 00150 00151 // XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it... 00152 bContext *C= (bContext *)BPy_GetContext(); 00153 00154 if(C==NULL) { 00155 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators"); 00156 return NULL; 00157 } 00158 00159 if (!PyArg_ParseTuple(args, "sO|O!s:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str)) 00160 return NULL; 00161 00162 ot= WM_operatortype_find(opname, TRUE); 00163 00164 if (ot == NULL) { 00165 PyErr_Format(PyExc_AttributeError, 00166 "Calling operator \"bpy.ops.%s\" error, " 00167 "could not be found", opname); 00168 return NULL; 00169 } 00170 00171 if(!pyrna_write_check()) { 00172 PyErr_Format(PyExc_RuntimeError, 00173 "Calling operator \"bpy.ops.%s\" error, " 00174 "can't modify blend data in this state (drawing/rendering)", 00175 opname); 00176 return NULL; 00177 } 00178 00179 if(context_str) { 00180 if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) { 00181 char *enum_str= BPy_enum_as_string(operator_context_items); 00182 PyErr_Format(PyExc_TypeError, 00183 "Calling operator \"bpy.ops.%s\" error, " 00184 "expected a string enum in (%.200s)", 00185 opname, enum_str); 00186 MEM_freeN(enum_str); 00187 return NULL; 00188 } 00189 } 00190 00191 if(context_dict==NULL || context_dict==Py_None) { 00192 context_dict= NULL; 00193 } 00194 else if (!PyDict_Check(context_dict)) { 00195 PyErr_Format(PyExc_TypeError, 00196 "Calling operator \"bpy.ops.%s\" error, " 00197 "custom context expected a dict or None, got a %.200s", 00198 opname, Py_TYPE(context_dict)->tp_name); 00199 return NULL; 00200 } 00201 00202 context_dict_back= CTX_py_dict_get(C); 00203 00204 CTX_py_dict_set(C, (void *)context_dict); 00205 Py_XINCREF(context_dict); /* so we done loose it */ 00206 00207 if(WM_operator_poll_context((bContext*)C, ot, context) == FALSE) { 00208 const char *msg= CTX_wm_operator_poll_msg_get(C); 00209 PyErr_Format(PyExc_RuntimeError, 00210 "Operator bpy.ops.%.200s.poll() %.200s", 00211 opname, msg ? msg : "failed, context is incorrect"); 00212 CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */ 00213 error_val= -1; 00214 } 00215 else { 00216 WM_operator_properties_create_ptr(&ptr, ot); 00217 WM_operator_properties_sanitize(&ptr, 0); 00218 00219 if(kw && PyDict_Size(kw)) 00220 error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); 00221 00222 00223 if (error_val==0) { 00224 ReportList *reports; 00225 00226 reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); 00227 BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD); /* own so these dont move into global reports */ 00228 00229 #ifdef BPY_RELEASE_GIL 00230 /* release GIL, since a thread could be started from an operator 00231 * that updates a driver */ 00232 /* note: I havve not seen any examples of code that does this 00233 * so it may not be officially supported but seems to work ok. */ 00234 { 00235 PyThreadState *ts= PyEval_SaveThread(); 00236 #endif 00237 00238 operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports); 00239 00240 #ifdef BPY_RELEASE_GIL 00241 /* regain GIL */ 00242 PyEval_RestoreThread(ts); 00243 } 00244 #endif 00245 00246 error_val= BPy_reports_to_error(reports, PyExc_RuntimeError, FALSE); 00247 00248 /* operator output is nice to have in the terminal/console too */ 00249 if(reports->list.first) { 00250 char *report_str= BKE_reports_string(reports, 0); /* all reports */ 00251 00252 if(report_str) { 00253 PySys_WriteStdout("%s\n", report_str); 00254 MEM_freeN(report_str); 00255 } 00256 } 00257 00258 BKE_reports_clear(reports); 00259 if ((reports->flag & RPT_FREE) == 0) 00260 { 00261 MEM_freeN(reports); 00262 } 00263 } 00264 00265 WM_operator_properties_free(&ptr); 00266 00267 #if 0 00268 /* if there is some way to know an operator takes args we should use this */ 00269 { 00270 /* no props */ 00271 if (kw != NULL) { 00272 PyErr_Format(PyExc_AttributeError, 00273 "Operator \"%s\" does not take any args", 00274 opname); 00275 return NULL; 00276 } 00277 00278 WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL); 00279 } 00280 #endif 00281 } 00282 00283 /* restore with original context dict, probably NULL but need this for nested operator calls */ 00284 Py_XDECREF(context_dict); 00285 CTX_py_dict_set(C, (void *)context_dict_back); 00286 00287 if (error_val==-1) { 00288 return NULL; 00289 } 00290 00291 /* when calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(), 00292 * further access will crash blender. setting context is not needed in this case, only calling because this 00293 * function corrects bpy.data (internal Main pointer) */ 00294 BPY_modules_update(C); 00295 00296 /* needed for when WM_OT_read_factory_settings us called fro within a script */ 00297 bpy_import_main_set(CTX_data_main(C)); 00298 00299 /* return operator_ret as a bpy enum */ 00300 return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret); 00301 00302 } 00303 00304 static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args) 00305 { 00306 wmOperatorType *ot; 00307 PointerRNA ptr; 00308 00309 char *opname; 00310 PyObject *kw= NULL; /* optional args */ 00311 int all_args= 1; 00312 int error_val= 0; 00313 00314 char *buf= NULL; 00315 PyObject *pybuf; 00316 00317 bContext *C= (bContext *)BPy_GetContext(); 00318 00319 if(C==NULL) { 00320 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant get the string representation of this object."); 00321 return NULL; 00322 } 00323 00324 if (!PyArg_ParseTuple(args, "s|O!i:_bpy.ops.as_string", &opname, &PyDict_Type, &kw, &all_args)) 00325 return NULL; 00326 00327 ot= WM_operatortype_find(opname, TRUE); 00328 00329 if (ot == NULL) { 00330 PyErr_Format(PyExc_AttributeError, 00331 "_bpy.ops.as_string: operator \"%.200s\" " 00332 "could not be found", opname); 00333 return NULL; 00334 } 00335 00336 /* WM_operator_properties_create(&ptr, opname); */ 00337 /* Save another lookup */ 00338 RNA_pointer_create(NULL, ot->srna, NULL, &ptr); 00339 00340 if(kw && PyDict_Size(kw)) 00341 error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); 00342 00343 if (error_val==0) 00344 buf= WM_operator_pystring(C, ot, &ptr, all_args); 00345 00346 WM_operator_properties_free(&ptr); 00347 00348 if (error_val==-1) { 00349 return NULL; 00350 } 00351 00352 if(buf) { 00353 pybuf= PyUnicode_FromString(buf); 00354 MEM_freeN(buf); 00355 } 00356 else { 00357 pybuf= PyUnicode_FromString(""); 00358 } 00359 00360 return pybuf; 00361 } 00362 00363 static PyObject *pyop_dir(PyObject *UNUSED(self)) 00364 { 00365 GHashIterator *iter= WM_operatortype_iter(); 00366 PyObject *list= PyList_New(0), *name; 00367 00368 for( ; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { 00369 wmOperatorType *ot= BLI_ghashIterator_getValue(iter); 00370 00371 name= PyUnicode_FromString(ot->idname); 00372 PyList_Append(list, name); 00373 Py_DECREF(name); 00374 } 00375 BLI_ghashIterator_free(iter); 00376 00377 return list; 00378 } 00379 00380 static PyObject *pyop_getrna(PyObject *UNUSED(self), PyObject *value) 00381 { 00382 wmOperatorType *ot; 00383 PointerRNA ptr; 00384 char *opname= _PyUnicode_AsString(value); 00385 BPy_StructRNA *pyrna= NULL; 00386 00387 if(opname==NULL) { 00388 PyErr_SetString(PyExc_TypeError, "_bpy.ops.get_rna() expects a string argument"); 00389 return NULL; 00390 } 00391 ot= WM_operatortype_find(opname, TRUE); 00392 if(ot==NULL) { 00393 PyErr_Format(PyExc_KeyError, "_bpy.ops.get_rna(\"%s\") not found", opname); 00394 return NULL; 00395 } 00396 00397 /* type */ 00398 //RNA_pointer_create(NULL, &RNA_Struct, ot->srna, &ptr); 00399 00400 /* XXX - should call WM_operator_properties_free */ 00401 WM_operator_properties_create_ptr(&ptr, ot); 00402 WM_operator_properties_sanitize(&ptr, 0); 00403 00404 00405 pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); 00406 #ifdef PYRNA_FREE_SUPPORT 00407 pyrna->freeptr= TRUE; 00408 #endif 00409 return (PyObject *)pyrna; 00410 } 00411 00412 static struct PyMethodDef bpy_ops_methods[]= { 00413 {"poll", (PyCFunction) pyop_poll, METH_VARARGS, NULL}, 00414 {"call", (PyCFunction) pyop_call, METH_VARARGS, NULL}, 00415 {"as_string", (PyCFunction) pyop_as_string, METH_VARARGS, NULL}, 00416 {"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL}, 00417 {"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL}, 00418 {"macro_define", (PyCFunction) PYOP_wrap_macro_define, METH_VARARGS, NULL}, 00419 {NULL, NULL, 0, NULL} 00420 }; 00421 00422 static struct PyModuleDef bpy_ops_module= { 00423 PyModuleDef_HEAD_INIT, 00424 "_bpy.ops", 00425 NULL, 00426 -1,/* multiple "initialization" just copies the module dict. */ 00427 bpy_ops_methods, 00428 NULL, NULL, NULL, NULL 00429 }; 00430 00431 PyObject *BPY_operator_module(void) 00432 { 00433 PyObject *submodule; 00434 00435 submodule= PyModule_Create(&bpy_ops_module); 00436 00437 return submodule; 00438 }