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
;
158 static char* __nullArgv
[1] = { 0 };
162 // Start the user application, user App's OnInit method is a parameter here
163 PyObject
* __wxStart(PyObject
* /* self */, PyObject
* args
)
165 PyObject
* onInitFunc
= NULL
;
170 #ifdef WXP_WITH_THREAD
171 wxPyEventThreadState
= PyThreadState_Get();
174 if (!PyArg_ParseTuple(args
, "O", &onInitFunc
))
177 if (wxTopLevelWindows
.Number() > 0) {
178 PyErr_SetString(PyExc_TypeError
, "Only 1 wxApp per process!");
183 // This is the next part of the wxEntry functionality...
184 wxPythonApp
->argc
= 0;
185 wxPythonApp
->argv
= NULL
;
186 wxPythonApp
->OnInitGui();
189 // Call the Python App's OnInit function
190 arglist
= PyTuple_New(0);
191 result
= PyEval_CallObject(onInitFunc
, arglist
);
192 if (!result
) { // an exception was raised.
196 if (! PyInt_Check(result
)) {
197 PyErr_SetString(PyExc_TypeError
, "OnInit should return a boolean value");
200 bResult
= PyInt_AS_LONG(result
);
202 PyErr_SetString(PyExc_SystemExit
, "OnInit returned false, exiting...");
207 wxTheApp
->m_initialized
= (wxTopLevelWindows
.Number() > 0);
218 PyObject
* wxPython_dict
;
219 PyObject
* __wxSetDictionary(PyObject
* /* self */, PyObject
* args
)
222 if (!PyArg_ParseTuple(args
, "O", &wxPython_dict
))
225 if (!PyDict_Check(wxPython_dict
)) {
226 PyErr_SetString(PyExc_TypeError
, "_wxSetDictionary must have dictionary object!");
230 #define wxPlatform "__WXMOTIF__"
233 #define wxPlatform "__WXQT__"
236 #define wxPlatform "__WXGTK__"
238 #if defined(__WIN32__) || defined(__WXMSW__)
239 #define wxPlatform "__WXMSW__"
242 #define wxPlatform "__WXMAC__"
245 PyDict_SetItemString(wxPython_dict
, "wxPlatform", PyString_FromString(wxPlatform
));
252 //---------------------------------------------------------------------------
254 PyObject
* wxPyConstructObject(void* ptr
, char* className
) {
255 char buff
[64]; // should always be big enough...
258 sprintf(buff
, "_%s_p", className
);
259 SWIG_MakePtr(swigptr
, ptr
, buff
);
261 sprintf(buff
, "%sPtr", className
);
262 PyObject
* classobj
= PyDict_GetItemString(wxPython_dict
, buff
);
268 PyObject
* arg
= Py_BuildValue("(s)", swigptr
);
269 PyObject
* obj
= PyInstance_New(classobj
, arg
, NULL
);
275 //---------------------------------------------------------------------------
277 //static bool _wxPyInEvent = false;
278 static unsigned int _wxPyNestCount
= 0;
280 HELPEREXPORT
bool wxPyRestoreThread() {
281 // #ifdef WXP_WITH_THREAD
282 // //if (wxPyEventThreadState != PyThreadState_Get()) {
283 // if (! _wxPyInEvent) {
284 // PyEval_RestoreThread(wxPyEventThreadState);
285 // _wxPyInEvent = true;
291 // NOTE: The Python API docs state that if a thread already has the
292 // interpreter lock and calls PyEval_RestoreThread again a deadlock
293 // occurs, so I put in the above code as a guard condition since there are
294 // many possibilites for nested events and callbacks in wxPython.
296 // Unfortunately, it seems like somebody was lying (or I'm not
297 // understanding...) because each of the nested calls to this function
298 // MUST call PyEval_RestoreThread or Python pukes with a thread error (at
301 // until I know better, this is how I am doing it instead:
302 #ifdef WXP_WITH_THREAD
303 PyEval_RestoreThread(wxPyEventThreadState
);
305 if (_wxPyNestCount
== 1)
313 HELPEREXPORT
void wxPySaveThread(bool doSave
) {
314 #ifdef WXP_WITH_THREAD
317 //_wxPyInEvent = false;
323 //---------------------------------------------------------------------------
326 wxPyCallback::wxPyCallback(PyObject
* func
) {
331 wxPyCallback::~wxPyCallback() {
332 bool doSave
= wxPyRestoreThread();
334 wxPySaveThread(doSave
);
340 // This function is used for all events destined for Python event handlers.
341 void wxPyCallback::EventThunker(wxEvent
& event
) {
342 wxPyCallback
* cb
= (wxPyCallback
*)event
.m_callbackUserData
;
343 PyObject
* func
= cb
->m_func
;
349 bool doSave
= wxPyRestoreThread();
350 arg
= wxPyConstructObject((void*)&event
, event
.GetClassInfo()->GetClassName());
352 tuple
= PyTuple_New(1);
353 PyTuple_SET_ITEM(tuple
, 0, arg
);
354 result
= PyEval_CallObject(func
, tuple
);
362 wxPySaveThread(doSave
);
366 //----------------------------------------------------------------------
368 wxPyCallbackHelper::wxPyCallbackHelper() {
374 wxPyCallbackHelper::~wxPyCallbackHelper() {
375 bool doSave
= wxPyRestoreThread();
377 wxPySaveThread(doSave
);
380 void wxPyCallbackHelper::setSelf(PyObject
* self
) {
386 bool wxPyCallbackHelper::findCallback(const wxString
& name
) {
388 if (m_self
&& PyObject_HasAttrString(m_self
, (char*)name
.c_str()))
389 m_lastFound
= PyObject_GetAttrString(m_self
, (char*)name
.c_str());
391 return m_lastFound
!= NULL
;
395 int wxPyCallbackHelper::callCallback(PyObject
* argTuple
) {
399 result
= callCallbackObj(argTuple
);
400 if (result
) { // Assumes an integer return type...
401 retval
= PyInt_AsLong(result
);
403 PyErr_Clear(); // forget about it if it's not...
408 // Invoke the Python callable object, returning the raw PyObject return
409 // value. Caller should DECREF the return value and also call PyEval_SaveThread.
410 PyObject
* wxPyCallbackHelper::callCallbackObj(PyObject
* argTuple
) {
413 result
= PyEval_CallObject(m_lastFound
, argTuple
);
423 //---------------------------------------------------------------------------
424 //---------------------------------------------------------------------------
427 wxPyTimer::wxPyTimer(PyObject
* callback
) {
432 wxPyTimer::~wxPyTimer() {
433 bool doSave
= wxPyRestoreThread();
435 wxPySaveThread(doSave
);
438 void wxPyTimer::Notify() {
439 bool doSave
= wxPyRestoreThread();
442 PyObject
* args
= Py_BuildValue("()");
444 result
= PyEval_CallObject(func
, args
);
452 wxPySaveThread(doSave
);
456 //----------------------------------------------------------------------
458 IMPLEMENT_DYNAMIC_CLASS(wxPyEvent
, wxCommandEvent
)
460 wxPyEvent::wxPyEvent(wxEventType commandType
, PyObject
* userData
)
461 : wxCommandEvent(commandType
), m_userData(Py_None
)
463 m_userData
= userData
;
464 if (m_userData
!= Py_None
) {
465 Py_INCREF(m_userData
);
470 wxPyEvent::~wxPyEvent() {
471 bool doSave
= wxPyRestoreThread();
472 if (m_userData
!= Py_None
) {
473 Py_DECREF(m_userData
);
474 m_userData
= Py_None
;
476 wxPySaveThread(doSave
);
480 void wxPyEvent::SetUserData(PyObject
* userData
) {
481 if (m_userData
!= Py_None
) {
482 Py_DECREF(m_userData
);
483 m_userData
= Py_None
;
485 m_userData
= userData
;
486 if (m_userData
!= Py_None
) {
487 Py_INCREF(m_userData
);
492 PyObject
* wxPyEvent::GetUserData() {
496 //----------------------------------------------------------------------
497 //----------------------------------------------------------------------
498 // Some helper functions for typemaps in my_typemaps.i, so they won't be
499 // imcluded in every file...
502 HELPEREXPORT byte
* byte_LIST_helper(PyObject
* source
) {
503 if (!PyList_Check(source
)) {
504 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
507 int count
= PyList_Size(source
);
508 byte
* temp
= new byte
[count
];
510 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
513 for (int x
=0; x
<count
; x
++) {
514 PyObject
* o
= PyList_GetItem(source
, x
);
515 if (! PyInt_Check(o
)) {
516 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
519 temp
[x
] = (byte
)PyInt_AsLong(o
);
525 HELPEREXPORT
int* int_LIST_helper(PyObject
* source
) {
526 if (!PyList_Check(source
)) {
527 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
530 int count
= PyList_Size(source
);
531 int* temp
= new int[count
];
533 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
536 for (int x
=0; x
<count
; x
++) {
537 PyObject
* o
= PyList_GetItem(source
, x
);
538 if (! PyInt_Check(o
)) {
539 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
542 temp
[x
] = PyInt_AsLong(o
);
548 HELPEREXPORT
long* long_LIST_helper(PyObject
* source
) {
549 if (!PyList_Check(source
)) {
550 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
553 int count
= PyList_Size(source
);
554 long* temp
= new long[count
];
556 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
559 for (int x
=0; x
<count
; x
++) {
560 PyObject
* o
= PyList_GetItem(source
, x
);
561 if (! PyInt_Check(o
)) {
562 PyErr_SetString(PyExc_TypeError
, "Expected a list of integers.");
565 temp
[x
] = PyInt_AsLong(o
);
571 HELPEREXPORT
char** string_LIST_helper(PyObject
* source
) {
572 if (!PyList_Check(source
)) {
573 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
576 int count
= PyList_Size(source
);
577 char** temp
= new char*[count
];
579 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
582 for (int x
=0; x
<count
; x
++) {
583 PyObject
* o
= PyList_GetItem(source
, x
);
584 if (! PyString_Check(o
)) {
585 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
588 temp
[x
] = PyString_AsString(o
);
595 HELPEREXPORT wxPoint
* wxPoint_LIST_helper(PyObject
* source
) {
596 if (!PyList_Check(source
)) {
597 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
600 int count
= PyList_Size(source
);
601 wxPoint
* temp
= new wxPoint
[count
];
603 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
606 for (int x
=0; x
<count
; x
++) {
607 PyObject
* o
= PyList_GetItem(source
, x
);
608 if (PyTuple_Check(o
)) {
609 PyObject
* o1
= PyTuple_GetItem(o
, 0);
610 PyObject
* o2
= PyTuple_GetItem(o
, 1);
612 temp
[x
].x
= PyInt_AsLong(o1
);
613 temp
[x
].y
= PyInt_AsLong(o2
);
615 else if (PyInstance_Check(o
)) {
617 if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) {
618 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p.");
624 PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints.");
632 HELPEREXPORT wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) {
633 if (!PyList_Check(source
)) {
634 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
637 int count
= PyList_Size(source
);
638 wxBitmap
** temp
= new wxBitmap
*[count
];
640 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
643 for (int x
=0; x
<count
; x
++) {
644 PyObject
* o
= PyList_GetItem(source
, x
);
645 if (PyString_Check(o
)) {
646 char* st
= PyString_AsString(o
);
648 if (SWIG_GetPtr(st
,(void **) &pt
,"_wxBitmap_p")) {
649 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p.");
655 PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps.");
664 HELPEREXPORT wxString
* wxString_LIST_helper(PyObject
* source
) {
665 if (!PyList_Check(source
)) {
666 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
669 int count
= PyList_Size(source
);
670 wxString
* temp
= new wxString
[count
];
672 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
675 for (int x
=0; x
<count
; x
++) {
676 PyObject
* o
= PyList_GetItem(source
, x
);
677 if (! PyString_Check(o
)) {
678 PyErr_SetString(PyExc_TypeError
, "Expected a list of strings.");
681 temp
[x
] = PyString_AsString(o
);
687 HELPEREXPORT wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) {
688 if (!PyList_Check(source
)) {
689 PyErr_SetString(PyExc_TypeError
, "Expected a list object.");
692 int count
= PyList_Size(source
);
693 wxAcceleratorEntry
* temp
= new wxAcceleratorEntry
[count
];
695 PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array");
698 for (int x
=0; x
<count
; x
++) {
699 PyObject
* o
= PyList_GetItem(source
, x
);
700 if (PyString_Check(o
)) {
701 char* st
= PyString_AsString(o
);
702 wxAcceleratorEntry
* ae
;
703 if (SWIG_GetPtr(st
,(void **) &ae
,"_wxAcceleratorEntry_p")) {
704 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p.");
709 else if (PyTuple_Check(o
)) {
710 PyObject
* o1
= PyTuple_GetItem(o
, 0);
711 PyObject
* o2
= PyTuple_GetItem(o
, 1);
712 PyObject
* o3
= PyTuple_GetItem(o
, 2);
714 temp
[x
].m_flags
= PyInt_AsLong(o1
);
715 temp
[x
].m_keyCode
= PyInt_AsLong(o2
);
716 temp
[x
].m_command
= PyInt_AsLong(o3
);
719 PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects.");
728 //----------------------------------------------------------------------
730 //----------------------------------------------------------------------
731 //----------------------------------------------------------------------
732 //----------------------------------------------------------------------