X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d14a1e28567de23c586bc80017073d0c39f8d18f..93b663b8ccc9f82dd32d492c8a6081a8c75e8419:/wxPython/src/helpers.cpp diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index a94b911bc7..18081078e9 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -41,17 +41,18 @@ //---------------------------------------------------------------------- wxPyApp* wxPythonApp = NULL; // Global instance of application object -bool wxPyDoCleanup = FALSE; -bool wxPyDoingCleanup = FALSE; +bool wxPyDoCleanup = False; +bool wxPyDoingCleanup = False; #ifdef WXP_WITH_THREAD struct wxPyThreadState { unsigned long tid; PyThreadState* tstate; + int blocked; wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL) - : tid(_tid), tstate(_tstate) {} + : tid(_tid), tstate(_tstate), blocked(1) {} }; #include @@ -85,7 +86,7 @@ BOOL WINAPI DllMain( // the inatance has already been set. if (! wxGetInstance()) wxSetInstance(hinstDLL); - return TRUE; + return True; } #endif @@ -98,7 +99,7 @@ IMPLEMENT_ABSTRACT_CLASS(wxPyApp, wxApp); wxPyApp::wxPyApp() { m_assertMode = wxPYAPP_ASSERT_EXCEPTION; - m_startupComplete = false; + m_startupComplete = False; } @@ -108,7 +109,7 @@ wxPyApp::~wxPyApp() { // This one isn't acutally called... We fake it with _BootstrapApp bool wxPyApp::OnInit() { - return FALSE; + return False; } @@ -130,7 +131,7 @@ int wxPyApp::MainLoop() { bool wxPyApp::OnInitGui() { - bool rval=TRUE; + bool rval=True; wxApp::OnInitGui(); // in this case always call the base class version wxPyBeginBlockThreads(); if (wxPyCBH_findCallback(m_myInst, "OnInitGui")) @@ -359,15 +360,23 @@ void wxPyApp::_BootstrapApp() // The stock objects were all NULL when they were loaded into // SWIG generated proxies, so re-init those now... - wxPy_ReinitStockObjects(false); + wxPy_ReinitStockObjects(3); // It's now ok to generate exceptions for assertion errors. - wxPythonApp->SetStartupComplete(true); + wxPythonApp->SetStartupComplete(True); // Call the Python wxApp's OnInit function if (wxPyCBH_findCallback(m_myInst, "OnInit")) { - retval = wxPyCBH_callCallbackObj(m_myInst, Py_BuildValue("()")); - pyint = PyNumber_Int(retval); + + PyObject* method = m_myInst.GetLastFound(); + PyObject* argTuple = PyTuple_New(0); + retval = PyEval_CallObject(method, argTuple); + Py_DECREF(argTuple); + Py_DECREF(method); + if (retval == NULL) + goto error; + + pyint = PyNumber_Int(retval); if (! pyint) { PyErr_SetString(PyExc_TypeError, "OnInit should return a boolean value"); goto error; @@ -376,7 +385,7 @@ void wxPyApp::_BootstrapApp() } else { // Is it okay if there is no OnInit? Probably so... - result = true; + result = True; } @@ -464,15 +473,15 @@ void __wxPyPreStart(PyObject* moduleDict) wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "wxPython"); // Init the stock objects to a non-NULL value so SWIG doesn't create them as None - wxPy_ReinitStockObjects(true); + wxPy_ReinitStockObjects(1); } void __wxPyCleanup() { - wxPyDoingCleanup = TRUE; + wxPyDoingCleanup = True; if (wxPyDoCleanup) { - wxPyDoCleanup = FALSE; + wxPyDoCleanup = False; wxEntryCleanup(); } #ifdef WXP_WITH_THREAD @@ -540,7 +549,7 @@ PyObject* __wxPySetDictionary(PyObject* /* self */, PyObject* args) //--------------------------------------------------------------------------- -// Python's PyInstance_Check does not return true for instances of new-style +// Python's PyInstance_Check does not return True for instances of new-style // classes. This should get close enough for both new and old classes but I // should re-evaluate the need for doing instance checks... bool wxPyInstance_Check(PyObject* obj) { @@ -556,33 +565,86 @@ bool wxPySwigInstance_Check(PyObject* obj) { //--------------------------------------------------------------------------- -// The stock objects are no longer created when the wxc module is imported, but -// only after the app object has been created. This function will be called before -// OnInit is called so we can hack the new pointer values into the obj.this attributes. +// The stock objects are no longer created when the wxc module is imported, +// but only after the app object has been created. The +// wxPy_ReinitStockObjects function will be called 3 times to pass the stock +// objects though various stages of evolution: +// +// pass 1: Set all the pointers to a non-NULL value so the Python proxy +// object will be created (otherwise it will just use None.) +// +// pass 2: After the module has been imported and the python proxys have +// been created, then set the __class__ to be _wxPyUnbornObject so +// it will catch any access to the object and will raise an exception. +// +// pass 3: Finally, from OnInit patch things up so the stock objects can +// be used. -void wxPy_ReinitStockObjects(bool init) + +PyObject* __wxPyFixStockObjects(PyObject* /* self */, PyObject* args) +{ + wxPy_ReinitStockObjects(2); + RETURN_NONE(); +} + + +static void rsoPass2(const char* name) +{ + static PyObject* unbornObjectClass = NULL; + PyObject* obj; + + if (unbornObjectClass == NULL) { + unbornObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyUnbornObject"); + Py_INCREF(unbornObjectClass); + } + + // Find the object instance + obj = PyDict_GetItemString(wxPython_dict, (char*)dropwx(name)); + wxCHECK_RET(obj != NULL, wxT("Unable to find stock object")); + wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance")); + + // Change its class + PyObject_SetAttrString(obj, "__class__", unbornObjectClass); + +} + +static void rsoPass3(const char* name, const char* classname, void* ptr) { PyObject* obj; + PyObject* classobj; PyObject* ptrobj; + // Find the object instance + obj = PyDict_GetItemString(wxPython_dict, (char*)dropwx(name)); + wxCHECK_RET(obj != NULL, wxT("Unable to find stock object")); + wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance")); + + // Find the class object and put it back in the instance + classobj = PyDict_GetItemString(wxPython_dict, (char*)dropwx(classname)); + wxCHECK_RET(classobj != NULL, wxT("Unable to find stock class object")); + PyObject_SetAttrString(obj, "__class__", classobj); + + // Rebuild the .this swigified pointer with the new value of the C++ pointer + ptrobj = wxPyMakeSwigPtr(ptr, wxString(classname, *wxConvCurrent)); + PyObject_SetAttrString(obj, "this", ptrobj); + Py_DECREF(ptrobj); +} + + + +void wxPy_ReinitStockObjects(int pass) +{ #define REINITOBJ(name, classname) \ - if ( init ) { name = (classname*)0xC0C0C0C0; } else { \ - obj = PyDict_GetItemString(wxPython_dict, dropwx(#name)); \ - wxCHECK_RET(obj != NULL, wxT("Unable to find stock object for " #name)) \ - wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance: " #name)); \ - ptrobj = wxPyMakeSwigPtr((void*)name, #classname); \ - PyObject_SetAttrString(obj, "this", ptrobj); \ - Py_DECREF(ptrobj); } + if (pass == 1) { name = (classname*)0xC0C0C0C0; } \ + else if (pass == 2) { rsoPass2(#name); } \ + else if (pass == 3) { rsoPass3(#name, #classname, (void*)name); } + #define REINITOBJ2(name, classname) \ - if ( init ) { } else { \ - obj = PyDict_GetItemString(wxPython_dict, dropwx(#name)); \ - wxCHECK_RET(obj != NULL, wxT("Unable to find stock object for " #name)) \ - wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance: " #name)); \ - ptrobj = wxPyMakeSwigPtr((void*)&name, #classname); \ - PyObject_SetAttrString(obj, "this", ptrobj); \ - Py_DECREF(ptrobj); } + if (pass == 1) { } \ + else if (pass == 2) { rsoPass2(#name); } \ + else if (pass == 3) { rsoPass3(#name, #classname, (void*)&name); } REINITOBJ(wxNORMAL_FONT, wxFont); @@ -754,14 +816,14 @@ void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) { PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) { PyObject* target = NULL; - bool isEvtHandler = FALSE; + bool isEvtHandler = False; if (source) { // If it's derived from wxEvtHandler then there may // already be a pointer to a Python object that we can use // in the OOR data. if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) { - isEvtHandler = TRUE; + isEvtHandler = True; wxEvtHandler* eh = (wxEvtHandler*)source; wxPyOORClientData* data = (wxPyOORClientData*)eh->GetClientObject(); if (data) { @@ -785,7 +847,7 @@ PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) { exists = wxPyCheckSwigType(name); } if (info) { - target = wxPyConstructObject((void*)source, name, FALSE); + target = wxPyConstructObject((void*)source, name, False); if (target && isEvtHandler) ((wxEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target)); } else { @@ -817,7 +879,7 @@ PyObject* wxPyMake_wxSizer(wxSizer* source) { } } if (! target) { - target = wxPyMake_wxObject(source, FALSE); + target = wxPyMake_wxObject(source, False); if (target != Py_None) ((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target)); } @@ -834,21 +896,21 @@ unsigned long wxPyGetCurrentThreadId() { return wxThread::GetCurrentId(); } -static PyThreadState* gs_shutdownTState; +static wxPyThreadState gs_shutdownTState; static -PyThreadState* wxPyGetThreadState() { +wxPyThreadState* wxPyGetThreadState() { if (wxPyTMutex == NULL) // Python is shutting down... - return gs_shutdownTState; + return &gs_shutdownTState; unsigned long ctid = wxPyGetCurrentThreadId(); - PyThreadState* tstate = NULL; + wxPyThreadState* tstate = NULL; wxPyTMutex->Lock(); for(size_t i=0; i < wxPyTStates->GetCount(); i++) { wxPyThreadState& info = wxPyTStates->Item(i); if (info.tid == ctid) { - tstate = info.tstate; + tstate = &info; break; } } @@ -857,10 +919,11 @@ PyThreadState* wxPyGetThreadState() { return tstate; } + static void wxPySaveThreadState(PyThreadState* tstate) { if (wxPyTMutex == NULL) { // Python is shutting down, assume a single thread... - gs_shutdownTState = tstate; + gs_shutdownTState.tstate = tstate; return; } unsigned long ctid = wxPyGetCurrentThreadId(); @@ -889,6 +952,7 @@ void wxPySaveThreadState(PyThreadState* tstate) { #endif + // Calls from Python to wxWindows code are wrapped in calls to these // functions: @@ -896,6 +960,7 @@ PyThreadState* wxPyBeginAllowThreads() { #ifdef WXP_WITH_THREAD PyThreadState* saved = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS; wxPySaveThreadState(saved); + wxPyGetThreadState()->blocked -= 1; return saved; #else return NULL; @@ -904,6 +969,7 @@ PyThreadState* wxPyBeginAllowThreads() { void wxPyEndAllowThreads(PyThreadState* saved) { #ifdef WXP_WITH_THREAD + wxPyGetThreadState()->blocked += 1; PyEval_RestoreThread(saved); // Py_END_ALLOW_THREADS; #endif } @@ -915,17 +981,21 @@ void wxPyEndAllowThreads(PyThreadState* saved) { void wxPyBeginBlockThreads() { #ifdef WXP_WITH_THREAD - PyThreadState* tstate = wxPyGetThreadState(); - PyEval_RestoreThread(tstate); + wxPyThreadState* tstate = wxPyGetThreadState(); + if (tstate->blocked++ == 0) { // if nested calls then do nothing + PyEval_RestoreThread(tstate->tstate); + } #endif } void wxPyEndBlockThreads() { #ifdef WXP_WITH_THREAD - // Is there any need to save it again? - // PyThreadState* tstate = - PyEval_SaveThread(); + wxPyThreadState* tstate = wxPyGetThreadState(); + tstate->blocked -= 1; + if ( tstate->blocked == 0) { // if nested calls then do nothing + PyEval_SaveThread(); + } #endif } @@ -946,7 +1016,7 @@ bool wxPyInputStream::eof() { if (m_wxis) return m_wxis->Eof(); else - return TRUE; + return True; } wxPyInputStream::~wxPyInputStream() { @@ -1218,9 +1288,8 @@ off_t wxPyCBInputStream::OnSysTell() const { if (PyLong_Check(result)) o = PyLong_AsLongLong(result); else -#else - o = PyInt_AsLong(result); #endif + o = PyInt_AsLong(result); Py_DECREF(result); }; wxPyEndBlockThreads(); @@ -1256,7 +1325,7 @@ void wxPyCallback::EventThunker(wxEvent& event) { PyObject* result; PyObject* arg; PyObject* tuple; - bool checkSkip = FALSE; + bool checkSkip = False; wxPyBeginBlockThreads(); wxString className = event.GetClassInfo()->GetClassName(); @@ -1275,31 +1344,34 @@ void wxPyCallback::EventThunker(wxEvent& event) { arg = wxPyConstructObject((void*)&event, className); } - // Call the event handler, passing the event object - tuple = PyTuple_New(1); - PyTuple_SET_ITEM(tuple, 0, arg); // steals ref to arg - result = PyEval_CallObject(func, tuple); - if ( result ) { - Py_DECREF(result); // result is ignored, but we still need to decref it - PyErr_Clear(); // Just in case... - } else { + if (!arg) { PyErr_Print(); - } - - if ( checkSkip ) { - // if the event object was one of our special types and - // it had been cloned, then we need to extract the Skipped - // value from the original and set it in the clone. - result = PyObject_CallMethod(arg, "GetSkipped", ""); + } else { + // Call the event handler, passing the event object + tuple = PyTuple_New(1); + PyTuple_SET_ITEM(tuple, 0, arg); // steals ref to arg + result = PyEval_CallObject(func, tuple); if ( result ) { - event.Skip(PyInt_AsLong(result)); - Py_DECREF(result); + Py_DECREF(result); // result is ignored, but we still need to decref it + PyErr_Clear(); // Just in case... } else { PyErr_Print(); } - } - Py_DECREF(tuple); + if ( checkSkip ) { + // if the event object was one of our special types and + // it had been cloned, then we need to extract the Skipped + // value from the original and set it in the clone. + result = PyObject_CallMethod(arg, "GetSkipped", ""); + if ( result ) { + event.Skip(PyInt_AsLong(result)); + Py_DECREF(result); + } else { + PyErr_Print(); + } + } + Py_DECREF(tuple); + } wxPyEndBlockThreads(); } @@ -1435,7 +1507,7 @@ bool wxPyCallbackHelper::findCallback(const char* name) const { int wxPyCallbackHelper::callCallback(PyObject* argTuple) const { PyObject* result; - int retval = FALSE; + int retval = False; result = callCallbackObj(argTuple); if (result) { // Assumes an integer return type... @@ -1447,7 +1519,7 @@ int wxPyCallbackHelper::callCallback(PyObject* argTuple) const { } // Invoke the Python callable object, returning the raw PyObject return -// value. Caller should DECREF the return value and also call PyEval_SaveThread. +// value. Caller should DECREF the return value and also manage the GIL. PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const { PyObject* result; @@ -1502,7 +1574,7 @@ void wxPyCBH_delete(wxPyCallbackHelper* cbh) { wxPyEvtSelfRef::wxPyEvtSelfRef() { //m_self = Py_None; // **** We don't do normal ref counting to prevent //Py_INCREF(m_self); // circular loops... - m_cloned = FALSE; + m_cloned = False; } wxPyEvtSelfRef::~wxPyEvtSelfRef() { @@ -1519,7 +1591,7 @@ void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) { m_self = self; if (clone) { Py_INCREF(m_self); - m_cloned = TRUE; + m_cloned = True; } wxPyEndBlockThreads(); } @@ -1542,7 +1614,7 @@ wxPyEvent::wxPyEvent(int winid, wxEventType commandType) wxPyEvent::wxPyEvent(const wxPyEvent& evt) : wxEvent(evt) { - SetSelf(evt.m_self, TRUE); + SetSelf(evt.m_self, True); } @@ -1558,7 +1630,7 @@ wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType, int id) wxPyCommandEvent::wxPyCommandEvent(const wxPyCommandEvent& evt) : wxCommandEvent(evt) { - SetSelf(evt.m_self, TRUE); + SetSelf(evt.m_self, True); } @@ -1671,13 +1743,13 @@ wxString* wxString_in_helper(PyObject* source) { wxString Py2wxString(PyObject* source) { wxString target; - bool doDecRef = FALSE; + bool doDecRef = False; #if PYTHON_API_VERSION >= 1009 // Have Python unicode API if (!PyString_Check(source) && !PyUnicode_Check(source)) { // Convert to String if not one already... (TODO: Unicode too?) source = PyObject_Str(source); - doDecRef = TRUE; + doDecRef = True; } #if wxUSE_UNICODE @@ -1703,7 +1775,7 @@ wxString Py2wxString(PyObject* source) if (!PyString_Check(source)) { // Convert to String if not one already... source = PyObject_Str(source); - doDecRef = TRUE; + doDecRef = True; } target = wxString(PyString_AS_STRING(source), PyString_GET_SIZE(source)); #endif @@ -1827,24 +1899,24 @@ static inline bool wxPointFromObjects(PyObject* o1, PyObject* o2, wxPoint* point if (PyInt_Check(o1) && PyInt_Check(o2)) { point->x = PyInt_AS_LONG(o1); point->y = PyInt_AS_LONG(o2); - return true; + return True; } if (PyFloat_Check(o1) && PyFloat_Check(o2)) { point->x = (int)PyFloat_AS_DOUBLE(o1); point->y = (int)PyFloat_AS_DOUBLE(o2); - return true; + return True; } if (wxPySwigInstance_Check(o1) || wxPySwigInstance_Check(o2)) { // TODO: Why??? // Disallow instances because they can cause havok - return false; + return False; } if (PyNumber_Check(o1) && PyNumber_Check(o2)) { // I believe this excludes instances, so this should be safe without INCREFFing o1 and o2 point->x = PyInt_AsLong(o1); point->y = PyInt_AsLong(o2); - return true; + return True; } - return false; + return False; } @@ -2070,7 +2142,7 @@ bool wxPy2int_seq_helper(PyObject* source, int* i1, int* i2) { PyObject *o1, *o2; if (!PySequence_Check(source) || PySequence_Length(source) != 2) - return FALSE; + return False; if (isFast) { o1 = PySequence_Fast_GET_ITEM(source, 0); @@ -2088,7 +2160,7 @@ bool wxPy2int_seq_helper(PyObject* source, int* i1, int* i2) { Py_DECREF(o1); Py_DECREF(o2); } - return TRUE; + return True; } @@ -2097,7 +2169,7 @@ bool wxPy4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4) { PyObject *o1, *o2, *o3, *o4; if (!PySequence_Check(source) || PySequence_Length(source) != 4) - return FALSE; + return False; if (isFast) { o1 = PySequence_Fast_GET_ITEM(source, 0); @@ -2123,7 +2195,7 @@ bool wxPy4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4) { Py_DECREF(o3); Py_DECREF(o4); } - return TRUE; + return True; } @@ -2135,13 +2207,13 @@ bool wxPySimple_typecheck(PyObject* source, const wxChar* classname, int seqLen) if (wxPySwigInstance_Check(source) && wxPyConvertSwigPtr(source, (void **)&ptr, classname)) - return true; + return True; PyErr_Clear(); if (PySequence_Check(source) && PySequence_Length(source) == seqLen) - return true; + return True; - return false; + return False; } bool wxSize_helper(PyObject* source, wxSize** obj) @@ -2165,7 +2237,7 @@ bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj) { if (! wxPyConvertSwigPtr(source, (void **)&ptr, wxT("wxRealPoint"))) goto error; *obj = ptr; - return TRUE; + return True; } // otherwise a 2-tuple of floats is expected else if (PySequence_Check(source) && PyObject_Length(source) == 2) { @@ -2179,12 +2251,12 @@ bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj) { **obj = wxRealPoint(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2)); Py_DECREF(o1); Py_DECREF(o2); - return TRUE; + return True; } error: PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wxRealPoint object."); - return FALSE; + return False; } @@ -2197,7 +2269,7 @@ bool wxRect_helper(PyObject* source, wxRect** obj) { if (! wxPyConvertSwigPtr(source, (void **)&ptr, wxT("wxRect"))) goto error; *obj = ptr; - return TRUE; + return True; } // otherwise a 4-tuple of integers is expected else if (PySequence_Check(source) && PyObject_Length(source) == 4) { @@ -2219,12 +2291,12 @@ bool wxRect_helper(PyObject* source, wxRect** obj) { Py_DECREF(o2); Py_DECREF(o3); Py_DECREF(o4); - return TRUE; + return True; } error: PyErr_SetString(PyExc_TypeError, "Expected a 4-tuple of integers or a wxRect object."); - return FALSE; + return False; } @@ -2237,7 +2309,7 @@ bool wxColour_helper(PyObject* source, wxColour** obj) { if (! wxPyConvertSwigPtr(source, (void **)&ptr, wxT("wxColour"))) goto error; *obj = ptr; - return TRUE; + return True; } // otherwise check for a string else if (PyString_Check(source) || PyUnicode_Check(source)) { @@ -2250,11 +2322,11 @@ bool wxColour_helper(PyObject* source, wxColour** obj) { spec.Mid(5,2).ToLong(&blue, 16); **obj = wxColour(red, green, blue); - return TRUE; + return True; } else { // it's a colour name **obj = wxColour(spec); - return TRUE; + return True; } } // last chance: 3-tuple of integers is expected @@ -2272,25 +2344,25 @@ bool wxColour_helper(PyObject* source, wxColour** obj) { Py_DECREF(o1); Py_DECREF(o2); Py_DECREF(o3); - return TRUE; + return True; } error: PyErr_SetString(PyExc_TypeError, "Expected a wxColour object or a string containing a colour name or '#RRGGBB'."); - return FALSE; + return False; } bool wxColour_typecheck(PyObject* source) { if (wxPySimple_typecheck(source, wxT("wxColour"), 3)) - return true; + return True; if (PyString_Check(source) || PyUnicode_Check(source)) - return true; + return True; - return false; + return False; } @@ -2302,7 +2374,7 @@ bool wxPoint2D_helper(PyObject* source, wxPoint2D** obj) { if (! wxPyConvertSwigPtr(source, (void **)&ptr, wxT("wxPoint2D"))) goto error; *obj = ptr; - return TRUE; + return True; } // otherwise a length-2 sequence of floats is expected if (PySequence_Check(source) && PySequence_Length(source) == 2) { @@ -2317,11 +2389,11 @@ bool wxPoint2D_helper(PyObject* source, wxPoint2D** obj) { **obj = wxPoint2D(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2)); Py_DECREF(o1); Py_DECREF(o2); - return TRUE; + return True; } error: PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wxPoint2D object."); - return FALSE; + return False; }