1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Helper functions/classes for the wxPython extension module
9 // Copyright: (c) 1998 by Total Control Software
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
22 #include <wx/msw/private.h>
25 #undef LoadAccelerators
29 #include <wx/module.h>
32 //---------------------------------------------------------------------------
34 //wxHashTable* wxPyWindows = NULL;
37 wxPoint wxPyDefaultPosition
; //wxDefaultPosition);
38 wxSize wxPyDefaultSize
; //wxDefaultSize);
39 wxString
wxPyEmptyStr("");
43 #ifdef __WXMSW__ // If building for win32...
44 //----------------------------------------------------------------------
45 // This gets run when the DLL is loaded. We just need to save a handle.
46 //----------------------------------------------------------------------
49 HINSTANCE hinstDLL
, // handle to DLL module
50 DWORD fdwReason
, // reason for calling function
51 LPVOID lpvReserved
// reserved
54 wxSetInstance(hinstDLL
);
59 //----------------------------------------------------------------------
60 // Class for implementing the wxp main application shell.
61 //----------------------------------------------------------------------
63 wxPyApp
*wxPythonApp
= NULL
; // Global instance of application object
67 // printf("**** ctor\n");
71 // printf("**** dtor\n");
75 // This one isn't acutally called... See __wxStart()
76 bool wxPyApp::OnInit(void) {
80 int wxPyApp::MainLoop(void) {
81 int retval
= wxApp::MainLoop();
83 wxPythonApp
->OnExit(); //#
88 //# void wxPyApp::AfterMainLoop(void) {
89 // // more stuff from wxEntry...
91 // if (wxPythonApp->GetTopWindow()) {
92 // // Forcibly delete the window.
93 // if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) ||
94 // wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) {
96 // wxPythonApp->GetTopWindow()->Close(TRUE);
97 // wxPythonApp->DeletePendingObjects();
100 // delete wxPythonApp->GetTopWindow();
101 // wxPythonApp->SetTopWindow(NULL);
105 // wxPythonApp->DeletePendingObjects();
108 // wxPythonApp->OnExit();
110 // // delete wxPythonApp;
114 //---------------------------------------------------------------------
115 // a few native methods to add to the module
116 //----------------------------------------------------------------------
119 // This is where we pick up the first part of the wxEntry functionality...
120 // The rest is in __wxStart and AfterMainLoop. This function is called when
121 // wxcmodule is imported. (Before there is a wxApp object.)
124 // Bail out if there is already windows created. This means that the
125 // toolkit has already been initialized, as in embedding wxPython in
126 // a C++ wxWindows app.
127 if (wxTopLevelWindows
.Number() > 0)
135 PyObject
* sysargv
= PySys_GetObject("argv");
136 int argc
= PyList_Size(sysargv
);
137 char** argv
= new char*[argc
+1];
139 for(x
=0; x
<argc
; x
++)
140 argv
[x
] = PyString_AsString(PyList_GetItem(sysargv
, x
));
145 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
147 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
149 gtk_init( &argc
, &argv
);
150 wxSetDetectableAutoRepeat( TRUE
);
153 wxApp::Initialize(); // may return FALSE. Should we check?
159 #ifdef WXP_WITH_THREAD
160 PyThreadState
* wxPyEventThreadState
= NULL
;
162 static char* __nullArgv
[1] = { 0 };
166 // Start the user application, user App's OnInit method is a parameter here
167 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
169 PyObject
* onInitFunc
= NULL
;
174 #ifdef WXP_WITH_THREAD
175 wxPyEventThreadState
= PyThreadState_Get();
178 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
181 if (wxTopLevelWindows
.Number() > 0) {
182 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
187 // This is the next part of the wxEntry functionality...
188 wxPythonApp
->argc
= 0;
189 wxPythonApp
->argv
= NULL
;
190 wxPythonApp
->OnInitGui();
193 // Call the Python App's OnInit function
194 arglist
= PyTuple_New(0);
195 result
= PyEval_CallObject(onInitFunc
, arglist
);
196 if (!result
) { // an exception was raised.
200 if (! PyInt_Check(result
)) {
201 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
204 bResult
= PyInt_AS_LONG(result
);
206 PyErr_SetString(PyExc_SystemExit
, "OnInit returned false, exiting...");
211 wxTheApp
->m_initialized
= (wxTopLevelWindows
.Number() > 0);
222 PyObject
* wxPython_dict
;
223 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
226 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
229 if (!PyDict_Check(wxPython_dict
)) {
230 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
234 #define wxPlatform "__WXMOTIF__"
237 #define wxPlatform "__WXQT__"
240 #define wxPlatform "__WXGTK__"
242 #if defined(__WIN32__) || defined(__WXMSW__)
243 #define wxPlatform "__WXMSW__"
246 #define wxPlatform "__WXMAC__"
249 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
256 //---------------------------------------------------------------------------
258 PyObject
* wxPyConstructObject(void* ptr
, char* className
) {
259 char buff
[64]; // should always be big enough...
262 sprintf(buff
, "_%s_p", className
);
263 SWIG_MakePtr(swigptr
, ptr
, buff
);
265 sprintf(buff
, "%sPtr", className
);
266 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
272 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
273 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
279 //---------------------------------------------------------------------------
281 //static bool _wxPyInEvent = false;
282 static unsigned int _wxPyNestCount
= 0;
284 HELPEREXPORT
bool wxPyRestoreThread() {
285 // #ifdef WXP_WITH_THREAD
286 // //if (wxPyEventThreadState != PyThreadState_Get()) {
287 // if (! _wxPyInEvent) {
288 // PyEval_RestoreThread(wxPyEventThreadState);
289 // _wxPyInEvent = true;
295 // NOTE: The Python API docs state that if a thread already has the
296 // interpreter lock and calls PyEval_RestoreThread again a deadlock
297 // occurs, so I put in the above code as a guard condition since there are
298 // many possibilites for nested events and callbacks in wxPython.
300 // Unfortunately, it seems like somebody was lying (or I'm not
301 // understanding...) because each of the nested calls to this function
302 // MUST call PyEval_RestoreThread or Python pukes with a thread error (at
305 // until I know better, this is how I am doing it instead:
306 #ifdef WXP_WITH_THREAD
307 PyEval_RestoreThread(wxPyEventThreadState
);
309 if (_wxPyNestCount
== 1)
317 HELPEREXPORT
void wxPySaveThread(bool doSave
) {
318 #ifdef WXP_WITH_THREAD
321 //_wxPyInEvent = false;
327 //---------------------------------------------------------------------------
330 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback
, wxObject
);
332 wxPyCallback::wxPyCallback(PyObject
* func
) {
337 wxPyCallback::wxPyCallback(const wxPyCallback
& other
) {
338 m_func
= other
.m_func
;
342 wxPyCallback::~wxPyCallback() {
343 bool doSave
= wxPyRestoreThread();
345 wxPySaveThread(doSave
);
351 // This function is used for all events destined for Python event handlers.
352 void wxPyCallback::EventThunker(wxEvent
& event
) {
353 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
354 PyObject
* func
= cb
->m_func
;
360 bool doSave
= wxPyRestoreThread();
361 arg
= wxPyConstructObject((void*)&event
, event
.GetClassInfo()->GetClassName());
363 tuple
= PyTuple_New(1);
364 PyTuple_SET_ITEM(tuple
, 0, arg
);
365 result
= PyEval_CallObject(func
, tuple
);
373 wxPySaveThread(doSave
);
377 //----------------------------------------------------------------------
379 wxPyCallbackHelper::wxPyCallbackHelper() {
385 wxPyCallbackHelper::~wxPyCallbackHelper() {
386 bool doSave
= wxPyRestoreThread();
388 wxPySaveThread(doSave
);
391 wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper
& other
) {
393 m_self
= other
.m_self
;
399 void wxPyCallbackHelper::setSelf(PyObject
* self
, int incref
) {
406 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
408 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
409 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
411 return m_lastFound
!= NULL
;
415 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
419 result
= callCallbackObj(argTuple
);
420 if (result
) { // Assumes an integer return type...
421 retval
= PyInt_AsLong(result
);
423 PyErr_Clear(); // forget about it if it's not...
428 // Invoke the Python callable object, returning the raw PyObject return
429 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
430 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
433 result
= PyEval_CallObject(m_lastFound
, argTuple
);
443 //---------------------------------------------------------------------------
444 //---------------------------------------------------------------------------
447 wxPyTimer::wxPyTimer(PyObject
* callback
) {
452 wxPyTimer::~wxPyTimer() {
453 bool doSave
= wxPyRestoreThread();
455 wxPySaveThread(doSave
);
458 void wxPyTimer::Notify() {
459 bool doSave
= wxPyRestoreThread();
462 PyObject
* args
= Py_BuildValue("()");
464 result
= PyEval_CallObject(func
, args
);
472 wxPySaveThread(doSave
);
477 //---------------------------------------------------------------------------
478 //---------------------------------------------------------------------------
479 // Convert a wxList to a Python List
481 PyObject
* wxPy_ConvertList(wxListBase
* list
, char* className
) {
485 wxNode
* node
= list
->First();
487 bool doSave
= wxPyRestoreThread();
488 pyList
= PyList_New(0);
490 wxObj
= node
->Data();
491 pyObj
= wxPyConstructObject(wxObj
, className
);
492 PyList_Append(pyList
, pyObj
);
495 wxPySaveThread(doSave
);
499 //----------------------------------------------------------------------
500 // Some helper functions for typemaps in my_typemaps.i, so they won't be
501 // included in every file...
504 byte
* byte_LIST_helper(PyObject
* source
) {
505 if (!PyList_Check(source
)) {
506 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
509 int count
= PyList_Size(source
);
510 byte
* temp
= new byte
[count
];
512 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
515 for (int x
=0; x
<count
; x
++) {
516 PyObject
* o
= PyList_GetItem(source
, x
);
517 if (! PyInt_Check(o
)) {
518 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
521 temp
[x
] = (byte
)PyInt_AsLong(o
);
527 int* int_LIST_helper(PyObject
* source
) {
528 if (!PyList_Check(source
)) {
529 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
532 int count
= PyList_Size(source
);
533 int* temp
= new int[count
];
535 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
538 for (int x
=0; x
<count
; x
++) {
539 PyObject
* o
= PyList_GetItem(source
, x
);
540 if (! PyInt_Check(o
)) {
541 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
544 temp
[x
] = PyInt_AsLong(o
);
550 long* long_LIST_helper(PyObject
* source
) {
551 if (!PyList_Check(source
)) {
552 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
555 int count
= PyList_Size(source
);
556 long* temp
= new long[count
];
558 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
561 for (int x
=0; x
<count
; x
++) {
562 PyObject
* o
= PyList_GetItem(source
, x
);
563 if (! PyInt_Check(o
)) {
564 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
567 temp
[x
] = PyInt_AsLong(o
);
573 char** string_LIST_helper(PyObject
* source
) {
574 if (!PyList_Check(source
)) {
575 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
578 int count
= PyList_Size(source
);
579 char** temp
= new char*[count
];
581 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
584 for (int x
=0; x
<count
; x
++) {
585 PyObject
* o
= PyList_GetItem(source
, x
);
586 if (! PyString_Check(o
)) {
587 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
590 temp
[x
] = PyString_AsString(o
);
597 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
598 if (!PyList_Check(source
)) {
599 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
602 int count
= PyList_Size(source
);
603 wxPoint
* temp
= new wxPoint
[count
];
605 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
608 for (int x
=0; x
<count
; x
++) {
609 PyObject
* o
= PyList_GetItem(source
, x
);
610 if (PyTuple_Check(o
)) {
611 PyObject
* o1
= PyTuple_GetItem(o
, 0);
612 PyObject
* o2
= PyTuple_GetItem(o
, 1);
614 temp
[x
].x
= PyInt_AsLong(o1
);
615 temp
[x
].y
= PyInt_AsLong(o2
);
617 else if (PyInstance_Check(o
)) {
619 if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) {
620 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
626 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
634 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
635 if (!PyList_Check(source
)) {
636 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
639 int count
= PyList_Size(source
);
640 wxBitmap
** temp
= new wxBitmap
*[count
];
642 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
645 for (int x
=0; x
<count
; x
++) {
646 PyObject
* o
= PyList_GetItem(source
, x
);
647 if (PyInstance_Check(o
)) {
649 if (SWIG_GetPtrObj(o
, (void **) &pt
,"_wxBitmap_p")) {
650 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
656 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
665 wxString
* wxString_LIST_helper(PyObject
* source
) {
666 if (!PyList_Check(source
)) {
667 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
670 int count
= PyList_Size(source
);
671 wxString
* temp
= new wxString
[count
];
673 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
676 for (int x
=0; x
<count
; x
++) {
677 PyObject
* o
= PyList_GetItem(source
, x
);
678 if (! PyString_Check(o
)) {
679 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
682 temp
[x
] = PyString_AsString(o
);
688 wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
689 if (!PyList_Check(source
)) {
690 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
693 int count
= PyList_Size(source
);
694 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
696 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
699 for (int x
=0; x
<count
; x
++) {
700 PyObject
* o
= PyList_GetItem(source
, x
);
701 if (PyInstance_Check(o
)) {
702 wxAcceleratorEntry
* ae
;
703 if (SWIG_GetPtrObj(o
, (void **) &ae
,"_wxAcceleratorEntry_p")) {
704 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
709 else if (PyTuple_Check(o
)) {
710 PyObject
* o1
= PyTuple_GetItem(o
, 0);
711 PyObject
* o2
= PyTuple_GetItem(o
, 1);
712 PyObject
* o3
= PyTuple_GetItem(o
, 2);
714 temp
[x
].m_flags
= PyInt_AsLong(o1
);
715 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
716 temp
[x
].m_command
= PyInt_AsLong(o3
);
719 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
728 //----------------------------------------------------------------------
730 bool wxSize_helper(PyObject
* source
, wxSize
** obj
) {
732 // If source is an object instance then it may already be the right type
733 if (PyInstance_Check(source
)) {
735 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxSize_p"))
740 // otherwise a 2-tuple of integers is expected
741 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
742 PyObject
* o1
= PySequence_GetItem(source
, 0);
743 PyObject
* o2
= PySequence_GetItem(source
, 1);
744 **obj
= wxSize(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
749 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxSize object.");
753 bool wxPoint_helper(PyObject
* source
, wxPoint
** obj
) {
755 // If source is an object instance then it may already be the right type
756 if (PyInstance_Check(source
)) {
758 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxPoint_p"))
763 // otherwise a 2-tuple of integers is expected
764 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
765 PyObject
* o1
= PySequence_GetItem(source
, 0);
766 PyObject
* o2
= PySequence_GetItem(source
, 1);
767 **obj
= wxPoint(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
772 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxPoint object.");
778 bool wxRealPoint_helper(PyObject
* source
, wxRealPoint
** obj
) {
780 // If source is an object instance then it may already be the right type
781 if (PyInstance_Check(source
)) {
783 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRealPoint_p"))
788 // otherwise a 2-tuple of floats is expected
789 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
790 PyObject
* o1
= PySequence_GetItem(source
, 0);
791 PyObject
* o2
= PySequence_GetItem(source
, 1);
792 **obj
= wxRealPoint(PyFloat_AsDouble(o1
), PyFloat_AsDouble(o2
));
797 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of floats or a wxRealPoint object.");
804 bool wxRect_helper(PyObject
* source
, wxRect
** obj
) {
806 // If source is an object instance then it may already be the right type
807 if (PyInstance_Check(source
)) {
809 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRect_p"))
814 // otherwise a 4-tuple of integers is expected
815 else if (PySequence_Check(source
) && PyObject_Length(source
) == 4) {
816 PyObject
* o1
= PySequence_GetItem(source
, 0);
817 PyObject
* o2
= PySequence_GetItem(source
, 1);
818 PyObject
* o3
= PySequence_GetItem(source
, 2);
819 PyObject
* o4
= PySequence_GetItem(source
, 3);
820 **obj
= wxRect(PyInt_AsLong(o1
), PyInt_AsLong(o2
),
821 PyInt_AsLong(o3
), PyInt_AsLong(o4
));
826 PyErr_SetString(PyExc_TypeError
, "Expected a 4-tuple of integers or a wxRect object.");
832 //----------------------------------------------------------------------
833 //----------------------------------------------------------------------
834 //----------------------------------------------------------------------