Add and use the wxPyThreadBlocker class.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@71603 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2012-05-30 03:24:34 +00:00
parent 209b24057c
commit 787cfb858e
19 changed files with 101 additions and 122 deletions

View File

@@ -39,6 +39,11 @@ def run():
tools.fixWindowClass(c)
module.addGlobalStr('wxAnimationCtrlNameStr', c)
# move this before wxAnimationCtrl so it can be used for default arg values
item = module.find('wxNullAnimation')
module.items.remove(item)
module.insertItemBefore(c, item)
# TODO: It would be nice to be able to use the generic verison on all
# platforms since the native GTK version has some limitations...

View File

@@ -224,12 +224,11 @@ def run():
body="""\
wxBitmap* bmp = new wxBitmap(width, height, 24);
wxPyCopyBitmapFromBuffer(bmp, (byte*)data->m_ptr, data->m_len, wxBitmapBufferFormat_RGB);
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
if (PyErr_Occurred()) {
delete bmp;
bmp = NULL;
}
wxPyEndBlockThreads(blocked);
return bmp;
""")
@@ -267,12 +266,11 @@ def run():
body="""\
wxBitmap* bmp = new wxBitmap(width, height, 32);
wxPyCopyBitmapFromBuffer(bmp, (byte*)data->m_ptr, data->m_len, wxBitmapBufferFormat_RGBA);
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
if (PyErr_Occurred()) {
delete bmp;
bmp = NULL;
}
wxPyEndBlockThreads(blocked);
return bmp;
""")

View File

@@ -67,23 +67,20 @@ def run():
# holding the data...
c.addCppMethod('PyObject*', 'GetPrivData', '()', """\
PyObject* data;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
data = PyBytes_FromStringAndSize(self->GetPrivData(),
self->GetPrivDataLen());
wxPyEndBlockThreads(blocked);
return data;
""")
c.addCppMethod('void', 'SetPrivData', '(PyObject* data)', """\
wxPyThreadBlocker blocker;
if (! PyBytes_Check(data)) {
wxPyBLOCK_THREADS(PyErr_SetString(PyExc_TypeError,
"Expected string object"));
return /* NULL */ ;
wxPyErr_SetString(PyExc_TypeError, "Expected string object");
return;
}
wxPyBlock_t blocked = wxPyBeginBlockThreads();
self->SetPrivData(PyBytes_AS_STRING(data), PyBytes_GET_SIZE(data));
wxPyEndBlockThreads(blocked);
""")
c.addAutoProperties()

View File

@@ -50,14 +50,13 @@ def addGetAllFormats(klass, pureVirtual=False):
size_t count = self->GetFormatCount(dir);
wxDataFormat* formats = new wxDataFormat[count];
self->GetAllFormats(formats, dir);
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* list = PyList_New(count);
for (size_t i=0; i<count; i++) {
wxDataFormat* format = new wxDataFormat(formats[i]);
PyObject* obj = wxPyConstructObject((void*)format, wxT("wxDataFormat"), true);
PyList_SET_ITEM(list, i, obj); // PyList_SET_ITEM steals a reference
}
wxPyEndBlockThreads(blocked);
delete [] formats;
return list;
""",

View File

@@ -205,10 +205,6 @@ def run():
(entry->m_callbackUserData != NULL))
{
wxPyCallback *cb = (wxPyCallback*)entry->m_callbackUserData;
//wxPyBlock_t blocked = wxPyBeginBlockThreads();
//int result = PyObject_Compare(cb->m_func, func);
//wxPyEndBlockThreads(blocked);
//if (result == 0) {
if (cb->m_func == func) {
delete cb;
self->GetDynamicEventTable()->Erase(node);
@@ -458,18 +454,16 @@ def run():
c.find('GetFiles').setCppCode("""\
int count = self->GetNumberOfFiles();
wxString* files = self->GetFiles();
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* list = PyList_New(count);
if (!list) {
PyErr_SetString(PyExc_MemoryError, "Can't allocate list of files!");
wxPyEndBlockThreads(blocked);
return NULL;
}
for (int i=0; i<count; i++) {
PyObject* s = wx2PyString(files[i]);
PyList_SET_ITEM(list, i, s);
}
wxPyEndBlockThreads(blocked);
return list;
""")

View File

@@ -228,11 +228,8 @@ def run():
byte* data = self->GetData();
Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3;
PyObject* rv;
Py_buffer view;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyBuffer_FillInfo(&view, NULL, data, len, 0, PyBUF_WRITABLE|PyBUF_FORMAT|PyBUF_ND);
rv = PyMemoryView_FromBuffer(&view);
wxPyEndBlockThreads(blocked);
wxPyThreadBlocker blocker;
rv = wxPyMakeBuffer(data, len);
return rv;
""")
@@ -245,11 +242,8 @@ def run():
byte* data = self->GetAlpha();
Py_ssize_t len = self->GetWidth() * self->GetHeight();
PyObject* rv;
Py_buffer view;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyBuffer_FillInfo(&view, NULL, data, len, 0, PyBUF_WRITABLE|PyBUF_FORMAT|PyBUF_ND);
rv = PyMemoryView_FromBuffer(&view);
wxPyEndBlockThreads(blocked);
wxPyThreadBlocker blocker;
rv = wxPyMakeBuffer(data, len);
return rv;
""")

View File

@@ -37,10 +37,8 @@ def run():
class wxJoystick : public wxObject {
public:
wxJoystick(int joystick = wxJOYSTICK1) {
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyErr_SetString(PyExc_NotImplementedError,
"wxJoystick is not available on this platform.");
wxPyEndBlockThreads(blocked);
wxPyErr_SetString(PyExc_NotImplementedError,
"wxJoystick is not available on this platform.");
}
wxPoint GetPosition() const { return wxPoint(-1,-1); }
int GetPosition(unsigned axis) const { return -1; }

View File

@@ -67,7 +67,7 @@ def run():
{
int retval = 0;
PyObject* func = (PyObject*)funcPtr;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* args = Py_BuildValue("(ii)", item1, item2);
PyObject* result = PyEval_CallObject(func, args);
@@ -77,7 +77,6 @@ def run():
Py_DECREF(result);
}
wxPyEndBlockThreads(blocked);
return retval;
}
""")

View File

@@ -111,7 +111,7 @@ def run():
static PyObject* _makeReadBufObj(wxInputStream* self, wxMemoryBuffer& buf) {
PyObject* obj = NULL;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
wxStreamError err = self->GetLastError(); // error check
if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF) {
PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
@@ -120,7 +120,6 @@ def run():
// Return the data as a string object. TODO: Py3
obj = PyBytes_FromStringAndSize(buf, buf.GetDataLen());
}
wxPyEndBlockThreads(blocked);
return obj;
}
""")

View File

@@ -74,7 +74,7 @@ def run():
doc='Returns a list of currently selected items in the tree. This function '
'can be called only if the control has the wx.TR_MULTIPLE style.',
body="""\
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* rval = PyList_New(0);
wxArrayTreeItemIds array;
size_t num, x;
@@ -85,7 +85,6 @@ def run():
PyList_Append(rval, item);
Py_DECREF(item);
}
wxPyEndBlockThreads(blocked);
return rval;
""")
@@ -104,10 +103,9 @@ def run():
body="""\
wxRect rect;
if (self->GetBoundingRect(*item, rect, textOnly)) {
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
wxRect* r = new wxRect(rect);
PyObject* val = wxPyConstructObject((void*)r, wxT("wxRect"), true);
wxPyEndBlockThreads(blocked);
return val;
}
else

View File

@@ -83,7 +83,6 @@ def nci(text, numSpaces=0, stripLeading=True):
# io.StringIO reads/writes unicode objects for both Python 2.7 and 3.x. For
# 2.7 we'll convert any string values to unicode objects before storing them
# in the StringIO
import io
class Utf8EncodingStream(io.StringIO):
if sys.version_info < (3,):

View File

@@ -867,7 +867,7 @@ static
{{
{objType}* array;
Py_ssize_t idx, len;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
// ensure that it is a sequence
if (! PySequence_Check(source))
@@ -893,7 +893,6 @@ static
array = new {objType}[*count];
if (!array) {{
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
wxPyEndBlockThreads(blocked);
return NULL;
}}
for (idx=0; idx<len; idx++) {{
@@ -906,12 +905,10 @@ static
sipReleaseType((void*)item, {sipType}, state); // delete temporary instances
Py_DECREF(obj);
}}
wxPyEndBlockThreads(blocked);
return array;
error0:
PyErr_SetString(PyExc_TypeError, "{errmsg}");
wxPyEndBlockThreads(blocked);
return NULL;
}}
""".format(**locals())

View File

@@ -152,11 +152,10 @@ void wxPyApp::OnAssertFailure(const wxChar *file,
buf << wxT(": ") << msg;
// set the exception
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* s = wx2PyString(buf);
PyErr_SetObject(wxAssertionError, s);
Py_DECREF(s);
wxPyEndBlockThreads(blocked);
// Now when control returns to whatever API wrapper was called from
// Python it should detect that an exception is set and will return
@@ -187,7 +186,6 @@ void wxPyApp::_BootstrapApp()
{
static bool haveInitialized = false;
bool result;
wxPyBlock_t blocked;
// Only initialize wxWidgets once
if (! haveInitialized) {
@@ -201,29 +199,29 @@ void wxPyApp::_BootstrapApp()
#endif
int argc = 0;
argType** argv = NULL;
blocked = wxPyBeginBlockThreads();
PyObject* sysargv = PySys_GetObject("argv");
if (sysargv != NULL) {
argc = PyList_Size(sysargv);
argv = new argType*[argc+1];
int x;
for(x=0; x<argc; x++) {
PyObject *pyArg = PyList_GetItem(sysargv, x); // borrowed reference
// if there isn't anything in sys.argv[0] then set it to the python executable
if (x == 0 && PyObject_Length(pyArg) < 1)
pyArg = PySys_GetObject("executable");
#if PY_MAJOR_VERSION >= 3
int len = PyObject_Length(pyArg);
argv[x] = new argType[len+1];
wxPyUnicode_AsWideChar(pyArg, argv[x], len+1);
#else
argv[x] = strdup(PyBytes_AsString(pyArg));
#endif
{
wxPyThreadBlocker blocker;
PyObject* sysargv = PySys_GetObject("argv");
if (sysargv != NULL) {
argc = PyList_Size(sysargv);
argv = new argType*[argc+1];
int x;
for(x=0; x<argc; x++) {
PyObject *pyArg = PyList_GetItem(sysargv, x); // borrowed reference
// if there isn't anything in sys.argv[0] then set it to the python executable
if (x == 0 && PyObject_Length(pyArg) < 1)
pyArg = PySys_GetObject("executable");
#if PY_MAJOR_VERSION >= 3
int len = PyObject_Length(pyArg);
argv[x] = new argType[len+1];
wxPyUnicode_AsWideChar(pyArg, argv[x], len+1);
#else
argv[x] = strdup(PyBytes_AsString(pyArg));
#endif
}
argv[argc] = NULL;
}
argv[argc] = NULL;
}
wxPyEndBlockThreads(blocked);
// Initialize wxWidgets
#ifdef __WXOSX__
@@ -232,17 +230,15 @@ void wxPyApp::_BootstrapApp()
result = wxEntryStart(argc, argv);
// wxApp takes ownership of the argv array, don't delete it here
blocked = wxPyBeginBlockThreads();
if (! result) {
PyErr_SetString(PyExc_SystemError,
"wxEntryStart failed, unable to initialize wxWidgets!"
wxPyErr_SetString(PyExc_SystemError,
"wxEntryStart failed, unable to initialize wxWidgets!"
#ifdef __WXGTK__
" (Is DISPLAY set properly?)"
" (Is DISPLAY set properly?)"
#endif
);
goto error;
}
wxPyEndBlockThreads(blocked);
haveInitialized = true;
}
else {
@@ -256,12 +252,11 @@ void wxPyApp::_BootstrapApp()
OnPreInit();
result = OnInit();
blocked = wxPyBeginBlockThreads();
if (! result) {
PyErr_SetString(PyExc_SystemExit, "OnInit returned false, exiting...");
wxPyErr_SetString(PyExc_SystemExit, "OnInit returned false, exiting...");
}
error:
wxPyEndBlockThreads(blocked);
return;
}

View File

@@ -40,7 +40,7 @@ void wxPyCallback::EventThunker(wxEvent& event) {
PyObject* tuple;
bool checkSkip = false;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
wxString className = event.GetClassInfo()->GetClassName();
arg = wxPyConstructObject((void*)&event, className);
@@ -59,5 +59,4 @@ void wxPyCallback::EventThunker(wxEvent& event) {
}
Py_DECREF(tuple);
}
wxPyEndBlockThreads(blocked);
}

View File

@@ -40,10 +40,9 @@
~wxPyEvtDict()
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
Py_DECREF(m_dict);
m_dict = NULL;
wxPyEndBlockThreads(blocked);
}
PyObject* _getAttrDict()
@@ -55,7 +54,7 @@
PyObject* __getattr__(PyObject* name)
{
PyObject* value = NULL;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
if (PyDict_Contains(m_dict, name)) {
value = PyDict_GetItem(m_dict, name);
Py_INCREF(value);
@@ -63,25 +62,22 @@
else {
PyErr_SetObject(PyExc_AttributeError, name);
}
wxPyEndBlockThreads(blocked);
return value;
}
void __setattr__(PyObject* name, PyObject* value)
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyDict_SetItem(m_dict, name, value);
wxPyEndBlockThreads(blocked);
}
void __delattr__(PyObject* name)
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
if (PyDict_Contains(m_dict, name))
PyDict_DelItem(m_dict, name);
else
PyErr_SetObject(PyExc_AttributeError, name);
wxPyEndBlockThreads(blocked);
}
protected:

View File

@@ -33,29 +33,24 @@ public:
wxPyInputStream(PyObject* fileObj, bool block=true)
{
m_block = block;
wxPyBlock_t blocked = wxPyBlock_t_default;
if (block) blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker(m_block);
m_read = wxPyGetMethod(fileObj, "read");
m_seek = wxPyGetMethod(fileObj, "seek");
m_tell = wxPyGetMethod(fileObj, "tell");
if (block) wxPyEndBlockThreads(blocked);
}
virtual ~wxPyInputStream()
{
wxPyBlock_t blocked = wxPyBlock_t_default;
if (m_block) blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker(m_block);
Py_XDECREF(m_read);
Py_XDECREF(m_seek);
Py_XDECREF(m_tell);
if (m_block) wxPyEndBlockThreads(blocked);
}
wxPyInputStream(const wxPyInputStream& other)
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
m_read = other.m_read;
m_seek = other.m_seek;
m_tell = other.m_tell;
@@ -63,7 +58,6 @@ public:
Py_INCREF(m_read);
Py_INCREF(m_seek);
Py_INCREF(m_tell);
wxPyEndBlockThreads(blocked);
}
protected:
@@ -88,7 +82,7 @@ protected:
if (bufsize == 0)
return 0;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* arglist = Py_BuildValue("(i)", bufsize);
PyObject* result = PyEval_CallObject(m_read, arglist);
Py_DECREF(arglist);
@@ -106,7 +100,6 @@ protected:
}
else
m_lasterror = wxSTREAM_READ_ERROR;
wxPyEndBlockThreads(blocked);
return o;
}
@@ -118,7 +111,7 @@ protected:
wxFileOffset OnSysSeek(wxFileOffset off, wxSeekMode mode)
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* arglist = PyTuple_New(2);
if (sizeof(wxFileOffset) > sizeof(long))
@@ -133,13 +126,12 @@ protected:
PyObject* result = PyEval_CallObject(m_seek, arglist);
Py_DECREF(arglist);
Py_XDECREF(result);
wxPyEndBlockThreads(blocked);
return OnSysTell();
}
wxFileOffset OnSysTell() const
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* arglist = Py_BuildValue("()");
PyObject* result = PyEval_CallObject(m_tell, arglist);
Py_DECREF(arglist);
@@ -151,7 +143,6 @@ protected:
o = wxPyInt_AsLong(result);
Py_DECREF(result);
};
wxPyEndBlockThreads(blocked);
return o;
}

View File

@@ -33,29 +33,24 @@ public:
wxPyOutputStream(PyObject* fileObj, bool block=true)
{
m_block = block;
wxPyBlock_t blocked = wxPyBlock_t_default;
if (block) blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker(m_block);
m_write = wxPyGetMethod(fileObj, "write");
m_seek = wxPyGetMethod(fileObj, "seek");
m_tell = wxPyGetMethod(fileObj, "tell");
if (block) wxPyEndBlockThreads(blocked);
}
virtual ~wxPyOutputStream()
{
wxPyBlock_t blocked = wxPyBlock_t_default;
if (m_block) blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker(m_block);
Py_XDECREF(m_write);
Py_XDECREF(m_seek);
Py_XDECREF(m_tell);
if (m_block) wxPyEndBlockThreads(blocked);
}
wxPyOutputStream(const wxPyOutputStream& other)
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
m_write = other.m_write;
m_seek = other.m_seek;
m_tell = other.m_tell;
@@ -63,7 +58,6 @@ public:
Py_INCREF(m_write);
Py_INCREF(m_seek);
Py_INCREF(m_tell);
wxPyEndBlockThreads(blocked);
}
protected:
@@ -94,7 +88,7 @@ protected:
if (bufsize == 0)
return 0;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* arglist = PyTuple_New(1);
PyTuple_SET_ITEM(arglist, 0, PyBytes_FromStringAndSize((char*)buffer, bufsize));
@@ -105,13 +99,12 @@ protected:
Py_DECREF(result);
else
m_lasterror = wxSTREAM_WRITE_ERROR;
wxPyEndBlockThreads(blocked);
return bufsize;
}
wxFileOffset OnSysSeek(wxFileOffset off, wxSeekMode mode)
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* arglist = PyTuple_New(2);
if (sizeof(wxFileOffset) > sizeof(long))
@@ -126,13 +119,12 @@ protected:
PyObject* result = PyEval_CallObject(m_seek, arglist);
Py_DECREF(arglist);
Py_XDECREF(result);
wxPyEndBlockThreads(blocked);
return OnSysTell();
}
wxFileOffset OnSysTell() const
{
wxPyBlock_t blocked = wxPyBeginBlockThreads();
wxPyThreadBlocker blocker;
PyObject* arglist = Py_BuildValue("()");
PyObject* result = PyEval_CallObject(m_tell, arglist);
Py_DECREF(arglist);
@@ -144,7 +136,6 @@ protected:
o = wxPyInt_AsLong(result);
Py_DECREF(result);
};
wxPyEndBlockThreads(blocked);
return o;
}

View File

@@ -64,7 +64,7 @@
%ConvertFromTypeCode
// Code to convert a wxClientData back to the PyObject.
// Code to convert a wxPyUserData back to the PyObject.
PyObject* obj;
if (sipCpp == NULL) {
obj = Py_None;

View File

@@ -46,6 +46,8 @@
//--------------------------------------------------------------------------
typedef PyGILState_STATE wxPyBlock_t;
#define wxPyBlock_t_default PyGILState_UNLOCKED
typedef unsigned char byte;
typedef unsigned char* buffer;
@@ -74,7 +76,7 @@ inline void wxPyEndAllowThreads(PyThreadState* saved) {
// A macro that will help to execute simple statments wrapped in
// StartBlock/EndBlockThreads calls
#define wxPyBLOCK_THREADS(stmt) \
{ wxPyBlock_t blocked = wxPyBeginBlockThreads(); stmt; wxPyEndBlockThreads(blocked); }
{ wxPyThreadBlocker _blocker; stmt; }
// Raise any exception with a string value (blocking threads)
#define wxPyErr_SetString(err, str) \
@@ -96,6 +98,7 @@ inline void wxPyEndAllowThreads(PyThreadState* saved) {
inline PyObject* wxPyMakeBuffer(void* ptr, Py_ssize_t len) {
// GIL should already be held
Py_buffer view;
PyBuffer_FillInfo(&view, NULL, ptr, len, 0, PyBUF_WRITABLE|PyBUF_FORMAT|PyBUF_ND);
return PyMemoryView_FromBuffer(&view);
@@ -123,6 +126,7 @@ inline PyObject* wxPyMakeBuffer(void* ptr, Py_ssize_t len) {
inline
Py_ssize_t wxPyUnicode_AsWideChar(PyObject* unicode, wchar_t* w, Py_ssize_t size)
{
// GIL should already be held
#if PY_MAJOR_VERSION >= 3
return PyUnicode_AsWideChar(unicode, w, size);
#else
@@ -162,7 +166,7 @@ inline wxPyAPI* wxPyGetAPIPtr()
}
//--------------------------------------------------------------------------
// Inline wrappers to call the API functions
// Inline wrappers which call the functions in the API structure
// Convert a PyObject to a wxString
// Assumes that the GIL has already been acquired.
@@ -184,4 +188,30 @@ inline wxPyBlock_t wxPyBeginBlockThreads()
inline void wxPyEndBlockThreads(wxPyBlock_t blocked)
{ wxPyGetAPIPtr()->p_wxPyEndBlockThreads(blocked); }
//--------------------------------------------------------------------------
// Convenience helper for RAII thread blocking
class wxPyThreadBlocker {
public:
explicit wxPyThreadBlocker(bool block=true)
: m_oldstate(block ? wxPyBeginBlockThreads() : wxPyBlock_t_default),
m_block(block)
{ }
~wxPyThreadBlocker() {
if (m_block) {
wxPyEndBlockThreads(m_oldstate);
}
}
private:
void operator=(const wxPyThreadBlocker&);
explicit wxPyThreadBlocker(const wxPyThreadBlocker&);
wxPyBlock_t m_oldstate;
bool m_block;
};
#endif