]> git.saurik.com Git - wxWidgets.git/commitdiff
Added wxWakeUpMainThread, wxMutexGuiEnter, wxMutexGuiLeave,
authorRobin Dunn <robin@alldunn.com>
Mon, 26 Mar 2001 22:17:24 +0000 (22:17 +0000)
committerRobin Dunn <robin@alldunn.com>
Mon, 26 Mar 2001 22:17:24 +0000 (22:17 +0000)
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

wxPython/CHANGES.txt
wxPython/src/_extras.py
wxPython/src/misc2.i
wxPython/src/msw/misc2.cpp
wxPython/src/msw/misc2.py
wxPython/src/msw/wx.cpp
wxPython/src/msw/wx.py
wxPython/tests/alternateThread.py [new file with mode: 0644]

index 2551b7fe2655e7dfe4bb7c63c736038db1e3252a..ec6dc14ac8b87006220b3ed2a2044c218dba5516 100644 (file)
@@ -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.
+
 
 
 
index 5e16b1f7a4278c8cbd95ba5edada622933901be7..25799cc90e57af2a0cc54a56beda34087f5579bd 100644 (file)
@@ -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__')
 
 #----------------------------------------------------------------------
index e68acb89f982891085e5dbff81dc95f0f8867585..35608d3bbacf6c4fd655e768313553b145986a37 100644 (file)
@@ -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();
+    }
+%}
 
 //----------------------------------------------------------------------
 
index 533cd27c06277ec89c02255b0aa7e60509dc8009..45ec4548cb0bbc9839ea115eed068cad19f8e839 100644 (file)
@@ -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},
index 203232ce6aca5943a66c175ddaa4bf04be06f7f3..b83609248956b9c29c4e84a961d3c07f3a64ba93 100644 (file)
@@ -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
 
index 250ddf2a18425d458fe472e31682b0c91d33764c..52a36713d90630c6c4b7d6b99b4c5930196ae269 100644 (file)
@@ -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},
index f960b79d8a906b7430959c72fa96716575287b55..fc3390761e80f4fd8d95d35600c566b22b9fcda1 100644 (file)
@@ -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 (file)
index 0000000..69d435b
--- /dev/null
@@ -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()
+
+
+
+