1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Helper functions/classes for the wxPython extension module
9 // Copyright: (c) 1998 by Total Control Software
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
13 #include <stdio.h> // get the correct definition of NULL
20 #include <wx/msw/private.h>
23 #undef LoadAccelerators
33 //---------------------------------------------------------------------------
35 //wxHashTable* wxPyWindows = NULL;
38 wxPoint wxPyDefaultPosition
; //wxDefaultPosition);
39 wxSize wxPyDefaultSize
; //wxDefaultSize);
40 wxString
wxPyEmptyStr("");
44 #ifdef __WXMSW__ // If building for win32...
45 //----------------------------------------------------------------------
46 // This gets run when the DLL is loaded. We just need to save a handle.
47 //----------------------------------------------------------------------
50 HINSTANCE hinstDLL
, // handle to DLL module
51 DWORD fdwReason
, // reason for calling function
52 LPVOID lpvReserved
// reserved
55 wxSetInstance(hinstDLL
);
60 //----------------------------------------------------------------------
61 // Class for implementing the wxp main application shell.
62 //----------------------------------------------------------------------
64 wxPyApp
*wxPythonApp
= NULL
; // Global instance of application object
68 // printf("**** ctor\n");
72 // printf("**** dtor\n");
76 // This one isn't acutally called... See __wxStart()
77 bool wxPyApp::OnInit(void) {
81 int wxPyApp::MainLoop(void) {
82 int retval
= wxApp::MainLoop();
84 wxPythonApp
->OnExit(); //#
89 //# void wxPyApp::AfterMainLoop(void) {
90 // // more stuff from wxEntry...
92 // if (wxPythonApp->GetTopWindow()) {
93 // // Forcibly delete the window.
94 // if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) ||
95 // wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) {
97 // wxPythonApp->GetTopWindow()->Close(TRUE);
98 // wxPythonApp->DeletePendingObjects();
101 // delete wxPythonApp->GetTopWindow();
102 // wxPythonApp->SetTopWindow(NULL);
106 // wxPythonApp->DeletePendingObjects();
109 // wxPythonApp->OnExit();
111 // // delete wxPythonApp;
115 //---------------------------------------------------------------------
116 // a few native methods to add to the module
117 //----------------------------------------------------------------------
120 // This is where we pick up the first part of the wxEntry functionality...
121 // The rest is in __wxStart and AfterMainLoop. This function is called when
122 // wxcmodule is imported. (Before there is a wxApp object.)
125 #ifdef WXP_WITH_THREAD
126 PyEval_InitThreads();
129 // Bail out if there is already windows created. This means that the
130 // toolkit has already been initialized, as in embedding wxPython in
131 // a C++ wxWindows app.
132 if (wxTopLevelWindows
.Number() > 0)
140 PyObject
* sysargv
= PySys_GetObject("argv");
141 int argc
= PyList_Size(sysargv
);
142 char** argv
= new char*[argc
+1];
144 for(x
=0; x
<argc
; x
++)
145 argv
[x
] = PyString_AsString(PyList_GetItem(sysargv
, x
));
150 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
152 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
154 gtk_init( &argc
, &argv
);
155 wxSetDetectableAutoRepeat( TRUE
);
158 wxApp::Initialize(); // may return FALSE. Should we check?
164 #ifdef WXP_WITH_THREAD
165 PyThreadState
* wxPyEventThreadState
= NULL
;
167 static char* __nullArgv
[1] = { 0 };
171 // Start the user application, user App's OnInit method is a parameter here
172 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
174 PyObject
* onInitFunc
= NULL
;
179 #ifdef WXP_WITH_THREAD
180 wxPyEventThreadState
= PyThreadState_Get();
183 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
186 if (wxTopLevelWindows
.Number() > 0) {
187 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
192 // This is the next part of the wxEntry functionality...
193 wxPythonApp
->argc
= 0;
194 wxPythonApp
->argv
= NULL
;
195 wxPythonApp
->OnInitGui();
198 // Call the Python App's OnInit function
199 arglist
= PyTuple_New(0);
200 result
= PyEval_CallObject(onInitFunc
, arglist
);
201 if (!result
) { // an exception was raised.
205 if (! PyInt_Check(result
)) {
206 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
209 bResult
= PyInt_AS_LONG(result
);
211 PyErr_SetString(PyExc_SystemExit
, "OnInit returned false, exiting...");
216 wxTheApp
->m_initialized
= (wxTopLevelWindows
.Number() > 0);
227 PyObject
* wxPython_dict
;
228 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
231 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
234 if (!PyDict_Check(wxPython_dict
)) {
235 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
239 #define wxPlatform "__WXMOTIF__"
242 #define wxPlatform "__WXQT__"
245 #define wxPlatform "__WXGTK__"
247 #if defined(__WIN32__) || defined(__WXMSW__)
248 #define wxPlatform "__WXMSW__"
251 #define wxPlatform "__WXMAC__"
254 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
261 //---------------------------------------------------------------------------
263 PyObject
* wxPyConstructObject(void* ptr
, const char* className
) {
264 char buff
[64]; // should always be big enough...
267 sprintf(buff
, "_%s_p", className
);
268 SWIG_MakePtr(swigptr
, ptr
, buff
);
270 sprintf(buff
, "%sPtr", className
);
271 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
277 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
278 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
284 //---------------------------------------------------------------------------
286 static unsigned int _wxPyNestCount
= 0;
288 static PyThreadState
* myPyThreadState_Get() {
289 PyThreadState
* current
;
290 current
= PyThreadState_Swap(NULL
);
291 PyThreadState_Swap(current
);
296 HELPEREXPORT
bool wxPyRestoreThread() {
297 // NOTE: The Python API docs state that if a thread already has the
298 // interpreter lock and calls PyEval_RestoreThread again a deadlock
299 // occurs, so I put in this code as a guard condition since there are
300 // many possibilites for nested events and callbacks in wxPython. If
301 // The current thread is our thread, then we can assume that we
302 // already have the lock. (I hope!)
304 #ifdef WXP_WITH_THREAD
306 if (wxPyEventThreadState
!= myPyThreadState_Get()) {
307 PyEval_RestoreThread(wxPyEventThreadState
);
316 HELPEREXPORT
void wxPySaveThread(bool doSave
) {
317 #ifdef WXP_WITH_THREAD
319 wxPyEventThreadState
= PyEval_SaveThread();
325 //---------------------------------------------------------------------------
328 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback
, wxObject
);
330 wxPyCallback::wxPyCallback(PyObject
* func
) {
335 wxPyCallback::wxPyCallback(const wxPyCallback
& other
) {
336 m_func
= other
.m_func
;
340 wxPyCallback::~wxPyCallback() {
341 bool doSave
= wxPyRestoreThread();
343 wxPySaveThread(doSave
);
348 // This function is used for all events destined for Python event handlers.
349 void wxPyCallback::EventThunker(wxEvent
& event
) {
350 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
351 PyObject
* func
= cb
->m_func
;
357 bool doSave
= wxPyRestoreThread();
358 wxString className
= event
.GetClassInfo()->GetClassName();
360 if (className
== "wxPyEvent")
361 arg
= ((wxPyEvent
*)&event
)->GetSelf();
362 else if (className
== "wxPyCommandEvent")
363 arg
= ((wxPyCommandEvent
*)&event
)->GetSelf();
365 arg
= wxPyConstructObject((void*)&event
, className
);
367 tuple
= PyTuple_New(1);
368 PyTuple_SET_ITEM(tuple
, 0, arg
);
369 result
= PyEval_CallObject(func
, tuple
);
377 wxPySaveThread(doSave
);
381 //----------------------------------------------------------------------
383 wxPyCallbackHelper::wxPyCallbackHelper() {
390 wxPyCallbackHelper::~wxPyCallbackHelper() {
391 bool doSave
= wxPyRestoreThread();
394 wxPySaveThread(doSave
);
397 wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper
& other
) {
399 m_self
= other
.m_self
;
405 void wxPyCallbackHelper::setSelf(PyObject
* self
, int incref
) {
413 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
415 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
416 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
418 return m_lastFound
!= NULL
;
422 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
426 result
= callCallbackObj(argTuple
);
427 if (result
) { // Assumes an integer return type...
428 retval
= PyInt_AsLong(result
);
430 PyErr_Clear(); // forget about it if it's not...
435 // Invoke the Python callable object, returning the raw PyObject return
436 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
437 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
440 result
= PyEval_CallObject(m_lastFound
, argTuple
);
450 //---------------------------------------------------------------------------
451 //---------------------------------------------------------------------------
452 // These classes can be derived from in Python and passed through the event
453 // system without loosing anything. They do this by keeping a reference to
454 // themselves and some special case handling in wxPyCallback::EventThunker.
457 wxPyEvtSelfRef::wxPyEvtSelfRef() {
458 //m_self = Py_None; // **** We don't do normal ref counting to prevent
459 //Py_INCREF(m_self); // circular loops...
463 wxPyEvtSelfRef::~wxPyEvtSelfRef() {
464 bool doSave
= wxPyRestoreThread();
467 wxPySaveThread(doSave
);
470 void wxPyEvtSelfRef::SetSelf(PyObject
* self
, bool clone
) {
471 bool doSave
= wxPyRestoreThread();
479 wxPySaveThread(doSave
);
482 PyObject
* wxPyEvtSelfRef::GetSelf() const {
488 wxPyEvent::wxPyEvent(int id
)
492 wxPyEvent::~wxPyEvent() {
495 // This one is so the event object can be Cloned...
496 void wxPyEvent::CopyObject(wxObject
& dest
) const {
497 wxEvent::CopyObject(dest
);
498 ((wxPyEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
502 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxEvent
);
505 wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType
, int id
)
506 : wxCommandEvent(commandType
, id
) {
509 wxPyCommandEvent::~wxPyCommandEvent() {
512 void wxPyCommandEvent::CopyObject(wxObject
& dest
) const {
513 wxCommandEvent::CopyObject(dest
);
514 ((wxPyCommandEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
518 IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent
, wxCommandEvent
);
522 //---------------------------------------------------------------------------
523 //---------------------------------------------------------------------------
526 wxPyTimer::wxPyTimer(PyObject
* callback
) {
531 wxPyTimer::~wxPyTimer() {
532 bool doSave
= wxPyRestoreThread();
534 wxPySaveThread(doSave
);
537 void wxPyTimer::Notify() {
538 bool doSave
= wxPyRestoreThread();
541 PyObject
* args
= Py_BuildValue("()");
543 result
= PyEval_CallObject(func
, args
);
551 wxPySaveThread(doSave
);
556 //---------------------------------------------------------------------------
557 //---------------------------------------------------------------------------
558 // Convert a wxList to a Python List
560 PyObject
* wxPy_ConvertList(wxListBase
* list
, const char* className
) {
564 wxNode
* node
= list
->First();
566 bool doSave
= wxPyRestoreThread();
567 pyList
= PyList_New(0);
569 wxObj
= node
->Data();
570 pyObj
= wxPyConstructObject(wxObj
, className
);
571 PyList_Append(pyList
, pyObj
);
574 wxPySaveThread(doSave
);
578 //----------------------------------------------------------------------
579 // Some helper functions for typemaps in my_typemaps.i, so they won't be
580 // included in every file...
583 byte
* byte_LIST_helper(PyObject
* source
) {
584 if (!PyList_Check(source
)) {
585 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
588 int count
= PyList_Size(source
);
589 byte
* temp
= new byte
[count
];
591 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
594 for (int x
=0; x
<count
; x
++) {
595 PyObject
* o
= PyList_GetItem(source
, x
);
596 if (! PyInt_Check(o
)) {
597 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
600 temp
[x
] = (byte
)PyInt_AsLong(o
);
606 int* int_LIST_helper(PyObject
* source
) {
607 if (!PyList_Check(source
)) {
608 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
611 int count
= PyList_Size(source
);
612 int* temp
= new int[count
];
614 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
617 for (int x
=0; x
<count
; x
++) {
618 PyObject
* o
= PyList_GetItem(source
, x
);
619 if (! PyInt_Check(o
)) {
620 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
623 temp
[x
] = PyInt_AsLong(o
);
629 long* long_LIST_helper(PyObject
* source
) {
630 if (!PyList_Check(source
)) {
631 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
634 int count
= PyList_Size(source
);
635 long* temp
= new long[count
];
637 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
640 for (int x
=0; x
<count
; x
++) {
641 PyObject
* o
= PyList_GetItem(source
, x
);
642 if (! PyInt_Check(o
)) {
643 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
646 temp
[x
] = PyInt_AsLong(o
);
652 char** string_LIST_helper(PyObject
* source
) {
653 if (!PyList_Check(source
)) {
654 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
657 int count
= PyList_Size(source
);
658 char** temp
= new char*[count
];
660 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
663 for (int x
=0; x
<count
; x
++) {
664 PyObject
* o
= PyList_GetItem(source
, x
);
665 if (! PyString_Check(o
)) {
666 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
669 temp
[x
] = PyString_AsString(o
);
676 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
677 if (!PyList_Check(source
)) {
678 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
681 int count
= PyList_Size(source
);
682 wxPoint
* temp
= new wxPoint
[count
];
684 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
687 for (int x
=0; x
<count
; x
++) {
688 PyObject
* o
= PyList_GetItem(source
, x
);
689 if (PyTuple_Check(o
)) {
690 PyObject
* o1
= PyTuple_GetItem(o
, 0);
691 PyObject
* o2
= PyTuple_GetItem(o
, 1);
693 temp
[x
].x
= PyInt_AsLong(o1
);
694 temp
[x
].y
= PyInt_AsLong(o2
);
696 else if (PyInstance_Check(o
)) {
698 if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) {
699 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
705 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
713 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
714 if (!PyList_Check(source
)) {
715 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
718 int count
= PyList_Size(source
);
719 wxBitmap
** temp
= new wxBitmap
*[count
];
721 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
724 for (int x
=0; x
<count
; x
++) {
725 PyObject
* o
= PyList_GetItem(source
, x
);
726 if (PyInstance_Check(o
)) {
728 if (SWIG_GetPtrObj(o
, (void **) &pt
,"_wxBitmap_p")) {
729 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
735 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
744 wxString
* wxString_LIST_helper(PyObject
* source
) {
745 if (!PyList_Check(source
)) {
746 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
749 int count
= PyList_Size(source
);
750 wxString
* temp
= new wxString
[count
];
752 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
755 for (int x
=0; x
<count
; x
++) {
756 PyObject
* o
= PyList_GetItem(source
, x
);
757 if (! PyString_Check(o
)) {
758 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
761 temp
[x
] = PyString_AsString(o
);
767 wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
768 if (!PyList_Check(source
)) {
769 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
772 int count
= PyList_Size(source
);
773 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
775 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
778 for (int x
=0; x
<count
; x
++) {
779 PyObject
* o
= PyList_GetItem(source
, x
);
780 if (PyInstance_Check(o
)) {
781 wxAcceleratorEntry
* ae
;
782 if (SWIG_GetPtrObj(o
, (void **) &ae
,"_wxAcceleratorEntry_p")) {
783 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
788 else if (PyTuple_Check(o
)) {
789 PyObject
* o1
= PyTuple_GetItem(o
, 0);
790 PyObject
* o2
= PyTuple_GetItem(o
, 1);
791 PyObject
* o3
= PyTuple_GetItem(o
, 2);
793 temp
[x
].m_flags
= PyInt_AsLong(o1
);
794 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
795 temp
[x
].m_command
= PyInt_AsLong(o3
);
798 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
807 //----------------------------------------------------------------------
809 bool wxSize_helper(PyObject
* source
, wxSize
** obj
) {
811 // If source is an object instance then it may already be the right type
812 if (PyInstance_Check(source
)) {
814 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxSize_p"))
819 // otherwise a 2-tuple of integers is expected
820 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
821 PyObject
* o1
= PySequence_GetItem(source
, 0);
822 PyObject
* o2
= PySequence_GetItem(source
, 1);
823 **obj
= wxSize(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
828 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxSize object.");
832 bool wxPoint_helper(PyObject
* source
, wxPoint
** obj
) {
834 // If source is an object instance then it may already be the right type
835 if (PyInstance_Check(source
)) {
837 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxPoint_p"))
842 // otherwise a 2-tuple of integers is expected
843 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
844 PyObject
* o1
= PySequence_GetItem(source
, 0);
845 PyObject
* o2
= PySequence_GetItem(source
, 1);
846 **obj
= wxPoint(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
851 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxPoint object.");
857 bool wxRealPoint_helper(PyObject
* source
, wxRealPoint
** obj
) {
859 // If source is an object instance then it may already be the right type
860 if (PyInstance_Check(source
)) {
862 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRealPoint_p"))
867 // otherwise a 2-tuple of floats is expected
868 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
869 PyObject
* o1
= PySequence_GetItem(source
, 0);
870 PyObject
* o2
= PySequence_GetItem(source
, 1);
871 **obj
= wxRealPoint(PyFloat_AsDouble(o1
), PyFloat_AsDouble(o2
));
876 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of floats or a wxRealPoint object.");
883 bool wxRect_helper(PyObject
* source
, wxRect
** obj
) {
885 // If source is an object instance then it may already be the right type
886 if (PyInstance_Check(source
)) {
888 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRect_p"))
893 // otherwise a 4-tuple of integers is expected
894 else if (PySequence_Check(source
) && PyObject_Length(source
) == 4) {
895 PyObject
* o1
= PySequence_GetItem(source
, 0);
896 PyObject
* o2
= PySequence_GetItem(source
, 1);
897 PyObject
* o3
= PySequence_GetItem(source
, 2);
898 PyObject
* o4
= PySequence_GetItem(source
, 3);
899 **obj
= wxRect(PyInt_AsLong(o1
), PyInt_AsLong(o2
),
900 PyInt_AsLong(o3
), PyInt_AsLong(o4
));
905 PyErr_SetString(PyExc_TypeError
, "Expected a 4-tuple of integers or a wxRect object.");
911 //----------------------------------------------------------------------
912 //----------------------------------------------------------------------
913 //----------------------------------------------------------------------