Files
wxWidgets/wxPython/src/helpers.cpp
Robin Dunn 4acff284f9 A little black magic... When the C++ object (for a window or
whatever) is deleted there is no way to force the Python shadow object
to also be destroyed and clean up all references to it.  This leads to
crashes if the shadow object tries to call a method with the old C++
pointer...  The black magic I've done is to replace the __class__ in the
Python instanc object with a class that raises an exception whenever a
method call is attempted.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15059 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2002-04-09 22:01:45 +00:00

2022 lines
56 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: helpers.cpp
// Purpose: Helper functions/classes for the wxPython extension module
//
// Author: Robin Dunn
//
// Created: 7/1/97
// RCS-ID: $Id$
// Copyright: (c) 1998 by Total Control Software
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#include <stdio.h> // get the correct definition of NULL
#undef DEBUG
#include <Python.h>
#include "helpers.h"
#include "pyistream.h"
#ifdef __WXMSW__
#include <wx/msw/private.h>
#include <wx/msw/winundef.h>
#include <wx/msw/msvcrt.h>
#endif
#ifdef __WXGTK__
#include <gtk/gtk.h>
#include <gdk/gdkprivate.h>
#include <wx/gtk/win_gtk.h>
#endif
//----------------------------------------------------------------------
#if PYTHON_API_VERSION <= 1007 && wxUSE_UNICODE
#error Python must support Unicode to use wxWindows Unicode
#endif
//----------------------------------------------------------------------
#ifdef __WXGTK__
int WXDLLEXPORT wxEntryStart( int& argc, char** argv );
#else
int WXDLLEXPORT wxEntryStart( int argc, char** argv );
#endif
int WXDLLEXPORT wxEntryInitGui();
void WXDLLEXPORT wxEntryCleanup();
wxPyApp* wxPythonApp = NULL; // Global instance of application object
#ifdef WXP_WITH_THREAD
struct wxPyThreadState {
unsigned long tid;
PyThreadState* tstate;
wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL)
: tid(_tid), tstate(_tstate) {}
};
#include <wx/dynarray.h>
WX_DECLARE_OBJARRAY(wxPyThreadState, wxPyThreadStateArray);
#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(wxPyThreadStateArray);
wxPyThreadStateArray* wxPyTStates = NULL;
wxMutex* wxPyTMutex = NULL;
#endif
#ifdef __WXMSW__ // If building for win32...
//----------------------------------------------------------------------
// This gets run when the DLL is loaded. We just need to save a handle.
//----------------------------------------------------------------------
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
)
{
wxSetInstance(hinstDLL);
return 1;
}
#endif
//----------------------------------------------------------------------
// Classes for implementing the wxp main application shell.
//----------------------------------------------------------------------
wxPyApp::wxPyApp() {
// printf("**** ctor\n");
}
wxPyApp::~wxPyApp() {
// printf("**** dtor\n");
}
// This one isn't acutally called... See __wxStart()
bool wxPyApp::OnInit() {
return FALSE;
}
int wxPyApp::MainLoop() {
int retval = 0;
DeletePendingObjects();
bool initialized = wxTopLevelWindows.GetCount() != 0;
#ifdef __WXGTK__
m_initialized = initialized;
#endif
if (initialized) {
retval = wxApp::MainLoop();
OnExit();
}
return retval;
}
//---------------------------------------------------------------------
//----------------------------------------------------------------------
static char* wxPyCopyCString(const wxChar* src)
{
wxWX2MBbuf buff = (wxWX2MBbuf)wxConvCurrent->cWX2MB(src);
size_t len = strlen(buff);
char* dest = new char[len+1];
strcpy(dest, buff);
return dest;
}
#if wxUSE_UNICODE
static char* wxPyCopyCString(const char* src) // we need a char version too
{
size_t len = strlen(src);
char* dest = new char[len+1];
strcpy(dest, src);
return dest;
}
#endif
static wxChar* wxPyCopyWString(const char *src)
{
//wxMB2WXbuf buff = wxConvCurrent->cMB2WX(src);
wxString str(src, *wxConvCurrent);
return copystring(str);
}
#if wxUSE_UNICODE
static wxChar* wxPyCopyWString(const wxChar *src)
{
return copystring(src);
}
#endif
//----------------------------------------------------------------------
// This is where we pick up the first part of the wxEntry functionality...
// The rest is in __wxStart and __wxCleanup. This function is called when
// wxcmodule is imported. (Before there is a wxApp object.)
void __wxPreStart()
{
#ifdef __WXMSW__
// wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
#endif
#ifdef WXP_WITH_THREAD
PyEval_InitThreads();
wxPyTStates = new wxPyThreadStateArray;
wxPyTMutex = new wxMutex;
#endif
// Bail out if there is already windows created. This means that the
// toolkit has already been initialized, as in embedding wxPython in
// a C++ wxWindows app.
if (wxTopLevelWindows.Number() > 0)
return;
int argc = 0;
char** argv = NULL;
PyObject* sysargv = PySys_GetObject("argv");
if (sysargv != NULL) {
argc = PyList_Size(sysargv);
argv = new char*[argc+1];
int x;
for(x=0; x<argc; x++) {
PyObject *item = PyList_GetItem(sysargv, x);
#if wxUSE_UNICODE
if (PyUnicode_Check(item))
argv[x] = wxPyCopyCString(PyUnicode_AS_UNICODE(item));
else
#endif
argv[x] = wxPyCopyCString(PyString_AsString(item));
}
argv[argc] = NULL;
}
wxEntryStart(argc, argv);
delete [] argv;
}
// Start the user application, user App's OnInit method is a parameter here
PyObject* __wxStart(PyObject* /* self */, PyObject* args)
{
PyObject* onInitFunc = NULL;
PyObject* arglist;
PyObject* result;
long bResult;
if (!PyArg_ParseTuple(args, "O", &onInitFunc))
return NULL;
#if 0 // Try it out without this check, see how it does...
if (wxTopLevelWindows.Number() > 0) {
PyErr_SetString(PyExc_TypeError, "Only 1 wxApp per process!");
return NULL;
}
#endif
// This is the next part of the wxEntry functionality...
int argc = 0;
wxChar** argv = NULL;
PyObject* sysargv = PySys_GetObject("argv");
if (sysargv != NULL) {
argc = PyList_Size(sysargv);
argv = new wxChar*[argc+1];
int x;
for(x=0; x<argc; x++) {
PyObject *pyArg = PyList_GetItem(sysargv, x);
#if wxUSE_UNICODE
if (PyUnicode_Check(pyArg))
argv[x] = wxPyCopyWString(PyUnicode_AS_UNICODE(pyArg));
else
#endif
argv[x] = wxPyCopyWString(PyString_AsString(pyArg));
}
argv[argc] = NULL;
}
wxPythonApp->argc = argc;
wxPythonApp->argv = argv;
wxEntryInitGui();
// Call the Python App's OnInit function
arglist = PyTuple_New(0);
result = PyEval_CallObject(onInitFunc, arglist);
if (!result) { // an exception was raised.
return NULL;
}
if (! PyInt_Check(result)) {
PyErr_SetString(PyExc_TypeError, "OnInit should return a boolean value");
return NULL;
}
bResult = PyInt_AS_LONG(result);
if (! bResult) {
PyErr_SetString(PyExc_SystemExit, "OnInit returned FALSE, exiting...");
return NULL;
}
#ifdef __WXGTK__
wxTheApp->m_initialized = (wxTopLevelWindows.GetCount() > 0);
#endif
Py_INCREF(Py_None);
return Py_None;
}
void __wxCleanup() {
wxEntryCleanup();
#ifdef WXP_WITH_THREAD
delete wxPyTMutex;
wxPyTMutex = NULL;
wxPyTStates->Empty();
delete wxPyTStates;
wxPyTStates = NULL;
#endif
}
static PyObject* wxPython_dict = NULL;
static PyObject* wxPyPtrTypeMap = NULL;
PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
{
if (!PyArg_ParseTuple(args, "O", &wxPython_dict))
return NULL;
if (!PyDict_Check(wxPython_dict)) {
PyErr_SetString(PyExc_TypeError, "_wxSetDictionary must have dictionary object!");
return NULL;
}
if (! wxPyPtrTypeMap)
wxPyPtrTypeMap = PyDict_New();
PyDict_SetItemString(wxPython_dict, "__wxPyPtrTypeMap", wxPyPtrTypeMap);
#ifdef __WXMOTIF__
#define wxPlatform "__WXMOTIF__"
#endif
#ifdef __WXX11__
#define wxPlatform "__WXX11__"
#endif
#ifdef __WXGTK__
#define wxPlatform "__WXGTK__"
#endif
#if defined(__WIN32__) || defined(__WXMSW__)
#define wxPlatform "__WXMSW__"
#endif
#ifdef __WXMAC__
#define wxPlatform "__WXMAC__"
#endif
PyDict_SetItemString(wxPython_dict, "wxPlatform", PyString_FromString(wxPlatform));
PyDict_SetItemString(wxPython_dict, "wxUSE_UNICODE", PyInt_FromLong(wxUSE_UNICODE));
Py_INCREF(Py_None);
return Py_None;
}
//---------------------------------------------------------------------------
void wxPyClientData_dtor(wxPyClientData* self) {
wxPyBeginBlockThreads();
Py_DECREF(self->m_obj);
wxPyEndBlockThreads();
}
void wxPyUserData_dtor(wxPyUserData* self) {
wxPyBeginBlockThreads();
Py_DECREF(self->m_obj);
wxPyEndBlockThreads();
}
// This is called when an OOR controled object is being destroyed. Although
// the C++ object is going away there is no way to force the Python object
// (and all references to it) to die too. This causes problems (crashes) in
// wxPython when a python shadow object attempts to call a C++ method using
// the now bogus pointer... So to try and prevent this we'll do a little black
// magic and change the class of the python instance to a class that will
// raise an exception for any attempt to call methods with it. See
// _wxPyDeadObject in _extras.py for the implementation of this class.
void wxPyOORClientData_dtor(wxPyOORClientData* self) {
static PyObject* deadObjectClass = NULL;
wxPyBeginBlockThreads();
if (deadObjectClass == NULL) {
deadObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyDeadObject");
wxASSERT_MSG(deadObjectClass != NULL, wxT("Can't get _wxPyDeadObject class!"));
Py_INCREF(deadObjectClass);
}
// Clear the instance's dictionary, put the name of the old class into the
// instance, and then reset the class to be the dead class.
if (self->m_obj->ob_refcnt > 1) { // but only if there is more than one reference
wxASSERT_MSG(PyInstance_Check(self->m_obj), wxT("m_obj not an instance!?!?!"));
PyInstanceObject* inst = (PyInstanceObject*)self->m_obj;
PyDict_Clear(inst->in_dict);
PyDict_SetItemString(inst->in_dict, "_name", inst->in_class->cl_name);
inst->in_class = (PyClassObject*)deadObjectClass;
Py_INCREF(deadObjectClass);
}
wxPyEndBlockThreads();
}
//---------------------------------------------------------------------------
// Stuff used by OOR to find the right wxPython class type to return and to
// build it.
// The pointer type map is used when the "pointer" type name generated by SWIG
// is not the same as the shadow class name, for example wxPyTreeCtrl
// vs. wxTreeCtrl. It needs to be referenced in Python as well as from C++,
// so we'll just make it a Python dictionary in the wx module's namespace.
// (See __wxSetDictionary)
void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) {
if (! wxPyPtrTypeMap)
wxPyPtrTypeMap = PyDict_New();
PyDict_SetItemString(wxPyPtrTypeMap,
(char*)commonName,
PyString_FromString((char*)ptrName));
}
PyObject* wxPyClassExists(const wxString& className) {
if (!className)
return NULL;
char buff[64]; // should always be big enough...
sprintf(buff, "%sPtr", className.mbc_str());
PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
return classobj; // returns NULL if not found
}
PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) {
PyObject* target = NULL;
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;
wxEvtHandler* eh = (wxEvtHandler*)source;
wxPyOORClientData* data = (wxPyOORClientData*)eh->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
}
}
if (! target) {
// Otherwise make it the old fashioned way by making a
// new shadow object and putting this pointer in it.
wxClassInfo* info = source->GetClassInfo();
wxChar* name = (wxChar*)info->GetClassName();
PyObject* klass = wxPyClassExists(name);
while (info && !klass) {
name = (wxChar*)info->GetBaseClassName1();
info = wxClassInfo::FindClass(name);
klass = wxPyClassExists(name);
}
if (info) {
target = wxPyConstructObject(source, name, klass, FALSE);
if (target && isEvtHandler)
((wxEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target));
} else {
wxString msg(wxT("wxPython class not found for "));
msg += source->GetClassInfo()->GetClassName();
PyErr_SetString(PyExc_NameError, msg.mbc_str());
target = NULL;
}
}
} else { // source was NULL so return None.
Py_INCREF(Py_None); target = Py_None;
}
return target;
}
PyObject* wxPyMake_wxSizer(wxSizer* source) {
PyObject* target = NULL;
if (source && wxIsKindOf(source, wxSizer)) {
// If it's derived from wxSizer then there may
// already be a pointer to a Python object that we can use
// in the OOR data.
wxSizer* sz = (wxSizer*)source;
wxPyOORClientData* data = (wxPyOORClientData*)sz->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
}
}
if (! target) {
target = wxPyMake_wxObject(source, FALSE);
if (target != Py_None)
((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target));
}
return target;
}
//---------------------------------------------------------------------------
PyObject* wxPyConstructObject(void* ptr,
const wxString& className,
PyObject* klass,
int setThisOwn) {
PyObject* obj;
PyObject* arg;
PyObject* item;
wxString name(className);
char swigptr[64]; // should always be big enough...
char buff[64];
if ((item = PyDict_GetItemString(wxPyPtrTypeMap, (char*)(const char*)name.mbc_str())) != NULL) {
name = wxString(PyString_AsString(item), *wxConvCurrent);
}
sprintf(buff, "_%s_p", (const char*)name.mbc_str());
SWIG_MakePtr(swigptr, ptr, buff);
arg = Py_BuildValue("(s)", swigptr);
obj = PyInstance_New(klass, arg, NULL);
Py_DECREF(arg);
if (setThisOwn) {
PyObject* one = PyInt_FromLong(1);
PyObject_SetAttrString(obj, "thisown", one);
Py_DECREF(one);
}
return obj;
}
PyObject* wxPyConstructObject(void* ptr,
const wxString& className,
int setThisOwn) {
PyObject* obj;
if (!ptr) {
Py_INCREF(Py_None);
return Py_None;
}
char buff[64]; // should always be big enough...
sprintf(buff, "%sPtr", (const char*)className.mbc_str());
wxASSERT_MSG(wxPython_dict, wxT("wxPython_dict is not set yet!!"));
PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
if (! classobj) {
char temp[128];
sprintf(temp,
"*** Unknown class name %s, tell Robin about it please ***",
buff);
obj = PyString_FromString(temp);
return obj;
}
return wxPyConstructObject(ptr, className, classobj, setThisOwn);
}
//---------------------------------------------------------------------------
#ifdef WXP_WITH_THREAD
inline
unsigned long wxPyGetCurrentThreadId() {
return wxThread::GetCurrentId();
}
static PyThreadState* gs_shutdownTState;
static
PyThreadState* wxPyGetThreadState() {
if (wxPyTMutex == NULL) // Python is shutting down...
return gs_shutdownTState;
unsigned long ctid = wxPyGetCurrentThreadId();
PyThreadState* 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;
break;
}
}
wxPyTMutex->Unlock();
wxASSERT_MSG(tstate, wxT("PyThreadState should not be NULL!"));
return tstate;
}
static
void wxPySaveThreadState(PyThreadState* tstate) {
if (wxPyTMutex == NULL) { // Python is shutting down, assume a single thread...
gs_shutdownTState = tstate;
return;
}
unsigned long ctid = wxPyGetCurrentThreadId();
wxPyTMutex->Lock();
for(size_t i=0; i < wxPyTStates->GetCount(); i++) {
wxPyThreadState& info = wxPyTStates->Item(i);
if (info.tid == ctid) {
info.tstate = tstate;
wxPyTMutex->Unlock();
return;
}
}
// not found, so add it...
wxPyTStates->Add(new wxPyThreadState(ctid, tstate));
wxPyTMutex->Unlock();
}
#endif
// Calls from Python to wxWindows code are wrapped in calls to these
// functions:
PyThreadState* wxPyBeginAllowThreads() {
#ifdef WXP_WITH_THREAD
PyThreadState* saved = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS;
wxPySaveThreadState(saved);
return saved;
#else
return NULL;
#endif
}
void wxPyEndAllowThreads(PyThreadState* saved) {
#ifdef WXP_WITH_THREAD
PyEval_RestoreThread(saved); // Py_END_ALLOW_THREADS;
#endif
}
// Calls from wxWindows back to Python code, or even any PyObject
// manipulations, PyDECREF's and etc. are wrapped in calls to these functions:
void wxPyBeginBlockThreads() {
#ifdef WXP_WITH_THREAD
PyThreadState* tstate = wxPyGetThreadState();
PyEval_RestoreThread(tstate);
#endif
}
void wxPyEndBlockThreads() {
#ifdef WXP_WITH_THREAD
PyThreadState* tstate = PyEval_SaveThread();
// Is there any need to save it again?
#endif
}
//---------------------------------------------------------------------------
// wxPyInputStream and wxPyCBInputStream methods
void wxPyInputStream::close() {
/* do nothing for now */
}
void wxPyInputStream::flush() {
/* do nothing for now */
}
bool wxPyInputStream::eof() {
if (m_wxis)
return m_wxis->Eof();
else
return TRUE;
}
wxPyInputStream::~wxPyInputStream() {
/* do nothing */
}
PyObject* wxPyInputStream::read(int size) {
PyObject* obj = NULL;
wxMemoryBuffer buf;
const int BUFSIZE = 1024;
// check if we have a real wxInputStream to work with
if (!m_wxis) {
PyErr_SetString(PyExc_IOError, "no valid C-wxInputStream");
return NULL;
}
if (size < 0) {
// read until EOF
while (! m_wxis->Eof()) {
m_wxis->Read(buf.GetAppendBuf(BUFSIZE), BUFSIZE);
buf.UngetAppendBuf(m_wxis->LastRead());
}
} else { // Read only size number of characters
m_wxis->Read(buf.GetWriteBuf(size), size);
buf.UngetWriteBuf(m_wxis->LastRead());
}
// error check
if (m_wxis->LastError() == wxSTREAM_READ_ERROR) {
PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
}
else {
// We use only strings for the streams, not unicode
obj = PyString_FromStringAndSize(buf, buf.GetDataLen());
}
return obj;
}
PyObject* wxPyInputStream::readline(int size) {
PyObject* obj = NULL;
wxMemoryBuffer buf;
int i;
char ch;
// check if we have a real wxInputStream to work with
if (!m_wxis) {
PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream");
return NULL;
}
// read until \n or byte limit reached
for (i=ch=0; (ch != '\n') && (!m_wxis->Eof()) && ((size < 0) || (i < size)); i++) {
ch = m_wxis->GetC();
buf.AppendByte(ch);
}
// errorcheck
if (m_wxis->LastError() == wxSTREAM_READ_ERROR) {
PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
}
else {
// We use only strings for the streams, not unicode
obj = PyString_FromStringAndSize((char*)buf.GetData(), buf.GetDataLen());
}
return obj;
}
PyObject* wxPyInputStream::readlines(int sizehint) {
PyObject* pylist;
// check if we have a real wxInputStream to work with
if (!m_wxis) {
PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream below");
return NULL;
}
// init list
pylist = PyList_New(0);
if (!pylist) {
PyErr_NoMemory();
return NULL;
}
// read sizehint bytes or until EOF
int i;
for (i=0; (!m_wxis->Eof()) && ((sizehint < 0) || (i < sizehint));) {
PyObject* s = this->readline();
if (s == NULL) {
Py_DECREF(pylist);
return NULL;
}
PyList_Append(pylist, s);
i += PyString_Size(s);
}
// error check
if (m_wxis->LastError() == wxSTREAM_READ_ERROR) {
Py_DECREF(pylist);
PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
return NULL;
}
return pylist;
}
void wxPyInputStream::seek(int offset, int whence) {
if (m_wxis)
m_wxis->SeekI(offset, wxSeekMode(whence));
}
int wxPyInputStream::tell(){
if (m_wxis)
return m_wxis->TellI();
else return 0;
}
wxPyCBInputStream::wxPyCBInputStream(PyObject *r, PyObject *s, PyObject *t, bool block)
: wxInputStream(), m_read(r), m_seek(s), m_tell(t), m_block(block)
{}
wxPyCBInputStream::~wxPyCBInputStream() {
if (m_block) wxPyBeginBlockThreads();
Py_XDECREF(m_read);
Py_XDECREF(m_seek);
Py_XDECREF(m_tell);
if (m_block) wxPyEndBlockThreads();
}
wxPyCBInputStream* wxPyCBInputStream::create(PyObject *py, bool block) {
if (block) wxPyBeginBlockThreads();
PyObject* read = getMethod(py, "read");
PyObject* seek = getMethod(py, "seek");
PyObject* tell = getMethod(py, "tell");
if (!read) {
PyErr_SetString(PyExc_TypeError, "Not a file-like object");
Py_XDECREF(read);
Py_XDECREF(seek);
Py_XDECREF(tell);
if (block) wxPyEndBlockThreads();
return NULL;
}
if (block) wxPyEndBlockThreads();
return new wxPyCBInputStream(read, seek, tell, block);
}
PyObject* wxPyCBInputStream::getMethod(PyObject* py, char* name) {
if (!PyObject_HasAttrString(py, name))
return NULL;
PyObject* o = PyObject_GetAttrString(py, name);
if (!PyMethod_Check(o) && !PyCFunction_Check(o)) {
Py_DECREF(o);
return NULL;
}
return o;
}
size_t wxPyCBInputStream::GetSize() const {
wxPyCBInputStream* self = (wxPyCBInputStream*)this; // cast off const
if (m_seek && m_tell) {
off_t temp = self->OnSysTell();
off_t ret = self->OnSysSeek(0, wxFromEnd);
self->OnSysSeek(temp, wxFromStart);
return ret;
}
else
return 0;
}
size_t wxPyCBInputStream::OnSysRead(void *buffer, size_t bufsize) {
if (bufsize == 0)
return 0;
wxPyBeginBlockThreads();
PyObject* arglist = Py_BuildValue("(i)", bufsize);
PyObject* result = PyEval_CallObject(m_read, arglist);
Py_DECREF(arglist);
size_t o = 0;
if ((result != NULL) && PyString_Check(result)) {
o = PyString_Size(result);
if (o == 0)
m_lasterror = wxSTREAM_EOF;
if (o > bufsize)
o = bufsize;
memcpy((char*)buffer, PyString_AsString(result), o); // strings only, not unicode...
Py_DECREF(result);
}
else
m_lasterror = wxSTREAM_READ_ERROR;
wxPyEndBlockThreads();
m_lastcount = o;
return o;
}
size_t wxPyCBInputStream::OnSysWrite(const void *buffer, size_t bufsize) {
m_lasterror = wxSTREAM_WRITE_ERROR;
return 0;
}
off_t wxPyCBInputStream::OnSysSeek(off_t off, wxSeekMode mode) {
wxPyBeginBlockThreads();
PyObject* arglist = Py_BuildValue("(ii)", off, mode);
PyObject* result = PyEval_CallObject(m_seek, arglist);
Py_DECREF(arglist);
Py_XDECREF(result);
wxPyEndBlockThreads();
return OnSysTell();
}
off_t wxPyCBInputStream::OnSysTell() const {
wxPyBeginBlockThreads();
PyObject* arglist = Py_BuildValue("()");
PyObject* result = PyEval_CallObject(m_tell, arglist);
Py_DECREF(arglist);
off_t o = 0;
if (result != NULL) {
o = PyInt_AsLong(result);
Py_DECREF(result);
};
wxPyEndBlockThreads();
return o;
}
//----------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject);
wxPyCallback::wxPyCallback(PyObject* func) {
m_func = func;
Py_INCREF(m_func);
}
wxPyCallback::wxPyCallback(const wxPyCallback& other) {
m_func = other.m_func;
Py_INCREF(m_func);
}
wxPyCallback::~wxPyCallback() {
wxPyBeginBlockThreads();
Py_DECREF(m_func);
wxPyEndBlockThreads();
}
// This function is used for all events destined for Python event handlers.
void wxPyCallback::EventThunker(wxEvent& event) {
wxPyCallback* cb = (wxPyCallback*)event.m_callbackUserData;
PyObject* func = cb->m_func;
PyObject* result;
PyObject* arg;
PyObject* tuple;
wxPyBeginBlockThreads();
wxString className = event.GetClassInfo()->GetClassName();
if (className == "wxPyEvent")
arg = ((wxPyEvent*)&event)->GetSelf();
else if (className == "wxPyCommandEvent")
arg = ((wxPyCommandEvent*)&event)->GetSelf();
else {
arg = wxPyConstructObject((void*)&event, className);
}
tuple = PyTuple_New(1);
PyTuple_SET_ITEM(tuple, 0, arg);
result = PyEval_CallObject(func, tuple);
Py_DECREF(tuple);
if (result) {
Py_DECREF(result);
PyErr_Clear(); // Just in case...
} else {
PyErr_Print();
}
wxPyEndBlockThreads();
}
//----------------------------------------------------------------------
wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) {
m_lastFound = NULL;
m_self = other.m_self;
m_class = other.m_class;
if (m_self) {
Py_INCREF(m_self);
Py_INCREF(m_class);
}
}
void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* klass, int incref) {
m_self = self;
m_class = klass;
m_incRef = incref;
if (incref) {
Py_INCREF(m_self);
Py_INCREF(m_class);
}
}
#if PYTHON_API_VERSION >= 1011
// Prior to Python 2.2 PyMethod_GetClass returned the class object
// in which the method was defined. Starting with 2.2 it returns
// "class that asked for the method" which seems totally bogus to me
// but apprently it fixes some obscure problem waiting to happen in
// Python. Since the API was not documented Guido and the gang felt
// safe in changing it. Needless to say that totally screwed up the
// logic below in wxPyCallbackHelper::findCallback, hence this icky
// code to find the class where the method is actually defined...
static
PyObject* PyFindClassWithAttr(PyObject *klass, PyObject *name)
{
int i, n;
if (PyType_Check(klass)) { // new style classes
// This code is borrowed/adapted from _PyType_Lookup in typeobject.c
// (TODO: This part is not tested yet, so I'm not sure it is correct...)
PyTypeObject* type = (PyTypeObject*)klass;
PyObject *mro, *res, *base, *dict;
/* Look in tp_dict of types in MRO */
mro = type->tp_mro;
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) {
base = PyTuple_GET_ITEM(mro, i);
if (PyClass_Check(base))
dict = ((PyClassObject *)base)->cl_dict;
else {
assert(PyType_Check(base));
dict = ((PyTypeObject *)base)->tp_dict;
}
assert(dict && PyDict_Check(dict));
res = PyDict_GetItem(dict, name);
if (res != NULL)
return base;
}
return NULL;
}
else if (PyClass_Check(klass)) { // old style classes
// This code is borrowed/adapted from class_lookup in classobject.c
PyClassObject* cp = (PyClassObject*)klass;
PyObject *value = PyDict_GetItem(cp->cl_dict, name);
if (value != NULL) {
return (PyObject*)cp;
}
n = PyTuple_Size(cp->cl_bases);
for (i = 0; i < n; i++) {
PyObject* base = PyTuple_GetItem(cp->cl_bases, i);
PyObject *v = PyFindClassWithAttr(base, name);
if (v != NULL)
return v;
}
return NULL;
}
return NULL;
}
#endif
static
PyObject* PyMethod_GetDefiningClass(PyObject* method, const char* name)
{
PyObject* mgc = PyMethod_GET_CLASS(method);
#if PYTHON_API_VERSION <= 1010 // prior to Python 2.2, the easy way
return mgc;
#else // 2.2 and after, the hard way...
PyObject* nameo = PyString_FromString(name);
PyObject* klass = PyFindClassWithAttr(mgc, nameo);
Py_DECREF(nameo);
return klass;
#endif
}
bool wxPyCallbackHelper::findCallback(const char* name) const {
wxPyCallbackHelper* self = (wxPyCallbackHelper*)this; // cast away const
self->m_lastFound = NULL;
// If the object (m_self) has an attibute of the given name...
if (m_self && PyObject_HasAttrString(m_self, (char*)name)) {
PyObject *method, *klass;
method = PyObject_GetAttrString(m_self, (char*)name);
// ...and if that attribute is a method, and if that method's class is
// not from a base class...
if (PyMethod_Check(method) &&
(klass = PyMethod_GetDefiningClass(method, (char*)name)) != NULL &&
((klass == m_class) || PyClass_IsSubclass(klass, m_class))) {
// ...then we'll save a pointer to the method so callCallback can call it.
self->m_lastFound = method;
}
else {
Py_DECREF(method);
}
}
return m_lastFound != NULL;
}
int wxPyCallbackHelper::callCallback(PyObject* argTuple) const {
PyObject* result;
int retval = FALSE;
result = callCallbackObj(argTuple);
if (result) { // Assumes an integer return type...
retval = PyInt_AsLong(result);
Py_DECREF(result);
PyErr_Clear(); // forget about it if it's not...
}
return retval;
}
// Invoke the Python callable object, returning the raw PyObject return
// value. Caller should DECREF the return value and also call PyEval_SaveThread.
PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const {
PyObject* result;
// Save a copy of the pointer in case the callback generates another
// callback. In that case m_lastFound will have a different value when
// it gets back here...
PyObject* method = m_lastFound;
result = PyEval_CallObject(method, argTuple);
Py_DECREF(argTuple);
Py_DECREF(method);
if (!result) {
PyErr_Print();
}
return result;
}
void wxPyCBH_setCallbackInfo(wxPyCallbackHelper& cbh, PyObject* self, PyObject* klass, int incref) {
cbh.setSelf(self, klass, incref);
}
bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name) {
return cbh.findCallback(name);
}
int wxPyCBH_callCallback(const wxPyCallbackHelper& cbh, PyObject* argTuple) {
return cbh.callCallback(argTuple);
}
PyObject* wxPyCBH_callCallbackObj(const wxPyCallbackHelper& cbh, PyObject* argTuple) {
return cbh.callCallbackObj(argTuple);
}
void wxPyCBH_delete(wxPyCallbackHelper* cbh) {
if (cbh->m_incRef) {
wxPyBeginBlockThreads();
Py_XDECREF(cbh->m_self);
Py_XDECREF(cbh->m_class);
wxPyEndBlockThreads();
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// These event classes can be derived from in Python and passed through the event
// system without losing anything. They do this by keeping a reference to
// themselves and some special case handling in wxPyCallback::EventThunker.
wxPyEvtSelfRef::wxPyEvtSelfRef() {
//m_self = Py_None; // **** We don't do normal ref counting to prevent
//Py_INCREF(m_self); // circular loops...
m_cloned = FALSE;
}
wxPyEvtSelfRef::~wxPyEvtSelfRef() {
wxPyBeginBlockThreads();
if (m_cloned)
Py_DECREF(m_self);
wxPyEndBlockThreads();
}
void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) {
wxPyBeginBlockThreads();
if (m_cloned)
Py_DECREF(m_self);
m_self = self;
if (clone) {
Py_INCREF(m_self);
m_cloned = TRUE;
}
wxPyEndBlockThreads();
}
PyObject* wxPyEvtSelfRef::GetSelf() const {
Py_INCREF(m_self);
return m_self;
}
IMPLEMENT_ABSTRACT_CLASS(wxPyEvent, wxEvent);
IMPLEMENT_ABSTRACT_CLASS(wxPyCommandEvent, wxCommandEvent);
wxPyEvent::wxPyEvent(int id)
: wxEvent(id) {
}
wxPyEvent::wxPyEvent(const wxPyEvent& evt)
: wxEvent(evt)
{
SetSelf(evt.m_self, TRUE);
}
wxPyEvent::~wxPyEvent() {
}
wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType, int id)
: wxCommandEvent(commandType, id) {
}
wxPyCommandEvent::wxPyCommandEvent(const wxPyCommandEvent& evt)
: wxCommandEvent(evt)
{
SetSelf(evt.m_self, TRUE);
}
wxPyCommandEvent::~wxPyCommandEvent() {
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
wxPyTimer::wxPyTimer(PyObject* callback) {
func = callback;
Py_INCREF(func);
}
wxPyTimer::~wxPyTimer() {
wxPyBeginBlockThreads();
Py_DECREF(func);
wxPyEndBlockThreads();
}
void wxPyTimer::Notify() {
if (!func || func == Py_None) {
wxTimer::Notify();
}
else {
wxPyBeginBlockThreads();
PyObject* result;
PyObject* args = Py_BuildValue("()");
result = PyEval_CallObject(func, args);
Py_DECREF(args);
if (result) {
Py_DECREF(result);
PyErr_Clear();
} else {
PyErr_Print();
}
wxPyEndBlockThreads();
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Convert a wxList to a Python List
PyObject* wxPy_ConvertList(wxListBase* list, const char* className) {
PyObject* pyList;
PyObject* pyObj;
wxObject* wxObj;
wxNode* node = list->First();
wxPyBeginBlockThreads();
pyList = PyList_New(0);
while (node) {
wxObj = node->Data();
pyObj = wxPyMake_wxObject(wxObj); //wxPyConstructObject(wxObj, className);
PyList_Append(pyList, pyObj);
node = node->Next();
}
wxPyEndBlockThreads();
return pyList;
}
//----------------------------------------------------------------------
long wxPyGetWinHandle(wxWindow* win) {
#ifdef __WXMSW__
return (long)win->GetHandle();
#endif
// Find and return the actual X-Window.
#ifdef __WXGTK__
if (win->m_wxwindow) {
GdkWindowPrivate* bwin = (GdkWindowPrivate*)GTK_PIZZA(win->m_wxwindow)->bin_window;
if (bwin) {
return (long)bwin->xwindow;
}
}
#endif
return 0;
}
//----------------------------------------------------------------------
// Some helper functions for typemaps in my_typemaps.i, so they won't be
// included in every file over and over again...
#if PYTHON_API_VERSION >= 1009
static char* wxStringErrorMsg = "String or Unicode type required";
#else
static char* wxStringErrorMsg = "String type required";
#endif
wxString* wxString_in_helper(PyObject* source) {
wxString* target;
#if PYTHON_API_VERSION >= 1009 // Have Python unicode API
if (!PyString_Check(source) && !PyUnicode_Check(source)) {
PyErr_SetString(PyExc_TypeError, wxStringErrorMsg);
return NULL;
}
#if wxUSE_UNICODE
if (PyUnicode_Check(source)) {
target = new wxString(PyUnicode_AS_UNICODE(source));
} else {
// It is a string, get pointers to it and transform to unicode
char* tmpPtr; int tmpSize;
PyString_AsStringAndSize(source, &tmpPtr, &tmpSize);
target = new wxString(tmpPtr, *wxConvCurrent, tmpSize);
}
#else
char* tmpPtr; int tmpSize;
if (PyString_AsStringAndSize(source, &tmpPtr, &tmpSize) == -1) {
PyErr_SetString(PyExc_TypeError, "Unable to convert string");
return NULL;
}
target = new wxString(tmpPtr, tmpSize);
#endif // wxUSE_UNICODE
#else // No Python unicode API (1.5.2)
if (!PyString_Check(source)) {
PyErr_SetString(PyExc_TypeError, wxStringErrorMsg);
return NULL;
}
target = new wxString(PyString_AS_STRING(source), PyString_GET_SIZE(source));
#endif
return target;
}
// Similar to above except doesn't use "new" and doesn't set an exception
wxString Py2wxString(PyObject* source)
{
wxString target;
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;
}
#if wxUSE_UNICODE
if (PyUnicode_Check(source)) {
target = PyUnicode_AS_UNICODE(source);
} else {
// It is a string, get pointers to it and transform to unicode
char* tmpPtr; int tmpSize;
PyString_AsStringAndSize(source, &tmpPtr, &tmpSize);
target = wxString(tmpPtr, *wxConvCurrent, tmpSize);
}
#else
char* tmpPtr; int tmpSize;
PyString_AsStringAndSize(source, &tmpPtr, &tmpSize);
target = wxString(tmpPtr, tmpSize);
#endif // wxUSE_UNICODE
#else // No Python unicode API (1.5.2)
if (!PyString_Check(source)) {
// Convert to String if not one already...
source = PyObject_Str(source);
doDecRef = TRUE;
}
target = wxString(PyString_AS_STRING(source), PyString_GET_SIZE(source));
#endif
if (doDecRef)
Py_DECREF(source);
return target;
}
// Make either a Python String or Unicode object, depending on build mode
PyObject* wx2PyString(const wxString& src)
{
PyObject* str;
#if wxUSE_UNICODE
str = PyUnicode_FromUnicode(src.c_str(), src.Len());
#else
str = PyString_FromStringAndSize(src.c_str(), src.Len());
#endif
return str;
}
//----------------------------------------------------------------------
byte* byte_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
byte* temp = new byte[count];
if (! temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
if (! PyInt_Check(o)) {
PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
return NULL;
}
temp[x] = (byte)PyInt_AsLong(o);
}
return temp;
}
int* int_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
int* temp = new int[count];
if (! temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
if (! PyInt_Check(o)) {
PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
return NULL;
}
temp[x] = PyInt_AsLong(o);
}
return temp;
}
long* long_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
long* temp = new long[count];
if (! temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
if (! PyInt_Check(o)) {
PyErr_SetString(PyExc_TypeError, "Expected a list of integers.");
return NULL;
}
temp[x] = PyInt_AsLong(o);
}
return temp;
}
char** string_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
char** temp = new char*[count];
if (! temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
if (! PyString_Check(o)) {
PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
return NULL;
}
temp[x] = PyString_AsString(o);
}
return temp;
}
//--------------------------------
// Part of patch from Tim Hochberg
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;
}
if (PyFloat_Check(o1) && PyFloat_Check(o2)) {
point->x = (int)PyFloat_AS_DOUBLE(o1);
point->y = (int)PyFloat_AS_DOUBLE(o2);
return true;
}
if (PyInstance_Check(o1) || PyInstance_Check(o2)) {
// Disallow instances because they can cause havok
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 false;
}
wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) {
// Putting all of the declarations here allows
// us to put the error handling all in one place.
int x;
wxPoint* temp;
PyObject *o, *o1, *o2;
bool isFast = PyList_Check(source) || PyTuple_Check(source);
if (!PySequence_Check(source)) {
goto error0;
}
// The length of the sequence is returned in count.
*count = PySequence_Length(source);
if (*count < 0) {
goto error0;
}
temp = new wxPoint[*count];
if (!temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (x=0; x<*count; x++) {
// Get an item: try fast way first.
if (isFast) {
o = PySequence_Fast_GET_ITEM(source, x);
}
else {
o = PySequence_GetItem(source, x);
if (o == NULL) {
goto error1;
}
}
// Convert o to wxPoint.
if ((PyTuple_Check(o) && PyTuple_GET_SIZE(o) == 2) ||
(PyList_Check(o) && PyList_GET_SIZE(o) == 2)) {
o1 = PySequence_Fast_GET_ITEM(o, 0);
o2 = PySequence_Fast_GET_ITEM(o, 1);
if (!wxPointFromObjects(o1, o2, &temp[x])) {
goto error2;
}
}
else if (PyInstance_Check(o)) {
wxPoint* pt;
if (SWIG_GetPtrObj(o, (void **)&pt, "_wxPoint_p")) {
goto error2;
}
temp[x] = *pt;
}
else if (PySequence_Check(o) && PySequence_Length(o) == 2) {
o1 = PySequence_GetItem(o, 0);
o2 = PySequence_GetItem(o, 1);
if (!wxPointFromObjects(o1, o2, &temp[x])) {
goto error3;
}
Py_DECREF(o1);
Py_DECREF(o2);
}
else {
goto error2;
}
// Clean up.
if (!isFast)
Py_DECREF(o);
}
return temp;
error3:
Py_DECREF(o1);
Py_DECREF(o2);
error2:
if (!isFast)
Py_DECREF(o);
error1:
delete temp;
error0:
PyErr_SetString(PyExc_TypeError, "Expected a sequence of length-2 sequences or wxPoints.");
return NULL;
}
// end of patch
//------------------------------
wxBitmap** wxBitmap_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
wxBitmap** temp = new wxBitmap*[count];
if (! temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
if (PyInstance_Check(o)) {
wxBitmap* pt;
if (SWIG_GetPtrObj(o, (void **) &pt,"_wxBitmap_p")) {
PyErr_SetString(PyExc_TypeError,"Expected _wxBitmap_p.");
return NULL;
}
temp[x] = pt;
}
else {
PyErr_SetString(PyExc_TypeError, "Expected a list of wxBitmaps.");
return NULL;
}
}
return temp;
}
wxString* wxString_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
wxString* temp = new wxString[count];
if (! temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
#if PYTHON_API_VERSION >= 1009
if (! PyString_Check(o) && ! PyUnicode_Check(o)) {
PyErr_SetString(PyExc_TypeError, "Expected a list of string or unicode objects.");
return NULL;
}
#else
if (! PyString_Check(o)) {
PyErr_SetString(PyExc_TypeError, "Expected a list of strings.");
return NULL;
}
#endif
wxString* pStr = wxString_in_helper(o);
temp[x] = *pStr;
delete pStr;
}
return temp;
}
wxAcceleratorEntry* wxAcceleratorEntry_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
wxAcceleratorEntry* temp = new wxAcceleratorEntry[count];
if (! temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
if (PyInstance_Check(o)) {
wxAcceleratorEntry* ae;
if (SWIG_GetPtrObj(o, (void **) &ae,"_wxAcceleratorEntry_p")) {
PyErr_SetString(PyExc_TypeError,"Expected _wxAcceleratorEntry_p.");
return NULL;
}
temp[x] = *ae;
}
else if (PyTuple_Check(o)) {
PyObject* o1 = PyTuple_GetItem(o, 0);
PyObject* o2 = PyTuple_GetItem(o, 1);
PyObject* o3 = PyTuple_GetItem(o, 2);
temp[x].Set(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3));
}
else {
PyErr_SetString(PyExc_TypeError, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
return NULL;
}
}
return temp;
}
wxPen** wxPen_LIST_helper(PyObject* source) {
if (!PyList_Check(source)) {
PyErr_SetString(PyExc_TypeError, "Expected a list object.");
return NULL;
}
int count = PyList_Size(source);
wxPen** temp = new wxPen*[count];
if (!temp) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
return NULL;
}
for (int x=0; x<count; x++) {
PyObject* o = PyList_GetItem(source, x);
if (PyInstance_Check(o)) {
wxPen* pt;
if (SWIG_GetPtrObj(o, (void **) &pt,"_wxPen_p")) {
delete temp;
PyErr_SetString(PyExc_TypeError,"Expected _wxPen_p.");
return NULL;
}
temp[x] = pt;
}
else {
delete temp;
PyErr_SetString(PyExc_TypeError, "Expected a list of wxPens.");
return NULL;
}
}
return temp;
}
bool _2int_seq_helper(PyObject* source, int* i1, int* i2) {
bool isFast = PyList_Check(source) || PyTuple_Check(source);
PyObject *o1, *o2;
if (!PySequence_Check(source) || PySequence_Length(source) != 2)
return FALSE;
if (isFast) {
o1 = PySequence_Fast_GET_ITEM(source, 0);
o2 = PySequence_Fast_GET_ITEM(source, 1);
}
else {
o1 = PySequence_GetItem(source, 0);
o2 = PySequence_GetItem(source, 1);
}
*i1 = PyInt_AsLong(o1);
*i2 = PyInt_AsLong(o2);
if (! isFast) {
Py_DECREF(o1);
Py_DECREF(o2);
}
return TRUE;
}
bool _4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4) {
bool isFast = PyList_Check(source) || PyTuple_Check(source);
PyObject *o1, *o2, *o3, *o4;
if (!PySequence_Check(source) || PySequence_Length(source) != 4)
return FALSE;
if (isFast) {
o1 = PySequence_Fast_GET_ITEM(source, 0);
o2 = PySequence_Fast_GET_ITEM(source, 1);
o3 = PySequence_Fast_GET_ITEM(source, 2);
o4 = PySequence_Fast_GET_ITEM(source, 3);
}
else {
o1 = PySequence_GetItem(source, 0);
o2 = PySequence_GetItem(source, 1);
o3 = PySequence_GetItem(source, 2);
o4 = PySequence_GetItem(source, 3);
}
*i1 = PyInt_AsLong(o1);
*i2 = PyInt_AsLong(o2);
*i3 = PyInt_AsLong(o3);
*i4 = PyInt_AsLong(o4);
if (! isFast) {
Py_DECREF(o1);
Py_DECREF(o2);
Py_DECREF(o3);
Py_DECREF(o4);
}
return TRUE;
}
//----------------------------------------------------------------------
bool wxSize_helper(PyObject* source, wxSize** obj) {
// If source is an object instance then it may already be the right type
if (PyInstance_Check(source)) {
wxSize* ptr;
if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxSize_p"))
goto error;
*obj = ptr;
return TRUE;
}
// otherwise a 2-tuple of integers is expected
else if (PySequence_Check(source) && PyObject_Length(source) == 2) {
PyObject* o1 = PySequence_GetItem(source, 0);
PyObject* o2 = PySequence_GetItem(source, 1);
if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) {
Py_DECREF(o1);
Py_DECREF(o2);
goto error;
}
**obj = wxSize(PyInt_AsLong(o1), PyInt_AsLong(o2));
Py_DECREF(o1);
Py_DECREF(o2);
return TRUE;
}
error:
PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of integers or a wxSize object.");
return FALSE;
}
bool wxPoint_helper(PyObject* source, wxPoint** obj) {
// If source is an object instance then it may already be the right type
if (PyInstance_Check(source)) {
wxPoint* ptr;
if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxPoint_p"))
goto error;
*obj = ptr;
return TRUE;
}
// otherwise a length-2 sequence of integers is expected
if (PySequence_Check(source) && PySequence_Length(source) == 2) {
PyObject* o1 = PySequence_GetItem(source, 0);
PyObject* o2 = PySequence_GetItem(source, 1);
// This should really check for integers, not numbers -- but that would break code.
if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) {
Py_DECREF(o1);
Py_DECREF(o2);
goto error;
}
**obj = wxPoint(PyInt_AsLong(o1), PyInt_AsLong(o2));
Py_DECREF(o1);
Py_DECREF(o2);
return TRUE;
}
error:
PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of integers or a wxPoint object.");
return FALSE;
}
bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj) {
// If source is an object instance then it may already be the right type
if (PyInstance_Check(source)) {
wxRealPoint* ptr;
if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRealPoint_p"))
goto error;
*obj = ptr;
return TRUE;
}
// otherwise a 2-tuple of floats is expected
else if (PySequence_Check(source) && PyObject_Length(source) == 2) {
PyObject* o1 = PySequence_GetItem(source, 0);
PyObject* o2 = PySequence_GetItem(source, 1);
if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) {
Py_DECREF(o1);
Py_DECREF(o2);
goto error;
}
**obj = wxRealPoint(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2));
Py_DECREF(o1);
Py_DECREF(o2);
return TRUE;
}
error:
PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wxRealPoint object.");
return FALSE;
}
bool wxRect_helper(PyObject* source, wxRect** obj) {
// If source is an object instance then it may already be the right type
if (PyInstance_Check(source)) {
wxRect* ptr;
if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRect_p"))
goto error;
*obj = ptr;
return TRUE;
}
// otherwise a 4-tuple of integers is expected
else if (PySequence_Check(source) && PyObject_Length(source) == 4) {
PyObject* o1 = PySequence_GetItem(source, 0);
PyObject* o2 = PySequence_GetItem(source, 1);
PyObject* o3 = PySequence_GetItem(source, 2);
PyObject* o4 = PySequence_GetItem(source, 3);
if (!PyNumber_Check(o1) || !PyNumber_Check(o2) ||
!PyNumber_Check(o3) || !PyNumber_Check(o4)) {
Py_DECREF(o1);
Py_DECREF(o2);
Py_DECREF(o3);
Py_DECREF(o4);
goto error;
}
**obj = wxRect(PyInt_AsLong(o1), PyInt_AsLong(o2),
PyInt_AsLong(o3), PyInt_AsLong(o4));
Py_DECREF(o1);
Py_DECREF(o2);
Py_DECREF(o3);
Py_DECREF(o4);
return TRUE;
}
error:
PyErr_SetString(PyExc_TypeError, "Expected a 4-tuple of integers or a wxRect object.");
return FALSE;
}
bool wxColour_helper(PyObject* source, wxColour** obj) {
// If source is an object instance then it may already be the right type
if (PyInstance_Check(source)) {
wxColour* ptr;
if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxColour_p"))
goto error;
*obj = ptr;
return TRUE;
}
// otherwise a string is expected
else if (PyString_Check(source)) {
wxString spec(PyString_AS_STRING(source), *wxConvCurrent);
if (spec.GetChar(0) == '#' && spec.Length() == 7) { // It's #RRGGBB
long red, green, blue;
red = green = blue = 0;
spec.Mid(1,2).ToLong(&red, 16);
spec.Mid(3,2).ToLong(&green, 16);
spec.Mid(5,2).ToLong(&blue, 16);
**obj = wxColour(red, green, blue);
return TRUE;
}
else { // it's a colour name
**obj = wxColour(spec);
return TRUE;
}
}
error:
PyErr_SetString(PyExc_TypeError,
"Expected a wxColour object or a string containing a colour "
"name or '#RRGGBB'.");
return FALSE;
}
//----------------------------------------------------------------------
PyObject* wxArrayString2PyList_helper(const wxArrayString& arr) {
PyObject* list = PyList_New(0);
for (size_t i=0; i < arr.GetCount(); i++) {
#if wxUSE_UNICODE
PyObject* str = PyUnicode_FromUnicode(arr[i].c_str(), arr[i].Len());
#else
PyObject* str = PyString_FromStringAndSize(arr[i].c_str(), arr[i].Len());
#endif
PyList_Append(list, str);
Py_DECREF(str);
}
return list;
}
PyObject* wxArrayInt2PyList_helper(const wxArrayInt& arr) {
PyObject* list = PyList_New(0);
for (size_t i=0; i < arr.GetCount(); i++) {
PyObject* number = PyInt_FromLong(arr[i]);
PyList_Append(list, number);
Py_DECREF(number);
}
return list;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------