+ wxCriticalSectionLocker lock(m_csCancelled);
+
+ m_cancelled = true;
+ }
+ }
+}
+
+void MyFrame::OnStartGUIThread(wxCommandEvent& WXUNUSED(event))
+{
+ // we use this to check that disabling logging only affects the main thread
+ // but the messages from the worker thread will still be logged
+ wxLogNull noLog;
+ wxLogMessage("You shouldn't see this message because of wxLogNull");
+
+ MyImageDialog dlg(this);
+
+ dlg.ShowModal();
+}
+
+
+// ----------------------------------------------------------------------------
+// MyImageDialog
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(MyImageDialog, wxDialog)
+ EVT_THREAD(GUITHREAD_EVENT, MyImageDialog::OnGUIThreadEvent)
+ EVT_PAINT(MyImageDialog::OnPaint)
+END_EVENT_TABLE()
+
+MyImageDialog::MyImageDialog(wxFrame *parent)
+ : wxDialog(parent, wxID_ANY, "Image created by a secondary thread",
+ wxDefaultPosition, wxSize(GUITHREAD_BMP_SIZE,GUITHREAD_BMP_SIZE)*1.5, wxDEFAULT_DIALOG_STYLE),
+ m_thread(this)
+{
+ m_nCurrentProgress = 0;
+
+ CentreOnScreen();
+
+ // NOTE: no need to lock m_csBmp until the thread isn't started:
+
+ // create the bitmap
+ if (!m_bmp.Create(GUITHREAD_BMP_SIZE,GUITHREAD_BMP_SIZE) || !m_bmp.IsOk())
+ {
+ wxLogError("Couldn't create the bitmap!");
+ return;
+ }
+
+ // clean it
+ wxMemoryDC dc(m_bmp);
+ dc.SetBackground(*wxBLACK_BRUSH);
+ dc.Clear();
+
+ // draw the bitmap from a secondary thread
+ if ( m_thread.Create() != wxTHREAD_NO_ERROR ||
+ m_thread.Run() != wxTHREAD_NO_ERROR )
+ {
+ wxLogError(wxT("Can't create/run thread!"));
+ return;
+ }
+}
+
+MyImageDialog::~MyImageDialog()
+{
+ // in case our thread is still running and for some reason we are destroyed,
+ // do wait for the thread to complete as it assumes that its MyImageDialog
+ // pointer is always valid
+ m_thread.Delete();
+}
+
+void MyImageDialog::OnGUIThreadEvent(wxThreadEvent& event)
+{
+ m_nCurrentProgress = int(((float)event.GetInt()*100)/GUITHREAD_NUM_UPDATES);
+
+ Refresh();
+}
+
+void MyImageDialog::OnPaint(wxPaintEvent& WXUNUSED(evt))
+{
+ wxPaintDC dc(this);
+
+ const wxSize& sz = dc.GetSize();
+
+ {
+ // paint the bitmap
+ wxCriticalSectionLocker locker(m_csBmp);
+ dc.DrawBitmap(m_bmp, (sz.GetWidth()-GUITHREAD_BMP_SIZE)/2,
+ (sz.GetHeight()-GUITHREAD_BMP_SIZE)/2);
+ }
+
+ // paint a sort of progress bar with a 10px border:
+ dc.SetBrush(*wxRED_BRUSH);
+ dc.DrawRectangle(10,10, m_nCurrentProgress*(sz.GetWidth()-20)/100,30);
+ dc.SetTextForeground(*wxBLUE);
+ dc.DrawText(wxString::Format("%d%%", m_nCurrentProgress),
+ (sz.GetWidth()-dc.GetCharWidth()*2)/2,
+ 25-dc.GetCharHeight()/2);
+}
+
+// ----------------------------------------------------------------------------
+// MyThread
+// ----------------------------------------------------------------------------
+
+MyThread::MyThread()
+ : wxThread()
+{
+ m_count = 0;
+}
+
+MyThread::~MyThread()
+{
+ wxCriticalSectionLocker locker(wxGetApp().m_critsect);
+
+ wxArrayThread& threads = wxGetApp().m_threads;
+ threads.Remove(this);
+
+ if ( threads.IsEmpty() )
+ {
+ // signal the main thread that there are no more threads left if it is
+ // waiting for us
+ if ( wxGetApp().m_shuttingDown )
+ {
+ wxGetApp().m_shuttingDown = false;