diff options
Diffstat (limited to 'source/blender/python/intern/bpy_operator_wrap.c')
-rw-r--r-- | source/blender/python/intern/bpy_operator_wrap.c | 132 |
1 files changed, 80 insertions, 52 deletions
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index b7e3c86dd91..bbf657d8ce0 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -37,15 +37,16 @@ #include "RNA_define.h" #include "bpy_rna.h" -#include "bpy_compat.h" #include "bpy_util.h" #include "../generic/bpy_internal_import.h" // our own imports #define PYOP_ATTR_PROP "__props__" #define PYOP_ATTR_UINAME "__label__" -#define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */ +#define PYOP_ATTR_IDNAME "__idname__" /* the name given by python */ +#define PYOP_ATTR_IDNAME_BL "__idname_bl__" /* our own name converted into blender syntax, users wont see this */ #define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */ +#define PYOP_ATTR_REGISTER "__register__" /* True/False. if this python operator should be registered */ static struct BPY_flag_def pyop_ret_flags[] = { {"RUNNING_MODAL", OPERATOR_RUNNING_MODAL}, @@ -80,9 +81,9 @@ static struct BPY_flag_def pyop_ret_flags[] = { extern void BPY_update_modules( void ); //XXX temp solution -static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *event) +static int PYTHON_OT_generic(int mode, bContext *C, wmOperatorType *ot, wmOperator *op, wmEvent *event) { - PyObject *py_class = op->type->pyop_data; + PyObject *py_class = ot->pyop_data; PyObject *args; PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); @@ -91,11 +92,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PointerRNA ptr_event; PyObject *py_operator; - PyGILState_STATE gilstate = PyGILState_Ensure(); + PyGILState_STATE gilstate; - bpy_import_main_set(CTX_data_main(C)); - - BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this. + bpy_context_set(C, &gilstate); args = PyTuple_New(1); PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(py_class, "__rna__")); // need to use an rna instance as the first arg @@ -106,7 +105,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve /* Assign instance attributes from operator properties */ - { + if(op) { const char *arg_name; RNA_STRUCT_BEGIN(op->ptr, prop) { @@ -122,10 +121,12 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } /* set operator pointer RNA as instance "__operator__" attribute */ - RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator); - py_operator= pyrna_struct_CreatePyObject(&ptr_operator); - PyObject_SetAttrString(py_class_instance, "__operator__", py_operator); - Py_DECREF(py_operator); + if(op) { + RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator); + py_operator= pyrna_struct_CreatePyObject(&ptr_operator); + PyObject_SetAttrString(py_class_instance, "__operator__", py_operator); + Py_DECREF(py_operator); + } RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); @@ -149,8 +150,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve else if (mode==PYOP_POLL) { item= PyObject_GetAttrString(py_class, "poll"); args = PyTuple_New(2); - //XXX Todo - wrap context in a useful way, None for now. - PyTuple_SET_ITEM(args, 1, Py_None); + PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); } PyTuple_SET_ITEM(args, 0, py_class_instance); @@ -161,21 +161,24 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } if (ret == NULL) { /* covers py_class_instance failing too */ - BPy_errors_to_report(op->reports); + if(op) + BPy_errors_to_report(op->reports); } else { if (mode==PYOP_POLL) { if (PyBool_Check(ret) == 0) { PyErr_SetString(PyExc_ValueError, "Python poll function return value "); - BPy_errors_to_report(op->reports); + if(op) + BPy_errors_to_report(op->reports); } else { ret_flag= ret==Py_True ? 1:0; } } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) { - /* the returned value could not be converted into a flag */ - BPy_errors_to_report(op->reports); + /* the returned value could not be converted into a flag */ + if(op) + BPy_errors_to_report(op->reports); ret_flag = OPERATOR_CANCELLED; } @@ -190,6 +193,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve Py_DECREF(ret); } +#if 0 /* only for testing */ + /* print operator return value */ if (mode != PYOP_POLL) { char flag_str[100]; @@ -210,33 +215,31 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve /* get class name */ item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); - Py_DECREF(item); strcpy(class_name, _PyUnicode_AsString(item)); + Py_DECREF(item); fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str); } +#endif - PyGILState_Release(gilstate); - bpy_import_main_set(NULL); + bpy_context_clear(C, &gilstate); return ret_flag; } static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event) { - return PYTHON_OT_generic(PYOP_INVOKE, C, op, event); + return PYTHON_OT_generic(PYOP_INVOKE, C, op->type, op, event); } -static int PYTHON_OT_exec(bContext *C, wmOperator *op) +static int PYTHON_OT_execute(bContext *C, wmOperator *op) { - return PYTHON_OT_generic(PYOP_EXEC, C, op, NULL); + return PYTHON_OT_generic(PYOP_EXEC, C, op->type, op, NULL); } -static int PYTHON_OT_poll(bContext *C) +static int PYTHON_OT_poll(bContext *C, wmOperatorType *ot) { - // XXX TODO - no way to get the operator type (and therefor class) from the poll function. - //return PYTHON_OT_generic(PYOP_POLL, C, NULL, NULL); - return 1; + return PYTHON_OT_generic(PYOP_POLL, C, ot, NULL, NULL); } void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) @@ -245,15 +248,14 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) PyObject *props, *item; /* identifiers */ - item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); - Py_DECREF(item); + item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME_BL); ot->idname= _PyUnicode_AsString(item); - + Py_DECREF(item); item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME); if (item) { - Py_DECREF(item); ot->name= _PyUnicode_AsString(item); + Py_DECREF(item); } else { ot->name= ot->idname; @@ -261,32 +263,41 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) } item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION); - Py_DECREF(item); - ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):""; + ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"undocumented python operator"; + Py_XDECREF(item); /* api callbacks, detailed checks dont on adding */ if (PyObject_HasAttrString(py_class, "invoke")) ot->invoke= PYTHON_OT_invoke; if (PyObject_HasAttrString(py_class, "execute")) - ot->exec= PYTHON_OT_exec; + ot->exec= PYTHON_OT_execute; if (PyObject_HasAttrString(py_class, "poll")) - ot->poll= PYTHON_OT_poll; + ot->pyop_poll= PYTHON_OT_poll; ot->pyop_data= userdata; + /* flags */ + item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER); + if (item) { + ot->flag= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0; + Py_DECREF(item); + } + else { + ot->flag= OPTYPE_REGISTER; /* unspesified, leave on for now to help debug */ + PyErr_Clear(); + } + props= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP); if (props) { PyObject *dummy_args = PyTuple_New(0); int i; - - Py_DECREF(props); for(i=0; i<PyList_Size(props); i++) { PyObject *py_func_ptr, *py_kw, *py_srna_cobject, *py_ret; item = PyList_GET_ITEM(props, i); - if (PyArg_ParseTuple(item, "O!O!", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) { + if (PyArg_ParseTuple(item, "O!O!:PYTHON_OT_wrapper", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) { PyObject *(*pyfunc)(PyObject *, PyObject *, PyObject *); pyfunc = PyCObject_AsVoidPtr(py_func_ptr); @@ -296,6 +307,8 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) if (py_ret) { Py_DECREF(py_ret); } else { + fprintf(stderr, "BPy Operator \"%s\" registration error: %s item %d could not run\n", ot->idname, PYOP_ATTR_PROP, i); + PyLineSpit(); PyErr_Print(); PyErr_Clear(); } @@ -310,6 +323,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) // expect a tuple with a CObject and a dict } Py_DECREF(dummy_args); + Py_DECREF(props); } else { PyErr_Clear(); } @@ -324,43 +338,56 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) char *idname= NULL; + char idname_bl[OP_MAX_TYPENAME]; /* converted to blender syntax */ int i; static struct BPY_class_attr_check pyop_class_attr_values[]= { - {PYOP_ATTR_IDNAME, 's', 0, 0}, - {PYOP_ATTR_UINAME, 's', 0, BPY_CLASS_ATTR_OPTIONAL}, - {PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL}, - {PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK}, - {"execute", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, - {"invoke", 'f', 3, BPY_CLASS_ATTR_OPTIONAL}, - {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {PYOP_ATTR_IDNAME, 's', -1, OP_MAX_TYPENAME-3, 0}, /* -3 because a.b -> A_OT_b */ + {PYOP_ATTR_UINAME, 's', -1,-1, BPY_CLASS_ATTR_OPTIONAL}, + {PYOP_ATTR_PROP, 'l', -1,-1, BPY_CLASS_ATTR_OPTIONAL}, + {PYOP_ATTR_DESCRIPTION, 's', -1,-1, BPY_CLASS_ATTR_NONE_OK}, + {"execute", 'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL}, + {"invoke", 'f', 3, -1, BPY_CLASS_ATTR_OPTIONAL}, + {"poll", 'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL}, {NULL, 0, 0, 0} }; // in python would be... //PyObject *optype = PyObject_GetAttrString(PyObject_GetAttrString(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), "types"), "Operator"); base_class = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Operator"); - Py_DECREF(base_class); if(BPY_class_validate("Operator", py_class, base_class, pyop_class_attr_values, NULL) < 0) { return NULL; /* BPY_class_validate sets the error */ } + Py_DECREF(base_class); /* class name is used for operator ID - this can be changed later if we want */ item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); + idname = _PyUnicode_AsString(item); + + + /* annoying conversion! */ + WM_operator_bl_idname(idname_bl, idname); Py_DECREF(item); + + item= PyUnicode_FromString(idname_bl); + PyObject_SetAttrString(py_class, PYOP_ATTR_IDNAME_BL, item); idname = _PyUnicode_AsString(item); + Py_DECREF(item); + /* end annoying conversion! */ + /* remove if it already exists */ - if ((ot=WM_operatortype_find(idname))) { - Py_XDECREF((PyObject*)ot->pyop_data); + if ((ot=WM_operatortype_exists(idname))) { + if(ot->pyop_data) { + Py_XDECREF((PyObject*)ot->pyop_data); + } WM_operatortype_remove(idname); } /* If we have properties set, check its a list of dicts */ item= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP); if (item) { - Py_DECREF(item); for(i=0; i<PyList_Size(item); i++) { PyObject *py_args = PyList_GET_ITEM(item, i); PyObject *py_func_ptr, *py_kw; /* place holders */ @@ -370,6 +397,7 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) return NULL; } } + Py_DECREF(item); } else { PyErr_Clear(); @@ -401,7 +429,7 @@ PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value) return NULL; } - if (!(ot= WM_operatortype_find(idname))) { + if (!(ot= WM_operatortype_exists(idname))) { PyErr_Format( PyExc_AttributeError, "Operator \"%s\" does not exists, cant remove", idname); return NULL; } |