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();
83 wxPythonApp
->OnExit(); //#
88 //# void wxPyApp::AfterMainLoop(void) {
89 // // more stuff from wxEntry...
91 // if (wxPythonApp->GetTopWindow()) {
92 // // Forcibly delete the window.
93 // if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) ||
94 // wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) {
96 // wxPythonApp->GetTopWindow()->Close(TRUE);
97 // wxPythonApp->DeletePendingObjects();
100 // delete wxPythonApp->GetTopWindow();
101 // wxPythonApp->SetTopWindow(NULL);
105 // wxPythonApp->DeletePendingObjects();
108 // wxPythonApp->OnExit();
110 // // delete wxPythonApp;
114 //---------------------------------------------------------------------
115 // a few native methods to add to the module
116 //----------------------------------------------------------------------
119 // This is where we pick up the first part of the wxEntry functionality...
120 // The rest is in __wxStart and AfterMainLoop. This function is called when
121 // wxcmodule is imported. (Before there is a wxApp object.)
124 // Bail out if there is already windows created. This means that the
125 // toolkit has already been initialized, as in embedding wxPython in
126 // a C++ wxWindows app.
127 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 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
145 gtk_init( &argc
, &argv
);
146 wxSetDetectableAutoRepeat( TRUE
);
149 wxApp::Initialize(); // may return FALSE. Should we check?
155 #ifdef WXP_WITH_THREAD
156 PyThreadState
* wxPyEventThreadState
= NULL
;
157 bool wxPyInEvent
= false;
159 static char* __nullArgv
[1] = { 0 };
163 // Start the user application, user App's OnInit method is a parameter here
164 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
166 PyObject
* onInitFunc
= NULL
;
171 #ifdef WXP_WITH_THREAD
172 wxPyEventThreadState
= PyThreadState_Get();
175 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
178 if (wxTopLevelWindows
.Number() > 0) {
179 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
184 // This is the next part of the wxEntry functionality...
185 wxPythonApp
->argc
= 0;
186 wxPythonApp
->argv
= NULL
;
187 wxPythonApp
->OnInitGui();
190 // Call the Python App's OnInit function
191 arglist
= PyTuple_New(0);
192 result
= PyEval_CallObject(onInitFunc
, arglist
);
193 if (!result
) { // an exception was raised.
197 if (! PyInt_Check(result
)) {
198 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
201 bResult
= PyInt_AS_LONG(result
);
203 PyErr_SetString(PyExc_SystemExit
, "OnInit returned false, exiting...");
208 wxTheApp
->m_initialized
= (wxTopLevelWindows
.Number() > 0);
219 PyObject
* wxPython_dict
;
220 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
223 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
226 if (!PyDict_Check(wxPython_dict
)) {
227 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
231 #define wxPlatform "__WXMOTIF__"
234 #define wxPlatform "__WXQT__"
237 #define wxPlatform "__WXGTK__"
239 #if defined(__WIN32__) || defined(__WXMSW__)
240 #define wxPlatform "__WXMSW__"
243 #define wxPlatform "__WXMAC__"
246 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
253 //---------------------------------------------------------------------------
255 PyObject
* wxPyConstructObject(void* ptr
, char* className
)
257 char buff
[64]; // should always be big enough...
260 sprintf(buff
, "_%s_p", className
);
261 SWIG_MakePtr(swigptr
, ptr
, buff
);
263 sprintf(buff
, "%sPtr", className
);
264 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
270 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
271 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
279 wxPyCallback::wxPyCallback(PyObject
* func
) {
284 wxPyCallback::~wxPyCallback() {
285 #ifdef WXP_WITH_THREAD
287 PyEval_RestoreThread(wxPyEventThreadState
);
292 #ifdef WXP_WITH_THREAD
301 // This function is used for all events destined for Python event handlers.
302 void wxPyCallback::EventThunker(wxEvent
& event
) {
303 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
304 PyObject
* func
= cb
->m_func
;
310 #ifdef WXP_WITH_THREAD
311 PyEval_RestoreThread(wxPyEventThreadState
);
314 arg
= wxPyConstructObject((void*)&event
, event
.GetClassInfo()->GetClassName());
316 tuple
= PyTuple_New(1);
317 PyTuple_SET_ITEM(tuple
, 0, arg
);
318 result
= PyEval_CallObject(func
, tuple
);
326 #ifdef WXP_WITH_THREAD
333 //---------------------------------------------------------------------------
335 // wxPyMenu::wxPyMenu(const wxString& title, PyObject* _func)
336 // : wxMenu(title, (wxFunction)(func ? MenuCallback : NULL)), func(0) {
344 // wxPyMenu::~wxPyMenu() {
345 // #ifdef WXP_WITH_THREAD
346 // //if (! wxPyInEvent)
347 // PyEval_RestoreThread(wxPyEventThreadState);
353 // #ifdef WXP_WITH_THREAD
354 // //if (! wxPyInEvent)
355 // PyEval_SaveThread();
360 // void wxPyMenu::MenuCallback(wxMenu& menu, wxCommandEvent& evt) {
362 // PyObject* menuobj;
367 // #ifdef WXP_WITH_THREAD
368 // PyEval_RestoreThread(wxPyEventThreadState);
369 // wxPyInEvent = true;
371 // evtobj = wxPyConstructObject((void*)&evt, "wxCommandEvent");
372 // menuobj = wxPyConstructObject((void*)&menu, "wxMenu");
373 // if (PyErr_Occurred()) {
374 // // bail out if a problem
378 // // Now call the callback...
379 // func = ((wxPyMenu*)&menu)->func;
380 // args = PyTuple_New(2);
381 // PyTuple_SET_ITEM(args, 0, menuobj);
382 // PyTuple_SET_ITEM(args, 1, evtobj);
383 // res = PyEval_CallObject(func, args);
385 // Py_XDECREF(res); /* In case res is a NULL pointer */
387 // #ifdef WXP_WITH_THREAD
388 // PyEval_SaveThread();
389 // wxPyInEvent = false;
395 //---------------------------------------------------------------------------
397 wxPyTimer::wxPyTimer(PyObject
* callback
) {
402 wxPyTimer::~wxPyTimer() {
403 #ifdef WXP_WITH_THREAD
405 PyEval_RestoreThread(wxPyEventThreadState
);
410 #ifdef WXP_WITH_THREAD
416 void wxPyTimer::Notify() {
417 #ifdef WXP_WITH_THREAD
418 PyEval_RestoreThread(wxPyEventThreadState
);
422 PyObject
* args
= Py_BuildValue("()");
424 result
= PyEval_CallObject(func
, args
);
432 #ifdef WXP_WITH_THREAD
439 //----------------------------------------------------------------------
441 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxCommandEvent
)
443 wxPyEvent::wxPyEvent(wxEventType commandType
, PyObject
* userData
)
444 : wxCommandEvent(commandType
), m_userData(Py_None
)
446 m_userData
= userData
;
447 if (m_userData
!= Py_None
) {
448 Py_INCREF(m_userData
);
453 wxPyEvent::~wxPyEvent() {
454 #ifdef WXP_WITH_THREAD
456 PyEval_RestoreThread(wxPyEventThreadState
);
458 if (m_userData
!= Py_None
) {
459 Py_DECREF(m_userData
);
460 m_userData
= Py_None
;
462 #ifdef WXP_WITH_THREAD
469 void wxPyEvent::SetUserData(PyObject
* userData
) {
470 if (m_userData
!= Py_None
) {
471 Py_DECREF(m_userData
);
472 m_userData
= Py_None
;
474 m_userData
= userData
;
475 if (m_userData
!= Py_None
) {
476 Py_INCREF(m_userData
);
481 PyObject
* wxPyEvent::GetUserData() {
485 //----------------------------------------------------------------------
486 //----------------------------------------------------------------------
487 // Some helper functions for typemaps in my_typemaps.i, so they won't be
488 // imcluded in every file...
491 byte
* byte_LIST_helper(PyObject
* source
) {
492 if (!PyList_Check(source
)) {
493 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
496 int count
= PyList_Size(source
);
497 byte
* temp
= new byte
[count
];
499 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
502 for (int x
=0; x
<count
; x
++) {
503 PyObject
* o
= PyList_GetItem(source
, x
);
504 if (! PyInt_Check(o
)) {
505 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
508 temp
[x
] = (byte
)PyInt_AsLong(o
);
514 int* int_LIST_helper(PyObject
* source
) {
515 if (!PyList_Check(source
)) {
516 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
519 int count
= PyList_Size(source
);
520 int* temp
= new int[count
];
522 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
525 for (int x
=0; x
<count
; x
++) {
526 PyObject
* o
= PyList_GetItem(source
, x
);
527 if (! PyInt_Check(o
)) {
528 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
531 temp
[x
] = PyInt_AsLong(o
);
537 long* long_LIST_helper(PyObject
* source
) {
538 if (!PyList_Check(source
)) {
539 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
542 int count
= PyList_Size(source
);
543 long* temp
= new long[count
];
545 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
548 for (int x
=0; x
<count
; x
++) {
549 PyObject
* o
= PyList_GetItem(source
, x
);
550 if (! PyInt_Check(o
)) {
551 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
554 temp
[x
] = PyInt_AsLong(o
);
560 char** string_LIST_helper(PyObject
* source
) {
561 if (!PyList_Check(source
)) {
562 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
565 int count
= PyList_Size(source
);
566 char** temp
= new char*[count
];
568 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
571 for (int x
=0; x
<count
; x
++) {
572 PyObject
* o
= PyList_GetItem(source
, x
);
573 if (! PyString_Check(o
)) {
574 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
577 temp
[x
] = PyString_AsString(o
);
584 wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
585 if (!PyList_Check(source
)) {
586 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
589 int count
= PyList_Size(source
);
590 wxPoint
* temp
= new wxPoint
[count
];
592 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
595 for (int x
=0; x
<count
; x
++) {
596 PyObject
* o
= PyList_GetItem(source
, x
);
597 if (PyString_Check(o
)) {
598 char* st
= PyString_AsString(o
);
600 if (SWIG_GetPtr(st
,(void **) &pt
,"_wxPoint_p")) {
601 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
606 else if (PyTuple_Check(o
)) {
607 PyObject
* o1
= PyTuple_GetItem(o
, 0);
608 PyObject
* o2
= PyTuple_GetItem(o
, 1);
610 temp
[x
].x
= PyInt_AsLong(o1
);
611 temp
[x
].y
= PyInt_AsLong(o2
);
614 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
622 wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
623 if (!PyList_Check(source
)) {
624 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
627 int count
= PyList_Size(source
);
628 wxBitmap
** temp
= new wxBitmap
*[count
];
630 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
633 for (int x
=0; x
<count
; x
++) {
634 PyObject
* o
= PyList_GetItem(source
, x
);
635 if (PyString_Check(o
)) {
636 char* st
= PyString_AsString(o
);
638 if (SWIG_GetPtr(st
,(void **) &pt
,"_wxBitmap_p")) {
639 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
645 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
654 wxString
* wxString_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 wxString
* temp
= new wxString
[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 (! PyString_Check(o
)) {
668 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
671 temp
[x
] = PyString_AsString(o
);
677 wxAcceleratorEntry
* wxAcceleratorEntry_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 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[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 (PyString_Check(o
)) {
691 char* st
= PyString_AsString(o
);
692 wxAcceleratorEntry
* ae
;
693 if (SWIG_GetPtr(st
,(void **) &ae
,"_wxAcceleratorEntry_p")) {
694 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
699 else if (PyTuple_Check(o
)) {
700 PyObject
* o1
= PyTuple_GetItem(o
, 0);
701 PyObject
* o2
= PyTuple_GetItem(o
, 1);
702 PyObject
* o3
= PyTuple_GetItem(o
, 2);
704 temp
[x
].m_flags
= PyInt_AsLong(o1
);
705 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
706 temp
[x
].m_command
= PyInt_AsLong(o3
);
709 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
718 //----------------------------------------------------------------------
719 //----------------------------------------------------------------------
721 wxPyCallbackHelper::wxPyCallbackHelper() {
727 wxPyCallbackHelper::~wxPyCallbackHelper() {
728 #ifdef WXP_WITH_THREAD
729 PyEval_RestoreThread(wxPyEventThreadState
);
734 #ifdef WXP_WITH_THREAD
739 void wxPyCallbackHelper::setSelf(PyObject
* self
) {
746 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
748 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
749 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
751 return m_lastFound
!= NULL
;
755 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
759 result
= callCallbackObj(argTuple
);
760 if (result
) { // Assumes an integer return type...
761 retval
= PyInt_AsLong(result
);
763 PyErr_Clear(); // forget about it if it's not...
765 #ifdef WXP_WITH_THREAD
771 // Invoke the Python callable object, returning the raw PyObject return
772 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
773 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
774 #ifdef WXP_WITH_THREAD
775 PyEval_RestoreThread(wxPyEventThreadState
);
779 result
= PyEval_CallObject(m_lastFound
, argTuple
);
790 //----------------------------------------------------------------------
791 //----------------------------------------------------------------------
792 //----------------------------------------------------------------------