From: Robin Dunn <robin@alldunn.com> Date: Mon, 26 Mar 2001 22:17:24 +0000 (+0000) Subject: Added wxWakeUpMainThread, wxMutexGuiEnter, wxMutexGuiLeave, X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/6e18ca6cf434f1bd7245a3bf03d5a9cfe41393b6 Added wxWakeUpMainThread, wxMutexGuiEnter, wxMutexGuiLeave, wxMutexGuiLocker and wxThread_IsMain to assist with dealing with GUI access from non-GUI threads. wxPyOnDemandOutputWindow is now thread safe if non-GUI threads use print, sys.stdout.write, etc. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9590 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/wxPython/CHANGES.txt b/wxPython/CHANGES.txt index 2551b7fe26..ec6dc14ac8 100644 --- a/wxPython/CHANGES.txt +++ b/wxPython/CHANGES.txt @@ -17,6 +17,13 @@ Also wxTheColourDatabase and added a library module (in the wxPython.lib.colourdb module) to load LOTS more colour names into the colour database. +Added wxWakeUpMainThread, wxMutexGuiEnter, wxMutexGuiLeave, +wxMutexGuiLocker and wxThread_IsMain to assist with dealing with GUI +access from non-GUI threads. + +wxPyOnDemandOutputWindow is now thread safe if non-GUI threads use +print, sys.stdout.write, etc. + diff --git a/wxPython/src/_extras.py b/wxPython/src/_extras.py index 5e16b1f7a4..25799cc90e 100644 --- a/wxPython/src/_extras.py +++ b/wxPython/src/_extras.py @@ -714,20 +714,22 @@ class wxPyOnDemandOutputWindow: self.title = title self.parent = None - def SetParent(self, parent): self.parent = parent - def OnCloseWindow(self, event): if self.frame != None: self.frame.Destroy() self.frame = None self.text = None - - # this provides the file-like output behaviour + # These methods provide the file-like output behaviour. def write(self, str): + if not wxThread_IsMain(): + # Aquire the GUI mutex before making GUI calls. Mutex is released + # when locker is deleted a the end of this function. + locker = wxMutexGuiLocker() + if not self.frame: self.frame = wxFrame(self.parent, -1, self.title) self.text = wxTextCtrl(self.frame, -1, "", @@ -737,13 +739,13 @@ class wxPyOnDemandOutputWindow: EVT_CLOSE(self.frame, self.OnCloseWindow) self.text.AppendText(str) - def close(self): if self.frame != None: + if not wxThread_IsMain(): + locker = wxMutexGuiLocker() self.frame.Close() - _defRedirect = (wxPlatform == '__WXMSW__') #---------------------------------------------------------------------- diff --git a/wxPython/src/misc2.i b/wxPython/src/misc2.i index e68acb89f9..35608d3bba 100644 --- a/wxPython/src/misc2.i +++ b/wxPython/src/misc2.i @@ -382,10 +382,28 @@ public: //---------------------------------------------------------------------- +bool wxSafeYield(wxWindow* win=NULL); void wxPostEvent(wxEvtHandler *dest, wxEvent& event); void wxWakeUpIdle(); -bool wxSafeYield(wxWindow* win=NULL); + +void wxWakeUpMainThread(); +void wxMutexGuiEnter(); +void wxMutexGuiLeave(); + + +class wxMutexGuiLocker { +public: + wxMutexGuiLocker(); + ~wxMutexGuiLocker(); +}; + + +%inline %{ + bool wxThread_IsMain() { + return wxThread::IsMain(); + } +%} //---------------------------------------------------------------------- diff --git a/wxPython/src/msw/misc2.cpp b/wxPython/src/msw/misc2.cpp index 533cd27c06..45ec4548cb 100644 --- a/wxPython/src/msw/misc2.cpp +++ b/wxPython/src/msw/misc2.cpp @@ -66,12 +66,12 @@ extern PyObject *SWIG_newvarlink(void); static PyObject* l_output_helper(PyObject* target, PyObject* o) { PyObject* o2; - if (!target) { + if (!target) { target = o; - } else if (target == Py_None) { + } else if (target == Py_None) { Py_DECREF(Py_None); target = o; - } else { + } else { if (!PyList_Check(target)) { o2 = target; target = PyList_New(0); @@ -88,23 +88,23 @@ static PyObject* t_output_helper(PyObject* target, PyObject* o) { PyObject* o2; PyObject* o3; - if (!target) { + if (!target) { target = o; - } else if (target == Py_None) { + } else if (target == Py_None) { Py_DECREF(Py_None); target = o; - } else { + } else { if (!PyTuple_Check(target)) { o2 = target; target = PyTuple_New(1); PyTuple_SetItem(target, 0, o2); } - o3 = PyTuple_New(1); - PyTuple_SetItem(o3, 0, o); + o3 = PyTuple_New(1); + PyTuple_SetItem(o3, 0, o); o2 = target; - target = PySequence_Concat(o2, o3); - Py_DECREF(o2); + target = PySequence_Concat(o2, o3); + Py_DECREF(o2); Py_DECREF(o3); } return target; @@ -158,6 +158,10 @@ IMP_PYCALLBACK_BOOL_STRING(wxPyFontEnumerator, wxFontEnumerator, OnFacename); IMP_PYCALLBACK_BOOL_STRINGSTRING(wxPyFontEnumerator, wxFontEnumerator, OnFontEncoding); + bool wxThread_IsMain() { + return wxThread::IsMain(); + } + class wxPyTipProvider : public wxTipProvider { public: wxPyTipProvider(size_t currentTip) @@ -1547,6 +1551,32 @@ static PyObject *_wrap_wxCaret_SetBlinkTime(PyObject *self, PyObject *args, PyOb return _resultobj; } +static PyObject *_wrap_wxSafeYield(PyObject *self, PyObject *args, PyObject *kwargs) { + PyObject * _resultobj; + bool _result; + wxWindow * _arg0 = (wxWindow *) NULL; + PyObject * _argo0 = 0; + char *_kwnames[] = { "win", NULL }; + + self = self; + if(!PyArg_ParseTupleAndKeywords(args,kwargs,"|O:wxSafeYield",_kwnames,&_argo0)) + return NULL; + if (_argo0) { + if (_argo0 == Py_None) { _arg0 = NULL; } + else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxWindow_p")) { + PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxSafeYield. Expected _wxWindow_p."); + return NULL; + } + } +{ + wxPy_BEGIN_ALLOW_THREADS; + _result = (bool )wxSafeYield(_arg0); + + wxPy_END_ALLOW_THREADS; +} _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + static PyObject *_wrap_wxPostEvent(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; wxEvtHandler * _arg0; @@ -1599,26 +1629,68 @@ static PyObject *_wrap_wxWakeUpIdle(PyObject *self, PyObject *args, PyObject *kw return _resultobj; } -static PyObject *_wrap_wxSafeYield(PyObject *self, PyObject *args, PyObject *kwargs) { +static PyObject *_wrap_wxWakeUpMainThread(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; - bool _result; - wxWindow * _arg0 = (wxWindow *) NULL; - PyObject * _argo0 = 0; - char *_kwnames[] = { "win", NULL }; + char *_kwnames[] = { NULL }; self = self; - if(!PyArg_ParseTupleAndKeywords(args,kwargs,"|O:wxSafeYield",_kwnames,&_argo0)) + if(!PyArg_ParseTupleAndKeywords(args,kwargs,":wxWakeUpMainThread",_kwnames)) return NULL; - if (_argo0) { - if (_argo0 == Py_None) { _arg0 = NULL; } - else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxWindow_p")) { - PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxSafeYield. Expected _wxWindow_p."); +{ + wxPy_BEGIN_ALLOW_THREADS; + wxWakeUpMainThread(); + + wxPy_END_ALLOW_THREADS; +} Py_INCREF(Py_None); + _resultobj = Py_None; + return _resultobj; +} + +static PyObject *_wrap_wxMutexGuiEnter(PyObject *self, PyObject *args, PyObject *kwargs) { + PyObject * _resultobj; + char *_kwnames[] = { NULL }; + + self = self; + if(!PyArg_ParseTupleAndKeywords(args,kwargs,":wxMutexGuiEnter",_kwnames)) return NULL; - } - } { wxPy_BEGIN_ALLOW_THREADS; - _result = (bool )wxSafeYield(_arg0); + wxMutexGuiEnter(); + + wxPy_END_ALLOW_THREADS; +} Py_INCREF(Py_None); + _resultobj = Py_None; + return _resultobj; +} + +static PyObject *_wrap_wxMutexGuiLeave(PyObject *self, PyObject *args, PyObject *kwargs) { + PyObject * _resultobj; + char *_kwnames[] = { NULL }; + + self = self; + if(!PyArg_ParseTupleAndKeywords(args,kwargs,":wxMutexGuiLeave",_kwnames)) + return NULL; +{ + wxPy_BEGIN_ALLOW_THREADS; + wxMutexGuiLeave(); + + wxPy_END_ALLOW_THREADS; +} Py_INCREF(Py_None); + _resultobj = Py_None; + return _resultobj; +} + +static PyObject *_wrap_wxThread_IsMain(PyObject *self, PyObject *args, PyObject *kwargs) { + PyObject * _resultobj; + bool _result; + char *_kwnames[] = { NULL }; + + self = self; + if(!PyArg_ParseTupleAndKeywords(args,kwargs,":wxThread_IsMain",_kwnames)) + return NULL; +{ + wxPy_BEGIN_ALLOW_THREADS; + _result = (bool )wxThread_IsMain(); wxPy_END_ALLOW_THREADS; } _resultobj = Py_BuildValue("i",_result); @@ -3160,6 +3232,58 @@ static PyObject *_wrap_delete_wxWindowDisabler(PyObject *self, PyObject *args, P return _resultobj; } +#define new_wxMutexGuiLocker() (new wxMutexGuiLocker()) +static PyObject *_wrap_new_wxMutexGuiLocker(PyObject *self, PyObject *args, PyObject *kwargs) { + PyObject * _resultobj; + wxMutexGuiLocker * _result; + char *_kwnames[] = { NULL }; + char _ptemp[128]; + + self = self; + if(!PyArg_ParseTupleAndKeywords(args,kwargs,":new_wxMutexGuiLocker",_kwnames)) + return NULL; +{ + wxPy_BEGIN_ALLOW_THREADS; + _result = (wxMutexGuiLocker *)new_wxMutexGuiLocker(); + + wxPy_END_ALLOW_THREADS; +} if (_result) { + SWIG_MakePtr(_ptemp, (char *) _result,"_wxMutexGuiLocker_p"); + _resultobj = Py_BuildValue("s",_ptemp); + } else { + Py_INCREF(Py_None); + _resultobj = Py_None; + } + return _resultobj; +} + +#define delete_wxMutexGuiLocker(_swigobj) (delete _swigobj) +static PyObject *_wrap_delete_wxMutexGuiLocker(PyObject *self, PyObject *args, PyObject *kwargs) { + PyObject * _resultobj; + wxMutexGuiLocker * _arg0; + PyObject * _argo0 = 0; + char *_kwnames[] = { "self", NULL }; + + self = self; + if(!PyArg_ParseTupleAndKeywords(args,kwargs,"O:delete_wxMutexGuiLocker",_kwnames,&_argo0)) + return NULL; + if (_argo0) { + if (_argo0 == Py_None) { _arg0 = NULL; } + else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxMutexGuiLocker_p")) { + PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of delete_wxMutexGuiLocker. Expected _wxMutexGuiLocker_p."); + return NULL; + } + } +{ + wxPy_BEGIN_ALLOW_THREADS; + delete_wxMutexGuiLocker(_arg0); + + wxPy_END_ALLOW_THREADS; +} Py_INCREF(Py_None); + _resultobj = Py_None; + return _resultobj; +} + #define delete_wxTipProvider(_swigobj) (delete _swigobj) static PyObject *_wrap_delete_wxTipProvider(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; @@ -6616,6 +6740,8 @@ static PyMethodDef misc2cMethods[] = { { "wxTipProvider_GetCurrentTip", (PyCFunction) _wrap_wxTipProvider_GetCurrentTip, METH_VARARGS | METH_KEYWORDS }, { "wxTipProvider_GetTip", (PyCFunction) _wrap_wxTipProvider_GetTip, METH_VARARGS | METH_KEYWORDS }, { "delete_wxTipProvider", (PyCFunction) _wrap_delete_wxTipProvider, METH_VARARGS | METH_KEYWORDS }, + { "delete_wxMutexGuiLocker", (PyCFunction) _wrap_delete_wxMutexGuiLocker, METH_VARARGS | METH_KEYWORDS }, + { "new_wxMutexGuiLocker", (PyCFunction) _wrap_new_wxMutexGuiLocker, METH_VARARGS | METH_KEYWORDS }, { "delete_wxWindowDisabler", (PyCFunction) _wrap_delete_wxWindowDisabler, METH_VARARGS | METH_KEYWORDS }, { "new_wxWindowDisabler", (PyCFunction) _wrap_new_wxWindowDisabler, METH_VARARGS | METH_KEYWORDS }, { "delete_wxBusyCursor", (PyCFunction) _wrap_delete_wxBusyCursor, METH_VARARGS | METH_KEYWORDS }, @@ -6664,9 +6790,13 @@ static PyMethodDef misc2cMethods[] = { { "wxDragIcon", (PyCFunction) _wrap_wxDragIcon, METH_VARARGS | METH_KEYWORDS }, { "wxCreateFileTipProvider", (PyCFunction) _wrap_wxCreateFileTipProvider, METH_VARARGS | METH_KEYWORDS }, { "wxShowTip", (PyCFunction) _wrap_wxShowTip, METH_VARARGS | METH_KEYWORDS }, - { "wxSafeYield", (PyCFunction) _wrap_wxSafeYield, METH_VARARGS | METH_KEYWORDS }, + { "wxThread_IsMain", (PyCFunction) _wrap_wxThread_IsMain, METH_VARARGS | METH_KEYWORDS }, + { "wxMutexGuiLeave", (PyCFunction) _wrap_wxMutexGuiLeave, METH_VARARGS | METH_KEYWORDS }, + { "wxMutexGuiEnter", (PyCFunction) _wrap_wxMutexGuiEnter, METH_VARARGS | METH_KEYWORDS }, + { "wxWakeUpMainThread", (PyCFunction) _wrap_wxWakeUpMainThread, METH_VARARGS | METH_KEYWORDS }, { "wxWakeUpIdle", (PyCFunction) _wrap_wxWakeUpIdle, METH_VARARGS | METH_KEYWORDS }, { "wxPostEvent", (PyCFunction) _wrap_wxPostEvent, METH_VARARGS | METH_KEYWORDS }, + { "wxSafeYield", (PyCFunction) _wrap_wxSafeYield, METH_VARARGS | METH_KEYWORDS }, { "wxCaret_SetBlinkTime", (PyCFunction) _wrap_wxCaret_SetBlinkTime, METH_VARARGS | METH_KEYWORDS }, { "wxCaret_GetBlinkTime", (PyCFunction) _wrap_wxCaret_GetBlinkTime, METH_VARARGS | METH_KEYWORDS }, { "wxToolTip_SetDelay", (PyCFunction) _wrap_wxToolTip_SetDelay, METH_VARARGS | METH_KEYWORDS }, @@ -6744,6 +6874,7 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_wxCursor","_class_wxCursor",0}, { "_wxNotifyEvent","_class_wxNotifyEvent",0}, { "_wxPyProcess","_class_wxPyProcess",0}, + { "_wxMutexGuiLocker","_class_wxMutexGuiLocker",0}, { "_wxLog","_class_wxLogWindow",SwigwxLogWindowTowxLog}, { "_wxLog","_wxLogWindow",SwigwxLogWindowTowxLog}, { "_wxLog","_class_wxLogGui",SwigwxLogGuiTowxLog}, @@ -6760,6 +6891,7 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_byte","_unsigned_char",0}, { "_wxDataObject","_class_wxDataObject",0}, { "_class_wxPyFontEnumerator","_wxPyFontEnumerator",0}, + { "_wxColourDatabase","_class_wxColourDatabase",0}, { "_wxPyDataObjectSimple","_class_wxPyDataObjectSimple",0}, { "_wxPyDropSource","_class_wxPyDropSource",0}, { "_long","_unsigned_long",0}, @@ -6825,6 +6957,7 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_class_wxWindowDisabler","_wxWindowDisabler",0}, { "_char","_wxChar",0}, { "_wxBitmap","_class_wxBitmap",0}, + { "_wxPenList","_class_wxPenList",0}, { "_wxWindowDC","_class_wxWindowDC",0}, { "_wxTimerEvent","_class_wxTimerEvent",0}, { "_wxPyTimer","_class_wxPyTimer",0}, @@ -6832,9 +6965,11 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_class_wxNotifyEvent","_wxNotifyEvent",0}, { "_class_wxValidator","_wxValidator",0}, { "_class_wxPyEvent","_wxPyEvent",0}, + { "_class_wxMutexGuiLocker","_wxMutexGuiLocker",0}, { "_class_wxIconizeEvent","_wxIconizeEvent",0}, { "_class_wxBusyCursor","_wxBusyCursor",0}, { "_wxDropTarget","_class_wxDropTarget",0}, + { "_class_wxColourDatabase","_wxColourDatabase",0}, { "_wxScrollEvent","_class_wxScrollEvent",0}, { "_EBool","_wxCoord",0}, { "_EBool","_wxPrintQuality",0}, @@ -6854,8 +6989,10 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_class_wxDC","_wxDC",0}, { "_wxScrollWinEvent","_class_wxScrollWinEvent",0}, { "_wxGenericDragImage","_class_wxGenericDragImage",0}, + { "_class_wxBrushList","_wxBrushList",0}, { "_wxQueryNewPaletteEvent","_class_wxQueryNewPaletteEvent",0}, { "_wxPyInputStream","_class_wxPyInputStream",0}, + { "_class_wxPenList","_wxPenList",0}, { "_class_wxWindowCreateEvent","_wxWindowCreateEvent",0}, { "_class_wxOutputStream","_wxOutputStream",0}, { "_wxLogTextCtrl","_class_wxLogTextCtrl",0}, @@ -6894,6 +7031,7 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_class_wxPyValidator","_wxPyValidator",0}, { "_class_wxCloseEvent","_wxCloseEvent",0}, { "_wxBusyInfo","_class_wxBusyInfo",0}, + { "_wxFontList","_class_wxFontList",0}, { "_class_wxMenuEvent","_wxMenuEvent",0}, { "_wxPaletteChangedEvent","_class_wxPaletteChangedEvent",0}, { "_wxJoystick","_class_wxJoystick",0}, @@ -7020,10 +7158,12 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_wxPyDropTarget","_class_wxPyDropTarget",0}, { "_wxActivateEvent","_class_wxActivateEvent",0}, { "_class_wxBusyInfo","_wxBusyInfo",0}, + { "_class_wxFontList","_wxFontList",0}, { "_class_wxJoystick","_wxJoystick",0}, { "_class_wxCommandEvent","_wxCommandEvent",0}, { "_class_wxClientDC","_wxClientDC",0}, { "_class_wxSizeEvent","_wxSizeEvent",0}, + { "_wxBrushList","_class_wxBrushList",0}, { "_wxCustomDataObject","_class_wxCustomDataObject",0}, { "_class_wxLogNull","_wxLogNull",0}, { "_class_wxSize","_wxSize",0}, diff --git a/wxPython/src/msw/misc2.py b/wxPython/src/msw/misc2.py index 203232ce6a..b836092489 100644 --- a/wxPython/src/msw/misc2.py +++ b/wxPython/src/msw/misc2.py @@ -162,6 +162,23 @@ class wxWindowDisabler(wxWindowDisablerPtr): +class wxMutexGuiLockerPtr : + def __init__(self,this): + self.this = this + self.thisown = 0 + def __del__(self,misc2c=misc2c): + if self.thisown == 1 : + misc2c.delete_wxMutexGuiLocker(self) + def __repr__(self): + return "<C wxMutexGuiLocker instance at %s>" % (self.this,) +class wxMutexGuiLocker(wxMutexGuiLockerPtr): + def __init__(self,*_args,**_kwargs): + self.this = apply(misc2c.new_wxMutexGuiLocker,_args,_kwargs) + self.thisown = 1 + + + + class wxTipProviderPtr : def __init__(self,this): self.this = this @@ -716,11 +733,19 @@ wxCaret_GetBlinkTime = misc2c.wxCaret_GetBlinkTime wxCaret_SetBlinkTime = misc2c.wxCaret_SetBlinkTime +wxSafeYield = misc2c.wxSafeYield + wxPostEvent = misc2c.wxPostEvent wxWakeUpIdle = misc2c.wxWakeUpIdle -wxSafeYield = misc2c.wxSafeYield +wxWakeUpMainThread = misc2c.wxWakeUpMainThread + +wxMutexGuiEnter = misc2c.wxMutexGuiEnter + +wxMutexGuiLeave = misc2c.wxMutexGuiLeave + +wxThread_IsMain = misc2c.wxThread_IsMain wxShowTip = misc2c.wxShowTip diff --git a/wxPython/src/msw/wx.cpp b/wxPython/src/msw/wx.cpp index 250ddf2a18..52a36713d9 100644 --- a/wxPython/src/msw/wx.cpp +++ b/wxPython/src/msw/wx.cpp @@ -59,12 +59,12 @@ extern PyObject *SWIG_newvarlink(void); static PyObject* l_output_helper(PyObject* target, PyObject* o) { PyObject* o2; - if (!target) { + if (!target) { target = o; - } else if (target == Py_None) { + } else if (target == Py_None) { Py_DECREF(Py_None); target = o; - } else { + } else { if (!PyList_Check(target)) { o2 = target; target = PyList_New(0); @@ -81,23 +81,23 @@ static PyObject* t_output_helper(PyObject* target, PyObject* o) { PyObject* o2; PyObject* o3; - if (!target) { + if (!target) { target = o; - } else if (target == Py_None) { + } else if (target == Py_None) { Py_DECREF(Py_None); target = o; - } else { + } else { if (!PyTuple_Check(target)) { o2 = target; target = PyTuple_New(1); PyTuple_SetItem(target, 0, o2); } - o3 = PyTuple_New(1); - PyTuple_SetItem(o3, 0, o); + o3 = PyTuple_New(1); + PyTuple_SetItem(o3, 0, o); o2 = target; - target = PySequence_Concat(o2, o3); - Py_DECREF(o2); + target = PySequence_Concat(o2, o3); + Py_DECREF(o2); Py_DECREF(o3); } return target; @@ -1829,6 +1829,7 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_wxPyProcess","_class_wxPyProcess",0}, { "_wxPyTreeCtrl","_class_wxPyTreeCtrl",0}, { "_wxImageHandler","_class_wxImageHandler",0}, + { "_wxMutexGuiLocker","_class_wxMutexGuiLocker",0}, { "_wxLog","_class_wxLog",0}, { "_class_wxToolBarBase","_wxToolBarBase",0}, { "_wxMask","_class_wxMask",0}, @@ -1974,6 +1975,7 @@ static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = { { "_wxMessageDialog","_class_wxMessageDialog",0}, { "_class_wxValidator","_wxValidator",0}, { "_class_wxPyEvent","_wxPyEvent",0}, + { "_class_wxMutexGuiLocker","_wxMutexGuiLocker",0}, { "_wxTextEntryDialog","_class_wxTextEntryDialog",0}, { "_wxConfig","_class_wxConfig",0}, { "_class_wxIconizeEvent","_wxIconizeEvent",0}, diff --git a/wxPython/src/msw/wx.py b/wxPython/src/msw/wx.py index f960b79d8a..fc3390761e 100644 --- a/wxPython/src/msw/wx.py +++ b/wxPython/src/msw/wx.py @@ -1535,20 +1535,22 @@ class wxPyOnDemandOutputWindow: self.title = title self.parent = None - def SetParent(self, parent): self.parent = parent - def OnCloseWindow(self, event): if self.frame != None: self.frame.Destroy() self.frame = None self.text = None - - # this provides the file-like output behaviour + # These methods provide the file-like output behaviour. def write(self, str): + if not wxThread_IsMain(): + # Aquire the GUI mutex before making GUI calls. Mutex is released + # when locker is deleted a the end of this function. + locker = wxMutexGuiLocker() + if not self.frame: self.frame = wxFrame(self.parent, -1, self.title) self.text = wxTextCtrl(self.frame, -1, "", @@ -1558,13 +1560,13 @@ class wxPyOnDemandOutputWindow: EVT_CLOSE(self.frame, self.OnCloseWindow) self.text.AppendText(str) - def close(self): if self.frame != None: + if not wxThread_IsMain(): + locker = wxMutexGuiLocker() self.frame.Close() - _defRedirect = (wxPlatform == '__WXMSW__') #---------------------------------------------------------------------- diff --git a/wxPython/tests/alternateThread.py b/wxPython/tests/alternateThread.py new file mode 100644 index 0000000000..69d435b326 --- /dev/null +++ b/wxPython/tests/alternateThread.py @@ -0,0 +1,52 @@ +from time import sleep +from threading import Thread + +def test_a_window(): + print "starting window thread" + + from wxPython.wx import * # <-- the wxWin DLL is not loaded until here + + app = wxPySimpleApp(1) + frame = wxFrame(None, -1, "Hello", size=(400,200)) + frame.Show(true) + EVT_SIZE(frame, OnFrameSize) + app.MainLoop() + print "finishing window thread" + +def OnFrameSize(evt): + print evt.GetSize() + + + +keep_going = 1 +def counter(): + print "starting counter thread" + count = 0 + while keep_going: + sleep(1) + count += 1 + print count + print "finishing counter thread" + +def main(): + print "main startup" + + ct = Thread(target=counter) + wt = Thread(target=test_a_window) + + ct.start() + wt.start() + wt.join() + + global keep_going + keep_going = 0 + + ct.join() + + print "main finished" + +main() + + + +