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 wxEntryStart( int argc
, char *argv
[] );
109 int wxEntryInitGui();
110 void 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)
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
));
144 /* GTK 1.2 up to version 1.2.3 has broken threads */
145 if ((gtk_major_version
== 1) &&
146 (gtk_minor_version
== 2) &&
147 (gtk_micro_version
< 4))
149 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
160 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
162 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
166 gtk_init( &argc
, &argv
);
167 wxSetDetectableAutoRepeat( TRUE
);
170 if (!wxApp::Initialize())
178 PyObject
* sysargv
= PySys_GetObject("argv");
179 int argc
= PyList_Size(sysargv
);
180 char** argv
= new char*[argc
+1];
182 for(x
=0; x
<argc
; x
++)
183 argv
[x
] = PyString_AsString(PyList_GetItem(sysargv
, x
));
186 wxEntryStart(argc
, argv
);
191 #ifdef WXP_WITH_THREAD
192 PyThreadState
* wxPyEventThreadState
= NULL
;
194 static char* __nullArgv
[1] = { 0 };
198 // Start the user application, user App's OnInit method is a parameter here
199 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
201 PyObject
* onInitFunc
= NULL
;
206 #ifdef WXP_WITH_THREAD
207 wxPyEventThreadState
= PyThreadState_Get();
210 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
213 if (wxTopLevelWindows
.Number() > 0) {
214 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
219 // This is the next part of the wxEntry functionality...
220 wxPythonApp
->argc
= 0;
221 wxPythonApp
->argv
= NULL
;
225 // Call the Python App's OnInit function
226 arglist
= PyTuple_New(0);
227 result
= PyEval_CallObject(onInitFunc
, arglist
);
228 if (!result
) { // an exception was raised.
232 if (! PyInt_Check(result
)) {
233 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
236 bResult
= PyInt_AS_LONG(result
);
238 PyErr_SetString(PyExc_SystemExit
, "OnInit returned FALSE, exiting...");
243 wxTheApp
->m_initialized
= (wxTopLevelWindows
.GetCount() > 0);
256 PyObject
* wxPython_dict
;
257 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
260 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
263 if (!PyDict_Check(wxPython_dict
)) {
264 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
268 #define wxPlatform "__WXMOTIF__"
271 #define wxPlatform "__WXQT__"
274 #define wxPlatform "__WXGTK__"
276 #if defined(__WIN32__) || defined(__WXMSW__)
277 #define wxPlatform "__WXMSW__"
280 #define wxPlatform "__WXMAC__"
283 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
290 //---------------------------------------------------------------------------
292 PyObject
* wxPyConstructObject(void* ptr
, const char* className
) {
293 char buff
[64]; // should always be big enough...
296 sprintf(buff
, "_%s_p", className
);
297 SWIG_MakePtr(swigptr
, ptr
, buff
);
299 sprintf(buff
, "%sPtr", className
);
300 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
306 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
307 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
313 //---------------------------------------------------------------------------
315 static unsigned int _wxPyNestCount
= 0;
317 static PyThreadState
* myPyThreadState_Get() {
318 PyThreadState
* current
;
319 current
= PyThreadState_Swap(NULL
);
320 PyThreadState_Swap(current
);
325 HELPEREXPORT
bool wxPyRestoreThread() {
326 // NOTE: The Python API docs state that if a thread already has the
327 // interpreter lock and calls PyEval_RestoreThread again a deadlock
328 // occurs, so I put in this code as a guard condition since there are
329 // many possibilites for nested events and callbacks in wxPython. If
330 // The current thread is our thread, then we can assume that we
331 // already have the lock. (I hope!)
333 #ifdef WXP_WITH_THREAD
335 if (wxPyEventThreadState
!= myPyThreadState_Get()) {
336 PyEval_RestoreThread(wxPyEventThreadState
);
345 HELPEREXPORT
void wxPySaveThread(bool doSave
) {
346 #ifdef WXP_WITH_THREAD
348 wxPyEventThreadState
= PyEval_SaveThread();
354 //---------------------------------------------------------------------------
357 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback
, wxObject
);
359 wxPyCallback::wxPyCallback(PyObject
* func
) {
364 wxPyCallback::wxPyCallback(const wxPyCallback
& other
) {
365 m_func
= other
.m_func
;
369 wxPyCallback::~wxPyCallback() {
370 bool doSave
= wxPyRestoreThread();
372 wxPySaveThread(doSave
);
377 // This function is used for all events destined for Python event handlers.
378 void wxPyCallback::EventThunker(wxEvent
& event
) {
379 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
380 PyObject
* func
= cb
->m_func
;
386 bool doSave
= wxPyRestoreThread();
387 wxString className
= event
.GetClassInfo()->GetClassName();
389 if (className
== "wxPyEvent")
390 arg
= ((wxPyEvent
*)&event
)->GetSelf();
391 else if (className
== "wxPyCommandEvent")
392 arg
= ((wxPyCommandEvent
*)&event
)->GetSelf();
394 arg
= wxPyConstructObject((void*)&event
, className
);
396 tuple
= PyTuple_New(1);
397 PyTuple_SET_ITEM(tuple
, 0, arg
);
398 result
= PyEval_CallObject(func
, tuple
);
406 wxPySaveThread(doSave
);
410 //----------------------------------------------------------------------
412 wxPyCallbackHelper::wxPyCallbackHelper() {
419 wxPyCallbackHelper::~wxPyCallbackHelper() {
420 bool doSave
= wxPyRestoreThread();
423 wxPySaveThread(doSave
);
426 wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper
& other
) {
428 m_self
= other
.m_self
;
434 void wxPyCallbackHelper::setSelf(PyObject
* self
, int incref
) {
442 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
444 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
445 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
447 return m_lastFound
!= NULL
;
451 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
455 result
= callCallbackObj(argTuple
);
456 if (result
) { // Assumes an integer return type...
457 retval
= PyInt_AsLong(result
);
459 PyErr_Clear(); // forget about it if it's not...
464 // Invoke the Python callable object, returning the raw PyObject return
465 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
466 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
469 result
= PyEval_CallObject(m_lastFound
, argTuple
);
479 //---------------------------------------------------------------------------
480 //---------------------------------------------------------------------------
481 // These classes can be derived from in Python and passed through the event
482 // system without loosing anything. They do this by keeping a reference to
483 // themselves and some special case handling in wxPyCallback::EventThunker.
486 wxPyEvtSelfRef::wxPyEvtSelfRef() {
487 //m_self = Py_None; // **** We don't do normal ref counting to prevent
488 //Py_INCREF(m_self); // circular loops...
492 wxPyEvtSelfRef::~wxPyEvtSelfRef() {
493 bool doSave
= wxPyRestoreThread();
496 wxPySaveThread(doSave
);
499 void wxPyEvtSelfRef::SetSelf(PyObject
* self
, bool clone
) {
500 bool doSave
= wxPyRestoreThread();
508 wxPySaveThread(doSave
);
511 PyObject
* wxPyEvtSelfRef::GetSelf() const {
517 wxPyEvent::wxPyEvent(int id
)
521 wxPyEvent::~wxPyEvent() {
524 // This one is so the event object can be Cloned...
525 void wxPyEvent::CopyObject(wxObject
& dest
) const {
526 wxEvent::CopyObject(dest
);
527 ((wxPyEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
531 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxEvent
);
534 wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType
, int id
)
535 : wxCommandEvent(commandType
, id
) {
538 wxPyCommandEvent::~wxPyCommandEvent() {
541 void wxPyCommandEvent::CopyObject(wxObject
& dest
) const {
542 wxCommandEvent::CopyObject(dest
);
543 ((wxPyCommandEvent
*)&dest
)->SetSelf(m_self
, TRUE
);
547 IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent
, wxCommandEvent
);
551 //---------------------------------------------------------------------------
552 //---------------------------------------------------------------------------
555 wxPyTimer::wxPyTimer(PyObject
* callback
) {
560 wxPyTimer::~wxPyTimer() {
561 bool doSave
= wxPyRestoreThread();
563 wxPySaveThread(doSave
);
566 void wxPyTimer::Notify() {
567 bool doSave
= wxPyRestoreThread();
570 PyObject
* args
= Py_BuildValue("()");
572 result
= PyEval_CallObject(func
, args
);
580 wxPySaveThread(doSave
);
585 //---------------------------------------------------------------------------
586 //---------------------------------------------------------------------------
587 // Convert a wxList to a Python List
589 PyObject
* wxPy_ConvertList(wxListBase
* list
, const char* className
) {
593 wxNode
* node
= list
->First();
595 bool doSave
= wxPyRestoreThread();
596 pyList
= PyList_New(0);
598 wxObj
= node
->Data();
599 pyObj
= wxPyConstructObject(wxObj
, className
);
600 PyList_Append(pyList
, pyObj
);
603 wxPySaveThread(doSave
);
607 //----------------------------------------------------------------------
609 long wxPyGetWinHandle(wxWindow
* win
) {
611 return (long)win
->GetHandle();
614 // Find and return the actual X-Window.
616 if (win
->m_wxwindow
) {
617 GdkWindowPrivate
* bwin
= (GdkWindowPrivate
*)GTK_PIZZA(win
->m_wxwindow
)->bin_window
;
619 return (long)bwin
->xwindow
;
626 //----------------------------------------------------------------------
627 // Some helper functions for typemaps in my_typemaps.i, so they won't be
628 // included in every file...
631 byte
* byte_LIST_helper(PyObject
* source
) {
632 if (!PyList_Check(source
)) {
633 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
636 int count
= PyList_Size(source
);
637 byte
* temp
= new byte
[count
];
639 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
642 for (int x
=0; x
<count
; x
++) {
643 PyObject
* o
= PyList_GetItem(source
, x
);
644 if (! PyInt_Check(o
)) {
645 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
648 temp
[x
] = (byte
)PyInt_AsLong(o
);
654 int* int_LIST_helper(PyObject
* source
) {
655 if (!PyList_Check(source
)) {
656 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
659 int count
= PyList_Size(source
);
660 int* temp
= new int[count
];
662 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
665 for (int x
=0; x
<count
; x
++) {
666 PyObject
* o
= PyList_GetItem(source
, x
);
667 if (! PyInt_Check(o
)) {
668 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
671 temp
[x
] = PyInt_AsLong(o
);
677 long* long_LIST_helper(PyObject
* source
) {
678 if (!PyList_Check(source
)) {
679 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
682 int count
= PyList_Size(source
);
683 long* temp
= new long[count
];
685 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
688 for (int x
=0; x
<count
; x
++) {
689 PyObject
* o
= PyList_GetItem(source
, x
);
690 if (! PyInt_Check(o
)) {
691 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
694 temp
[x
] = PyInt_AsLong(o
);
700 char** string_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 char** temp
= new char*[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 (! PyString_Check(o
)) {
714 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
717 temp
[x
] = PyString_AsString(o
);
724 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
725 if (!PyList_Check(source
)) {
726 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
729 int count
= PyList_Size(source
);
730 wxPoint
* temp
= new wxPoint
[count
];
732 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
735 for (int x
=0; x
<count
; x
++) {
736 PyObject
* o
= PyList_GetItem(source
, x
);
737 if (PyTuple_Check(o
)) {
738 PyObject
* o1
= PyTuple_GetItem(o
, 0);
739 PyObject
* o2
= PyTuple_GetItem(o
, 1);
741 temp
[x
].x
= PyInt_AsLong(o1
);
742 temp
[x
].y
= PyInt_AsLong(o2
);
744 else if (PyInstance_Check(o
)) {
746 if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) {
747 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
753 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
761 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
762 if (!PyList_Check(source
)) {
763 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
766 int count
= PyList_Size(source
);
767 wxBitmap
** temp
= new wxBitmap
*[count
];
769 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
772 for (int x
=0; x
<count
; x
++) {
773 PyObject
* o
= PyList_GetItem(source
, x
);
774 if (PyInstance_Check(o
)) {
776 if (SWIG_GetPtrObj(o
, (void **) &pt
,"_wxBitmap_p")) {
777 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
783 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
792 wxString
* wxString_LIST_helper(PyObject
* source
) {
793 if (!PyList_Check(source
)) {
794 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
797 int count
= PyList_Size(source
);
798 wxString
* temp
= new wxString
[count
];
800 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
803 for (int x
=0; x
<count
; x
++) {
804 PyObject
* o
= PyList_GetItem(source
, x
);
805 if (! PyString_Check(o
)) {
806 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
809 temp
[x
] = PyString_AsString(o
);
815 wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
816 if (!PyList_Check(source
)) {
817 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
820 int count
= PyList_Size(source
);
821 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
823 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
826 for (int x
=0; x
<count
; x
++) {
827 PyObject
* o
= PyList_GetItem(source
, x
);
828 if (PyInstance_Check(o
)) {
829 wxAcceleratorEntry
* ae
;
830 if (SWIG_GetPtrObj(o
, (void **) &ae
,"_wxAcceleratorEntry_p")) {
831 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
836 else if (PyTuple_Check(o
)) {
837 PyObject
* o1
= PyTuple_GetItem(o
, 0);
838 PyObject
* o2
= PyTuple_GetItem(o
, 1);
839 PyObject
* o3
= PyTuple_GetItem(o
, 2);
841 temp
[x
].m_flags
= PyInt_AsLong(o1
);
842 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
843 temp
[x
].m_command
= PyInt_AsLong(o3
);
846 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
855 //----------------------------------------------------------------------
857 bool wxSize_helper(PyObject
* source
, wxSize
** 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
, "_wxSize_p"))
867 // otherwise a 2-tuple of integers 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
= wxSize(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
876 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxSize object.");
880 bool wxPoint_helper(PyObject
* source
, wxPoint
** obj
) {
882 // If source is an object instance then it may already be the right type
883 if (PyInstance_Check(source
)) {
885 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxPoint_p"))
890 // otherwise a 2-tuple of integers is expected
891 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
892 PyObject
* o1
= PySequence_GetItem(source
, 0);
893 PyObject
* o2
= PySequence_GetItem(source
, 1);
894 **obj
= wxPoint(PyInt_AsLong(o1
), PyInt_AsLong(o2
));
899 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of integers or a wxPoint object.");
905 bool wxRealPoint_helper(PyObject
* source
, wxRealPoint
** obj
) {
907 // If source is an object instance then it may already be the right type
908 if (PyInstance_Check(source
)) {
910 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRealPoint_p"))
915 // otherwise a 2-tuple of floats is expected
916 else if (PySequence_Check(source
) && PyObject_Length(source
) == 2) {
917 PyObject
* o1
= PySequence_GetItem(source
, 0);
918 PyObject
* o2
= PySequence_GetItem(source
, 1);
919 **obj
= wxRealPoint(PyFloat_AsDouble(o1
), PyFloat_AsDouble(o2
));
924 PyErr_SetString(PyExc_TypeError
, "Expected a 2-tuple of floats or a wxRealPoint object.");
931 bool wxRect_helper(PyObject
* source
, wxRect
** obj
) {
933 // If source is an object instance then it may already be the right type
934 if (PyInstance_Check(source
)) {
936 if (SWIG_GetPtrObj(source
, (void **)&ptr
, "_wxRect_p"))
941 // otherwise a 4-tuple of integers is expected
942 else if (PySequence_Check(source
) && PyObject_Length(source
) == 4) {
943 PyObject
* o1
= PySequence_GetItem(source
, 0);
944 PyObject
* o2
= PySequence_GetItem(source
, 1);
945 PyObject
* o3
= PySequence_GetItem(source
, 2);
946 PyObject
* o4
= PySequence_GetItem(source
, 3);
947 **obj
= wxRect(PyInt_AsLong(o1
), PyInt_AsLong(o2
),
948 PyInt_AsLong(o3
), PyInt_AsLong(o4
));
953 PyErr_SetString(PyExc_TypeError
, "Expected a 4-tuple of integers or a wxRect object.");
959 //----------------------------------------------------------------------
960 //----------------------------------------------------------------------
961 //----------------------------------------------------------------------