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();
87 void wxPyApp::AfterMainLoop(void) {
88 // more stuff from wxEntry...
90 if (wxPythonApp
->GetTopWindow()) {
91 // Forcibly delete the window.
92 if (wxPythonApp
->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame
)) ||
93 wxPythonApp
->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog
))) {
95 wxPythonApp
->GetTopWindow()->Close(TRUE
);
96 wxPythonApp
->DeletePendingObjects();
99 delete wxPythonApp
->GetTopWindow();
100 wxPythonApp
->SetTopWindow(NULL
);
104 wxPythonApp
->DeletePendingObjects();
107 wxPythonApp
->OnExit();
109 // delete wxPythonApp;
113 //---------------------------------------------------------------------
114 // a few native methods to add to the module
115 //----------------------------------------------------------------------
118 // This is where we pick up the first part of the wxEntry functionality...
119 // The rest is in __wxStart and AfterMainLoop. This function is called when
120 // wxpc is imported. (Before there is a wxApp object.)
123 // Bail out if there is already windows created. This means that the
124 // toolkit has already been initialized, as in embedding wxPython in
125 // a C++ wxWindows app.
126 if (wxTopLevelWindows
.Number() > 0)
134 PyObject
* sysargv
= PySys_GetObject("argv");
135 int argc
= PyList_Size(sysargv
);
136 char** argv
= new char*[argc
+1];
138 for(x
=0; x
<argc
; x
++)
139 argv
[x
] = PyString_AsString(PyList_GetItem(sysargv
, x
));
143 gtk_init( &argc
, &argv
);
146 wxApp::Initialize(); // may return FALSE. Should we check?
152 #ifdef WXP_WITH_THREAD
153 PyThreadState
* wxPyEventThreadState
= NULL
;
154 bool wxPyInEvent
= false;
156 static char* __nullArgv
[1] = { 0 };
158 // Start the user application, user App's OnInit method is a parameter here
159 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
161 PyObject
* onInitFunc
= NULL
;
166 #ifdef WXP_WITH_THREAD
167 wxPyEventThreadState
= PyThreadState_Get();
170 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
173 if (wxTopLevelWindows
.Number() > 0) {
174 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
179 // This is the next part of the wxEntry functionality...
180 wxPythonApp
->argc
= 0;
181 wxPythonApp
->argv
= NULL
;
182 wxPythonApp
->OnInitGui();
185 // Call the Python App's OnInit function
186 arglist
= PyTuple_New(0);
188 // Py_END_ALLOW_THREADS; **** __wxStart was called from Python,
189 // should already have the lock
190 result
= PyEval_CallObject(onInitFunc
, arglist
);
191 // Py_BEGIN_ALLOW_THREADS;
198 if (! PyInt_Check(result
)) {
199 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
202 bResult
= PyInt_AS_LONG(result
);
204 wxPythonApp
->DeletePendingObjects();
205 wxPythonApp
->OnExit();
207 PyErr_SetString(PyExc_SystemExit
, "OnInit returned false, exiting...");
212 wxTheApp
->m_initialized
= (wxTopLevelWindows
.Number() > 0);
223 PyObject
* wxPython_dict
;
224 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
227 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
230 if (!PyDict_Check(wxPython_dict
)) {
231 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
235 #define wxPlatform "__WXMOTIF__"
238 #define wxPlatform "__WXQT__"
241 #define wxPlatform "__WXGTK__"
243 #if defined(__WIN32__) || defined(__WXMSW__)
244 #define wxPlatform "__WXMSW__"
247 #define wxPlatform "__WXMAC__"
250 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
257 //---------------------------------------------------------------------------
261 PyObject
* wxPyConstructObject(void* ptr
, 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
);
285 wxPyCallback::wxPyCallback(PyObject
* func
) {
290 wxPyCallback::~wxPyCallback() {
291 #ifdef WXP_WITH_THREAD
293 PyEval_RestoreThread(wxPyEventThreadState
);
298 #ifdef WXP_WITH_THREAD
307 // This function is used for all events destined for Python event handlers.
308 void wxPyCallback::EventThunker(wxEvent
& event
) {
309 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
310 PyObject
* func
= cb
->m_func
;
316 #ifdef WXP_WITH_THREAD
317 PyEval_RestoreThread(wxPyEventThreadState
);
320 arg
= wxPyConstructObject((void*)&event
, event
.GetClassInfo()->GetClassName());
322 tuple
= PyTuple_New(1);
323 PyTuple_SET_ITEM(tuple
, 0, arg
);
324 result
= PyEval_CallObject(func
, tuple
);
332 #ifdef WXP_WITH_THREAD
339 //---------------------------------------------------------------------------
341 wxPyMenu::wxPyMenu(const wxString
& title
, PyObject
* _func
)
342 : wxMenu(title
, (wxFunction
)(func
? MenuCallback
: NULL
)), func(0) {
350 wxPyMenu::~wxPyMenu() {
351 #ifdef WXP_WITH_THREAD
353 PyEval_RestoreThread(wxPyEventThreadState
);
359 #ifdef WXP_WITH_THREAD
366 void wxPyMenu::MenuCallback(wxMenu
& menu
, wxCommandEvent
& evt
) {
373 #ifdef WXP_WITH_THREAD
374 PyEval_RestoreThread(wxPyEventThreadState
);
377 evtobj
= wxPyConstructObject((void*)&evt
, "wxCommandEvent");
378 menuobj
= wxPyConstructObject((void*)&menu
, "wxMenu");
379 if (PyErr_Occurred()) {
380 // bail out if a problem
384 // Now call the callback...
385 func
= ((wxPyMenu
*)&menu
)->func
;
386 args
= PyTuple_New(2);
387 PyTuple_SET_ITEM(args
, 0, menuobj
);
388 PyTuple_SET_ITEM(args
, 1, evtobj
);
389 res
= PyEval_CallObject(func
, args
);
391 Py_XDECREF(res
); /* In case res is a NULL pointer */
393 #ifdef WXP_WITH_THREAD
400 //---------------------------------------------------------------------------
402 wxPyTimer::wxPyTimer(PyObject
* callback
) {
407 wxPyTimer::~wxPyTimer() {
408 #ifdef WXP_WITH_THREAD
410 PyEval_RestoreThread(wxPyEventThreadState
);
415 #ifdef WXP_WITH_THREAD
421 void wxPyTimer::Notify() {
422 #ifdef WXP_WITH_THREAD
423 PyEval_RestoreThread(wxPyEventThreadState
);
427 PyObject
* args
= Py_BuildValue("()");
429 result
= PyEval_CallObject(func
, args
);
437 #ifdef WXP_WITH_THREAD
444 //----------------------------------------------------------------------
446 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxCommandEvent
)
448 wxPyEvent::wxPyEvent(wxEventType commandType
, PyObject
* userData
)
449 : wxCommandEvent(commandType
), m_userData(Py_None
)
451 m_userData
= userData
;
452 if (m_userData
!= Py_None
) {
453 Py_INCREF(m_userData
);
458 wxPyEvent::~wxPyEvent() {
459 #ifdef WXP_WITH_THREAD
461 PyEval_RestoreThread(wxPyEventThreadState
);
463 if (m_userData
!= Py_None
) {
464 Py_DECREF(m_userData
);
465 m_userData
= Py_None
;
467 #ifdef WXP_WITH_THREAD
474 void wxPyEvent::SetUserData(PyObject
* userData
) {
475 if (m_userData
!= Py_None
) {
476 Py_DECREF(m_userData
);
477 m_userData
= Py_None
;
479 m_userData
= userData
;
480 if (m_userData
!= Py_None
) {
481 Py_INCREF(m_userData
);
486 PyObject
* wxPyEvent::GetUserData() {
490 //----------------------------------------------------------------------
491 //----------------------------------------------------------------------
492 // Some helper functions for typemaps in my_typemaps.i, so they won't be
493 // imcluded in every file...
496 byte
* byte_LIST_helper(PyObject
* source
) {
497 if (!PyList_Check(source
)) {
498 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
501 int count
= PyList_Size(source
);
502 byte
* temp
= new byte
[count
];
504 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
507 for (int x
=0; x
<count
; x
++) {
508 PyObject
* o
= PyList_GetItem(source
, x
);
509 if (! PyInt_Check(o
)) {
510 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
513 temp
[x
] = (byte
)PyInt_AsLong(o
);
519 int* int_LIST_helper(PyObject
* source
) {
520 if (!PyList_Check(source
)) {
521 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
524 int count
= PyList_Size(source
);
525 int* temp
= new int[count
];
527 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
530 for (int x
=0; x
<count
; x
++) {
531 PyObject
* o
= PyList_GetItem(source
, x
);
532 if (! PyInt_Check(o
)) {
533 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
536 temp
[x
] = PyInt_AsLong(o
);
542 long* long_LIST_helper(PyObject
* source
) {
543 if (!PyList_Check(source
)) {
544 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
547 int count
= PyList_Size(source
);
548 long* temp
= new long[count
];
550 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
553 for (int x
=0; x
<count
; x
++) {
554 PyObject
* o
= PyList_GetItem(source
, x
);
555 if (! PyInt_Check(o
)) {
556 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
559 temp
[x
] = PyInt_AsLong(o
);
565 char** string_LIST_helper(PyObject
* source
) {
566 if (!PyList_Check(source
)) {
567 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
570 int count
= PyList_Size(source
);
571 char** temp
= new char*[count
];
573 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
576 for (int x
=0; x
<count
; x
++) {
577 PyObject
* o
= PyList_GetItem(source
, x
);
578 if (! PyString_Check(o
)) {
579 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
582 temp
[x
] = PyString_AsString(o
);
589 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
590 if (!PyList_Check(source
)) {
591 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
594 int count
= PyList_Size(source
);
595 wxPoint
* temp
= new wxPoint
[count
];
597 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
600 for (int x
=0; x
<count
; x
++) {
601 PyObject
* o
= PyList_GetItem(source
, x
);
602 if (PyString_Check(o
)) {
603 char* st
= PyString_AsString(o
);
605 if (SWIG_GetPtr(st
,(void **) &pt
,"_wxPoint_p")) {
606 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
611 else if (PyTuple_Check(o
)) {
612 PyObject
* o1
= PyTuple_GetItem(o
, 0);
613 PyObject
* o2
= PyTuple_GetItem(o
, 1);
615 temp
[x
].x
= PyInt_AsLong(o1
);
616 temp
[x
].y
= PyInt_AsLong(o2
);
619 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
627 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
628 if (!PyList_Check(source
)) {
629 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
632 int count
= PyList_Size(source
);
633 wxBitmap
** temp
= new wxBitmap
*[count
];
635 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
638 for (int x
=0; x
<count
; x
++) {
639 PyObject
* o
= PyList_GetItem(source
, x
);
640 if (PyString_Check(o
)) {
641 char* st
= PyString_AsString(o
);
643 if (SWIG_GetPtr(st
,(void **) &pt
,"_wxBitmap_p")) {
644 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
650 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
659 wxString
* wxString_LIST_helper(PyObject
* source
) {
660 if (!PyList_Check(source
)) {
661 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
664 int count
= PyList_Size(source
);
665 wxString
* temp
= new wxString
[count
];
667 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
670 for (int x
=0; x
<count
; x
++) {
671 PyObject
* o
= PyList_GetItem(source
, x
);
672 if (! PyString_Check(o
)) {
673 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
676 temp
[x
] = PyString_AsString(o
);
682 wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
683 if (!PyList_Check(source
)) {
684 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
687 int count
= PyList_Size(source
);
688 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
690 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
693 for (int x
=0; x
<count
; x
++) {
694 PyObject
* o
= PyList_GetItem(source
, x
);
695 if (PyString_Check(o
)) {
696 char* st
= PyString_AsString(o
);
697 wxAcceleratorEntry
* ae
;
698 if (SWIG_GetPtr(st
,(void **) &ae
,"_wxAcceleratorEntry_p")) {
699 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
704 else if (PyTuple_Check(o
)) {
705 PyObject
* o1
= PyTuple_GetItem(o
, 0);
706 PyObject
* o2
= PyTuple_GetItem(o
, 1);
707 PyObject
* o3
= PyTuple_GetItem(o
, 2);
709 temp
[x
].m_flags
= PyInt_AsLong(o1
);
710 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
711 temp
[x
].m_command
= PyInt_AsLong(o3
);
714 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
723 //----------------------------------------------------------------------
724 //----------------------------------------------------------------------
726 wxPyCallbackHelper::wxPyCallbackHelper() {
732 wxPyCallbackHelper::~wxPyCallbackHelper() {
733 #ifdef WXP_WITH_THREAD
734 PyEval_RestoreThread(wxPyEventThreadState
);
739 #ifdef WXP_WITH_THREAD
744 void wxPyCallbackHelper::setSelf(PyObject
* self
) {
751 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
753 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
754 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
756 return m_lastFound
!= NULL
;
760 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
764 result
= callCallbackObj(argTuple
);
765 if (result
) { // Assumes an integer return type...
766 retval
= PyInt_AsLong(result
);
768 PyErr_Clear(); // forget about it if it's not...
770 #ifdef WXP_WITH_THREAD
776 // Invoke the Python callable object, returning the raw PyObject return
777 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
778 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
779 #ifdef WXP_WITH_THREAD
780 PyEval_RestoreThread(wxPyEventThreadState
);
784 result
= PyEval_CallObject(m_lastFound
, argTuple
);
795 //----------------------------------------------------------------------
796 //----------------------------------------------------------------------
797 //----------------------------------------------------------------------