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>
36 extern GtkWidget
*wxRootWindow
;
41 //---------------------------------------------------------------------------
43 //wxHashTable* wxPyWindows = NULL;
46 wxPoint wxPyDefaultPosition
; //wxDefaultPosition);
47 wxSize wxPyDefaultSize
; //wxDefaultSize);
48 wxString
wxPyEmptyStr("");
52 #ifdef __WXMSW__ // If building for win32...
53 //----------------------------------------------------------------------
54 // This gets run when the DLL is loaded. We just need to save a handle.
55 //----------------------------------------------------------------------
58 HINSTANCE hinstDLL
, // handle to DLL module
59 DWORD fdwReason
, // reason for calling function
60 LPVOID lpvReserved
// reserved
63 wxSetInstance(hinstDLL
);
68 //----------------------------------------------------------------------
69 // Class for implementing the wxp main application shell.
70 //----------------------------------------------------------------------
72 wxPyApp
*wxPythonApp
= NULL
; // Global instance of application object
76 // printf("**** ctor\n");
80 // printf("**** dtor\n");
84 // This one isn't acutally called... See __wxStart()
85 bool wxPyApp::OnInit(void) {
89 int wxPyApp::MainLoop(void) {
92 DeletePendingObjects();
94 m_initialized
= wxTopLevelWindows
.GetCount() != 0;
98 retval
= wxApp::MainLoop();
99 wxPythonApp
->OnExit();
105 //---------------------------------------------------------------------
106 //----------------------------------------------------------------------
108 int WXDLLEXPORT
wxEntryStart( int argc
, char** argv
);
109 int WXDLLEXPORT
wxEntryInitGui();
110 void WXDLLEXPORT
wxEntryCleanup();
113 // This is where we pick up the first part of the wxEntry functionality...
114 // The rest is in __wxStart and AfterMainLoop. This function is called when
115 // wxcmodule is imported. (Before there is a wxApp object.)
118 #ifdef WXP_WITH_THREAD
119 PyEval_InitThreads();
122 // Bail out if there is already windows created. This means that the
123 // toolkit has already been initialized, as in embedding wxPython in
124 // a C++ wxWindows app.
125 if (wxTopLevelWindows
.Number() > 0)
129 PyObject
* sysargv
= PySys_GetObject("argv");
130 int argc
= PyList_Size(sysargv
);
131 char** argv
= new char*[argc
+1];
133 for(x
=0; x
<argc
; x
++)
134 argv
[x
] = PyString_AsString(PyList_GetItem(sysargv
, x
));
137 wxEntryStart(argc
, argv
);
142 #ifdef WXP_WITH_THREAD
143 PyThreadState
* wxPyEventThreadState
= NULL
;
145 static char* __nullArgv
[1] = { 0 };
149 // Start the user application, user App's OnInit method is a parameter here
150 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
152 PyObject
* onInitFunc
= NULL
;
157 #ifdef WXP_WITH_THREAD
158 wxPyEventThreadState
= PyThreadState_Get();
161 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
164 if (wxTopLevelWindows
.Number() > 0) {
165 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
170 // This is the next part of the wxEntry functionality...
171 wxPythonApp
->argc
= 0;
172 wxPythonApp
->argv
= NULL
;
176 // Call the Python App's OnInit function
177 arglist
= PyTuple_New(0);
178 result
= PyEval_CallObject(onInitFunc
, arglist
);
179 if (!result
) { // an exception was raised.
183 if (! PyInt_Check(result
)) {
184 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
187 bResult
= PyInt_AS_LONG(result
);
189 PyErr_SetString(PyExc_SystemExit
, "OnInit returned FALSE, exiting...");
194 wxTheApp
->m_initialized
= (wxTopLevelWindows
.GetCount() > 0);
207 PyObject
* wxPython_dict
;
208 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
211 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
214 if (!PyDict_Check(wxPython_dict
)) {
215 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
219 #define wxPlatform "__WXMOTIF__"
222 #define wxPlatform "__WXQT__"
225 #define wxPlatform "__WXGTK__"
227 #if defined(__WIN32__) || defined(__WXMSW__)
228 #define wxPlatform "__WXMSW__"
231 #define wxPlatform "__WXMAC__"
234 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
241 //---------------------------------------------------------------------------
243 PyObject
* wxPyConstructObject(void* ptr
, const char* className
) {
244 char buff
[64]; // should always be big enough...
247 sprintf(buff
, "_%s_p", className
);
248 SWIG_MakePtr(swigptr
, ptr
, buff
);
250 sprintf(buff
, "%sPtr", className
);
251 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
257 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
258 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
264 //---------------------------------------------------------------------------
266 static unsigned int _wxPyNestCount
= 0;
268 static PyThreadState
* myPyThreadState_Get() {
269 PyThreadState
* current
;
270 current
= PyThreadState_Swap(NULL
);
271 PyThreadState_Swap(current
);
276 HELPEREXPORT
bool wxPyRestoreThread() {
277 // NOTE: The Python API docs state that if a thread already has the
278 // interpreter lock and calls PyEval_RestoreThread again a deadlock
279 // occurs, so I put in this code as a guard condition since there are
280 // many possibilites for nested events and callbacks in wxPython. If
281 // The current thread is our thread, then we can assume that we
282 // already have the lock. (I hope!)
284 #ifdef WXP_WITH_THREAD
286 if (wxPyEventThreadState
!= myPyThreadState_Get()) {
287 PyEval_RestoreThread(wxPyEventThreadState
);
296 HELPEREXPORT
void wxPySaveThread(bool doSave
) {
297 #ifdef WXP_WITH_THREAD
299 wxPyEventThreadState
= PyEval_SaveThread();
305 //---------------------------------------------------------------------------
308 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback
, wxObject
);
310 wxPyCallback::wxPyCallback(PyObject
* func
) {
315 wxPyCallback::wxPyCallback(const wxPyCallback
& other
) {
316 m_func
= other
.m_func
;
320 wxPyCallback::~wxPyCallback() {
321 bool doSave
= wxPyRestoreThread();
323 wxPySaveThread(doSave
);
328 // This function is used for all events destined for Python event handlers.
329 void wxPyCallback::EventThunker(wxEvent
& event
) {
330 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
331 PyObject
* func
= cb
->m_func
;
337 bool doSave
= wxPyRestoreThread();
338 wxString className
= event
.GetClassInfo()->GetClassName();
340 if (className
== "wxPyEvent")
341 arg
= ((wxPyEvent
*)&event
)->GetSelf();
342 else if (className
== "wxPyCommandEvent")
343 arg
= ((wxPyCommandEvent
*)&event
)->GetSelf();
345 arg
= wxPyConstructObject((void*)&event
, className
);
347 tuple
= PyTuple_New(1);
348 PyTuple_SET_ITEM(tuple
, 0, arg
);
349 result
= PyEval_CallObject(func
, tuple
);
357 wxPySaveThread(doSave
);
361 //----------------------------------------------------------------------
363 wxPyCallbackHelper::wxPyCallbackHelper() {
370 wxPyCallbackHelper::~wxPyCallbackHelper() {
371 bool doSave
= wxPyRestoreThread();
374 wxPySaveThread(doSave
);
377 wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper
& other
) {
379 m_self
= other
.m_self
;
385 void wxPyCallbackHelper::setSelf(PyObject
* self
, int incref
) {
393 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
395 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
396 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
398 return m_lastFound
!= NULL
;
402 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
406 result
= callCallbackObj(argTuple
);
407 if (result
) { // Assumes an integer return type...
408 retval
= PyInt_AsLong(result
);
410 PyErr_Clear(); // forget about it if it's not...
415 // Invoke the Python callable object, returning the raw PyObject return
416 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
417 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
420 result
= PyEval_CallObject(m_lastFound
, argTuple
);
430 //---------------------------------------------------------------------------
431 //---------------------------------------------------------------------------
432 // These classes can be derived from in Python and passed through the event
433 // system without loosing anything. They do this by keeping a reference to
434 // themselves and some special case handling in wxPyCallback::EventThunker.
437 wxPyEvtSelfRef::wxPyEvtSelfRef() {
438 //m_self = Py_None; // **** We don't do normal ref counting to prevent
439 //Py_INCREF(m_self); // circular loops...
443 wxPyEvtSelfRef::~wxPyEvtSelfRef() {
444 bool doSave
= wxPyRestoreThread();
447 wxPySaveThread(doSave
);
450 void wxPyEvtSelfRef::SetSelf(PyObject
* self
, bool clone
) {
451 bool doSave
= wxPyRestoreThread();
459 wxPySaveThread(doSave
);
462 PyObject
* wxPyEvtSelfRef::GetSelf() const {
468 wxPyEvent::wxPyEvent(int id
)
472 wxPyEvent::~wxPyEvent() {
475 // This one is so the event object can be Cloned...
476 void wxPyEvent::CopyObject(wxObject
& dest
) const {
477 wxEvent::CopyObject(dest
);
478 ((wxPyEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
482 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxEvent
);
485 wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType
, int id
)
486 : wxCommandEvent(commandType
, id
) {
489 wxPyCommandEvent::~wxPyCommandEvent() {
492 void wxPyCommandEvent::CopyObject(wxObject
& dest
) const {
493 wxCommandEvent::CopyObject(dest
);
494 ((wxPyCommandEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
498 IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent
, wxCommandEvent
);
502 //---------------------------------------------------------------------------
503 //---------------------------------------------------------------------------
506 wxPyTimer::wxPyTimer(PyObject
* callback
) {
511 wxPyTimer::~wxPyTimer() {
512 bool doSave
= wxPyRestoreThread();
514 wxPySaveThread(doSave
);
517 void wxPyTimer::Notify() {
518 bool doSave
= wxPyRestoreThread();
521 PyObject
* args
= Py_BuildValue("()");
523 result
= PyEval_CallObject(func
, args
);
531 wxPySaveThread(doSave
);
536 //---------------------------------------------------------------------------
537 //---------------------------------------------------------------------------
538 // Convert a wxList to a Python List
540 PyObject
* wxPy_ConvertList(wxListBase
* list
, const char* className
) {
544 wxNode
* node
= list
->First();
546 bool doSave
= wxPyRestoreThread();
547 pyList
= PyList_New(0);
549 wxObj
= node
->Data();
550 pyObj
= wxPyConstructObject(wxObj
, className
);
551 PyList_Append(pyList
, pyObj
);
554 wxPySaveThread(doSave
);
558 //----------------------------------------------------------------------
560 long wxPyGetWinHandle(wxWindow
* win
) {
562 return (long)win
->GetHandle();
565 // Find and return the actual X-Window.
567 if (win
->m_wxwindow
) {
568 GdkWindowPrivate
* bwin
= (GdkWindowPrivate
*)GTK_PIZZA(win
->m_wxwindow
)->bin_window
;
570 return (long)bwin
->xwindow
;
577 //----------------------------------------------------------------------
578 // Some helper functions for typemaps in my_typemaps.i, so they won't be
579 // included in every file...
582 byte
* byte_LIST_helper(PyObject
* source
) {
583 if (!PyList_Check(source
)) {
584 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
587 int count
= PyList_Size(source
);
588 byte
* temp
= new byte
[count
];
590 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
593 for (int x
=0; x
<count
; x
++) {
594 PyObject
* o
= PyList_GetItem(source
, x
);
595 if (! PyInt_Check(o
)) {
596 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
599 temp
[x
] = (byte
)PyInt_AsLong(o
);
605 int* int_LIST_helper(PyObject
* source
) {
606 if (!PyList_Check(source
)) {
607 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
610 int count
= PyList_Size(source
);
611 int* temp
= new int[count
];
613 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
616 for (int x
=0; x
<count
; x
++) {
617 PyObject
* o
= PyList_GetItem(source
, x
);
618 if (! PyInt_Check(o
)) {
619 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
622 temp
[x
] = PyInt_AsLong(o
);
628 long* long_LIST_helper(PyObject
* source
) {
629 if (!PyList_Check(source
)) {
630 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
633 int count
= PyList_Size(source
);
634 long* temp
= new long[count
];
636 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
639 for (int x
=0; x
<count
; x
++) {
640 PyObject
* o
= PyList_GetItem(source
, x
);
641 if (! PyInt_Check(o
)) {
642 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
645 temp
[x
] = PyInt_AsLong(o
);
651 char** string_LIST_helper(PyObject
* source
) {
652 if (!PyList_Check(source
)) {
653 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
656 int count
= PyList_Size(source
);
657 char** temp
= new char*[count
];
659 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
662 for (int x
=0; x
<count
; x
++) {
663 PyObject
* o
= PyList_GetItem(source
, x
);
664 if (! PyString_Check(o
)) {
665 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
668 temp
[x
] = PyString_AsString(o
);
675 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
676 if (!PyList_Check(source
)) {
677 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
680 int count
= PyList_Size(source
);
681 wxPoint
* temp
= new wxPoint
[count
];
683 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
686 for (int x
=0; x
<count
; x
++) {
687 PyObject
* o
= PyList_GetItem(source
, x
);
688 if (PyTuple_Check(o
)) {
689 PyObject
* o1
= PyTuple_GetItem(o
, 0);
690 PyObject
* o2
= PyTuple_GetItem(o
, 1);
692 temp
[x
].x
= PyInt_AsLong(o1
);
693 temp
[x
].y
= PyInt_AsLong(o2
);
695 else if (PyInstance_Check(o
)) {
697 if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) {
698 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
704 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
712 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
713 if (!PyList_Check(source
)) {
714 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
717 int count
= PyList_Size(source
);
718 wxBitmap
** temp
= new wxBitmap
*[count
];
720 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
723 for (int x
=0; x
<count
; x
++) {
724 PyObject
* o
= PyList_GetItem(source
, x
);
725 if (PyInstance_Check(o
)) {
727 if (SWIG_GetPtrObj(o
, (void **) &pt
,"_wxBitmap_p")) {
728 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
734 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
743 wxString
* wxString_LIST_helper(PyObject
* source
) {
744 if (!PyList_Check(source
)) {
745 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
748 int count
= PyList_Size(source
);
749 wxString
* temp
= new wxString
[count
];
751 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
754 for (int x
=0; x
<count
; x
++) {
755 PyObject
* o
= PyList_GetItem(source
, x
);
756 if (! PyString_Check(o
)) {
757 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
760 temp
[x
] = PyString_AsString(o
);
766 wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
767 if (!PyList_Check(source
)) {
768 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
771 int count
= PyList_Size(source
);
772 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
774 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
777 for (int x
=0; x
<count
; x
++) {
778 PyObject
* o
= PyList_GetItem(source
, x
);
779 if (PyInstance_Check(o
)) {
780 wxAcceleratorEntry
* ae
;
781 if (SWIG_GetPtrObj(o
, (void **) &ae
,"_wxAcceleratorEntry_p")) {
782 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
787 else if (PyTuple_Check(o
)) {
788 PyObject
* o1
= PyTuple_GetItem(o
, 0);
789 PyObject
* o2
= PyTuple_GetItem(o
, 1);
790 PyObject
* o3
= PyTuple_GetItem(o
, 2);
792 temp
[x
].m_flags
= PyInt_AsLong(o1
);
793 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
794 temp
[x
].m_command
= PyInt_AsLong(o3
);
797 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
806 //----------------------------------------------------------------------
808 bool wxSize_helper(PyObject
* source
, wxSize
** obj
) {
810 // If source is an object instance then it may already be the right type
811 if (PyInstance_Check(source
)) {
813 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxSize_p"))
818 // otherwise a 2-tuple of integers is expected
819 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
820 PyObject
* o1
= PySequence_GetItem(source
, 0);
821 PyObject
* o2
= PySequence_GetItem(source
, 1);
822 **obj
= wxSize(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
827 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxSize object.");
831 bool wxPoint_helper(PyObject
* source
, wxPoint
** obj
) {
833 // If source is an object instance then it may already be the right type
834 if (PyInstance_Check(source
)) {
836 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxPoint_p"))
841 // otherwise a 2-tuple of integers is expected
842 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
843 PyObject
* o1
= PySequence_GetItem(source
, 0);
844 PyObject
* o2
= PySequence_GetItem(source
, 1);
845 **obj
= wxPoint(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
850 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxPoint object.");
856 bool wxRealPoint_helper(PyObject
* source
, wxRealPoint
** 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
, "_wxRealPoint_p"))
866 // otherwise a 2-tuple of floats 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
= wxRealPoint(PyFloat_AsDouble(o1
), PyFloat_AsDouble(o2
));
875 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of floats or a wxRealPoint object.");
882 bool wxRect_helper(PyObject
* source
, wxRect
** obj
) {
884 // If source is an object instance then it may already be the right type
885 if (PyInstance_Check(source
)) {
887 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRect_p"))
892 // otherwise a 4-tuple of integers is expected
893 else if (PySequence_Check(source
) && PyObject_Length(source
) == 4) {
894 PyObject
* o1
= PySequence_GetItem(source
, 0);
895 PyObject
* o2
= PySequence_GetItem(source
, 1);
896 PyObject
* o3
= PySequence_GetItem(source
, 2);
897 PyObject
* o4
= PySequence_GetItem(source
, 3);
898 **obj
= wxRect(PyInt_AsLong(o1
), PyInt_AsLong(o2
),
899 PyInt_AsLong(o3
), PyInt_AsLong(o4
));
904 PyErr_SetString(PyExc_TypeError
, "Expected a 4-tuple of integers or a wxRect object.");
910 //----------------------------------------------------------------------
911 //----------------------------------------------------------------------
912 //----------------------------------------------------------------------