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 // Convert a wxList to a Python List 
 500 PyObject
* wxPy_ConvertList(wxListBase
* list
, char* className
) { 
 504     wxNode
*     node 
= list
->First(); 
 506     bool doSave 
= wxPyRestoreThread(); 
 507     pyList 
= PyList_New(0); 
 509         wxObj 
= node
->Data(); 
 510         pyObj 
= wxPyConstructObject(wxObj
, className
); 
 511         PyList_Append(pyList
, pyObj
); 
 514     wxPySaveThread(doSave
); 
 518 //---------------------------------------------------------------------- 
 519 // Some helper functions for typemaps in my_typemaps.i, so they won't be 
 520 // included in every file... 
 523 HELPEREXPORT byte
* byte_LIST_helper(PyObject
* source
) { 
 524     if (!PyList_Check(source
)) { 
 525         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 528     int count 
= PyList_Size(source
); 
 529     byte
* temp 
= new byte
[count
]; 
 531         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 534     for (int x
=0; x
<count
; x
++) { 
 535         PyObject
* o 
= PyList_GetItem(source
, x
); 
 536         if (! PyInt_Check(o
)) { 
 537             PyErr_SetString(PyExc_TypeError
, "Expected a list of integers."); 
 540         temp
[x
] = (byte
)PyInt_AsLong(o
); 
 546 HELPEREXPORT 
int* int_LIST_helper(PyObject
* source
) { 
 547     if (!PyList_Check(source
)) { 
 548         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 551     int count 
= PyList_Size(source
); 
 552     int* temp 
= new int[count
]; 
 554         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 557     for (int x
=0; x
<count
; x
++) { 
 558         PyObject
* o 
= PyList_GetItem(source
, x
); 
 559         if (! PyInt_Check(o
)) { 
 560             PyErr_SetString(PyExc_TypeError
, "Expected a list of integers."); 
 563         temp
[x
] = PyInt_AsLong(o
); 
 569 HELPEREXPORT 
long* long_LIST_helper(PyObject
* source
) { 
 570     if (!PyList_Check(source
)) { 
 571         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 574     int count 
= PyList_Size(source
); 
 575     long* temp 
= new long[count
]; 
 577         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 580     for (int x
=0; x
<count
; x
++) { 
 581         PyObject
* o 
= PyList_GetItem(source
, x
); 
 582         if (! PyInt_Check(o
)) { 
 583             PyErr_SetString(PyExc_TypeError
, "Expected a list of integers."); 
 586         temp
[x
] = PyInt_AsLong(o
); 
 592 HELPEREXPORT 
char** string_LIST_helper(PyObject
* source
) { 
 593     if (!PyList_Check(source
)) { 
 594         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 597     int count 
= PyList_Size(source
); 
 598     char** temp 
= new char*[count
]; 
 600         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 603     for (int x
=0; x
<count
; x
++) { 
 604         PyObject
* o 
= PyList_GetItem(source
, x
); 
 605         if (! PyString_Check(o
)) { 
 606             PyErr_SetString(PyExc_TypeError
, "Expected a list of strings."); 
 609         temp
[x
] = PyString_AsString(o
); 
 616 HELPEREXPORT wxPoint
* wxPoint_LIST_helper(PyObject
* source
) { 
 617     if (!PyList_Check(source
)) { 
 618         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 621     int count 
= PyList_Size(source
); 
 622     wxPoint
* temp 
= new wxPoint
[count
]; 
 624         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 627     for (int x
=0; x
<count
; x
++) { 
 628         PyObject
* o 
= PyList_GetItem(source
, x
); 
 629         if (PyTuple_Check(o
)) { 
 630             PyObject
* o1 
= PyTuple_GetItem(o
, 0); 
 631             PyObject
* o2 
= PyTuple_GetItem(o
, 1); 
 633             temp
[x
].x 
= PyInt_AsLong(o1
); 
 634             temp
[x
].y 
= PyInt_AsLong(o2
); 
 636         else if (PyInstance_Check(o
)) { 
 638             if (SWIG_GetPtrObj(o
,(void **) &pt
,"_wxPoint_p")) { 
 639                 PyErr_SetString(PyExc_TypeError
,"Expected _wxPoint_p."); 
 645             PyErr_SetString(PyExc_TypeError
, "Expected a list of 2-tuples or wxPoints."); 
 653 HELPEREXPORT wxBitmap
** wxBitmap_LIST_helper(PyObject
* source
) { 
 654     if (!PyList_Check(source
)) { 
 655         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 658     int count 
= PyList_Size(source
); 
 659     wxBitmap
** temp 
= new wxBitmap
*[count
]; 
 661         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 664     for (int x
=0; x
<count
; x
++) { 
 665         PyObject
* o 
= PyList_GetItem(source
, x
); 
 666         if (PyInstance_Check(o
)) { 
 668             if (SWIG_GetPtrObj(o
, (void **) &pt
,"_wxBitmap_p")) { 
 669                 PyErr_SetString(PyExc_TypeError
,"Expected _wxBitmap_p."); 
 675             PyErr_SetString(PyExc_TypeError
, "Expected a list of wxBitmaps."); 
 684 HELPEREXPORT wxString
* wxString_LIST_helper(PyObject
* source
) { 
 685     if (!PyList_Check(source
)) { 
 686         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 689     int count 
= PyList_Size(source
); 
 690     wxString
* temp 
= new wxString
[count
]; 
 692         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 695     for (int x
=0; x
<count
; x
++) { 
 696         PyObject
* o 
= PyList_GetItem(source
, x
); 
 697         if (! PyString_Check(o
)) { 
 698             PyErr_SetString(PyExc_TypeError
, "Expected a list of strings."); 
 701         temp
[x
] = PyString_AsString(o
); 
 707 HELPEREXPORT wxAcceleratorEntry
* wxAcceleratorEntry_LIST_helper(PyObject
* source
) { 
 708     if (!PyList_Check(source
)) { 
 709         PyErr_SetString(PyExc_TypeError
, "Expected a list object."); 
 712     int count                
= PyList_Size(source
); 
 713     wxAcceleratorEntry
* temp 
= new wxAcceleratorEntry
[count
]; 
 715         PyErr_SetString(PyExc_MemoryError
, "Unable to allocate temporary array"); 
 718     for (int x
=0; x
<count
; x
++) { 
 719         PyObject
* o 
= PyList_GetItem(source
, x
); 
 720         if (PyInstance_Check(o
)) { 
 721             wxAcceleratorEntry
* ae
; 
 722             if (SWIG_GetPtrObj(o
, (void **) &ae
,"_wxAcceleratorEntry_p")) { 
 723                 PyErr_SetString(PyExc_TypeError
,"Expected _wxAcceleratorEntry_p."); 
 728         else if (PyTuple_Check(o
)) { 
 729             PyObject
* o1 
= PyTuple_GetItem(o
, 0); 
 730             PyObject
* o2 
= PyTuple_GetItem(o
, 1); 
 731             PyObject
* o3 
= PyTuple_GetItem(o
, 2); 
 733             temp
[x
].m_flags   
= PyInt_AsLong(o1
); 
 734             temp
[x
].m_keyCode 
= PyInt_AsLong(o2
); 
 735             temp
[x
].m_command 
= PyInt_AsLong(o3
); 
 738             PyErr_SetString(PyExc_TypeError
, "Expected a list of 3-tuples or wxAcceleratorEntry objects."); 
 747 //---------------------------------------------------------------------- 
 749 //---------------------------------------------------------------------- 
 750 //---------------------------------------------------------------------- 
 751 //----------------------------------------------------------------------