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