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 #ifdef WXP_WITH_THREAD
125 PyEval_InitThreads();
128 // Bail out if there is already windows created. This means that the
129 // toolkit has already been initialized, as in embedding wxPython in
130 // a C++ wxWindows app.
131 if (wxTopLevelWindows
.Number() > 0)
139 PyObject
* sysargv
= PySys_GetObject("argv");
140 int argc
= PyList_Size(sysargv
);
141 char** argv
= new char*[argc
+1];
143 for(x
=0; x
<argc
; x
++)
144 argv
[x
] = PyString_AsString(PyList_GetItem(sysargv
, x
));
149 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
151 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
153 gtk_init( &argc
, &argv
);
154 wxSetDetectableAutoRepeat( TRUE
);
157 wxApp::Initialize(); // may return FALSE. Should we check?
163 #ifdef WXP_WITH_THREAD
164 PyThreadState
* wxPyEventThreadState
= NULL
;
166 static char* __nullArgv
[1] = { 0 };
170 // Start the user application, user App's OnInit method is a parameter here
171 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
173 PyObject
* onInitFunc
= NULL
;
178 #ifdef WXP_WITH_THREAD
179 wxPyEventThreadState
= PyThreadState_Get();
182 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
185 if (wxTopLevelWindows
.Number() > 0) {
186 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
191 // This is the next part of the wxEntry functionality...
192 wxPythonApp
->argc
= 0;
193 wxPythonApp
->argv
= NULL
;
194 wxPythonApp
->OnInitGui();
197 // Call the Python App's OnInit function
198 arglist
= PyTuple_New(0);
199 result
= PyEval_CallObject(onInitFunc
, arglist
);
200 if (!result
) { // an exception was raised.
204 if (! PyInt_Check(result
)) {
205 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
208 bResult
= PyInt_AS_LONG(result
);
210 PyErr_SetString(PyExc_SystemExit
, "OnInit returned false, exiting...");
215 wxTheApp
->m_initialized
= (wxTopLevelWindows
.Number() > 0);
226 PyObject
* wxPython_dict
;
227 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
230 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
233 if (!PyDict_Check(wxPython_dict
)) {
234 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
238 #define wxPlatform "__WXMOTIF__"
241 #define wxPlatform "__WXQT__"
244 #define wxPlatform "__WXGTK__"
246 #if defined(__WIN32__) || defined(__WXMSW__)
247 #define wxPlatform "__WXMSW__"
250 #define wxPlatform "__WXMAC__"
253 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
260 //---------------------------------------------------------------------------
262 PyObject
* wxPyConstructObject(void* ptr
, const char* className
) {
263 char buff
[64]; // should always be big enough...
266 sprintf(buff
, "_%s_p", className
);
267 SWIG_MakePtr(swigptr
, ptr
, buff
);
269 sprintf(buff
, "%sPtr", className
);
270 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
276 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
277 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
283 //---------------------------------------------------------------------------
285 static unsigned int _wxPyNestCount
= 0;
287 static PyThreadState
* myPyThreadState_Get() {
288 PyThreadState
* current
;
289 current
= PyThreadState_Swap(NULL
);
290 PyThreadState_Swap(current
);
295 HELPEREXPORT
bool wxPyRestoreThread() {
296 // NOTE: The Python API docs state that if a thread already has the
297 // interpreter lock and calls PyEval_RestoreThread again a deadlock
298 // occurs, so I put in this code as a guard condition since there are
299 // many possibilites for nested events and callbacks in wxPython. If
300 // The current thread is our thread, then we can assume that we
301 // already have the lock. (I hope!)
303 #ifdef WXP_WITH_THREAD
305 if (wxPyEventThreadState
!= myPyThreadState_Get()) {
306 PyEval_RestoreThread(wxPyEventThreadState
);
315 HELPEREXPORT
void wxPySaveThread(bool doSave
) {
316 #ifdef WXP_WITH_THREAD
318 wxPyEventThreadState
= PyEval_SaveThread();
324 //---------------------------------------------------------------------------
327 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback
, wxObject
);
329 wxPyCallback::wxPyCallback(PyObject
* func
) {
334 wxPyCallback::wxPyCallback(const wxPyCallback
& other
) {
335 m_func
= other
.m_func
;
339 wxPyCallback::~wxPyCallback() {
340 bool doSave
= wxPyRestoreThread();
342 wxPySaveThread(doSave
);
347 // This function is used for all events destined for Python event handlers.
348 void wxPyCallback::EventThunker(wxEvent
& event
) {
349 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
350 PyObject
* func
= cb
->m_func
;
356 bool doSave
= wxPyRestoreThread();
357 wxString className
= event
.GetClassInfo()->GetClassName();
359 if (className
== "wxPyEvent")
360 arg
= ((wxPyEvent
*)&event
)->GetSelf();
361 else if (className
== "wxPyCommandEvent")
362 arg
= ((wxPyCommandEvent
*)&event
)->GetSelf();
364 arg
= wxPyConstructObject((void*)&event
, className
);
366 tuple
= PyTuple_New(1);
367 PyTuple_SET_ITEM(tuple
, 0, arg
);
368 result
= PyEval_CallObject(func
, tuple
);
376 wxPySaveThread(doSave
);
380 //----------------------------------------------------------------------
382 wxPyCallbackHelper::wxPyCallbackHelper() {
388 wxPyCallbackHelper::~wxPyCallbackHelper() {
389 bool doSave
= wxPyRestoreThread();
391 wxPySaveThread(doSave
);
394 wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper
& other
) {
396 m_self
= other
.m_self
;
402 void wxPyCallbackHelper::setSelf(PyObject
* self
, int incref
) {
409 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
411 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
412 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
414 return m_lastFound
!= NULL
;
418 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
422 result
= callCallbackObj(argTuple
);
423 if (result
) { // Assumes an integer return type...
424 retval
= PyInt_AsLong(result
);
426 PyErr_Clear(); // forget about it if it's not...
431 // Invoke the Python callable object, returning the raw PyObject return
432 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
433 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
436 result
= PyEval_CallObject(m_lastFound
, argTuple
);
446 //---------------------------------------------------------------------------
447 //---------------------------------------------------------------------------
448 // These classes can be derived from in Python and passed through the event
449 // system without loosing anything. They do this by keeping a reference to
450 // themselves and some special case handling in wxPyCallback::EventThunker.
453 wxPySelfRef::wxPySelfRef() {
454 //m_self = Py_None; // **** We don't do normal ref counting to prevent
455 //Py_INCREF(m_self); // circular loops...
459 wxPySelfRef::~wxPySelfRef() {
460 bool doSave
= wxPyRestoreThread();
463 wxPySaveThread(doSave
);
466 void wxPySelfRef::SetSelf(PyObject
* self
, bool clone
) {
467 bool doSave
= wxPyRestoreThread();
475 wxPySaveThread(doSave
);
478 PyObject
* wxPySelfRef::GetSelf() const {
484 wxPyEvent::wxPyEvent(int id
)
488 wxPyEvent::~wxPyEvent() {
491 // This one is so the event object can be Cloned...
492 void wxPyEvent::CopyObject(wxObject
& dest
) const {
493 wxEvent::CopyObject(dest
);
494 ((wxPyEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
498 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxEvent
);
501 wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType
, int id
)
502 : wxCommandEvent(commandType
, id
) {
505 wxPyCommandEvent::~wxPyCommandEvent() {
508 void wxPyCommandEvent::CopyObject(wxObject
& dest
) const {
509 wxCommandEvent::CopyObject(dest
);
510 ((wxPyCommandEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
514 IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent
, wxCommandEvent
);
518 //---------------------------------------------------------------------------
519 //---------------------------------------------------------------------------
522 wxPyTimer::wxPyTimer(PyObject
* callback
) {
527 wxPyTimer::~wxPyTimer() {
528 bool doSave
= wxPyRestoreThread();
530 wxPySaveThread(doSave
);
533 void wxPyTimer::Notify() {
534 bool doSave
= wxPyRestoreThread();
537 PyObject
* args
= Py_BuildValue("()");
539 result
= PyEval_CallObject(func
, args
);
547 wxPySaveThread(doSave
);
552 //---------------------------------------------------------------------------
553 //---------------------------------------------------------------------------
554 // Convert a wxList to a Python List
556 PyObject
* wxPy_ConvertList(wxListBase
* list
, const char* className
) {
560 wxNode
* node
= list
->First();
562 bool doSave
= wxPyRestoreThread();
563 pyList
= PyList_New(0);
565 wxObj
= node
->Data();
566 pyObj
= wxPyConstructObject(wxObj
, className
);
567 PyList_Append(pyList
, pyObj
);
570 wxPySaveThread(doSave
);
574 //----------------------------------------------------------------------
575 // Some helper functions for typemaps in my_typemaps.i, so they won't be
576 // included in every file...
579 byte
* byte_LIST_helper(PyObject
* source
) {
580 if (!PyList_Check(source
)) {
581 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
584 int count
= PyList_Size(source
);
585 byte
* temp
= new byte
[count
];
587 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
590 for (int x
=0; x
<count
; x
++) {
591 PyObject
* o
= PyList_GetItem(source
, x
);
592 if (! PyInt_Check(o
)) {
593 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
596 temp
[x
] = (byte
)PyInt_AsLong(o
);
602 int* int_LIST_helper(PyObject
* source
) {
603 if (!PyList_Check(source
)) {
604 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
607 int count
= PyList_Size(source
);
608 int* temp
= new int[count
];
610 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
613 for (int x
=0; x
<count
; x
++) {
614 PyObject
* o
= PyList_GetItem(source
, x
);
615 if (! PyInt_Check(o
)) {
616 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
619 temp
[x
] = PyInt_AsLong(o
);
625 long* long_LIST_helper(PyObject
* source
) {
626 if (!PyList_Check(source
)) {
627 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
630 int count
= PyList_Size(source
);
631 long* temp
= new long[count
];
633 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
636 for (int x
=0; x
<count
; x
++) {
637 PyObject
* o
= PyList_GetItem(source
, x
);
638 if (! PyInt_Check(o
)) {
639 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
642 temp
[x
] = PyInt_AsLong(o
);
648 char** string_LIST_helper(PyObject
* source
) {
649 if (!PyList_Check(source
)) {
650 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
653 int count
= PyList_Size(source
);
654 char** temp
= new char*[count
];
656 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
659 for (int x
=0; x
<count
; x
++) {
660 PyObject
* o
= PyList_GetItem(source
, x
);
661 if (! PyString_Check(o
)) {
662 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
665 temp
[x
] = PyString_AsString(o
);
672 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
673 if (!PyList_Check(source
)) {
674 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
677 int count
= PyList_Size(source
);
678 wxPoint
* temp
= new wxPoint
[count
];
680 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
683 for (int x
=0; x
<count
; x
++) {
684 PyObject
* o
= PyList_GetItem(source
, x
);
685 if (PyTuple_Check(o
)) {
686 PyObject
* o1
= PyTuple_GetItem(o
, 0);
687 PyObject
* o2
= PyTuple_GetItem(o
, 1);
689 temp
[x
].x
= PyInt_AsLong(o1
);
690 temp
[x
].y
= PyInt_AsLong(o2
);
692 else if (PyInstance_Check(o
)) {
694 if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) {
695 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
701 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
709 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
710 if (!PyList_Check(source
)) {
711 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
714 int count
= PyList_Size(source
);
715 wxBitmap
** temp
= new wxBitmap
*[count
];
717 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
720 for (int x
=0; x
<count
; x
++) {
721 PyObject
* o
= PyList_GetItem(source
, x
);
722 if (PyInstance_Check(o
)) {
724 if (SWIG_GetPtrObj(o
, (void **) &pt
,"_wxBitmap_p")) {
725 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
731 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
740 wxString
* wxString_LIST_helper(PyObject
* source
) {
741 if (!PyList_Check(source
)) {
742 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
745 int count
= PyList_Size(source
);
746 wxString
* temp
= new wxString
[count
];
748 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
751 for (int x
=0; x
<count
; x
++) {
752 PyObject
* o
= PyList_GetItem(source
, x
);
753 if (! PyString_Check(o
)) {
754 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
757 temp
[x
] = PyString_AsString(o
);
763 wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
764 if (!PyList_Check(source
)) {
765 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
768 int count
= PyList_Size(source
);
769 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
771 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
774 for (int x
=0; x
<count
; x
++) {
775 PyObject
* o
= PyList_GetItem(source
, x
);
776 if (PyInstance_Check(o
)) {
777 wxAcceleratorEntry
* ae
;
778 if (SWIG_GetPtrObj(o
, (void **) &ae
,"_wxAcceleratorEntry_p")) {
779 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
784 else if (PyTuple_Check(o
)) {
785 PyObject
* o1
= PyTuple_GetItem(o
, 0);
786 PyObject
* o2
= PyTuple_GetItem(o
, 1);
787 PyObject
* o3
= PyTuple_GetItem(o
, 2);
789 temp
[x
].m_flags
= PyInt_AsLong(o1
);
790 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
791 temp
[x
].m_command
= PyInt_AsLong(o3
);
794 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
803 //----------------------------------------------------------------------
805 bool wxSize_helper(PyObject
* source
, wxSize
** obj
) {
807 // If source is an object instance then it may already be the right type
808 if (PyInstance_Check(source
)) {
810 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxSize_p"))
815 // otherwise a 2-tuple of integers is expected
816 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
817 PyObject
* o1
= PySequence_GetItem(source
, 0);
818 PyObject
* o2
= PySequence_GetItem(source
, 1);
819 **obj
= wxSize(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
824 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxSize object.");
828 bool wxPoint_helper(PyObject
* source
, wxPoint
** obj
) {
830 // If source is an object instance then it may already be the right type
831 if (PyInstance_Check(source
)) {
833 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxPoint_p"))
838 // otherwise a 2-tuple of integers is expected
839 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
840 PyObject
* o1
= PySequence_GetItem(source
, 0);
841 PyObject
* o2
= PySequence_GetItem(source
, 1);
842 **obj
= wxPoint(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
847 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxPoint object.");
853 bool wxRealPoint_helper(PyObject
* source
, wxRealPoint
** obj
) {
855 // If source is an object instance then it may already be the right type
856 if (PyInstance_Check(source
)) {
858 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRealPoint_p"))
863 // otherwise a 2-tuple of floats is expected
864 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
865 PyObject
* o1
= PySequence_GetItem(source
, 0);
866 PyObject
* o2
= PySequence_GetItem(source
, 1);
867 **obj
= wxRealPoint(PyFloat_AsDouble(o1
), PyFloat_AsDouble(o2
));
872 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of floats or a wxRealPoint object.");
879 bool wxRect_helper(PyObject
* source
, wxRect
** obj
) {
881 // If source is an object instance then it may already be the right type
882 if (PyInstance_Check(source
)) {
884 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRect_p"))
889 // otherwise a 4-tuple of integers is expected
890 else if (PySequence_Check(source
) && PyObject_Length(source
) == 4) {
891 PyObject
* o1
= PySequence_GetItem(source
, 0);
892 PyObject
* o2
= PySequence_GetItem(source
, 1);
893 PyObject
* o3
= PySequence_GetItem(source
, 2);
894 PyObject
* o4
= PySequence_GetItem(source
, 3);
895 **obj
= wxRect(PyInt_AsLong(o1
), PyInt_AsLong(o2
),
896 PyInt_AsLong(o3
), PyInt_AsLong(o4
));
901 PyErr_SetString(PyExc_TypeError
, "Expected a 4-tuple of integers or a wxRect object.");
907 //----------------------------------------------------------------------
908 //----------------------------------------------------------------------
909 //----------------------------------------------------------------------