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
30 #include <gdk/gdkprivate.h>
31 #include <wx/gtk/win_gtk.h>
32 //#include <gdk/gdk.h>
33 //#include <gdk/gdkx.h>
34 //#include <gtk/gtkwindow.h>
38 //---------------------------------------------------------------------------
40 //wxHashTable* wxPyWindows = NULL;
43 wxPoint wxPyDefaultPosition
; //wxDefaultPosition);
44 wxSize wxPyDefaultSize
; //wxDefaultSize);
45 wxString
wxPyEmptyStr("");
49 #ifdef __WXMSW__ // If building for win32...
50 //----------------------------------------------------------------------
51 // This gets run when the DLL is loaded. We just need to save a handle.
52 //----------------------------------------------------------------------
55 HINSTANCE hinstDLL
, // handle to DLL module
56 DWORD fdwReason
, // reason for calling function
57 LPVOID lpvReserved
// reserved
60 wxSetInstance(hinstDLL
);
65 //----------------------------------------------------------------------
66 // Class for implementing the wxp main application shell.
67 //----------------------------------------------------------------------
69 wxPyApp
*wxPythonApp
= NULL
; // Global instance of application object
73 // printf("**** ctor\n");
77 // printf("**** dtor\n");
81 // This one isn't acutally called... See __wxStart()
82 bool wxPyApp::OnInit(void) {
86 int wxPyApp::MainLoop(void) {
87 int retval
= wxApp::MainLoop();
89 wxPythonApp
->OnExit(); //#
94 //# void wxPyApp::AfterMainLoop(void) {
95 // // more stuff from wxEntry...
97 // if (wxPythonApp->GetTopWindow()) {
98 // // Forcibly delete the window.
99 // if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) ||
100 // wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) {
102 // wxPythonApp->GetTopWindow()->Close(TRUE);
103 // wxPythonApp->DeletePendingObjects();
106 // delete wxPythonApp->GetTopWindow();
107 // wxPythonApp->SetTopWindow(NULL);
111 // wxPythonApp->DeletePendingObjects();
114 // wxPythonApp->OnExit();
116 // // delete wxPythonApp;
120 //---------------------------------------------------------------------
121 // a few native methods to add to the module
122 //----------------------------------------------------------------------
125 // This is where we pick up the first part of the wxEntry functionality...
126 // The rest is in __wxStart and AfterMainLoop. This function is called when
127 // wxcmodule is imported. (Before there is a wxApp object.)
130 #ifdef WXP_WITH_THREAD
131 PyEval_InitThreads();
134 // Bail out if there is already windows created. This means that the
135 // toolkit has already been initialized, as in embedding wxPython in
136 // a C++ wxWindows app.
137 if (wxTopLevelWindows
.Number() > 0)
145 PyObject
* sysargv
= PySys_GetObject("argv");
146 int argc
= PyList_Size(sysargv
);
147 char** argv
= new char*[argc
+1];
149 for(x
=0; x
<argc
; x
++)
150 argv
[x
] = PyString_AsString(PyList_GetItem(sysargv
, x
));
155 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
157 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
159 gtk_init( &argc
, &argv
);
160 wxSetDetectableAutoRepeat( TRUE
);
163 wxApp::Initialize(); // may return FALSE. Should we check?
169 #ifdef WXP_WITH_THREAD
170 PyThreadState
* wxPyEventThreadState
= NULL
;
172 static char* __nullArgv
[1] = { 0 };
176 // Start the user application, user App's OnInit method is a parameter here
177 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
179 PyObject
* onInitFunc
= NULL
;
184 #ifdef WXP_WITH_THREAD
185 wxPyEventThreadState
= PyThreadState_Get();
188 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
191 if (wxTopLevelWindows
.Number() > 0) {
192 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
197 // This is the next part of the wxEntry functionality...
198 wxPythonApp
->argc
= 0;
199 wxPythonApp
->argv
= NULL
;
200 wxPythonApp
->OnInitGui();
203 // Call the Python App's OnInit function
204 arglist
= PyTuple_New(0);
205 result
= PyEval_CallObject(onInitFunc
, arglist
);
206 if (!result
) { // an exception was raised.
210 if (! PyInt_Check(result
)) {
211 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
214 bResult
= PyInt_AS_LONG(result
);
216 PyErr_SetString(PyExc_SystemExit
, "OnInit returned FALSE, exiting...");
221 wxTheApp
->m_initialized
= (wxTopLevelWindows
.Number() > 0);
232 PyObject
* wxPython_dict
;
233 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
236 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
239 if (!PyDict_Check(wxPython_dict
)) {
240 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
244 #define wxPlatform "__WXMOTIF__"
247 #define wxPlatform "__WXQT__"
250 #define wxPlatform "__WXGTK__"
252 #if defined(__WIN32__) || defined(__WXMSW__)
253 #define wxPlatform "__WXMSW__"
256 #define wxPlatform "__WXMAC__"
259 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
266 //---------------------------------------------------------------------------
268 PyObject
* wxPyConstructObject(void* ptr
, const char* className
) {
269 char buff
[64]; // should always be big enough...
272 sprintf(buff
, "_%s_p", className
);
273 SWIG_MakePtr(swigptr
, ptr
, buff
);
275 sprintf(buff
, "%sPtr", className
);
276 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
282 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
283 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
289 //---------------------------------------------------------------------------
291 static unsigned int _wxPyNestCount
= 0;
293 static PyThreadState
* myPyThreadState_Get() {
294 PyThreadState
* current
;
295 current
= PyThreadState_Swap(NULL
);
296 PyThreadState_Swap(current
);
301 HELPEREXPORT
bool wxPyRestoreThread() {
302 // NOTE: The Python API docs state that if a thread already has the
303 // interpreter lock and calls PyEval_RestoreThread again a deadlock
304 // occurs, so I put in this code as a guard condition since there are
305 // many possibilites for nested events and callbacks in wxPython. If
306 // The current thread is our thread, then we can assume that we
307 // already have the lock. (I hope!)
309 #ifdef WXP_WITH_THREAD
311 if (wxPyEventThreadState
!= myPyThreadState_Get()) {
312 PyEval_RestoreThread(wxPyEventThreadState
);
321 HELPEREXPORT
void wxPySaveThread(bool doSave
) {
322 #ifdef WXP_WITH_THREAD
324 wxPyEventThreadState
= PyEval_SaveThread();
330 //---------------------------------------------------------------------------
333 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback
, wxObject
);
335 wxPyCallback::wxPyCallback(PyObject
* func
) {
340 wxPyCallback::wxPyCallback(const wxPyCallback
& other
) {
341 m_func
= other
.m_func
;
345 wxPyCallback::~wxPyCallback() {
346 bool doSave
= wxPyRestoreThread();
348 wxPySaveThread(doSave
);
353 // This function is used for all events destined for Python event handlers.
354 void wxPyCallback::EventThunker(wxEvent
& event
) {
355 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
356 PyObject
* func
= cb
->m_func
;
362 bool doSave
= wxPyRestoreThread();
363 wxString className
= event
.GetClassInfo()->GetClassName();
365 if (className
== "wxPyEvent")
366 arg
= ((wxPyEvent
*)&event
)->GetSelf();
367 else if (className
== "wxPyCommandEvent")
368 arg
= ((wxPyCommandEvent
*)&event
)->GetSelf();
370 arg
= wxPyConstructObject((void*)&event
, className
);
372 tuple
= PyTuple_New(1);
373 PyTuple_SET_ITEM(tuple
, 0, arg
);
374 result
= PyEval_CallObject(func
, tuple
);
382 wxPySaveThread(doSave
);
386 //----------------------------------------------------------------------
388 wxPyCallbackHelper::wxPyCallbackHelper() {
395 wxPyCallbackHelper::~wxPyCallbackHelper() {
396 bool doSave
= wxPyRestoreThread();
399 wxPySaveThread(doSave
);
402 wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper
& other
) {
404 m_self
= other
.m_self
;
410 void wxPyCallbackHelper::setSelf(PyObject
* self
, int incref
) {
418 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
420 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
421 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
423 return m_lastFound
!= NULL
;
427 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
431 result
= callCallbackObj(argTuple
);
432 if (result
) { // Assumes an integer return type...
433 retval
= PyInt_AsLong(result
);
435 PyErr_Clear(); // forget about it if it's not...
440 // Invoke the Python callable object, returning the raw PyObject return
441 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
442 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
445 result
= PyEval_CallObject(m_lastFound
, argTuple
);
455 //---------------------------------------------------------------------------
456 //---------------------------------------------------------------------------
457 // These classes can be derived from in Python and passed through the event
458 // system without loosing anything. They do this by keeping a reference to
459 // themselves and some special case handling in wxPyCallback::EventThunker.
462 wxPyEvtSelfRef::wxPyEvtSelfRef() {
463 //m_self = Py_None; // **** We don't do normal ref counting to prevent
464 //Py_INCREF(m_self); // circular loops...
468 wxPyEvtSelfRef::~wxPyEvtSelfRef() {
469 bool doSave
= wxPyRestoreThread();
472 wxPySaveThread(doSave
);
475 void wxPyEvtSelfRef::SetSelf(PyObject
* self
, bool clone
) {
476 bool doSave
= wxPyRestoreThread();
484 wxPySaveThread(doSave
);
487 PyObject
* wxPyEvtSelfRef::GetSelf() const {
493 wxPyEvent::wxPyEvent(int id
)
497 wxPyEvent::~wxPyEvent() {
500 // This one is so the event object can be Cloned...
501 void wxPyEvent::CopyObject(wxObject
& dest
) const {
502 wxEvent::CopyObject(dest
);
503 ((wxPyEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
507 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxEvent
);
510 wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType
, int id
)
511 : wxCommandEvent(commandType
, id
) {
514 wxPyCommandEvent::~wxPyCommandEvent() {
517 void wxPyCommandEvent::CopyObject(wxObject
& dest
) const {
518 wxCommandEvent::CopyObject(dest
);
519 ((wxPyCommandEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
523 IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent
, wxCommandEvent
);
527 //---------------------------------------------------------------------------
528 //---------------------------------------------------------------------------
531 wxPyTimer::wxPyTimer(PyObject
* callback
) {
536 wxPyTimer::~wxPyTimer() {
537 bool doSave
= wxPyRestoreThread();
539 wxPySaveThread(doSave
);
542 void wxPyTimer::Notify() {
543 bool doSave
= wxPyRestoreThread();
546 PyObject
* args
= Py_BuildValue("()");
548 result
= PyEval_CallObject(func
, args
);
556 wxPySaveThread(doSave
);
561 //---------------------------------------------------------------------------
562 //---------------------------------------------------------------------------
563 // Convert a wxList to a Python List
565 PyObject
* wxPy_ConvertList(wxListBase
* list
, const char* className
) {
569 wxNode
* node
= list
->First();
571 bool doSave
= wxPyRestoreThread();
572 pyList
= PyList_New(0);
574 wxObj
= node
->Data();
575 pyObj
= wxPyConstructObject(wxObj
, className
);
576 PyList_Append(pyList
, pyObj
);
579 wxPySaveThread(doSave
);
583 //----------------------------------------------------------------------
585 long wxPyGetWinHandle(wxWindow
* win
) {
587 return (long)win
->GetHandle();
590 // Find and return the actual X-Window.
592 if (win
->m_wxwindow
) {
593 GdkWindowPrivate
* bwin
= (GdkWindowPrivate
*)GTK_PIZZA(win
->m_wxwindow
)->bin_window
;
595 return (long)bwin
->xwindow
;
602 //----------------------------------------------------------------------
603 // Some helper functions for typemaps in my_typemaps.i, so they won't be
604 // included in every file...
607 byte
* byte_LIST_helper(PyObject
* source
) {
608 if (!PyList_Check(source
)) {
609 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
612 int count
= PyList_Size(source
);
613 byte
* temp
= new byte
[count
];
615 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
618 for (int x
=0; x
<count
; x
++) {
619 PyObject
* o
= PyList_GetItem(source
, x
);
620 if (! PyInt_Check(o
)) {
621 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
624 temp
[x
] = (byte
)PyInt_AsLong(o
);
630 int* int_LIST_helper(PyObject
* source
) {
631 if (!PyList_Check(source
)) {
632 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
635 int count
= PyList_Size(source
);
636 int* temp
= new int[count
];
638 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
641 for (int x
=0; x
<count
; x
++) {
642 PyObject
* o
= PyList_GetItem(source
, x
);
643 if (! PyInt_Check(o
)) {
644 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
647 temp
[x
] = PyInt_AsLong(o
);
653 long* long_LIST_helper(PyObject
* source
) {
654 if (!PyList_Check(source
)) {
655 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
658 int count
= PyList_Size(source
);
659 long* temp
= new long[count
];
661 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
664 for (int x
=0; x
<count
; x
++) {
665 PyObject
* o
= PyList_GetItem(source
, x
);
666 if (! PyInt_Check(o
)) {
667 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
670 temp
[x
] = PyInt_AsLong(o
);
676 char** string_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 char** temp
= new char*[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 (! PyString_Check(o
)) {
690 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
693 temp
[x
] = PyString_AsString(o
);
700 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
701 if (!PyList_Check(source
)) {
702 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
705 int count
= PyList_Size(source
);
706 wxPoint
* temp
= new wxPoint
[count
];
708 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
711 for (int x
=0; x
<count
; x
++) {
712 PyObject
* o
= PyList_GetItem(source
, x
);
713 if (PyTuple_Check(o
)) {
714 PyObject
* o1
= PyTuple_GetItem(o
, 0);
715 PyObject
* o2
= PyTuple_GetItem(o
, 1);
717 temp
[x
].x
= PyInt_AsLong(o1
);
718 temp
[x
].y
= PyInt_AsLong(o2
);
720 else if (PyInstance_Check(o
)) {
722 if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) {
723 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
729 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
737 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
738 if (!PyList_Check(source
)) {
739 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
742 int count
= PyList_Size(source
);
743 wxBitmap
** temp
= new wxBitmap
*[count
];
745 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
748 for (int x
=0; x
<count
; x
++) {
749 PyObject
* o
= PyList_GetItem(source
, x
);
750 if (PyInstance_Check(o
)) {
752 if (SWIG_GetPtrObj(o
, (void **) &pt
,"_wxBitmap_p")) {
753 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
759 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
768 wxString
* wxString_LIST_helper(PyObject
* source
) {
769 if (!PyList_Check(source
)) {
770 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
773 int count
= PyList_Size(source
);
774 wxString
* temp
= new wxString
[count
];
776 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
779 for (int x
=0; x
<count
; x
++) {
780 PyObject
* o
= PyList_GetItem(source
, x
);
781 if (! PyString_Check(o
)) {
782 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
785 temp
[x
] = PyString_AsString(o
);
791 wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
792 if (!PyList_Check(source
)) {
793 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
796 int count
= PyList_Size(source
);
797 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
799 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
802 for (int x
=0; x
<count
; x
++) {
803 PyObject
* o
= PyList_GetItem(source
, x
);
804 if (PyInstance_Check(o
)) {
805 wxAcceleratorEntry
* ae
;
806 if (SWIG_GetPtrObj(o
, (void **) &ae
,"_wxAcceleratorEntry_p")) {
807 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
812 else if (PyTuple_Check(o
)) {
813 PyObject
* o1
= PyTuple_GetItem(o
, 0);
814 PyObject
* o2
= PyTuple_GetItem(o
, 1);
815 PyObject
* o3
= PyTuple_GetItem(o
, 2);
817 temp
[x
].m_flags
= PyInt_AsLong(o1
);
818 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
819 temp
[x
].m_command
= PyInt_AsLong(o3
);
822 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
831 //----------------------------------------------------------------------
833 bool wxSize_helper(PyObject
* source
, wxSize
** obj
) {
835 // If source is an object instance then it may already be the right type
836 if (PyInstance_Check(source
)) {
838 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxSize_p"))
843 // otherwise a 2-tuple of integers is expected
844 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
845 PyObject
* o1
= PySequence_GetItem(source
, 0);
846 PyObject
* o2
= PySequence_GetItem(source
, 1);
847 **obj
= wxSize(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
852 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxSize object.");
856 bool wxPoint_helper(PyObject
* source
, wxPoint
** obj
) {
858 // If source is an object instance then it may already be the right type
859 if (PyInstance_Check(source
)) {
861 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxPoint_p"))
866 // otherwise a 2-tuple of integers is expected
867 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
868 PyObject
* o1
= PySequence_GetItem(source
, 0);
869 PyObject
* o2
= PySequence_GetItem(source
, 1);
870 **obj
= wxPoint(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
875 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxPoint object.");
881 bool wxRealPoint_helper(PyObject
* source
, wxRealPoint
** obj
) {
883 // If source is an object instance then it may already be the right type
884 if (PyInstance_Check(source
)) {
886 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRealPoint_p"))
891 // otherwise a 2-tuple of floats is expected
892 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
893 PyObject
* o1
= PySequence_GetItem(source
, 0);
894 PyObject
* o2
= PySequence_GetItem(source
, 1);
895 **obj
= wxRealPoint(PyFloat_AsDouble(o1
), PyFloat_AsDouble(o2
));
900 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of floats or a wxRealPoint object.");
907 bool wxRect_helper(PyObject
* source
, wxRect
** obj
) {
909 // If source is an object instance then it may already be the right type
910 if (PyInstance_Check(source
)) {
912 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRect_p"))
917 // otherwise a 4-tuple of integers is expected
918 else if (PySequence_Check(source
) && PyObject_Length(source
) == 4) {
919 PyObject
* o1
= PySequence_GetItem(source
, 0);
920 PyObject
* o2
= PySequence_GetItem(source
, 1);
921 PyObject
* o3
= PySequence_GetItem(source
, 2);
922 PyObject
* o4
= PySequence_GetItem(source
, 3);
923 **obj
= wxRect(PyInt_AsLong(o1
), PyInt_AsLong(o2
),
924 PyInt_AsLong(o3
), PyInt_AsLong(o4
));
929 PyErr_SetString(PyExc_TypeError
, "Expected a 4-tuple of integers or a wxRect object.");
935 //----------------------------------------------------------------------
936 //----------------------------------------------------------------------
937 //----------------------------------------------------------------------