1//-------------------------------------------------------------------------- 2// Name: wxpy_api.sip 3// Purpose: The implementation of the API functions that are exported 4// from the core extension module. 5// 6// Author: Robin Dunn 7// 8// Created: 19-Nov-2010 9// Copyright: (c) 2010-2018 by Total Control Software 10// Licence: wxWindows license 11//-------------------------------------------------------------------------- 12 13 14%ModuleHeaderCode 15#include <wxPython/wxpy_api.h> 16%End 17 18//-------------------------------------------------------------------------- 19 20 21%ModuleCode 22// wxPython's API helper and utility functions 23 24//-------------------------------------------------------------------------- 25// wxString conversion 26 27// See also the wxString MappedType. This code is similar, but doesn't 28// allocate a new wxString instance on the heap, is able to convert 29// non-string/unicode objects to unicode, and won't raise exceptions 30static wxString i_Py2wxString(PyObject* source) 31{ 32#if wxUSE_UNICODE_WCHAR == 0 33#error wxString conversion can only handle WCHAR wxStrings currently 34#endif 35 PyErr_Clear(); 36 PyObject* uni = source; 37 if (PyBytes_Check(source)) { 38 // if it's a string object convert it to unicode first, assumes utf-8 39 uni = PyUnicode_FromEncodedObject(source, "utf-8", "strict"); 40 if (PyErr_Occurred()) { 41 PyErr_Clear(); 42 return wxEmptyString; 43 } 44 } 45 else if (!PyUnicode_Check(source)) { 46#if PY_MAJOR_VERSION >= 3 47 uni = PyObject_Str(source); 48#else 49 uni = PyObject_Unicode(source); 50#endif 51 if (PyErr_Occurred()) { 52 PyErr_Clear(); 53 return wxEmptyString; 54 } 55 } 56 wxString target; 57 size_t len = PyUnicode_GET_SIZE(uni); 58 if (len) { 59 wxPyUnicode_AsWideChar(uni, wxStringBuffer(target, len), len); 60 } 61 if (!PyUnicode_Check(source)) 62 Py_DECREF(uni); // release the temporary Unicode object we created 63 return target; 64} 65 66 67// TODO: This might be a good way to share the string conversion code here and in string.sip... 68// A function to convert a Python string or unicode object to a wxString 69// NOTE that it is inline so it should go in the header section 70//inline wxString Py2wxString(PyObject* obj, bool setException=false, int& isErr=0) { 71// wxString str; 72// PyObject* uni = obj; 73// if (PyBytes_Check(obj)) { 74// // if it's a string object convert it to unicode first, assuming utf-8 75// uni = PyUnicode_FromEncodedObject(sipPy, "utf-8", "strict"); 76// if (PyErr_Occurred()) { 77// if (setException) { 78// isErr = 1; 79// } 80// else { 81// PyErr_Clear(); 82// } 83// return wxEmptyString; 84// } 85// } 86// // TODO: Coerce non-unicode types to unicode here? (Classic does) 87// size_t len = PyUnicode_GET_SIZE(uni); 88// if (len) { 89// wxPyUnicode_AsWideChar(uni, wxStringBuffer(str, len), len); 90// } 91// if (obj != uni) 92// Py_DECREF(uni) // release the temporary Unicode object we may have created 93// return str; 94//} 95 96//-------------------------------------------------------------------------- 97// Wrapped object checks and converters 98// 99// TODO: Add some versions of these helpers that take a sipTypeDef 100// instead of a name? They're accessible everywhere we need them, and 101// it may be enough of an efficiency boost to make it worth it. 102 103// Create a PyObject of the requested type from a void* and a class name. 104static PyObject* i_wxPyConstructObject(void* ptr, 105 const wxString& className, 106 bool setThisOwn) 107{ 108 wxString name = className; 109 wxString nsDelimiter = "::"; 110 int pos = name.Find(nsDelimiter); 111 if (pos != wxNOT_FOUND) 112 name = name.Mid(pos + nsDelimiter.Len()); 113 114 const sipTypeDef* td = sipFindType(name); 115 if (!td) 116 return NULL; 117 PyObject* transferObj = setThisOwn ? Py_None : NULL; 118 return sipConvertFromType(ptr, td, transferObj); 119} 120 121 122// Check if a PyObject is a wrapped type 123static bool i_wxPyWrappedPtr_Check(PyObject* obj) 124{ 125 return PyObject_TypeCheck(obj, sipWrapper_Type); 126} 127 128 129// Check if a PyObject is a specific wrapped class or subclass 130static bool i_wxPyWrappedPtr_TypeCheck(PyObject* obj, const wxString& className) 131{ 132 const sipTypeDef* td = sipFindType(className); 133 if (!td) 134 return false; 135 return sipCanConvertToType(obj, td, SIP_NO_CONVERTORS); 136} 137 138 139// Convert a wrapped SIP object to its C++ pointer, ensuring that it is of the expected type 140static bool i_wxPyConvertWrappedPtr(PyObject* obj, void **ptr, const wxString& className) 141{ 142 const sipTypeDef* td = sipFindType(className); 143 if (!td) 144 return false; 145 if (! sipCanConvertToType(obj, td, SIP_NO_CONVERTORS)) 146 return false; 147 int sipIsErr = 0; 148 *ptr = sipConvertToType(obj, td, NULL, SIP_NO_CONVERTORS, 0, &sipIsErr); 149 return true; 150} 151 152 153//-------------------------------------------------------------------------- 154// Deal with the GIL 155 156// Calls from wxWindows back to Python code, or even any PyObject 157// manipulations, PyDECREF's and etc. should be wrapped in calls to these functions: 158static wxPyBlock_t i_wxPyBeginBlockThreads() 159{ 160 if (! Py_IsInitialized()) { 161 return (wxPyBlock_t)0; 162 } 163 PyGILState_STATE state = PyGILState_Ensure(); 164 return state; 165} 166 167static void i_wxPyEndBlockThreads(wxPyBlock_t blocked) 168{ 169 if (! Py_IsInitialized()) { 170 return; 171 } 172 PyGILState_Release(blocked); 173} 174 175//-------------------------------------------------------------------------- 176// Commonly used helpers for converting small sequences of numbers 177// TODO: Are these still needed? 178 179// A helper for converting a 2 element sequence to a pair of integers 180static bool i_wxPy2int_seq_helper(PyObject* source, int* i1, int* i2) 181{ 182 bool isFast = PyList_Check(source) || PyTuple_Check(source); 183 PyObject *o1, *o2; 184 185 if (!PySequence_Check(source) || PySequence_Length(source) != 2) 186 return false; 187 188 if (isFast) { 189 o1 = PySequence_Fast_GET_ITEM(source, 0); 190 o2 = PySequence_Fast_GET_ITEM(source, 1); 191 } 192 else { 193 o1 = PySequence_GetItem(source, 0); 194 o2 = PySequence_GetItem(source, 1); 195 } 196 197 *i1 = wxPyInt_AsLong(o1); 198 *i2 = wxPyInt_AsLong(o2); 199 200 if (! isFast) { 201 Py_DECREF(o1); 202 Py_DECREF(o2); 203 } 204 return true; 205} 206 207// A helper for converting a 4 element sequence to a set of integers 208static bool i_wxPy4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4) 209{ 210 bool isFast = PyList_Check(source) || PyTuple_Check(source); 211 PyObject *o1, *o2, *o3, *o4; 212 213 if (!PySequence_Check(source) || PySequence_Length(source) != 4) 214 return false; 215 216 if (isFast) { 217 o1 = PySequence_Fast_GET_ITEM(source, 0); 218 o2 = PySequence_Fast_GET_ITEM(source, 1); 219 o3 = PySequence_Fast_GET_ITEM(source, 2); 220 o4 = PySequence_Fast_GET_ITEM(source, 3); 221 } 222 else { 223 o1 = PySequence_GetItem(source, 0); 224 o2 = PySequence_GetItem(source, 1); 225 o3 = PySequence_GetItem(source, 2); 226 o4 = PySequence_GetItem(source, 3); 227 } 228 229 *i1 = wxPyInt_AsLong(o1); 230 *i2 = wxPyInt_AsLong(o2); 231 *i3 = wxPyInt_AsLong(o3); 232 *i4 = wxPyInt_AsLong(o4); 233 234 if (! isFast) { 235 Py_DECREF(o1); 236 Py_DECREF(o2); 237 Py_DECREF(o3); 238 Py_DECREF(o4); 239 } 240 return true; 241} 242 243 244//-------------------------------------------------------------------------- 245// wxVariant helpers 246 247 248// A wxVariantData class that can hold a PyObject 249class wxVariantDataPyObject : public wxPyUserDataHelper<wxVariantData> 250{ 251public: 252 explicit wxVariantDataPyObject(PyObject* obj = 0) 253 : wxPyUserDataHelper<wxVariantData>(obj) {} 254 255 virtual bool Eq(wxVariantData& data) const; 256 257 virtual wxString GetType() const { return wxT("PyObject"); } 258 wxVariantData* Clone() const { return new wxVariantDataPyObject(BorrowData()); } 259}; 260 261bool wxVariantDataPyObject::Eq(wxVariantData& data) const 262{ 263 wxASSERT_MSG( (data.GetType() == wxT("PyObject")), 264 wxT("wxVariantDataPyObject::Eq: argument mismatch") ); 265 wxVariantDataPyObject& otherData = (wxVariantDataPyObject&) data; 266 267 wxPyThreadBlocker blocker; 268 return PyObject_RichCompareBool(BorrowData(), otherData.BorrowData(), Py_EQ); 269} 270 271 272 273 274// Helper functions for the wxVariant mapped type. For the basic types that 275// wxVariant knows about we will try to store/fetch natively, otherwise we'll 276// just carry the PyObject through. 277// 278// These functions are here in the API so they can be used by both the 279// wxVariant MappedType and by other classes or types that want to add support 280// for additional kinds of natively supported types (see dataview for example.) 281 282// PyObject --> wxVariant 283wxVariant i_wxVariant_in_helper(PyObject* obj) 284{ 285 wxVariant value; 286 287 PyErr_Clear(); 288 289 if (PyBytes_Check(obj) || PyUnicode_Check(obj)) 290 value = Py2wxString(obj); 291 292 else if (PyBool_Check(obj)) 293 value = (obj == Py_True); 294 295 else if (wxPyInt_Check(obj)) 296 value = (long)wxPyInt_AS_LONG(obj); 297 298 else if (PyLong_Check(obj)) 299 value = (long)PyLong_AsLong(obj); 300 301 else if (PyFloat_Check(obj)) 302 value = PyFloat_AS_DOUBLE(obj); 303 304 else if (obj == Py_None) 305 value.MakeNull(); 306 307 else if (sipCanConvertToType(obj, sipType_wxDateTime, 0)) { 308 wxDateTime* ptr; 309 int state = 0; 310 int isErr = 0; 311 ptr = (wxDateTime*)sipConvertToType(obj, sipType_wxDateTime, NULL, 0, &state, &isErr); 312 if (!isErr) { 313 value = *ptr; 314 sipReleaseType(ptr, sipType_wxDateTime, state); 315 } 316 } 317 318 else if (wxPyWrappedPtr_TypeCheck(obj, wxT("wxBitmap"))) { 319 wxBitmap* ptr; 320 wxPyConvertWrappedPtr(obj, (void**)&ptr, wxT("wxBitmap")); 321 value << *ptr; 322 } 323 324 else if (wxPyWrappedPtr_TypeCheck(obj, wxT("wxImage"))) { 325 wxImage* ptr; 326 wxPyConvertWrappedPtr(obj, (void**)&ptr, wxT("wxImage")); 327 value << *ptr; 328 } 329 330 else if (wxPyWrappedPtr_TypeCheck(obj, wxT("wxIcon"))) { 331 wxIcon* ptr; 332 wxPyConvertWrappedPtr(obj, (void**)&ptr, wxT("wxIcon")); 333 value << *ptr; 334 } 335 336 else if (wxPyWrappedPtr_TypeCheck(obj, wxT("wxColour"))) { 337 wxColour* ptr; 338 wxPyConvertWrappedPtr(obj, (void**)&ptr, wxT("wxColour")); 339 value << *ptr; 340 } 341 342 else if (sipCanConvertToType(obj, sipType_wxArrayString, 0)) { 343 wxArrayString* ptr; 344 int state = 0; 345 int isErr = 0; 346 ptr = (wxArrayString*)sipConvertToType(obj, sipType_wxArrayString, NULL, 0, &state, &isErr); 347 if (!isErr) { 348 value = *ptr; 349 sipReleaseType(ptr, sipType_wxArrayString, state); 350 } 351 } 352 353 else { 354 // Just use the PyObject itself 355 PyErr_Clear(); 356 value = new wxVariantDataPyObject(obj); 357 } 358 359 return value; 360} 361 362 363// wxVariant --> PyObject 364PyObject* i_wxVariant_out_helper(const wxVariant& value) 365{ 366 PyObject* obj; 367 368 if (value.IsNull()) { 369 obj = Py_None; 370 Py_INCREF(obj); 371 } 372 373 else if (value.IsType("string")) 374 obj = wx2PyString(value.GetString()); 375 376 else if (value.IsType("bool")) 377 obj = PyBool_FromLong((long)value.GetBool()); 378 379 else if (value.IsType("long")) 380 obj = PyLong_FromLong(value.GetLong()); 381 382 else if (value.IsType("double")) 383 obj = PyFloat_FromDouble(value.GetDouble()); 384 385 else if ( value.IsType("datetime") ) { 386 wxDateTime val = value.GetDateTime(); 387 obj = wxPyConstructObject(new wxDateTime(val), "wxDateTime", true); 388 } 389 390 else if ( value.IsType("wxBitmap") ) { 391 wxBitmap val; 392 val << value; 393 obj = wxPyConstructObject(new wxBitmap(val), "wxBitmap", true); 394 } 395 396 else if ( value.IsType("wxImage") ) { 397 wxImage val; 398 val << value; 399 obj = wxPyConstructObject(new wxImage(val), "wxImage", true); 400 } 401 402 else if ( value.IsType("wxIcon") ) { 403 wxIcon val; 404 val << value; 405 obj = wxPyConstructObject(new wxIcon(val), "wxIcon", true); 406 } 407 408 else if ( value.IsType("wxColour") ) { 409 wxColour val; 410 val << value; 411 obj = wxPyConstructObject(new wxColour(val), "wxColour", true); 412 } 413 414 else if ( value.IsType("arrstring") ) { 415 wxArrayString arr = value.GetArrayString(); 416 obj = sipConvertFromType(&arr, sipType_wxArrayString, NULL); 417 } 418 419 else if ( value.IsType("PyObject") ) { 420 wxVariantDataPyObject* data = (wxVariantDataPyObject*)value.GetData(); 421 obj = data->GetData(); 422 } 423 424 else { 425 wxString msg = "Unexpected type (\"" + value.GetType() + "\") in wxVariant."; 426 wxPyErr_SetString(PyExc_TypeError, msg.mb_str()); 427 obj = NULL; 428 } 429 430 return obj; 431} 432 433 434//-------------------------------------------------------------------------- 435// Check if the app object has been created. Raises an exception if not. 436 437// Exception for when the wx.App hasn't been created yet 438// (Initialized in wxPyCoreModuleInject) 439PyObject* wxPyNoAppError = NULL; 440 441bool i_wxPyCheckForApp(bool raiseException) { 442 if (wxApp::GetInstance() != NULL) 443 return true; 444 else { 445 if (raiseException) 446 PyErr_SetString(wxPyNoAppError, "The wx.App object must be created first!"); 447 return false; 448 } 449} 450 451//-------------------------------------------------------------------------- 452// Make a memory view object from a C buffer and size. 453 454PyObject* i_wxPyMakeBuffer(void* ptr, Py_ssize_t len, bool readOnly=false) { 455 // GIL should already be held 456 if (ptr && len) { 457 Py_buffer view; 458 int flags = PyBUF_FORMAT|PyBUF_ND; 459 if (!readOnly) 460 flags |= PyBUF_WRITABLE; 461 PyBuffer_FillInfo(&view, NULL, ptr, len, readOnly ? 1:0, flags); 462 return PyMemoryView_FromBuffer(&view); 463 } else { 464 Py_INCREF(Py_None); return Py_None; 465 // return PyBytes_FromString(""); TODO: None or an empty string? 466 } 467 468// // TODO: Consider using a sip.array object instead, like this: 469// // Create a sip.array of bytes, and then convert to a memoryview which is 470// // basically the same thing but is a documented built-in Python type 471// int flags = 0; 472// if (readOnly) 473// flags |= SIP_READ_ONLY; 474// PyObject* array = sipConvertToArray(ptr, "B", len, flags); 475// return array; 476} 477 478 479//-------------------------------------------------------------------------- 480// Check if an object is suitable for conversion to various "value" types that 481// can be created from a sequence of numbers, such as wx.Point, wx.Colour, 482// wx.Rect, etc. 483 484bool i_wxPyNumberSequenceCheck(PyObject* obj, int reqLength=-1) { 485 // Used in the various places where a sequence of numbers can be converted 486 // to a wx type, like wxPoint, wxSize, wxColour, etc. Returns true if the 487 // object is a Tuple, List or numpy Array of the proper length. 488 489 // tuples or lists are easy 490 bool isFast = (PyTuple_Check(obj) || PyList_Check(obj)); 491 492 if (!isFast ) { 493 // If it's not one of those, then check for an array. 494 // It's probably not a good idea to do it this way, but this allows us 495 // to check if the object is a numpy array without requiring that 496 // numpy be imported even for those applications that are not using it. 497 if (strcmp(obj->ob_type->tp_name, "numpy.ndarray") != 0) 498 return false; 499 } 500 501 // Bail out here if the length isn't given 502 if (reqLength == -1) 503 return true; 504 505 // Now check that the length matches the expected length 506 if (PySequence_Length(obj) != reqLength) 507 return false; 508 509 // Check that each item is a number 510 for (int i=0; i<reqLength; i+=1) { 511 PyObject* item; 512 if (isFast) 513 item = PySequence_Fast_GET_ITEM(obj, i); 514 else 515 item = PySequence_ITEM(obj, i); 516 bool isNum = PyNumber_Check(item); 517 if (!isFast) 518 Py_DECREF(item); 519 if (!isNum) 520 return false; 521 } 522 return true; 523} 524 525 526//-------------------------------------------------------------------------- 527// Get the pointer to the C++ object out of the sipSimpleWrapper structure. 528// Yes, it's super unsafe and probably stupid, but here it is... 529 530void* i_wxPyGetCppPtr(sipSimpleWrapper* sipPyObj) { 531 return sipPyObj->data; 532} 533 534//-------------------------------------------------------------------------- 535// Call the PyMethod_Self API, which is not available when the Python 536// limited API is activated. 537 538inline PyObject* i_wxPyMethod_Self(PyObject* method) { 539 return PyMethod_Self(method); 540} 541 542 543 544//-------------------------------------------------------------------------- 545// Cleanup and reinitialize the wxModules. This is needed because sometimes an 546// Extension module will first be imported *after* the wx.App has been 547// created, so the wxModules in that extension will not have been registered 548// and initialized because they were not yet in memory. 549 550void i_wxPyReinitializeModules() { 551 if (i_wxPyCheckForApp(false)) { 552 // NOTE: We are intentionally NOT calling wxModule::CleanUpModules 553 // here because that could clear some things that will not be reset 554 // when used again, leading to crashes. For example, in 555 // wxMSWDCImpl::DoGradientFillLinear it is saving a pointer to an API 556 // function in a dyn-loaded DLL. When modules are cleaned up then that 557 // DLL will be unloaded, leaving a dangling function pointer. We'll 558 // likely end up with multiple instances of some things, but that is 559 // better than the alternaive currently. 560 //wxModule::CleanUpModules(); 561 562 wxModule::RegisterModules(); 563 wxModule::InitializeModules(); 564 565 // And since we're not calling CleanUpModules there is no longer any 566 // need to re-init the image handlers. 567 //wxInitAllImageHandlers(); 568 } 569} 570 571//-------------------------------------------------------------------------- 572// Route the various usages of the PyDate_ APIs through our API, so we only 573// have to worry about PyDateTime_IMPORT being needed in one compilation unit. 574 575int i_wxPyDateTime_Check(PyObject *obj) { 576 return PyDateTime_Check(obj); 577} 578 579int i_wxPyDate_Check(PyObject *obj) { 580 return PyDate_Check(obj); 581} 582 583wxDateTime* i_wxPyDateTime_ToWxDateTime(PyObject *obj) { 584 return new wxDateTime(PyDateTime_GET_DAY(obj), 585 (wxDateTime::Month)(PyDateTime_GET_MONTH(obj)-1), 586 PyDateTime_GET_YEAR(obj), 587 PyDateTime_DATE_GET_HOUR(obj), 588 PyDateTime_DATE_GET_MINUTE(obj), 589 PyDateTime_DATE_GET_SECOND(obj), 590 PyDateTime_DATE_GET_MICROSECOND(obj)/1000); // micro to milli 591} 592 593wxDateTime* i_wxPyDate_ToWxDateTime(PyObject *obj) { 594 return new wxDateTime(PyDateTime_GET_DAY(obj), 595 (wxDateTime::Month)(PyDateTime_GET_MONTH(obj)-1), 596 PyDateTime_GET_YEAR(obj)); 597} 598 599 600 601//-------------------------------------------------------------------------- 602// An instance of the API structure 603static wxPyAPI API = { 604 i_Py2wxString, 605 i_wxPyConstructObject, 606 i_wxPyBeginBlockThreads, 607 i_wxPyEndBlockThreads, 608 i_wxPyWrappedPtr_Check, 609 i_wxPyConvertWrappedPtr, 610 i_wxPy2int_seq_helper, 611 i_wxPy4int_seq_helper, 612 i_wxPyWrappedPtr_TypeCheck, 613 i_wxVariant_in_helper, 614 i_wxVariant_out_helper, 615 i_wxPyCheckForApp, 616 i_wxPyMakeBuffer, 617 i_wxPyNumberSequenceCheck, 618 i_wxPyGetCppPtr, 619 i_wxPyMethod_Self, 620 i_wxPyReinitializeModules, 621 i_wxPyDateTime_Check, 622 i_wxPyDate_Check, 623 i_wxPyDateTime_ToWxDateTime, 624 i_wxPyDate_ToWxDateTime 625}; 626%End 627 628 629%ModuleHeaderCode 630 #include <datetime.h> 631%End 632 633%InitialisationCode 634 PyDateTime_IMPORT; 635%End 636 637 638 639%PostInitialisationCode 640 // Code that will run when _core is imported that will stash away a 641 // pointer to the API structure. 642 PyObject* wxmod = PyImport_ImportModule("wx"); 643 PyObject* wxmodDict = PyModule_GetDict(wxmod); 644 PyObject* apiObj = PyCapsule_New(&API, "wx._wxPyAPI", NULL); 645 PyDict_SetItemString(wxmodDict, "_wxPyAPI", apiObj); 646 647 Py_XDECREF(apiObj); 648 Py_DECREF(wxmod); 649 wxPyGetAPIPtr(); 650%End 651 652//-------------------------------------------------------------------------- 653