]> git.saurik.com Git - wxWidgets.git/blobdiff - interface/wx/thread.h
Fix crash in wxDataViewCtrl::UpdateColWidths().
[wxWidgets.git] / interface / wx / thread.h
index 20d0f92a608d4210e801fd0a36f0eb806484069f..adfe7740916d08bfdfd19436d6e6c5c0ef3d7487 100644 (file)
@@ -3,7 +3,7 @@
 // Purpose:     interface of all thread-related wxWidgets classes
 // Author:      wxWidgets team
 // RCS-ID:      $Id$
 // Purpose:     interface of all thread-related wxWidgets classes
 // Author:      wxWidgets team
 // RCS-ID:      $Id$
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 
 /////////////////////////////////////////////////////////////////////////////
 
 
@@ -279,7 +279,7 @@ public:
 
     Example:
     @code
 
     Example:
     @code
-        extern const wxEventType wxEVT_COMMAND_MYTHREAD_UPDATE;
+        wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
 
         class MyFrame : public wxFrame, public wxThreadHelper
         {
 
         class MyFrame : public wxFrame, public wxThreadHelper
         {
@@ -298,7 +298,7 @@ public:
 
             ...
             void DoStartALongTask();
 
             ...
             void DoStartALongTask();
-            void OnThreadUpdate(wxCommandEvent& evt);
+            void OnThreadUpdate(wxThreadEvent& evt);
             void OnClose(wxCloseEvent& evt);
             ...
 
             void OnClose(wxCloseEvent& evt);
             ...
 
@@ -309,14 +309,14 @@ public:
             char m_data[1024];
             wxCriticalSection m_dataCS; // protects field above
 
             char m_data[1024];
             wxCriticalSection m_dataCS; // protects field above
 
-            DECLARE_EVENT_TABLE()
+            wxDECLARE_EVENT_TABLE();
         };
 
         };
 
-        DEFINE_EVENT_TYPE(wxEVT_COMMAND_MYTHREAD_UPDATE)
-        BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+        wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent)
+        wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
             EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
             EVT_CLOSE(MyFrame::OnClose)
             EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
             EVT_CLOSE(MyFrame::OnClose)
-        END_EVENT_TABLE()
+        wxEND_EVENT_TABLE()
 
         void MyFrame::DoStartALongTask()
         {
 
         void MyFrame::DoStartALongTask()
         {
@@ -355,7 +355,7 @@ public:
                 download_chunk(buffer, 1024);     // this takes time...
 
                 {
                 download_chunk(buffer, 1024);     // this takes time...
 
                 {
-                    // ensure noone reads m_data while we write it
+                    // ensure no one reads m_data while we write it
                     wxCriticalSectionLocker lock(m_dataCS);
                     memcpy(m_data+offset, buffer, 1024);
                     offset += 1024;
                     wxCriticalSectionLocker lock(m_dataCS);
                     memcpy(m_data+offset, buffer, 1024);
                     offset += 1024;
@@ -364,7 +364,7 @@ public:
 
                 // VERY IMPORTANT: do not call any GUI function inside this
                 //                 function; rather use wxQueueEvent():
 
                 // VERY IMPORTANT: do not call any GUI function inside this
                 //                 function; rather use wxQueueEvent():
-                wxQueueEvent(this, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
+                wxQueueEvent(this, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
                     // we used pointer 'this' assuming it's safe; see OnClose()
             }
 
                     // we used pointer 'this' assuming it's safe; see OnClose()
             }
 
@@ -386,7 +386,7 @@ public:
             Destroy();
         }
 
             Destroy();
         }
 
-        void MyFrame::OnThreadUpdate(wxCommandEvent&evt)
+        void MyFrame::OnThreadUpdate(wxThreadEvent& evt)
         {
             // ...do something... e.g. m_pGauge->Pulse();
 
         {
             // ...do something... e.g. m_pGauge->Pulse();
 
@@ -399,7 +399,7 @@ public:
     @library{wxbase}
     @category{threading}
 
     @library{wxbase}
     @category{threading}
 
-    @see wxThread
+    @see wxThread, wxThreadEvent
 */
 class wxThreadHelper
 {
 */
 class wxThreadHelper
 {
@@ -454,6 +454,43 @@ public:
     */
     virtual ExitCode Entry() = 0;
 
     */
     virtual ExitCode Entry() = 0;
 
+    /**
+        Callback called by Delete() before actually deleting the thread.
+
+        This function can be overridden by the derived class to perform some
+        specific task when the thread is gracefully destroyed. Notice that it
+        will be executed in the context of the thread that called Delete() and
+        <b>not</b> in this thread's context.
+
+        TestDestroy() will be true for the thread before OnDelete() gets
+        executed.
+
+        @since 2.9.2
+
+        @see OnKill()
+    */
+    virtual void OnDelete();
+
+    /**
+        Callback called by Kill() before actually killing the thread.
+
+        This function can be overridden by the derived class to perform some
+        specific task when the thread is terminated. Notice that it will be
+        executed in the context of the thread that called Kill() and <b>not</b>
+        in this thread's context.
+
+        @since 2.9.2
+
+        @see OnDelete()
+    */
+    virtual void OnKill();
+
+    /**
+        @deprecated
+        Use CreateThread() instead.
+    */
+    wxThreadError Create(unsigned int stackSize = 0);
+
     /**
         Creates a new thread of the given @a kind.
 
     /**
         Creates a new thread of the given @a kind.
 
@@ -507,11 +544,15 @@ enum wxCriticalSectionType
 
     Finally, you should try to use wxCriticalSectionLocker class whenever
     possible instead of directly using wxCriticalSection for the same reasons
 
     Finally, you should try to use wxCriticalSectionLocker class whenever
     possible instead of directly using wxCriticalSection for the same reasons
-    wxMutexLocker is preferrable to wxMutex - please see wxMutex for an example.
+    wxMutexLocker is preferable to wxMutex - please see wxMutex for an example.
 
     @library{wxbase}
     @category{threading}
 
 
     @library{wxbase}
     @category{threading}
 
+    @note Critical sections can be used before the wxWidgets library is fully
+          initialized. In particular, it's safe to create global
+          wxCriticalSection instances.
+
     @see wxThread, wxCondition, wxCriticalSectionLocker
 */
 class wxCriticalSection
     @see wxThread, wxCondition, wxCriticalSectionLocker
 */
 class wxCriticalSection
@@ -529,11 +570,17 @@ public:
     ~wxCriticalSection();
 
     /**
     ~wxCriticalSection();
 
     /**
-        Enter the critical section (same as locking a mutex).
-
+        Enter the critical section (same as locking a mutex): if another thread
+        has already entered it, this call will block until the other thread
+        calls Leave().
         There is no error return for this function.
         There is no error return for this function.
-        After entering the critical section protecting some global
-        data the thread running in critical section may safely use/modify it.
+
+        After entering the critical section protecting a data variable,
+        the thread running inside the critical section may safely use/modify it.
+
+        Note that entering the same critical section twice or more from the same
+        thread doesn't result in a deadlock; in this case in fact this function will
+        immediately return.
     */
     void Enter();
 
     */
     void Enter();
 
@@ -544,6 +591,46 @@ public:
     void Leave();
 };
 
     void Leave();
 };
 
+/**
+    The possible thread wait types.
+
+    @since 2.9.2
+*/
+enum wxThreadWait
+{
+    /**
+        No events are processed while waiting.
+
+        This is the default under all platforms except for wxMSW.
+     */
+    wxTHREAD_WAIT_BLOCK,
+
+    /**
+        Yield for event dispatching while waiting.
+
+        This flag is dangerous as it exposes the program using it to unexpected
+        reentrancies in the same way as calling wxYield() function does so you
+        are strongly advised to avoid its use and not wait for the thread
+        termination from the main (GUI) thread at all to avoid making your
+        application unresponsive.
+
+        Also notice that this flag is not portable as it is only implemented in
+        wxMSW and simply ignored under the other platforms.
+     */
+    wxTHREAD_WAIT_YIELD,
+
+    /**
+        Default wait mode for wxThread::Wait() and wxThread::Delete().
+
+        For compatibility reasons, the default wait mode is currently
+        wxTHREAD_WAIT_YIELD if WXWIN_COMPATIBILITY_2_8 is defined (and it is
+        by default). However, as mentioned above, you're strongly encouraged to
+        not use wxTHREAD_WAIT_YIELD and pass wxTHREAD_WAIT_BLOCK to wxThread
+        method explicitly.
+     */
+    wxTHREAD_WAIT_DEFAULT = wxTHREAD_WAIT_YIELD
+};
+
 /**
   The possible thread kinds.
 */
 /**
   The possible thread kinds.
 */
@@ -610,10 +697,10 @@ enum
     @section thread_types Types of wxThreads
 
     There are two types of threads in wxWidgets: @e detached and @e joinable,
     @section thread_types Types of wxThreads
 
     There are two types of threads in wxWidgets: @e detached and @e joinable,
-    modeled after the the POSIX thread API. This is different from the Win32 API
+    modeled after the POSIX thread API. This is different from the Win32 API
     where all threads are joinable.
 
     where all threads are joinable.
 
-    By default wxThreads in wxWidgets use the @b detached behavior.
+    By default wxThreads in wxWidgets use the @b detached behaviour.
     Detached threads delete themselves once they have completed, either by themselves
     when they complete processing or through a call to Delete(), and thus
     @b must be created on the heap (through the new operator, for example).
     Detached threads delete themselves once they have completed, either by themselves
     when they complete processing or through a call to Delete(), and thus
     @b must be created on the heap (through the new operator, for example).
@@ -625,8 +712,8 @@ enum
 
     @code
     // declare a new type of event, to be used by our MyThread class:
 
     @code
     // declare a new type of event, to be used by our MyThread class:
-    extern const wxEventType wxEVT_COMMAND_MYTHREAD_COMPLETED;
-    extern const wxEventType wxEVT_COMMAND_MYTHREAD_UPDATE;
+    wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
+    wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
     class MyFrame;
 
     class MyThread : public wxThread
     class MyFrame;
 
     class MyThread : public wxThread
@@ -663,25 +750,26 @@ enum
         // a resume routine would be nearly identic to DoPauseThread()
         void DoResumeThread() { ... }
 
         // a resume routine would be nearly identic to DoPauseThread()
         void DoResumeThread() { ... }
 
-        void OnThreadCompletion(wxCommandEvent&);
+        void OnThreadUpdate(wxThreadEvent&);
+        void OnThreadCompletion(wxThreadEvent&);
         void OnClose(wxCloseEvent&);
 
     protected:
         MyThread *m_pThread;
         wxCriticalSection m_pThreadCS;    // protects the m_pThread pointer
 
         void OnClose(wxCloseEvent&);
 
     protected:
         MyThread *m_pThread;
         wxCriticalSection m_pThreadCS;    // protects the m_pThread pointer
 
-        DECLARE_EVENT_TABLE()
+        wxDECLARE_EVENT_TABLE();
     };
 
     };
 
-    BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+    wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
         EVT_CLOSE(MyFrame::OnClose)
         EVT_MENU(Minimal_Start,  MyFrame::DoStartThread)
         EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
         EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
         EVT_CLOSE(MyFrame::OnClose)
         EVT_MENU(Minimal_Start,  MyFrame::DoStartThread)
         EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
         EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
-    END_EVENT_TABLE()
+    wxEND_EVENT_TABLE()
 
 
-    DEFINE_EVENT_TYPE(wxEVT_COMMAND_MYTHREAD_COMPLETED)
-    DEFINE_EVENT_TYPE(wxEVT_COMMAND_MYTHREAD_UPDATE)
+    wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent)
+    wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent)
 
     void MyFrame::DoStartThread()
     {
 
     void MyFrame::DoStartThread()
     {
@@ -715,13 +803,13 @@ enum
         {
             // ... do a bit of work...
 
         {
             // ... do a bit of work...
 
-            wxQueueEvent(m_pHandler, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
+            wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
         }
 
         // signal the event handler that this thread is going to be destroyed
         // NOTE: here we assume that using the m_pHandler pointer is safe,
         //       (in this case this is assured by the MyFrame destructor)
         }
 
         // signal the event handler that this thread is going to be destroyed
         // NOTE: here we assume that using the m_pHandler pointer is safe,
         //       (in this case this is assured by the MyFrame destructor)
-        wxQueueEvent(m_pHandler, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
+        wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
 
         return (wxThread::ExitCode)0;     // success
     }
 
         return (wxThread::ExitCode)0;     // success
     }
@@ -734,12 +822,12 @@ enum
         m_pHandler->m_pThread = NULL;
     }
 
         m_pHandler->m_pThread = NULL;
     }
 
-    void MyFrame::OnThreadCompletion(wxCommandEvent&)
+    void MyFrame::OnThreadCompletion(wxThreadEvent&)
     {
         wxMessageOutputDebug().Printf("MYFRAME: MyThread exited!\n");
     }
 
     {
         wxMessageOutputDebug().Printf("MYFRAME: MyThread exited!\n");
     }
 
-    void MyFrame::OnThreadUpdate(wxCommandEvent&)
+    void MyFrame::OnThreadUpdate(wxThreadEvent&)
     {
         wxMessageOutputDebug().Printf("MYFRAME: MyThread update...\n");
     }
     {
         wxMessageOutputDebug().Printf("MYFRAME: MyThread update...\n");
     }
@@ -771,7 +859,7 @@ enum
 
             if (m_pThread)         // does the thread still exist?
             {
 
             if (m_pThread)         // does the thread still exist?
             {
-                m_out.Printf("MYFRAME: deleting thread");
+                wxMessageOutputDebug().Printf("MYFRAME: deleting thread");
 
                 if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
                     wxLogError("Can't delete the thread!");
 
                 if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
                     wxLogError("Can't delete the thread!");
@@ -857,9 +945,9 @@ enum
     as MFC.
 
     A workaround for some wxWidgets ports is calling wxMutexGUIEnter()
     as MFC.
 
     A workaround for some wxWidgets ports is calling wxMutexGUIEnter()
-    before any GUI calls and then calling wxMutexGUILeave() afterwords. However,
-    the recommended way is to simply process the GUI calls in the main thread
-    through an event that is posted by wxQueueEvent().
+    before any GUI calls and then calling wxMutexGUILeave() afterwords.
+    However, the recommended way is to simply process the GUI calls in the main
+    thread through an event that is posted by wxQueueEvent().
     This does not imply that calls to these classes are thread-safe, however,
     as most wxWidgets classes are not thread-safe, including wxString.
 
     This does not imply that calls to these classes are thread-safe, however,
     as most wxWidgets classes are not thread-safe, including wxString.
 
@@ -869,10 +957,10 @@ enum
     A common problem users experience with wxThread is that in their main thread
     they will check the thread every now and then to see if it has ended through
     IsRunning(), only to find that their application has run into problems
     A common problem users experience with wxThread is that in their main thread
     they will check the thread every now and then to see if it has ended through
     IsRunning(), only to find that their application has run into problems
-    because the thread is using the default behavior (i.e. it's @b detached) and
+    because the thread is using the default behaviour (i.e. it's @b detached) and
     has already deleted itself.
     Naturally, they instead attempt to use joinable threads in place of the previous
     has already deleted itself.
     Naturally, they instead attempt to use joinable threads in place of the previous
-    behavior. However, polling a wxThread for when it has ended is in general a
+    behaviour. However, polling a wxThread for when it has ended is in general a
     bad idea - in fact calling a routine on any running wxThread should be avoided
     if possible. Instead, find a way to notify yourself when the thread has ended.
 
     bad idea - in fact calling a routine on any running wxThread should be avoided
     if possible. Instead, find a way to notify yourself when the thread has ended.
 
@@ -939,7 +1027,7 @@ public:
             performance issues on those systems with small default stack since those
             typically use fully committed memory for the stack.
             On the contrary, if you use a lot of threads (say several hundred),
             performance issues on those systems with small default stack since those
             typically use fully committed memory for the stack.
             On the contrary, if you use a lot of threads (say several hundred),
-            virtual adress space can get tight unless you explicitly specify a
+            virtual address space can get tight unless you explicitly specify a
             smaller amount of thread stack space for each thread.
 
         @return One of:
             smaller amount of thread stack space for each thread.
 
         @return One of:
@@ -953,6 +1041,15 @@ public:
         Calling Delete() gracefully terminates a @b detached thread, either when
         the thread calls TestDestroy() or when it finishes processing.
 
         Calling Delete() gracefully terminates a @b detached thread, either when
         the thread calls TestDestroy() or when it finishes processing.
 
+        @param rc
+            The thread exit code, if rc is not NULL.
+
+        @param waitMode
+            As described in wxThreadWait documentation, wxTHREAD_WAIT_BLOCK
+            should be used as the wait mode even although currently
+            wxTHREAD_WAIT_YIELD is for compatibility reasons. This parameter is
+            new in wxWidgets 2.9.2.
+
         @note
             This function works on a joinable thread but in that case makes
             the TestDestroy() function of the thread return @true and then
         @note
             This function works on a joinable thread but in that case makes
             the TestDestroy() function of the thread return @true and then
@@ -961,20 +1058,28 @@ public:
 
         See @ref thread_deletion for a broader explanation of this routine.
     */
 
         See @ref thread_deletion for a broader explanation of this routine.
     */
-    wxThreadError Delete(void** rc = NULL);
+    wxThreadError Delete(ExitCode *rc = NULL,
+                         wxThreadWait waitMode = wxTHREAD_WAIT_BLOCK);
 
     /**
         Returns the number of system CPUs or -1 if the value is unknown.
 
 
     /**
         Returns the number of system CPUs or -1 if the value is unknown.
 
+        For multi-core systems the returned value is typically the total number
+        of @e cores, since the OS usually abstract a single N-core CPU
+        as N different cores.
+
         @see SetConcurrency()
     */
     static int GetCPUCount();
 
     /**
         Returns the platform specific thread ID of the current thread as a long.
         @see SetConcurrency()
     */
     static int GetCPUCount();
 
     /**
         Returns the platform specific thread ID of the current thread as a long.
+
         This can be used to uniquely identify threads, even if they are not wxThreads.
         This can be used to uniquely identify threads, even if they are not wxThreads.
+
+        @see GetMainId()
     */
     */
-    static unsigned long GetCurrentId();
+    static wxThreadIdType GetCurrentId();
 
     /**
         Gets the thread identifier: this is a platform dependent number that uniquely
 
     /**
         Gets the thread identifier: this is a platform dependent number that uniquely
@@ -990,6 +1095,15 @@ public:
     */
     wxThreadKind GetKind() const;
 
     */
     wxThreadKind GetKind() const;
 
+    /**
+        Returns the thread ID of the main thread.
+
+        @see IsMain()
+
+        @since 2.9.1
+     */
+    static wxThreadIdType GetMainId();
+
     /**
         Gets the priority of the thread, between zero and 100.
 
     /**
         Gets the priority of the thread, between zero and 100.
 
@@ -1018,6 +1132,11 @@ public:
 
     /**
         Returns @true if the calling thread is the main application thread.
 
     /**
         Returns @true if the calling thread is the main application thread.
+
+        Main thread in the context of wxWidgets is the one which initialized
+        the library.
+
+        @see GetMainId(), GetCurrentId()
     */
     static bool IsMain();
 
     */
     static bool IsMain();
 
@@ -1087,6 +1206,10 @@ public:
         of detached threads.
 
         This function can only be called from another thread context.
         of detached threads.
 
         This function can only be called from another thread context.
+        
+        Finally, note that once a thread has completed and its Entry() function
+        returns, you cannot call Run() on it again (an assert will fail in debug
+        builds or @c wxTHREAD_RUNNING will be returned in release builds).
     */
     wxThreadError Run();
 
     */
     wxThreadError Run();
 
@@ -1151,9 +1274,15 @@ public:
 
         This function can only be called from another thread context.
 
 
         This function can only be called from another thread context.
 
+        @param waitMode
+            As described in wxThreadWait documentation, wxTHREAD_WAIT_BLOCK
+            should be used as the wait mode even although currently
+            wxTHREAD_WAIT_YIELD is for compatibility reasons. This parameter is
+            new in wxWidgets 2.9.2.
+
         See @ref thread_deletion for a broader explanation of this routine.
     */
         See @ref thread_deletion for a broader explanation of this routine.
     */
-    ExitCode Wait();
+    ExitCode Wait(wxThreadWait flags = wxTHREAD_WAIT_BLOCK);
 
     /**
         Give the rest of the thread's time-slice to the system allowing the other
 
     /**
         Give the rest of the thread's time-slice to the system allowing the other
@@ -1495,6 +1624,9 @@ public:
         Locks the mutex object.
         This is equivalent to LockTimeout() with infinite timeout.
 
         Locks the mutex object.
         This is equivalent to LockTimeout() with infinite timeout.
 
+        Note that if this mutex is already locked by the caller thread,
+        this function doesn't block but rather immediately returns.
+
         @return One of: @c wxMUTEX_NO_ERROR, @c wxMUTEX_DEAD_LOCK.
     */
     wxMutexError Lock();
         @return One of: @c wxMUTEX_NO_ERROR, @c wxMUTEX_DEAD_LOCK.
     */
     wxMutexError Lock();
@@ -1527,7 +1659,7 @@ public:
 // Global functions/macros
 // ============================================================================
 
 // Global functions/macros
 // ============================================================================
 
-/** @ingroup group_funcmacro_thread */
+/** @addtogroup group_funcmacro_thread */
 //@{
 
 /**
 //@{
 
 /**
@@ -1610,6 +1742,8 @@ public:
 */
 bool wxIsMainThread();
 
 */
 bool wxIsMainThread();
 
+
+
 /**
     This function must be called when any thread other than the main GUI thread
     wants to get access to the GUI library. This function will block the
 /**
     This function must be called when any thread other than the main GUI thread
     wants to get access to the GUI library. This function will block the
@@ -1628,14 +1762,14 @@ bool wxIsMainThread();
         wxMutexGuiEnter();
 
         // Call GUI here:
         wxMutexGuiEnter();
 
         // Call GUI here:
-        my_window-DrawSomething();
+        my_window->DrawSomething();
 
         wxMutexGuiLeave();
     }
     @endcode
 
     This function is only defined on platforms which support preemptive
 
         wxMutexGuiLeave();
     }
     @endcode
 
     This function is only defined on platforms which support preemptive
-    threads.
+    threads and only works under some ports (wxMSW currently).
 
     @note Under GTK, no creation of top-level windows is allowed in any thread
           but the main one.
 
     @note Under GTK, no creation of top-level windows is allowed in any thread
           but the main one.