]> git.saurik.com Git - wxWidgets.git/commitdiff
second part of #10320: move wxApp event handling functions to wxEventLoopBase (in...
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Sun, 15 Feb 2009 14:25:08 +0000 (14:25 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Sun, 15 Feb 2009 14:25:08 +0000 (14:25 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58911 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

50 files changed:
docs/changes.txt
include/wx/app.h
include/wx/cocoa/app.h
include/wx/cocoa/evtloop.h
include/wx/dfb/app.h
include/wx/dfb/evtloop.h
include/wx/event.h
include/wx/evtloop.h
include/wx/gtk/app.h
include/wx/gtk/evtloop.h
include/wx/gtk1/app.h
include/wx/mgl/app.h
include/wx/motif/app.h
include/wx/msw/app.h
include/wx/msw/evtloop.h
include/wx/os2/app.h
include/wx/osx/app.h
include/wx/osx/carbon/evtloop.h
include/wx/osx/cocoa/evtloop.h
include/wx/palmos/app.h
include/wx/palmos/evtloop.h
include/wx/unix/evtloop.h
include/wx/x11/app.h
interface/wx/app.h
interface/wx/event.h
interface/wx/evtloop.h
src/common/appbase.cpp
src/common/appcmn.cpp
src/common/event.cpp
src/common/evtloopcmn.cpp
src/dfb/app.cpp
src/dfb/evtloop.cpp
src/generic/progdlgg.cpp
src/gtk/app.cpp
src/gtk/clipbrd.cpp
src/gtk/evtloop.cpp
src/gtk1/app.cpp
src/gtk1/evtloop.cpp
src/mgl/app.cpp
src/mgl/evtloop.cpp
src/motif/app.cpp
src/motif/evtloop.cpp
src/msw/app.cpp
src/msw/evtloop.cpp
src/os2/app.cpp
src/os2/evtloop.cpp
src/palmos/app.cpp
src/palmos/evtloop.cpp
src/x11/app.cpp
src/x11/evtloop.cpp

index 7cfb0b0c337cd6e4c6780ddfb16f9bfdc4c562a1..c8b5cc79258912c0d255631ba30ffbe9efaadb78 100644 (file)
@@ -261,6 +261,8 @@ Deprecated methods and their replacements
 - wxDos2UnixFilename, wxUnix2DosFilename, wxStripExtension, wxGetTempFileName,
   wxExpandPath, wxContractPath, wxRealPath, wxCopyAbsolutePath, wxSplitPath
   were deprecated in favour of wxFileName methods. See docs for more info.
+- global wxPendingEvents and wxPendingEventsLocker objects were removed; now you may use
+  wxEventLoopBase::SuspendProcessingOfPendingEvents instead of locking wxPendingEventsLocker.
 
 Major new features in this release
 ----------------------------------
@@ -472,6 +474,9 @@ All (GUI):
 - Added wxIMAGE_OPTION_PNG_FILTER and many wxIMAGE_OPTION_PNG_COMPRESSION_* options
   to wxImage and wxPNGHandler to allow for custom compression levels when saving PNGs
 - Added GetValue(), GetRange(), GetMessage() functions to wxProgressDialog
+- Moved yield functions to wxEventLoopBase and implemented for wxMSW and wxGTK
+  a selective wxEventLoopBase::YieldFor() function.
+  Added also wxEventLoopBase::IsYielding to help cure re-entrancy problems with Yield().
 
 wxGTK:
 
index a5b60fed2b6660bb972947190cbfcd06d8d878db..8a6a135df983d94d3be021f20c48d1b15bd8f7fb 100644 (file)
@@ -221,6 +221,10 @@ public:
     // had been already processed or won't be processed at all, respectively
     virtual int FilterEvent(wxEvent& event);
 
+    // return true if we're running event loop, i.e. if the events can
+    // (already) be dispatched
+    static bool IsMainLoopRunning();
+
 #if wxUSE_EXCEPTIONS
     // execute the functor to handle the given event
     //
@@ -246,88 +250,35 @@ public:
     // exit, if you need to really handle the exceptions you need to override
     // OnExceptionInMainLoop()
     virtual void OnUnhandledException();
+
+    // Function called if an uncaught exception is caught inside the main
+    // event loop: it may return true to continue running the event loop or
+    // false to stop it (in the latter case it may rethrow the exception as
+    // well)
+    virtual bool OnExceptionInMainLoop();
+
 #endif // wxUSE_EXCEPTIONS
 
-    // event processing functions
-    // --------------------------
 
-    // return true if we're running event loop, i.e. if the events can
-    // (already) be dispatched
-    static bool IsMainLoopRunning();
+    // wxEventLoop redirections
+    // ------------------------
 
-    // temporary suspends processing of the pending events
     virtual void SuspendProcessingOfPendingEvents();
-
-    // resume processing of the pending events previously stopped because of a
-    // call to SuspendProcessingOfPendingEvents()
     virtual void ResumeProcessingOfPendingEvents();
-
-    // process all events in the wxHandlersWithPendingEvents list -- it is necessary
-    // to call this function to process posted events. This happens during each
-    // event loop iteration in GUI mode but if there is no main loop, it may be
-    // also called directly.
     virtual void ProcessPendingEvents();
-
-    // check if there are pending events on global pending event list
     bool HasPendingEvents() const;
 
-    // make sure that idle events are sent again
-    virtual void WakeUpIdle();
+    virtual bool Pending();
+    virtual bool Dispatch();
 
-        // execute the main GUI loop, the function returns when the loop ends
     virtual int MainLoop();
-
-        // exit the main GUI loop during the next iteration (i.e. it does not
-        // stop the program immediately!)
     virtual void ExitMainLoop();
 
-        // returns true if there are unprocessed events in the event queue
-    virtual bool Pending();
+    bool Yield(bool onlyIfNeeded = false);
 
-        // process the first event in the event queue (blocks until an event
-        // appears if there are none currently, use Pending() if this is not
-        // wanted), returns false if the event loop should stop and true
-        // otherwise
-    virtual bool Dispatch();
-
-        // this virtual function is called  when the application
-        // becomes idle and normally just sends wxIdleEvent to all interested
-        // parties
-        //
-        // it should return true if more idle events are needed, false if not
+    virtual void WakeUpIdle();
     virtual bool ProcessIdle();
 
-#if wxUSE_EXCEPTIONS
-    // Function called if an uncaught exception is caught inside the main
-    // event loop: it may return true to continue running the event loop or
-    // false to stop it (in the latter case it may rethrow the exception as
-    // well)
-    virtual bool OnExceptionInMainLoop();
-#endif // wxUSE_EXCEPTIONS
-
-    // Yield-related hooks
-    // -------------------
-
-        // process all currently pending events right now
-        //
-        // it is an error to call Yield() recursively unless the value of
-        // onlyIfNeeded is true
-        //
-        // WARNING: this function is dangerous as it can lead to unexpected
-        //          reentrancies (i.e. when called from an event handler it
-        //          may result in calling the same event handler again), use
-        //          with _extreme_ care or, better, don't use at all!
-        // NOTE: in wxConsoleBase it doesn't do anything, just a hook for GUI wxApp
-    bool Yield(bool onlyIfNeeded = false)
-        { return DoYield(onlyIfNeeded, wxEVT_CATEGORY_ALL); }
-    bool YieldFor(long eventsToProcess)
-        { return DoYield(true, eventsToProcess); }
-    virtual bool IsYielding() const
-        { return false; }
-    virtual bool IsEventAllowedInsideYield(wxEventCategory WXUNUSED(cat)) const
-        { return true; }
-    // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
-
 
     // debugging support
     // -----------------
@@ -395,10 +346,6 @@ protected:
     // for the first time
     virtual wxAppTraits *CreateTraits();
 
-    // the real yield function hook:
-    virtual bool DoYield(bool WXUNUSED(onlyIfNeeded), long WXUNUSED(eventsToProcess))
-        { return true; }
-
     // function used for dynamic wxApp creation
     static wxAppInitializerFunction ms_appInitFn;
 
@@ -424,13 +371,6 @@ protected:
     // been started yet or has already terminated)
     wxEventLoopBase *m_mainLoop;
 
-    // the array of the handlers with pending events which needs to be processed
-    // inside ProcessPendingEvents()
-    // wxEvtHandlerArray m_handlersWithPendingEvents;    FIXME: enable this and remove global lists
-
-    // helper array used by ProcessPendingEvents()
-    // wxEvtHandlerArray m_handlersWithPendingDelayedEvents;    FIXME: enable this and remove global lists
-
     friend class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
 
     // the application object is a singleton anyhow, there is no sense in
@@ -496,15 +436,6 @@ public:
     virtual bool SafeYield(wxWindow *win, bool onlyIfNeeded);
     virtual bool SafeYieldFor(wxWindow *win, long eventsToProcess);
 
-        // returns true if the main thread is inside a Yield() call
-    virtual bool IsYielding() const
-        { return m_isInsideYield; }
-
-        // returns true if events of the given event category should be immediately
-        // processed inside a wxApp::Yield() call or rather should be queued for
-        // later processing by the main event loop
-    virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const;
-
         // this virtual function is called in the GUI mode when the application
         // becomes idle and normally just sends wxIdleEvent to all interested
         // parties
@@ -627,10 +558,6 @@ protected:
     // does any of our windows have focus?
     bool m_isActive;
 
-    // Yield() helpers:
-    bool m_isInsideYield;
-    long m_eventsToProcessInsideYield;
-
     wxDECLARE_NO_COPY_CLASS(wxAppBase);
 };
 
index 7285f71e65fd1c7d7db0fa1dc4e59abc4f92f1bf..a0a65f94272bc5977d86ee4a2e3293ddf665c377 100644 (file)
@@ -57,7 +57,6 @@ public:
     // Implement wxAppBase pure virtuals
     virtual void Exit();
 
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
     virtual void WakeUpIdle();
 
     virtual bool Initialize(int& argc, wxChar **argv);
index b61f011185227f6e01c8358d427328bb05a8986b..7e0d4768090ff44e1e030a58686c7b897d3ffe15 100644 (file)
@@ -26,6 +26,7 @@ public:
     virtual bool Dispatch();
     virtual int DispatchTimeout(unsigned long timeout);
     virtual void WakeUp() { }
+    virtual bool YieldFor(long eventsToProcess);
 
 protected:
     int m_exitcode;
index b76af79ce3a693b334b49017cde09ff4a5aa5710..5407b18c5ade6cdc1d3facdf02aa6a04ef2fdecf 100644 (file)
@@ -39,8 +39,6 @@ public:
 private:
     wxVideoMode m_videoMode;
 
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
     DECLARE_DYNAMIC_CLASS(wxApp)
 };
 
index d6fa511ddca0a838d3028bcd2baa5d6a6c949edd..2a58619ed1dfab9b6d8b13cd7d8a98970fe36d53 100644 (file)
@@ -25,14 +25,12 @@ class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxConsoleEventLoop
 public:
     wxGUIEventLoop();
 
+    virtual bool YieldFor(long eventsToProcess);
+
     // returns DirectFB event buffer used by wx
     static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer();
 
 private:
-    // wxYield implementation: iterate the loop as long as there are any
-    // pending events
-    void Yield();
-
     static void InitBuffer();
     static void CleanUp();
 
index 073fef666a40294d9ebea3c4e662f53fd3deccda..215acd74a4ee2568742e0d201188b9e0f97a10f8 100644 (file)
@@ -772,7 +772,7 @@ enum wxEventPropagation
 };
 
 // The different categories for a wxEvent; see wxEvent::GetEventCategory.
-// NOTE: they are used as OR-combinable flags by wxApp::Yield
+// NOTE: they are used as OR-combinable flags by wxEventLoopBase::YieldFor
 enum wxEventCategory
 {
     // this is the category for those events which are generated to update
@@ -802,10 +802,10 @@ enum wxEventCategory
 
     // implementation only
 
-    // used in the implementations of DoYield()
+    // used in the implementations of wxEventLoopBase::YieldFor
     wxEVT_CATEGORY_UNKNOWN = 32,
 
-    // a special category used as an argument to wxApp::Yield() to indicate that
+    // a special category used as an argument to wxEventLoopBase::YieldFor to indicate that
     // Yield() should leave all wxEvents on the queue while emptying the native event queue
     // (native events will be processed but the wxEvents they generate will be queued)
     wxEVT_CATEGORY_CLIPBOARD = 64,
@@ -817,7 +817,7 @@ enum wxEventCategory
     // events of the native toolkit and which typically are not-"delayable".
     wxEVT_CATEGORY_NATIVE_EVENTS = wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT,
 
-    // used in wxApp::Yield to specify all event categories should be processed:
+    // used in wxEventLoopBase::YieldFor to specify all event categories should be processed:
     wxEVT_CATEGORY_ALL =
         wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
         wxEVT_CATEGORY_TIMER|wxEVT_CATEGORY_THREAD
@@ -864,7 +864,7 @@ public:
     // for them wouldn't work (it needs to do a copy of the event)
     virtual wxEvent *Clone() const = 0;
 
-    // this function is used to selectively process events in wxApp::YieldFor
+    // this function is used to selectively process events in wxEventLoopBase::YieldFor
     // NOTE: by default it returns wxEVT_CATEGORY_UI just because the major
     //       part of wxWidgets events belong to that category.
     virtual wxEventCategory GetEventCategory() const
@@ -1120,7 +1120,7 @@ public:
         return ev;
     }
 
-    // this is important to avoid that calling wxApp::Yield() thread events
+    // this is important to avoid that calling wxEventLoopBase::YieldFor thread events
     // gets processed when this is unwanted:
     virtual wxEventCategory GetEventCategory() const
         { return wxEVT_CATEGORY_THREAD; }
@@ -3985,24 +3985,6 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
 // Thread events
 #define EVT_THREAD(id, func)  wx__DECLARE_EVT1(wxEVT_COMMAND_THREAD, id, wxThreadEventHandler(func))
 
-// ----------------------------------------------------------------------------
-// Global data
-// ----------------------------------------------------------------------------
-
-// list containing event handlers with pending events for them
-//
-// notice that each event handler should occur at most once in this list
-extern WXDLLIMPEXP_BASE wxList *wxHandlersWithPendingEvents;
-extern WXDLLIMPEXP_BASE wxList *wxHandlersWithPendingDelayedEvents;
-#if wxUSE_THREADS
-    // this critical section protectes both the lists above
-    extern WXDLLIMPEXP_BASE wxCriticalSection *wxHandlersWithPendingEventsLocker;
-#endif
-
-// old list names:
-#define wxPendingEvents         wxHandlersWithPendingEvents
-#define wxPendingEventsLocker   wxHandlersWithPendingEventsLocker
-
 // ----------------------------------------------------------------------------
 // Helper functions
 // ----------------------------------------------------------------------------
index 7d85458ff8f28f45d4e76f8b7f83296b61b4a7f5..9ff5edbe649aaaf7da86bf9324659ccdab98a985 100644 (file)
 
 #include "wx/utils.h"
 
+
+/*
+    NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
+    ------------------------------------------
+
+    The YieldFor() function helps to avoid re-entrancy problems and problems
+    caused by out-of-order event processing
+    (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
+
+    The logic behind YieldFor() is simple: it analyzes the queue of the native
+    events generated by the underlying GUI toolkit and picks out and processes
+    only those matching the given mask.
+
+    It's important to note that YieldFor() is used to selectively process the
+    events generated by the NATIVE toolkit.
+    Events syntethized by wxWidgets code or by user code are instead selectively
+    processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
+    In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
+    YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
+    if the pending events for that event handler can be processed.
+    If all the pending events associated with that event handler result as "not processable",
+    the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
+    (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
+    Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
+    event handlers back into the list of handlers with pending events
+    (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
+    a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
+    will process all pending events as usual.
+*/
+
 // ----------------------------------------------------------------------------
 // wxEventLoopBase: interface for wxEventLoop
 // ----------------------------------------------------------------------------
@@ -22,7 +52,7 @@ class WXDLLIMPEXP_BASE wxEventLoopBase
 {
 public:
     // trivial, but needed (because of wxEventLoopBase) ctor
-    wxEventLoopBase() { }
+    wxEventLoopBase();
 
     // dtor
     virtual ~wxEventLoopBase() { }
@@ -32,9 +62,18 @@ public:
     virtual bool IsOk() const { return true; }
 
 
+    // dispatch&processing
+    // -------------------
+
     // start the event loop, return the exit code when it is finished
     virtual int Run() = 0;
 
+    // is this event loop running now?
+    //
+    // notice that even if this event loop hasn't terminated yet but has just
+    // spawned a nested (e.g. modal) event loop, this would return false
+    bool IsRunning() const;
+
     // exit from the loop with the given exit code
     virtual void Exit(int rc = 0) = 0;
 
@@ -49,6 +88,86 @@ public:
     // exit the loop or -1 if timeout expired
     virtual int DispatchTimeout(unsigned long timeout) = 0;
 
+    // implement this to wake up the loop: usually done by posting a dummy event
+    // to it (can be called from non main thread)
+    virtual void WakeUp() = 0;
+
+
+    // pending events
+    // --------------
+
+    // process all events in the wxHandlersWithPendingEvents list -- it is necessary
+    // to call this function to process posted events. This happens during each
+    // event loop iteration in GUI mode but if there is no main loop, it may be
+    // also called directly.
+    virtual void ProcessPendingEvents();
+
+    // check if there are pending events on global pending event list
+    bool HasPendingEvents() const;
+
+    // temporary suspends processing of the pending events
+    void SuspendProcessingOfPendingEvents();
+
+    // resume processing of the pending events previously stopped because of a
+    // call to SuspendProcessingOfPendingEvents()
+    void ResumeProcessingOfPendingEvents();
+
+    // called by ~wxEvtHandler to (eventually) remove the handler from the list of
+    // the handlers with pending events
+    void RemovePendingEventHandler(wxEvtHandler* toRemove);
+
+    // adds an event handler to the list of the handlers with pending events
+    void AppendPendingEventHandler(wxEvtHandler* toAppend);
+
+    // moves the event handler from the list of the handlers with pending events
+    //to the list of the handlers with _delayed_ pending events
+    void DelayPendingEventHandler(wxEvtHandler* toDelay);
+
+
+    // idle handling
+    // -------------
+
+    // make sure that idle events are sent again
+    virtual void WakeUpIdle();
+
+        // this virtual function is called  when the application
+        // becomes idle and normally just sends wxIdleEvent to all interested
+        // parties
+        //
+        // it should return true if more idle events are needed, false if not
+    virtual bool ProcessIdle();
+
+
+    // Yield-related hooks
+    // -------------------
+
+        // process all currently pending events right now
+        //
+        // it is an error to call Yield() recursively unless the value of
+        // onlyIfNeeded is true
+        //
+        // WARNING: this function is dangerous as it can lead to unexpected
+        //          reentrancies (i.e. when called from an event handler it
+        //          may result in calling the same event handler again), use
+        //          with _extreme_ care or, better, don't use at all!
+    bool Yield(bool onlyIfNeeded = false);
+    virtual bool YieldFor(long eventsToProcess) = 0;
+
+        // returns true if the main thread is inside a Yield() call
+    virtual bool IsYielding() const
+        { return m_isInsideYield; }
+
+        // returns true if events of the given event category should be immediately
+        // processed inside a wxApp::Yield() call or rather should be queued for
+        // later processing by the main event loop
+    virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const
+        { return (m_eventsToProcessInsideYield & cat) != 0; }
+
+    // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
+
+
+    // active loop
+    // -----------
 
     // return currently active (running) event loop, may be NULL
     static wxEventLoopBase *GetActive() { return ms_activeLoop; }
@@ -56,15 +175,6 @@ public:
     // set currently active (running) event loop
     static void SetActive(wxEventLoopBase* loop) { ms_activeLoop = loop; }
 
-    // is this event loop running now?
-    //
-    // notice that even if this event loop hasn't terminated yet but has just
-    // spawned a nested (e.g. modal) event loop, this would return false
-    bool IsRunning() const;
-
-    // implement this to wake up the loop: usually done by posting a dummy event
-    // to it (can be called from non main thread)
-    virtual void WakeUp() = 0;
 
 protected:
     // this function should be called before the event loop terminates, whether
@@ -72,10 +182,25 @@ protected:
     // an exception thrown from inside the loop)
     virtual void OnExit() { }
 
-
     // the pointer to currently active loop
     static wxEventLoopBase *ms_activeLoop;
 
+    // the array of the handlers with pending events which needs to be processed
+    // inside ProcessPendingEvents()
+    wxEvtHandlerArray m_handlersWithPendingEvents;
+
+    // helper array used by ProcessPendingEvents()
+    wxEvtHandlerArray m_handlersWithPendingDelayedEvents;
+
+#if wxUSE_THREADS
+    // this critical section protects both the lists above
+    wxCriticalSection m_handlersWithPendingEventsLocker;
+#endif
+
+    // Yield() helpers:
+    bool m_isInsideYield;
+    long m_eventsToProcessInsideYield;
+
     wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
 };
 
@@ -161,6 +286,7 @@ public:
         }
     }
     virtual void WakeUp() { }
+    virtual bool YieldFor(long eventsToProcess);
 
 protected:
     // the pointer to the port specific implementation class
index 87a2ff8c437e26157ed1fd2289293fcc0fd8cd64..630bf9b04d41f46b25705bf2d5a3537bd3c31763 100644 (file)
@@ -78,10 +78,6 @@ public:
     bool EventsPending();
     bool DoIdle();
 
-protected:
-
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
 private:
     // true if we're inside an assert modal dialog
 #ifdef __WXDEBUG__
index d19cd557c1fd15c7b9315bbc455e771253a5452c..36c62e168e1be2607f2ef90bc0af1a32bbd01e18 100644 (file)
@@ -26,11 +26,16 @@ public:
     virtual bool Dispatch();
     virtual int DispatchTimeout(unsigned long timeout);
     virtual void WakeUp();
+    virtual bool YieldFor(long eventsToProcess);
 
 protected:
+
     // the exit code of this event loop
     int m_exitcode;
 
+    // used to temporarily store events in DoYield()
+    wxArrayPtrVoid m_arrGdkEvents;
+
     wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
 };
 
index 32ef7416a0b2817300506f9e572b80ed730279aa..273d29eda4bca58d5d88982ac71edf2d888c6386 100644 (file)
@@ -70,8 +70,6 @@ private:
     bool m_isInAssert;
 #endif // __WXDEBUG__
 
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
     DECLARE_DYNAMIC_CLASS(wxApp)
 };
 
index d771014e8d4d3b9b222446d04d474bf989ad58e6..40b6e0bf68028a174f4a9f00b2b05a3472911cd5 100644 (file)
@@ -51,8 +51,6 @@ public:
 private:
     DECLARE_DYNAMIC_CLASS(wxApp)
 
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
     wxVideoMode m_displayMode;
 };
 
index 8879381460d0d245d93efea91629567dc862a152..f021442498ce5f8ad1dc15510bbf8154f19ac3a5 100644 (file)
@@ -65,7 +65,6 @@ public:
     // Implementation
     virtual bool Initialize(int& argc, wxChar **argv);
     virtual void CleanUp();
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
 
     // Motif-specific
     WXAppContext   GetAppContext() const { return m_appContext; }
index ade87d8c30617b82bf453419cbaf515f3f65ae90..a83d52ead82188c0ac5bd7d8d760c09694e46247 100644 (file)
@@ -78,8 +78,6 @@ public:
 protected:
     int    m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
 
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
 public:
     // unregister any window classes registered by GetRegisteredClassName()
     static void UnregisterWindowClasses();
index 2869b07a92449a77532295830e0a4ec3ea83e468..934e3cfef540c319e3711c8bcd43261afaf431d1 100644 (file)
@@ -40,6 +40,8 @@ protected:
 
 #if wxUSE_GUI
 
+WX_DECLARE_OBJARRAY(MSG, wxMSGArray);
+
 class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxMSWEventLoopBase
 {
 public:
@@ -72,6 +74,7 @@ public:
     virtual bool Dispatch();
     virtual int DispatchTimeout(unsigned long timeout);
     virtual void WakeUp();
+    virtual bool YieldFor(long eventsToProcess);
 
 protected:
     virtual void OnNextIteration();
@@ -81,6 +84,8 @@ private:
     // non NULL)
     static bool IsChildOfCriticalWindow(wxWindowMSW *win);
 
+    // array of messages used for temporary storage by YieldFor()
+    wxMSGArray m_arrMSG;
 
     // critical window or NULL
     static wxWindowMSW *ms_winCritical;
index 93c1dd37d6def6c5b3cad46bc599908eda406010..f4d6fe2fa0af3f5adf52c139589e0daa06084eaf 100644 (file)
@@ -110,8 +110,6 @@ public:
     // Implementation
     static bool  RegisterWindowClasses(HAB vHab);
 
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
 public:
     int                             m_nCmdShow;
     HMQ                             m_hMq;
index ad80d008a5f1be8cee2352f441832b1b6fd313b0..02710e57b1999bbf99c7649ebacfe5bb77a636c6 100644 (file)
@@ -66,7 +66,6 @@ public:
     // Implementation
     virtual bool Initialize(int& argc, wxChar **argv);
     virtual void CleanUp();
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
 
     // the installed application event handler
     WXEVENTHANDLERREF    MacGetEventHandler() { return m_macEventHandler ; }
index b55112994f35784a4d4a09d85033b8d6b6bc3e8c..d704a9c50ca4b284ede5c64e002fb41eddf9e49c 100644 (file)
@@ -26,6 +26,7 @@ public:
     virtual int DispatchTimeout(unsigned long timeout);
 
     virtual void WakeUp();
+    virtual bool YieldFor(long eventsToProcess);
 
 private:
     // dispatch an event and release it
index ed222c2bcbd30fe79a1a8eaf8b789b3fa470a313..d0040bd92056039af2617257e4efd9c318ec6241 100644 (file)
@@ -22,6 +22,7 @@ public:
     virtual int DispatchTimeout(unsigned long timeout);
 
     virtual void WakeUp();
+    virtual bool YieldFor(long eventsToProcess);
 
 private:
     double m_sleepTime;
index 292830482d482c547fe8225002995fc6b00ba277..0590f5e5891124077397cc8efbdcb11400c104b6 100644 (file)
@@ -51,8 +51,6 @@ public:
 protected:
     int    m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
 
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
-
 public:
     // Implementation
     static bool RegisterWindowClasses();
index 36341946e8ab356be34ddcfbcbda78bea77f46d0..07dc85073357ed1b6e5caef7c0fde7156162407c 100644 (file)
@@ -28,6 +28,7 @@ public:
     virtual bool Dispatch();
     virtual int DispatchTimeout(unsigned long timeout);
     virtual bool IsRunning() const;
+    virtual bool YieldFor(long eventsToProcess);
 
     // MSW-specific methods
     // --------------------
index 42d16625a9f7fb16b04b48ddee5df295e7501584..19bfe8bb51f907bdb946a39c74911ea19d96a13b 100644 (file)
@@ -37,6 +37,7 @@ public:
     virtual int DispatchTimeout(unsigned long timeout);
     virtual void WakeUp();
     virtual bool IsOk() const { return m_dispatcher != NULL; }
+    virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; }
 
 protected:
     virtual void OnNextIteration();
index 588d62242d74b2292b2510a2ecd938fa9eb6f2f9..d5de438792f67f1d549c90c01f9025494e1ae6f7 100644 (file)
@@ -63,7 +63,6 @@ public:
     // Implementation
     virtual bool Initialize(int& argc, wxChar **argv);
     virtual void CleanUp();
-    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
 
     WXWindow       GetTopLevelWidget() const { return m_topLevelWidget; }
     WXColormap     GetMainColormap(WXDisplay* display);
index ad5ef7b621482e73b2ac5d604c765f171afcb20b..a67a414d695f30b8d46999b962e045b809e64a89 100644 (file)
@@ -57,31 +57,26 @@ public:
 
     /**
         @name Event-handling
+
+        Note that you should look at wxEvtLoopBase for more event-processing
+        documentation.
     */
     //@{
 
     /**
-        Dispatches the next event in the windowing system event queue.
-        Blocks until an event appears if there are none currently
-        (use Pending() if this is not wanted).
-
-        This can be used for programming event loops, e.g.
-
-        @code
-        while (app.Pending())
-            Dispatch();
-        @endcode
-
-        @return @false if the event loop should stop and @true otherwise.
+        Called by wxWidgets on creation of the application. Override this if you wish
+        to provide your own (environment-dependent) main loop.
 
-        @see Pending(), wxEventLoopBase
+        @return 0 under X, and the wParam of the WM_QUIT message under Windows.
     */
-    virtual bool Dispatch();
+    virtual int MainLoop();
 
     /**
         Call this to explicitly exit the main message (event) loop.
         You should normally exit the main loop (and the application) by deleting
         the top window.
+
+        This function simply calls wxEvtLoopBase::Exit() on the active loop.
     */
     virtual void ExitMainLoop();
 
@@ -108,81 +103,6 @@ public:
                              wxEventFunction func,
                              wxEvent& event) const;
 
-    /**
-        Returns @true if called from inside Yield().
-    */
-    virtual bool IsYielding() const;
-
-    /**
-        Process all pending events; it is necessary to call this function to
-        process posted events.
-
-        This happens during each event loop iteration in GUI mode but if there is
-        no main loop, it may be also called directly.
-    */
-    virtual void ProcessPendingEvents();
-
-    /**
-        Called by wxWidgets on creation of the application. Override this if you wish
-        to provide your own (environment-dependent) main loop.
-
-        @return 0 under X, and the wParam of the WM_QUIT message under Windows.
-    */
-    virtual int MainLoop();
-
-    /**
-        Returns @true if unprocessed events are in the window system event queue.
-
-        @see Dispatch()
-    */
-    virtual bool Pending();
-
-    /**
-        Yields control to pending messages in the windowing system.
-
-        This can be useful, for example, when a time-consuming process writes to a
-        text window. Without an occasional yield, the text window will not be updated
-        properly, and on systems with cooperative multitasking, such as Windows 3.1
-        other processes will not respond.
-
-        Caution should be exercised, however, since yielding may allow the
-        user to perform actions which are not compatible with the current task.
-        Disabling menu items or whole menus during processing can avoid unwanted
-        reentrance of code: see ::wxSafeYield for a better function.
-        You can avoid unwanted reentrancies also using IsYielding().
-
-        Note that Yield() will not flush the message logs. This is intentional as
-        calling Yield() is usually done to quickly update the screen and popping up
-        a message box dialog may be undesirable. If you do wish to flush the log
-        messages immediately (otherwise it will be done during the next idle loop
-        iteration), call wxLog::FlushActive.
-
-        Calling Yield() recursively is normally an error and an assert failure is
-        raised in debug build if such situation is detected. However if the
-        @a onlyIfNeeded parameter is @true, the method will just silently
-        return @false instead.
-    */
-    bool Yield(bool onlyIfNeeded = false);
-
-    /**
-        Works like Yield() with @e onlyIfNeeded == @true, except that it allows
-        the caller to specify a mask of the ::wxEventCategory values which
-        indicates which events should be processed and which should instead
-        be "delayed" (i.e. processed by the main loop later).
-
-        Note that this is a safer alternative to Yield() since it ensures that
-        only the events you're interested to are processed; i.e. helps to avoid
-        unwanted reentrancies.
-    */
-    bool YieldFor(long eventsToProcess);
-
-    /**
-        Returns @true if the given event category is allowed inside
-        a YieldFor() call (i.e. compares the given category against the
-        last mask passed to YieldFor()).
-    */
-    virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const;
-
     //@}
 
 
index 030d3415f623f558974cea1a97ff9c4efa6dd779..bb19a3c7c78f7207c1fb3f3a1167a61ec65ff143 100644 (file)
@@ -23,7 +23,7 @@ enum wxEventPropagation
 /**
     The different categories for a wxEvent; see wxEvent::GetEventCategory.
 
-    @note They are used as OR-combinable flags by wxApp::Yield.
+    @note They are used as OR-combinable flags by wxEventLoopBase::YieldFor.
 */
 enum wxEventCategory
 {
@@ -58,8 +58,8 @@ enum wxEventCategory
     wxEVT_CATEGORY_THREAD = 16,
 
     /**
-        This mask is used in wxApp::Yield to specify that all event categories should
-        be processed.
+        This mask is used in wxEventLoopBase::YieldFor to specify that all event
+        categories should be processed.
     */
     wxEVT_CATEGORY_ALL =
         wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
@@ -148,7 +148,7 @@ public:
     /**
         Returns a generic category for this event.
 
-        This function is used to selectively process events in wxApp::Yield.
+        This function is used to selectively process events in wxEventLoopBase::YieldFor.
     */
     virtual wxEventCategory GetEventCategory() const;
 
@@ -2537,7 +2537,7 @@ public:
     @library{wxcore}
     @category{events}
 
-    @see @ref overview_thread, wxApp::YieldFor
+    @see @ref overview_thread, wxEventLoopBase::YieldFor
 */
 class wxThreadEvent : public wxCommandEvent
 {
@@ -2558,7 +2558,7 @@ public:
         Returns @c wxEVT_CATEGORY_THREAD.
 
         This is important to avoid unwanted processing of thread events
-        when calling wxApp::YieldFor().
+        when calling wxEventLoopBase::YieldFor().
     */
     virtual wxEventCategory GetEventCategory() const;
 };
index be246731b55a19210606cadd71aa6ce426d85dfd..659a6b964e2e8aedbd6e1e3e4a2bf3c1afafadfb 100644 (file)
@@ -18,7 +18,7 @@
     @library{wxbase}
     @category{appmanagement}
 
-    @see wxApp
+    @see wxApp, wxEventLoopActivator
 */
 class wxEventLoopBase
 {
@@ -42,10 +42,9 @@ public:
 
 
     /**
-        Use this to check whether the event loop was successfully created
-        before using it
-     */
-    virtual bool IsOk() const;
+        @name Dispatch and processing
+    */
+    //@{
 
     /**
         Start the event loop, return the exit code when it is finished.
@@ -60,6 +59,21 @@ public:
      */
     virtual int Run() = 0;
 
+    /**
+        Return true if this event loop is currently running.
+
+        Notice that even if this event loop hasn't terminated yet but has just
+        spawned a nested (e.g. modal) event loop, this method would return
+        @false.
+     */
+    bool IsRunning() const;
+
+    /**
+        Use this to check whether the event loop was successfully created
+        before using it
+     */
+    virtual bool IsOk() const;
+
     /**
         Exit from the loop with the given exit code.
      */
@@ -73,13 +87,21 @@ public:
     virtual bool Pending() const = 0;
 
     /**
-        Dispatch a single event.
+        Dispatches the next event in the windowing system event queue.
+        Blocks until an event appears if there are none currently
+        (use Pending() if this is not wanted).
 
-        If there are currently no events in the queue, blocks until an event
-        becomes available.
+        This can be used for programming event loops, e.g.
 
-        @return @false only if the event loop should terminate.
-     */
+        @code
+        while (evtloop->Pending())
+            evtloop->Dispatch();
+        @endcode
+
+        @return @false if the event loop should stop and @true otherwise.
+
+        @see Pending(), wxEventLoopBase
+    */
     virtual bool Dispatch() = 0;
 
     /**
@@ -100,21 +122,139 @@ public:
      */
     virtual int DispatchTimeout(unsigned long timeout) = 0;
 
-    /**
-        Return true if this event loop is currently running.
-
-        Notice that even if this event loop hasn't terminated yet but has just
-        spawned a nested (e.g. modal) event loop, this method would return
-        @false.
-     */
-    bool IsRunning() const;
-
     /**
         Called by wxWidgets to wake up the event loop even if it is currently
         blocked inside Dispatch().
      */
     virtual void WakeUp() = 0;
 
+    //@}
+
+
+    /**
+        @name Pending events
+    */
+    //@{
+
+    /**
+        Process all pending events; it is necessary to call this function to
+        process posted events.
+
+        This happens during each event loop iteration in GUI mode but
+        it may be also called directly.
+    */
+    virtual void ProcessPendingEvents();
+
+    /**
+        Returns @true if there are pending events on the internal pending event list.
+    */
+    bool HasPendingEvents() const;
+
+    /**
+        Temporary suspends processing of the pending events.
+
+        @see ResumeProcessingOfPendingEvents()
+    */
+    void SuspendProcessingOfPendingEvents();
+
+    /**
+        Resume processing of the pending events previously stopped because of a
+        call to SuspendProcessingOfPendingEvents().
+    */
+    void ResumeProcessingOfPendingEvents();
+
+    //@}
+
+
+    /**
+        @name Idle handling
+    */
+    //@{
+
+    /**
+        Makes sure that idle events are sent again.
+    */
+    virtual void WakeUpIdle();
+
+    /**
+        This virtual function is called  when the application becomes idle and
+        normally just sends wxIdleEvent to all interested parties.
+
+        It should return @true if more idle events are needed, @false if not.
+    */
+    virtual bool ProcessIdle();
+
+    //@}
+
+
+    /**
+        @name Yield-related hooks
+    */
+    //@{
+
+    /**
+        Returns @true if called from inside Yield().
+    */
+    virtual bool IsYielding() const;
+
+    /**
+        Yields control to pending messages in the windowing system.
+
+        This can be useful, for example, when a time-consuming process writes to a
+        text window. Without an occasional yield, the text window will not be updated
+        properly, and on systems with cooperative multitasking, such as Windows 3.1
+        other processes will not respond.
+
+        Caution should be exercised, however, since yielding may allow the
+        user to perform actions which are not compatible with the current task.
+        Disabling menu items or whole menus during processing can avoid unwanted
+        reentrance of code: see ::wxSafeYield for a better function.
+        You can avoid unwanted reentrancies also using IsYielding().
+
+        Note that Yield() will not flush the message logs. This is intentional as
+        calling Yield() is usually done to quickly update the screen and popping up
+        a message box dialog may be undesirable. If you do wish to flush the log
+        messages immediately (otherwise it will be done during the next idle loop
+        iteration), call wxLog::FlushActive.
+
+        Calling Yield() recursively is normally an error and an assert failure is
+        raised in debug build if such situation is detected. However if the
+        @a onlyIfNeeded parameter is @true, the method will just silently
+        return @false instead.
+    */
+    bool Yield(bool onlyIfNeeded = false);
+
+    /**
+        Works like Yield() with @e onlyIfNeeded == @true, except that it allows
+        the caller to specify a mask of the ::wxEventCategory values which
+        indicates which events should be processed and which should instead
+        be "delayed" (i.e. processed by the main loop later).
+
+        Note that this is a safer alternative to Yield() since it ensures that
+        only the events you're interested to will be processed; i.e. this method
+        helps to avoid unwanted reentrancies.
+
+        Note that currently only wxMSW and wxGTK do support selective yield of
+        native events coming from the underlying GUI toolkit.
+        wxWidgets events posted using wxEvtHandler::AddPendingEvent or
+        wxEvtHandler::QueueEvent are instead selectively processed by all ports.
+
+        @see wxEvent::GetEventCategory
+    */
+    bool YieldFor(long eventsToProcess);
+
+    /**
+        Returns @true if the given event category is allowed inside
+        a YieldFor() call (i.e. compares the given category against the
+        last mask passed to YieldFor()).
+
+        @see wxEvent::GetEventCategory
+    */
+    virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const;
+
+    //@}
+
+
 protected:
     /**
         This function is called before the event loop terminates, whether this
index d159c9bdd8eb71738a15fa4b43e776ff77318fa0..8a774ae6a037dcf31bf7cfbc6e491b32236deb10 100644 (file)
@@ -162,11 +162,6 @@ bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc), wxChar **argv)
     GetTraits()->SetLocale();
 #endif // wxUSE_INTL
 
-#if wxUSE_THREADS
-    wxHandlersWithPendingEventsLocker = new wxCriticalSection;
-    wxHandlersWithPendingDelayedEvents = new wxList;
-#endif
-
 #ifndef __WXPALMOS__
     if ( m_appName.empty() && argv && argv[0] )
     {
@@ -190,17 +185,6 @@ void wxAppConsoleBase::CleanUp()
         delete m_mainLoop;
         m_mainLoop = NULL;
     }
-
-    delete wxHandlersWithPendingEvents;
-    wxHandlersWithPendingEvents = NULL;
-
-    delete wxHandlersWithPendingDelayedEvents;
-    wxHandlersWithPendingDelayedEvents = NULL;
-
-#if wxUSE_THREADS
-    delete wxHandlersWithPendingEventsLocker;
-    wxHandlersWithPendingEventsLocker = NULL;
-#endif // wxUSE_THREADS
 }
 
 // ----------------------------------------------------------------------------
@@ -291,7 +275,7 @@ wxAppTraits *wxAppConsoleBase::GetTraitsIfExists()
 }
 
 // ----------------------------------------------------------------------------
-// event processing
+// wxEventLoop redirection
 // ----------------------------------------------------------------------------
 
 int wxAppConsoleBase::MainLoop()
@@ -331,81 +315,37 @@ bool wxAppConsoleBase::Dispatch()
 
 bool wxAppConsoleBase::HasPendingEvents() const
 {
-    wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-
-    bool has = wxHandlersWithPendingEvents && !wxHandlersWithPendingEvents->IsEmpty();
-
-    wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
 
-    return has;
+    return loop && loop->HasPendingEvents();
 }
 
 void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
 {
-    wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-}
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
 
-void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
-{
-    wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+    if (loop) loop->SuspendProcessingOfPendingEvents();
 }
 
-/* static */
-bool wxAppConsoleBase::IsMainLoopRunning()
+void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
 {
-    const wxAppConsole * const app = GetInstance();
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
 
-    return app && app->m_mainLoop != NULL;
+    if (loop) loop->ResumeProcessingOfPendingEvents();
 }
 
 void wxAppConsoleBase::ProcessPendingEvents()
 {
-#if wxUSE_THREADS
-    if ( !wxHandlersWithPendingEventsLocker )
-        return;
-#endif
-
-    wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-
-    wxCHECK_RET( wxHandlersWithPendingDelayedEvents->IsEmpty(),
-                 "this helper list should be empty" );
-
-    if (wxHandlersWithPendingEvents)
-    {
-        // iterate until the list becomes empty: the handlers remove themselves
-        // from it when they don't have any more pending events
-        wxList::compatibility_iterator node = wxHandlersWithPendingEvents->GetFirst();
-        while (node)
-        {
-            // In ProcessPendingEvents(), new handlers might be added
-            // and we can safely leave the critical section here.
-            wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-
-            wxEvtHandler *handler = (wxEvtHandler *)node->GetData();
-            handler->ProcessPendingEvents();
-
-            wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
-
-            // restart as the iterators could have been invalidated
-            node = wxHandlersWithPendingEvents->GetFirst();
-        }
-    }
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
 
-    // now the wxHandlersWithPendingEvents is surely empty; however some event
-    // handlers may have moved themselves into wxHandlersWithPendingDelayedEvents
-    // because of a selective wxYield call in progress.
-    // Now we need to move them back to wxHandlersWithPendingEvents so the next
-    // call to this function has the chance of processing them:
-    if (!wxHandlersWithPendingDelayedEvents->IsEmpty())
-    {
-        if (!wxHandlersWithPendingEvents)
-            wxHandlersWithPendingEvents = new wxList;
+    if (loop) loop->ProcessPendingEvents();
+}
 
-        WX_APPEND_LIST(wxHandlersWithPendingEvents, wxHandlersWithPendingDelayedEvents);
-        wxHandlersWithPendingDelayedEvents->Clear();
-    }
+bool wxAppConsoleBase::Yield(bool onlyIfNeeded)
+{
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
 
-    wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+    return loop && loop->Yield(onlyIfNeeded);
 }
 
 void wxAppConsoleBase::WakeUpIdle()
@@ -416,14 +356,21 @@ void wxAppConsoleBase::WakeUpIdle()
 
 bool wxAppConsoleBase::ProcessIdle()
 {
-    // process pending wx events before sending idle events
-    ProcessPendingEvents();
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
+
+    return loop && loop->ProcessIdle();
+}
+
+// ----------------------------------------------------------------------------
+// events
+// ----------------------------------------------------------------------------
 
-    wxIdleEvent event;
+/* static */
+bool wxAppConsoleBase::IsMainLoopRunning()
+{
+    const wxAppConsole * const app = GetInstance();
 
-    event.SetEventObject(this);
-    ProcessEvent(event);
-    return event.MoreRequested();
+    return app && app->m_mainLoop != NULL;
 }
 
 int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event))
@@ -603,7 +550,6 @@ bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature,
         // normally wxLogFatalError doesn't return
         return false;
     }
-#undef wxCMP
 
     return true;
 }
index f70be7b5add6a464df6e0d20731ddff6dd1d6dbe..9a6cb43f66eb61b8d3a0241901fbeca9e3747263 100644 (file)
@@ -40,6 +40,7 @@
 #include "wx/msgout.h"
 #include "wx/thread.h"
 #include "wx/vidmode.h"
+#include "wx/evtloop.h"
 
 #ifdef __WXDEBUG__
     #if wxUSE_STACKWALKER
@@ -78,9 +79,6 @@ wxAppBase::wxAppBase()
 
     m_isActive = true;
 
-    m_isInsideYield = false;
-    m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
-
     // We don't want to exit the app if the user code shows a dialog from its
     // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
     // to Yes initially as this dialog would be the last top level window.
@@ -326,23 +324,22 @@ void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
     (void)ProcessEvent(event);
 }
 
-bool wxAppBase::IsEventAllowedInsideYield(wxEventCategory cat) const
-{
-    return (m_eventsToProcessInsideYield & cat) != 0;
-}
-
 bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
 {
     wxWindowDisabler wd(win);
 
-    return Yield(onlyIfNeeded);
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
+
+    return loop && loop->Yield(onlyIfNeeded);
 }
 
 bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
 {
     wxWindowDisabler wd(win);
 
-    return YieldFor(eventsToProcess);
+    wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
+
+    return loop && loop->YieldFor(eventsToProcess);
 }
 
 
index ce2a0815261caa50d60075b8bca6ef45b74338a3..7cd4a484c40ce4e718bf3c3d6516c8e5c058b86b 100644 (file)
@@ -145,16 +145,6 @@ IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule)
 // global variables
 // ----------------------------------------------------------------------------
 
-// List containing event handlers with pending events (each handler can occur
-// at most once here)
-wxList *wxHandlersWithPendingEvents = NULL;
-wxList *wxHandlersWithPendingDelayedEvents = NULL;
-
-#if wxUSE_THREADS
-    // protects wxHandlersWithPendingEvents list
-    wxCriticalSection *wxHandlersWithPendingEventsLocker = NULL;
-#endif
-
 // common event types are defined here, other event types are defined by the
 // components which use them
 
@@ -1037,10 +1027,6 @@ void wxEventHashTable::GrowEventTypeTable()
 // wxEvtHandler
 // ----------------------------------------------------------------------------
 
-/*
- * Event handler
- */
-
 wxEvtHandler::wxEvtHandler()
 {
     m_nextHandler = NULL;
@@ -1085,41 +1071,16 @@ wxEvtHandler::~wxEvtHandler()
             delete entry;
         }
         delete m_dynamicEvents;
-    };
+    }
 
     if (m_pendingEvents)
         m_pendingEvents->DeleteContents(true);
     delete m_pendingEvents;
 
-    // Remove us from wxHandlersWithPendingEvents if necessary.
-    if ( wxHandlersWithPendingEvents )
-    {
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
-
-        if ( wxHandlersWithPendingEvents->DeleteObject(this) )
-        {
-            // check that we were present only once in the list
-            wxASSERT_MSG( !wxHandlersWithPendingEvents->Find(this),
-                          "Handler occurs twice in wxHandlersWithPendingEvents list" );
-        }
-        //else: we weren't in this list at all, it's ok
-
-        if ( wxHandlersWithPendingDelayedEvents->DeleteObject(this) )
-        {
-            // check that we were present only once in the list
-            wxASSERT_MSG( !wxHandlersWithPendingDelayedEvents->Find(this),
-                          "Handler occurs twice in wxHandlersWithPendingDelayedEvents list" );
-        }
-        //else: we weren't in this list at all, it's ok
-
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
-    }
+    // Remove us from the list of the pending events if necessary.
+    wxEventLoopBase *loop = wxEventLoopBase::GetActive();
+    if (loop)
+        loop->RemovePendingEventHandler(this);
 
     // we only delete object data, not untyped
     if ( m_clientDataType == wxClientData_Object )
@@ -1165,6 +1126,15 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
 {
     wxCHECK_RET( event, "NULL event can't be posted" );
 
+    wxEventLoopBase* loop = wxEventLoopBase::GetActive();
+    if (!loop)
+    {
+        // we need an event loop which manages the list of event handlers with
+        // pending events... cannot proceed without it!
+        wxLogDebug("No event loop is running!");
+        return;
+    }
+
     // 1) Add this event to our list of pending events
     wxENTER_CRIT_SECT( m_pendingEventsLock );
 
@@ -1176,14 +1146,7 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
     // 2) Add this event handler to list of event handlers that
     //    have pending events.
 
-    wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-
-    if ( !wxHandlersWithPendingEvents )
-        wxHandlersWithPendingEvents = new wxList;
-    if ( !wxHandlersWithPendingEvents->Find(this) )
-        wxHandlersWithPendingEvents->Append(this);
-
-    wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
+    loop->AppendPendingEventHandler(this);
 
     // only release m_pendingEventsLock now because otherwise there is a race
     // condition as described in the ticket #9093: we could process the event
@@ -1200,6 +1163,15 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
 
 void wxEvtHandler::ProcessPendingEvents()
 {
+    wxEventLoopBase* loop = wxEventLoopBase::GetActive();
+    if (!loop)
+    {
+        // we need an event loop which manages the list of event handlers with
+        // pending events... cannot proceed without it!
+        wxLogDebug("No event loop is running!");
+        return;
+    }
+
     // we need to process only a single pending event in this call because
     // each call to ProcessEvent() could result in the destruction of this
     // same event handler (see the comment at the end of this function)
@@ -1215,9 +1187,10 @@ void wxEvtHandler::ProcessPendingEvents()
     wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
 
     // find the first event which can be processed now:
-    if (wxTheApp && wxTheApp->IsYielding())
+    wxEventLoopBase* evtLoop = wxEventLoopBase::GetActive();
+    if (evtLoop && evtLoop->IsYielding())
     {
-        while (node && pEvent && !wxTheApp->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
+        while (node && pEvent && !evtLoop->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
         {
             node = node->GetNext();
             pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
@@ -1226,19 +1199,11 @@ void wxEvtHandler::ProcessPendingEvents()
         if (!node)
         {
             // all our events are NOT processable now... signal this:
-#if wxUSE_THREADS
-            if (wxHandlersWithPendingEventsLocker)
-                wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
-            // move us from the list of handlers with processable pending events
-            // to the list of handlers with pending events which needs to be processed later
-            wxHandlersWithPendingEvents->DeleteObject(this);
-            if ( !wxHandlersWithPendingDelayedEvents->Find(this) )
-                wxHandlersWithPendingDelayedEvents->Append(this);
-#if wxUSE_THREADS
-            if (wxHandlersWithPendingEventsLocker)
-                wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
+            loop->DelayPendingEventHandler(this);
+
+            // see the comment at the beginning of evtloop.h header for the
+            // logic behind YieldFor() and behind DelayPendingEventHandler()
+
             wxLEAVE_CRIT_SECT( m_pendingEventsLock );
 
             return;
@@ -1252,19 +1217,11 @@ void wxEvtHandler::ProcessPendingEvents()
     // same event again.
     m_pendingEvents->Erase(node);
 
-    // if there are no more pending events left, we don't need to stay in this
-    // list
     if ( m_pendingEvents->IsEmpty() )
     {
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
-        wxHandlersWithPendingEvents->DeleteObject(this);
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
+        // if there are no more pending events left, we don't need to
+        // stay in this list
+        loop->RemovePendingEventHandler(this);
     }
 
     wxLEAVE_CRIT_SECT( m_pendingEventsLock );
index 18f9967c57d887deb8d1dec265eb0a4da6563594..26848196fa87237c4c7f7997d8f4674aaa7dfb1e 100644 (file)
 
 wxEventLoopBase *wxEventLoopBase::ms_activeLoop = NULL;
 
+wxEventLoopBase::wxEventLoopBase()
+{
+    m_isInsideYield = false;
+    m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
+}
+
+void wxEventLoopBase::DelayPendingEventHandler(wxEvtHandler* toDelay)
+{
+    wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+    // move the handler from the list of handlers with processable pending events
+    // to the list of handlers with pending events which needs to be processed later
+    m_handlersWithPendingEvents.Remove(toDelay);
+
+    if (m_handlersWithPendingDelayedEvents.Index(toDelay) == wxNOT_FOUND)
+        m_handlersWithPendingDelayedEvents.Add(toDelay);
+
+    wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::RemovePendingEventHandler(wxEvtHandler* toRemove)
+{
+    wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+    if (m_handlersWithPendingEvents.Index(toRemove) != wxNOT_FOUND)
+    {
+        m_handlersWithPendingEvents.Remove(toRemove);
+
+        // check that the handler was present only once in the list
+        wxASSERT_MSG( m_handlersWithPendingEvents.Index(toRemove) == wxNOT_FOUND,
+                        "Handler occurs twice in the m_handlersWithPendingEvents list!" );
+    }
+    //else: it wasn't in this list at all, it's ok
+
+    if (m_handlersWithPendingDelayedEvents.Index(toRemove) != wxNOT_FOUND)
+    {
+        m_handlersWithPendingDelayedEvents.Remove(toRemove);
+
+        // check that the handler was present only once in the list
+        wxASSERT_MSG( m_handlersWithPendingDelayedEvents.Index(toRemove) == wxNOT_FOUND,
+                        "Handler occurs twice in m_handlersWithPendingDelayedEvents list!" );
+    }
+    //else: it wasn't in this list at all, it's ok
+
+    wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::AppendPendingEventHandler(wxEvtHandler* toAppend)
+{
+    wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+    if ( m_handlersWithPendingEvents.Index(toAppend) == wxNOT_FOUND )
+        m_handlersWithPendingEvents.Add(toAppend);
+
+    wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+bool wxEventLoopBase::HasPendingEvents() const
+{
+    wxENTER_CRIT_SECT(const_cast<wxEventLoopBase*>(this)->m_handlersWithPendingEventsLocker);
+
+    bool has = !m_handlersWithPendingEvents.IsEmpty();
+
+    wxLEAVE_CRIT_SECT(const_cast<wxEventLoopBase*>(this)->m_handlersWithPendingEventsLocker);
+
+    return has;
+}
+
+void wxEventLoopBase::SuspendProcessingOfPendingEvents()
+{
+    wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::ResumeProcessingOfPendingEvents()
+{
+    wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::ProcessPendingEvents()
+{
+    wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+    wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
+                 "this helper list should be empty" );
+
+    // iterate until the list becomes empty: the handlers remove themselves
+    // from it when they don't have any more pending events
+    while (!m_handlersWithPendingEvents.IsEmpty())
+    {
+        // In ProcessPendingEvents(), new handlers might be added
+        // and we can safely leave the critical section here.
+        wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
+
+        // NOTE: we always call ProcessPendingEvents() on the first event handler
+        //       with pending events because handlers auto-remove themselves
+        //       from this list (see RemovePendingEventHandler) if they have no
+        //       more pending events.
+        m_handlersWithPendingEvents[0]->ProcessPendingEvents();
+
+        wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+    }
+
+    // now the wxHandlersWithPendingEvents is surely empty; however some event
+    // handlers may have moved themselves into wxHandlersWithPendingDelayedEvents
+    // because of a selective wxYield call in progress.
+    // Now we need to move them back to wxHandlersWithPendingEvents so the next
+    // call to this function has the chance of processing them:
+    if (!m_handlersWithPendingDelayedEvents.IsEmpty())
+    {
+        WX_APPEND_ARRAY(m_handlersWithPendingEvents, m_handlersWithPendingDelayedEvents);
+        m_handlersWithPendingDelayedEvents.Clear();
+    }
+
+    wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+}
+
+void wxEventLoopBase::WakeUpIdle()
+{
+    WakeUp();
+}
+
+bool wxEventLoopBase::ProcessIdle()
+{
+    // process pending wx events before sending idle events
+    ProcessPendingEvents();
+
+    wxIdleEvent event;
+
+    event.SetEventObject(wxTheApp);
+    wxTheApp->ProcessEvent(event);
+    return event.MoreRequested();
+}
+
+bool wxEventLoopBase::Yield(bool onlyIfNeeded)
+{
+    if ( m_isInsideYield )
+    {
+        if ( !onlyIfNeeded )
+        {
+            wxFAIL_MSG( wxT("wxYield called recursively" ) );
+        }
+
+        return false;
+    }
+
+    return YieldFor(wxEVT_CATEGORY_ALL);
+}
+
 // wxEventLoopManual is unused in the other ports
 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && wxUSE_BASE)
 
index 141bd1a031dbc8dec32542ae02c8875880732870..931a9bfbe3345fddc18b01e453d829c04b02c91b 100644 (file)
@@ -162,46 +162,3 @@ void wxApp::WakeUpIdle()
         wxMutexGuiLeave();
 #endif
 }
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-#if wxUSE_THREADS
-    if ( !wxThread::IsMain() )
-        return true; // can't process events from other threads
-#endif // wxUSE_THREADS
-
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
-        }
-
-        return false;
-    }
-
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-#if wxUSE_LOG
-    wxLog::Suspend();
-#endif // wxUSE_LOG
-
-    wxEventLoop * const
-        loop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
-    if ( loop )
-        loop->Yield();
-
-    // it's necessary to call ProcessIdle() to update the frames sizes which
-    // might have been changed (it also will update other things set from
-    // OnUpdateUI() which is a nice (and desired) side effect)
-    while ( ProcessIdle() ) {}
-
-#if wxUSE_LOG
-    wxLog::Resume();
-#endif // wxUSE_LOG
-
-    m_isInsideYield = false;
-
-    return true;
-}
index d18b73a2515c2ec75ab20897e9f10b429f445f90..eb86834bc56b85d2293263a55477dd5416e29a95 100644 (file)
@@ -202,8 +202,20 @@ wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
 // events dispatch and loop handling
 //-----------------------------------------------------------------------------
 
-void wxGUIEventLoop::Yield()
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
 {
+#if wxUSE_THREADS
+    if ( !wxThread::IsMain() )
+        return true; // can't process events from other threads
+#endif // wxUSE_THREADS
+
+    m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
+
+#if wxUSE_LOG
+    wxLog::Suspend();
+#endif // wxUSE_LOG
+
     // TODO: implement event filtering using the eventsToProcess mask
 
     // process all pending events:
@@ -212,4 +224,17 @@ void wxGUIEventLoop::Yield()
 
     // handle timers, sockets etc.
     OnNextIteration();
+
+    // it's necessary to call ProcessIdle() to update the frames sizes which
+    // might have been changed (it also will update other things set from
+    // OnUpdateUI() which is a nice (and desired) side effect)
+    while ( ProcessIdle() ) {}
+
+#if wxUSE_LOG
+    wxLog::Resume();
+#endif // wxUSE_LOG
+
+    m_isInsideYield = false;
+
+    return true;
 }
index d05fdad6b1c1b12b50ff3a8ca3020d4bdcc5059c..6677a2ea33db11c7438f6cf9d1824415304452f7 100644 (file)
@@ -42,6 +42,7 @@
 #endif
 
 #include "wx/progdlg.h"
+#include "wx/evtloop.h"
 
 // ---------------------------------------------------------------------------
 // macros
@@ -402,7 +403,7 @@ wxProgressDialog::Update(int value, const wxString& newmsg, bool *skip)
                 m_msg->SetLabel(_("Done."));
             }
 
-            wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
+            wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
 
             (void)ShowModal();
         }
@@ -452,7 +453,7 @@ bool wxProgressDialog::DoAfterUpdate(bool *skip)
 {
     // we have to yield because not only we want to update the display but
     // also to process the clicks on the cancel and skip buttons
-    wxTheApp->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT);
+    wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT);
 
     Update();
 
@@ -671,7 +672,7 @@ void wxProgressDialog::UpdateMessage(const wxString &newmsg)
 
         Fit();   // adapt to the new label size
 
-        wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
+        wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
     }
 }
 
index a7c984dd3bdc1746228868bc6d204431b8a69cbb..18c05dda50e4904e76f0819a70913def3d33106e 100644 (file)
     wxFORCE_LINK_MODULE(gnome_vfs)
 #endif
 
-//-----------------------------------------------------------------------------
-// global data
-//-----------------------------------------------------------------------------
-
-static GtkWidget *gs_RootWindow = NULL;
-static wxArrayPtrVoid g_arrGdkEvents;
-
-//-----------------------------------------------------------------------------
-// wxYield
-//-----------------------------------------------------------------------------
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
-        }
-
-        return false;
-    }
-
-#if wxUSE_THREADS
-    if ( !wxThread::IsMain() )
-    {
-        // can't call gtk_main_iteration() from other threads like this
-        return true;
-    }
-#endif // wxUSE_THREADS
-
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-#if wxUSE_LOG
-    // disable log flushing from here because a call to wxYield() shouldn't
-    // normally result in message boxes popping up &c
-    wxLog::Suspend();
-#endif
-
-    // NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
-    //       rather use gtk_main_do_event() after filtering the events at
-    //       GDK level
-
-    GdkDisplay* disp = gtk_widget_get_display(gs_RootWindow);
-
-    // gdk_display_get_event() will transform X11 events into GDK events
-    // and will queue all of them in the display (private) structure;
-    // finally it will "unqueue" the last one and return it to us
-    GdkEvent* event = gdk_display_get_event(disp);
-    while (event)
-    {
-        // categorize the GDK event according to wxEventCategory.
-        // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
-        // for more info.
-
-        wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
-        switch (event->type)
-        {
-        case GDK_SELECTION_REQUEST:
-        case GDK_SELECTION_NOTIFY:
-        case GDK_SELECTION_CLEAR:
-        case GDK_OWNER_CHANGE:
-            cat = wxEVT_CATEGORY_CLIPBOARD;
-            break;
-
-
-        case GDK_KEY_PRESS:
-        case GDK_KEY_RELEASE:
-        case GDK_BUTTON_PRESS:
-        case GDK_2BUTTON_PRESS:
-        case GDK_3BUTTON_PRESS:
-        case GDK_BUTTON_RELEASE:
-        case GDK_SCROLL:        // generated from mouse buttons
-        case GDK_CLIENT_EVENT:
-            cat = wxEVT_CATEGORY_USER_INPUT;
-            break;
-
-
-        case GDK_PROXIMITY_IN:
-        case GDK_PROXIMITY_OUT:
-
-        case GDK_MOTION_NOTIFY:
-        case GDK_ENTER_NOTIFY:
-        case GDK_LEAVE_NOTIFY:
-        case GDK_VISIBILITY_NOTIFY:
-        case GDK_PROPERTY_NOTIFY:
-
-        case GDK_FOCUS_CHANGE:
-        case GDK_CONFIGURE:
-        case GDK_WINDOW_STATE:
-        case GDK_SETTING:
-        case GDK_DELETE:
-        case GDK_DESTROY:
-
-        case GDK_EXPOSE:
-        case GDK_NO_EXPOSE:
-        case GDK_MAP:
-        case GDK_UNMAP:
-        //case GDK_DAMAGE:
-
-        case GDK_DRAG_ENTER:
-        case GDK_DRAG_LEAVE:
-        case GDK_DRAG_MOTION:
-        case GDK_DRAG_STATUS:
-        case GDK_DROP_START:
-        case GDK_DROP_FINISHED:
-        case GDK_GRAB_BROKEN:
-            cat = wxEVT_CATEGORY_UI;
-            break;
-
-        default:
-            cat = wxEVT_CATEGORY_UNKNOWN;
-            break;
-        }
-
-        if (eventsToProcess & cat)
-            gtk_main_do_event(event);       // process it now
-        else
-            g_arrGdkEvents.Add(event);      // process it later
-
-        // get next event
-        event = gdk_display_get_event(disp);
-    }
-
-    if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
-    {
-        // It's necessary to call ProcessIdle() to update the frames sizes which
-        // might have been changed (it also will update other things set from
-        // OnUpdateUI() which is a nice (and desired) side effect). But we
-        // call ProcessIdle() only once since this is not meant for longish
-        // background jobs (controlled by wxIdleEvent::RequestMore() and the
-        // return value of Processidle().
-        ProcessIdle();      // ProcessIdle() also calls ProcessPendingEvents()
-    }
-    //else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
-    //      the user app contains an UI update handler which calls wxClipboard::IsSupported,
-    //      then we fall into a never-ending loop...
-
-    // put all unprocessed GDK events back in the queue
-    for (size_t i=0; i<g_arrGdkEvents.GetCount(); i++)
-    {
-        GdkEvent* ev = (GdkEvent*)g_arrGdkEvents[i];
-
-        // NOTE: gdk_display_put_event makes a copy of the event passed to it
-        gdk_display_put_event(disp, ev);
-        gdk_event_free(ev);
-    }
-
-    g_arrGdkEvents.Clear();
-
-#if wxUSE_LOG
-    // let the logs be flashed again
-    wxLog::Resume();
-#endif
-
-    m_isInsideYield = false;
-
-    return true;
-}
-
 //-----------------------------------------------------------------------------
 // local functions
 //-----------------------------------------------------------------------------
@@ -324,12 +163,14 @@ bool wxApp::DoIdle()
 
 GtkWidget* wxGetRootWindow()
 {
-    if (gs_RootWindow == NULL)
+    static GtkWidget *s_RootWindow = NULL;
+
+    if (s_RootWindow == NULL)
     {
-        gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
-        gtk_widget_realize( gs_RootWindow );
+        s_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+        gtk_widget_realize( s_RootWindow );
     }
-    return gs_RootWindow;
+    return s_RootWindow;
 }
 
 //-----------------------------------------------------------------------------
index 92fb7ecd8a335efd0fd4c72ae16dce3db34f12f4..2938ec3861228f706f606342eee9347baadc7fa1 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "wx/scopedarray.h"
 #include "wx/scopeguard.h"
+#include "wx/evtloop.h"
 
 #include "wx/gtk/private.h"
 
@@ -75,7 +76,7 @@ public:
     ~wxClipboardSync()
     {
         while (ms_clipboard)
-            wxTheApp->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
+            wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
     }
 
     // this method must be called by GTK+ callbacks to indicate that we got the
index a609bed7296cb87a56045b80334f9b53bdf35ac8..0096351d1e313636f10d5006905861bc968fdae7 100644 (file)
@@ -36,6 +36,8 @@
 // wxEventLoop implementation
 // ============================================================================
 
+extern GtkWidget *wxGetRootWindow();
+
 // ----------------------------------------------------------------------------
 // wxEventLoop running and exiting
 // ----------------------------------------------------------------------------
@@ -126,4 +128,146 @@ int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
     return !quit;
 }
 
+//-----------------------------------------------------------------------------
+// YieldFor
+//-----------------------------------------------------------------------------
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+#if wxUSE_THREADS
+    if ( !wxThread::IsMain() )
+    {
+        // can't call gtk_main_iteration() from other threads like this
+        return true;
+    }
+#endif // wxUSE_THREADS
+
+    m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
+
+#if wxUSE_LOG
+    // disable log flushing from here because a call to wxYield() shouldn't
+    // normally result in message boxes popping up &c
+    wxLog::Suspend();
+#endif
+
+    // NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
+    //       rather use gtk_main_do_event() after filtering the events at
+    //       GDK level
+
+    GdkDisplay* disp = gtk_widget_get_display(wxGetRootWindow());
+
+    // gdk_display_get_event() will transform X11 events into GDK events
+    // and will queue all of them in the display (private) structure;
+    // finally it will "unqueue" the last one and return it to us
+    GdkEvent* event = gdk_display_get_event(disp);
+    while (event)
+    {
+        // categorize the GDK event according to wxEventCategory.
+        // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
+        // for more info.
+
+        wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
+        switch (event->type)
+        {
+        case GDK_SELECTION_REQUEST:
+        case GDK_SELECTION_NOTIFY:
+        case GDK_SELECTION_CLEAR:
+        case GDK_OWNER_CHANGE:
+            cat = wxEVT_CATEGORY_CLIPBOARD;
+            break;
+
+
+        case GDK_KEY_PRESS:
+        case GDK_KEY_RELEASE:
+        case GDK_BUTTON_PRESS:
+        case GDK_2BUTTON_PRESS:
+        case GDK_3BUTTON_PRESS:
+        case GDK_BUTTON_RELEASE:
+        case GDK_SCROLL:        // generated from mouse buttons
+        case GDK_CLIENT_EVENT:
+            cat = wxEVT_CATEGORY_USER_INPUT;
+            break;
+
+
+        case GDK_PROXIMITY_IN:
+        case GDK_PROXIMITY_OUT:
+
+        case GDK_MOTION_NOTIFY:
+        case GDK_ENTER_NOTIFY:
+        case GDK_LEAVE_NOTIFY:
+        case GDK_VISIBILITY_NOTIFY:
+        case GDK_PROPERTY_NOTIFY:
+
+        case GDK_FOCUS_CHANGE:
+        case GDK_CONFIGURE:
+        case GDK_WINDOW_STATE:
+        case GDK_SETTING:
+        case GDK_DELETE:
+        case GDK_DESTROY:
+
+        case GDK_EXPOSE:
+        case GDK_NO_EXPOSE:
+        case GDK_MAP:
+        case GDK_UNMAP:
+        //case GDK_DAMAGE:
+
+        case GDK_DRAG_ENTER:
+        case GDK_DRAG_LEAVE:
+        case GDK_DRAG_MOTION:
+        case GDK_DRAG_STATUS:
+        case GDK_DROP_START:
+        case GDK_DROP_FINISHED:
+        case GDK_GRAB_BROKEN:
+            cat = wxEVT_CATEGORY_UI;
+            break;
+
+        default:
+            cat = wxEVT_CATEGORY_UNKNOWN;
+            break;
+        }
+
+        if (eventsToProcess & cat)
+            gtk_main_do_event(event);       // process it now
+        else
+            m_arrGdkEvents.Add(event);      // process it later
+
+        // get next event
+        event = gdk_display_get_event(disp);
+    }
 
+    if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
+    {
+        // It's necessary to call ProcessIdle() to update the frames sizes which
+        // might have been changed (it also will update other things set from
+        // OnUpdateUI() which is a nice (and desired) side effect). But we
+        // call ProcessIdle() only once since this is not meant for longish
+        // background jobs (controlled by wxIdleEvent::RequestMore() and the
+        // return value of Processidle().
+        ProcessIdle();      // ProcessIdle() also calls ProcessPendingEvents()
+    }
+    //else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
+    //      the user app contains an UI update handler which calls wxClipboard::IsSupported,
+    //      then we fall into a never-ending loop...
+
+    // put all unprocessed GDK events back in the queue
+    for (size_t i=0; i<m_arrGdkEvents.GetCount(); i++)
+    {
+        GdkEvent* ev = (GdkEvent*)m_arrGdkEvents[i];
+
+        // NOTE: gdk_display_put_event makes a copy of the event passed to it
+        gdk_display_put_event(disp, ev);
+        gdk_event_free(ev);
+    }
+
+    m_arrGdkEvents.Clear();
+
+#if wxUSE_LOG
+    // let the logs be flashed again
+    wxLog::Resume();
+#endif
+
+    m_isInsideYield = false;
+
+    return true;
+}
index 17aa4029004d25ab6b783ed23bea973f8f0c74fc..2c4b9bff43cf87ad1cc5f53b7b89ff73e89d5afa 100644 (file)
@@ -99,64 +99,6 @@ void wxapp_install_idle_handler();
 static wxMutex gs_idleTagsMutex;
 #endif
 
-//-----------------------------------------------------------------------------
-// wxYield
-//-----------------------------------------------------------------------------
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
-        }
-
-        return false;
-    }
-
-#if wxUSE_THREADS
-    if ( !wxThread::IsMain() )
-    {
-        // can't call gtk_main_iteration() from other threads like this
-        return true;
-    }
-#endif // wxUSE_THREADS
-
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-    // We need to remove idle callbacks or the loop will
-    // never finish.
-    wxTheApp->RemoveIdleTag();
-
-#if wxUSE_LOG
-    // disable log flushing from here because a call to wxYield() shouldn't
-    // normally result in message boxes popping up &c
-    wxLog::Suspend();
-#endif
-
-    // TODO: implement event filtering using the eventsToProcess mask
-    while (gtk_events_pending())
-        gtk_main_iteration();
-
-    // It's necessary to call ProcessIdle() to update the frames sizes which
-    // might have been changed (it also will update other things set from
-    // OnUpdateUI() which is a nice (and desired) side effect). But we
-    // call ProcessIdle() only once since this is not meant for longish
-    // background jobs (controlled by wxIdleEvent::RequestMore() and the
-    // return value of Processidle().
-    ProcessIdle();
-
-#if wxUSE_LOG
-    // let the logs be flashed again
-    wxLog::Resume();
-#endif
-
-    m_isInsideYield = false;
-
-    return true;
-}
 
 //-----------------------------------------------------------------------------
 // wxWakeUpIdle
index 4364bb312215fd316a80f3d6d39a058c36cbfef5..1a32789eb91f1db0a28d2413ec8bb7b26dfa2bc8 100644 (file)
@@ -117,3 +117,52 @@ bool wxGUIEventLoop::Dispatch()
 
     return true;
 }
+
+//-----------------------------------------------------------------------------
+// wxYield
+//-----------------------------------------------------------------------------
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+#if wxUSE_THREADS
+    if ( !wxThread::IsMain() )
+    {
+        // can't call gtk_main_iteration() from other threads like this
+        return true;
+    }
+#endif // wxUSE_THREADS
+
+    m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
+
+    // We need to remove idle callbacks or the loop will
+    // never finish.
+    wxTheApp->RemoveIdleTag();
+
+#if wxUSE_LOG
+    // disable log flushing from here because a call to wxYield() shouldn't
+    // normally result in message boxes popping up &c
+    wxLog::Suspend();
+#endif
+
+    // TODO: implement event filtering using the eventsToProcess mask
+    while (gtk_events_pending())
+        gtk_main_iteration();
+
+    // It's necessary to call ProcessIdle() to update the frames sizes which
+    // might have been changed (it also will update other things set from
+    // OnUpdateUI() which is a nice (and desired) side effect). But we
+    // call ProcessIdle() only once since this is not meant for longish
+    // background jobs (controlled by wxIdleEvent::RequestMore() and the
+    // return value of Processidle().
+    ProcessIdle();
+
+#if wxUSE_LOG
+    // let the logs be flashed again
+    wxLog::Resume();
+#endif
+
+    m_isInsideYield = false;
+
+    return true;
+}
index a43beb61f1f54b016f1fa82d8d5d2ba87bbd1ab1..eaa8a042564a6610911a152dfafb7453ca3e8309 100644 (file)
@@ -44,56 +44,6 @@ void wxApp::Exit()
     exit(0);
 }
 
-//-----------------------------------------------------------------------------
-// wxYield
-//-----------------------------------------------------------------------------
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
-        }
-
-        return false;
-    }
-
-#if wxUSE_THREADS
-    if ( !wxThread::IsMain() )
-    {
-        // can't process events from other threads, MGL is thread-unsafe
-        return true;
-    }
-#endif // wxUSE_THREADS
-
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-    wxLog::Suspend();
-
-    wxEventLoopBase * const eventLoop = wxEventLoop::GetActive();
-    if ( eventLoop )
-    {
-        // TODO: implement event filtering using the eventsToProcess mask
-
-        while (eventLoop->Pending())
-            eventLoop->Dispatch();
-    }
-
-    /* it's necessary to call ProcessIdle() to update the frames sizes which
-       might have been changed (it also will update other things set from
-       OnUpdateUI() which is a nice (and desired) side effect) */
-    while (wxTheApp->ProcessIdle()) { }
-
-    wxLog::Resume();
-
-    m_isInsideYield = false;
-
-    return true;
-}
-
 
 //-----------------------------------------------------------------------------
 // wxWakeUpIdle
index ff5d985cceac03ccc4cc51bd84d362982585d3a9..452dbb4e0ced61f0592a02e2a7c10b399add09fe 100644 (file)
@@ -184,3 +184,39 @@ bool wxGUIEventLoop::Dispatch()
     return m_impl->GetKeepLooping();
 }
 
+
+//-----------------------------------------------------------------------------
+// wxYield
+//-----------------------------------------------------------------------------
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+#if wxUSE_THREADS
+    if ( !wxThread::IsMain() )
+    {
+        // can't process events from other threads, MGL is thread-unsafe
+        return true;
+    }
+#endif // wxUSE_THREADS
+
+    m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
+
+    wxLog::Suspend();
+
+    // TODO: implement event filtering using the eventsToProcess mask
+
+    while (Pending())
+        Dispatch();
+
+    /* it's necessary to call ProcessIdle() to update the frames sizes which
+       might have been changed (it also will update other things set from
+       OnUpdateUI() which is a nice (and desired) side effect) */
+    while (wxTheApp->ProcessIdle()) { }
+
+    wxLog::Resume();
+
+    m_isInsideYield = false;
+
+    return true;
+}
index 11d8129d7026b508d1815abdb660d62a54b06b97..0a073548e787f54b933a7c197e97d2be88003fd3 100644 (file)
@@ -468,32 +468,6 @@ void wxApp::SetTopLevelRealizedWidget(WXDisplay* display, WXWidget widget)
         .m_topLevelRealizedWidget = (Widget)widget;
 }
 
-// Yield to other processes
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
-        }
-
-        return false;
-    }
-
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-    wxEventLoopGuarantor dummyLoopIfNeeded;
-    while (wxTheApp && wxTheApp->Pending())
-        // TODO: implement event filtering using the eventsToProcess mask
-        wxTheApp->Dispatch();
-
-    m_isInsideYield = false;
-
-    return true;
-}
 
 // ----------------------------------------------------------------------------
 // accessors for C modules
index 367982dcb83ec4c41571bbc330639584ff7746a9..cd7800a3806610e8f9f4869a44a608fe901d5d78 100644 (file)
@@ -137,6 +137,20 @@ void wxGUIEventLoop::Exit(int rc)
     ::wxBreakDispatch();
 }
 
+bool wxGUIEventLoop::YieldFor(ong eventsToProcess)
+{
+    m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
+
+    while (wxTheApp && wxTheApp->Pending())
+        // TODO: implement event filtering using the eventsToProcess mask
+        wxTheApp->Dispatch();
+
+    m_isInsideYield = false;
+
+    return true;
+}
+
 // ----------------------------------------------------------------------------
 // wxEventLoop message processing dispatching
 // ----------------------------------------------------------------------------
index 5273274406626d2b8fb68d518d9ebcd33f1a615a..8222bb7060ed3c1c3a4a41340fcf3a2fee5d26a8 100644 (file)
@@ -1011,177 +1011,6 @@ int wxApp::GetShell32Version()
 
 #endif // !__WXWINCE__
 
-// ----------------------------------------------------------------------------
-// Yield to incoming messages
-// ----------------------------------------------------------------------------
-
-WX_DECLARE_OBJARRAY(MSG, wxMSGArray);
-
-#include <wx/arrimpl.cpp>
-WX_DEFINE_OBJARRAY(wxMSGArray);
-
-static wxMSGArray g_arrMSG;
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
-        }
-
-        return false;
-    }
-
-    // set the flag and don't forget to reset it before returning
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-    wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
-
-#if wxUSE_LOG
-    // disable log flushing from here because a call to wxYield() shouldn't
-    // normally result in message boxes popping up &c
-    wxLog::Suspend();
-
-    // ensure the logs will be flashed again when we exit
-    wxON_BLOCK_EXIT0(wxLog::Resume);
-#endif // wxUSE_LOG
-
-    // we don't want to process WM_QUIT from here - it should be processed in
-    // the main event loop in order to stop it
-    wxEventLoopGuarantor dummyLoopIfNeeded;
-    MSG msg;
-    while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
-            msg.message != WM_QUIT )
-    {
-#if wxUSE_THREADS
-        wxMutexGuiLeaveOrEnter();
-#endif // wxUSE_THREADS
-
-        if (msg.message == WM_PAINT)
-        {
-            // WM_PAINT messages are the last ones of the queue...
-            break;
-        }
-
-        // choose a wxEventCategory for this Windows message
-        wxEventCategory cat;
-        switch (msg.message)
-        {
-            case WM_NCMOUSEMOVE:
-            case WM_NCLBUTTONDOWN:
-            case WM_NCLBUTTONUP:
-            case WM_NCLBUTTONDBLCLK:
-            case WM_NCRBUTTONDOWN:
-            case WM_NCRBUTTONUP:
-            case WM_NCRBUTTONDBLCLK:
-            case WM_NCMBUTTONDOWN:
-            case WM_NCMBUTTONUP:
-            case WM_NCMBUTTONDBLCLK:
-
-            case WM_KEYDOWN:
-            case WM_KEYUP:
-            case WM_CHAR:
-            case WM_DEADCHAR:
-            case WM_SYSKEYDOWN:
-            case WM_SYSKEYUP:
-            case WM_SYSCHAR:
-            case WM_SYSDEADCHAR:
-#ifdef WM_UNICHAR
-            case WM_UNICHAR:
-#endif
-            case WM_HOTKEY:
-            case WM_IME_STARTCOMPOSITION:
-            case WM_IME_ENDCOMPOSITION:
-            case WM_IME_COMPOSITION:
-            case WM_COMMAND:
-            case WM_SYSCOMMAND:
-
-            case WM_IME_SETCONTEXT:
-            case WM_IME_NOTIFY:
-            case WM_IME_CONTROL:
-            case WM_IME_COMPOSITIONFULL:
-            case WM_IME_SELECT:
-            case WM_IME_CHAR:
-            case WM_IME_KEYDOWN:
-            case WM_IME_KEYUP:
-
-            case WM_MOUSEHOVER:
-#ifdef WM_NCMOUSELEAVE
-            case WM_NCMOUSELEAVE:
-#endif
-            case WM_MOUSELEAVE:
-
-            case WM_CUT:
-            case WM_COPY:
-            case WM_PASTE:
-            case WM_CLEAR:
-            case WM_UNDO:
-
-            case WM_MOUSEMOVE:
-            case WM_LBUTTONDOWN:
-            case WM_LBUTTONUP:
-            case WM_LBUTTONDBLCLK:
-            case WM_RBUTTONDOWN:
-            case WM_RBUTTONUP:
-            case WM_RBUTTONDBLCLK:
-            case WM_MBUTTONDOWN:
-            case WM_MBUTTONUP:
-            case WM_MBUTTONDBLCLK:
-            case WM_MOUSEWHEEL:
-                cat = wxEVT_CATEGORY_USER_INPUT;
-                break;
-
-            case WM_TIMER:
-                cat = wxEVT_CATEGORY_TIMER;
-                break;
-
-            default:
-                if (msg.message < WM_USER)
-                {
-                    // 0;WM_USER-1 is the range of message IDs reserved for use
-                    // by the system.
-
-                    // there are too many of these types of messages to handle
-                    // them in this switch
-                    cat = wxEVT_CATEGORY_UI;
-                }
-                else
-                    cat = wxEVT_CATEGORY_UNKNOWN;
-        }
-
-        // should we process this event now?
-        if (cat & eventsToProcess)
-        {
-            if ( !wxTheApp->Dispatch() )
-                break;
-        }
-        else
-        {
-            // remove the message and store it
-            ::GetMessage(&msg, NULL, 0, 0);
-            g_arrMSG.Add(msg);
-        }
-    }
-
-    // if there are pending events, we must process them.
-    ProcessPendingEvents();
-
-    // put back unprocessed events in the queue
-    DWORD id = GetCurrentThreadId();
-    for (size_t i=0; i<g_arrMSG.GetCount(); i++)
-    {
-        PostThreadMessage(id, g_arrMSG[i].message,
-                          g_arrMSG[i].wParam, g_arrMSG[i].lParam);
-    }
-
-    g_arrMSG.Clear();
-
-    return true;
-}
-
 #if wxUSE_EXCEPTIONS
 
 // ----------------------------------------------------------------------------
index 96e618066449a292e439f4a5c4a59c53f190c374..aa294c31c4787f1559d037d4f8b11c9d2fa9c822 100644 (file)
@@ -35,6 +35,7 @@
 #include "wx/thread.h"
 #include "wx/except.h"
 #include "wx/msw/private.h"
+#include "wx/scopeguard.h"
 
 #if wxUSE_GUI
     #include "wx/tooltip.h"
@@ -358,6 +359,164 @@ void wxGUIEventLoop::WakeUp()
     ::PostMessage(NULL, WM_NULL, 0, 0);
 }
 
+
+// ----------------------------------------------------------------------------
+// Yield to incoming messages
+// ----------------------------------------------------------------------------
+
+#include <wx/arrimpl.cpp>
+WX_DEFINE_OBJARRAY(wxMSGArray);
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+    // set the flag and don't forget to reset it before returning
+    m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
+
+    wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
+
+#if wxUSE_LOG
+    // disable log flushing from here because a call to wxYield() shouldn't
+    // normally result in message boxes popping up &c
+    wxLog::Suspend();
+
+    // ensure the logs will be flashed again when we exit
+    wxON_BLOCK_EXIT0(wxLog::Resume);
+#endif // wxUSE_LOG
+
+    // we don't want to process WM_QUIT from here - it should be processed in
+    // the main event loop in order to stop it
+    MSG msg;
+    while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
+            msg.message != WM_QUIT )
+    {
+#if wxUSE_THREADS
+        wxMutexGuiLeaveOrEnter();
+#endif // wxUSE_THREADS
+
+        if (msg.message == WM_PAINT)
+        {
+            // WM_PAINT messages are the last ones of the queue...
+            break;
+        }
+
+        // choose a wxEventCategory for this Windows message
+        wxEventCategory cat;
+        switch (msg.message)
+        {
+            case WM_NCMOUSEMOVE:
+            case WM_NCLBUTTONDOWN:
+            case WM_NCLBUTTONUP:
+            case WM_NCLBUTTONDBLCLK:
+            case WM_NCRBUTTONDOWN:
+            case WM_NCRBUTTONUP:
+            case WM_NCRBUTTONDBLCLK:
+            case WM_NCMBUTTONDOWN:
+            case WM_NCMBUTTONUP:
+            case WM_NCMBUTTONDBLCLK:
+
+            case WM_KEYDOWN:
+            case WM_KEYUP:
+            case WM_CHAR:
+            case WM_DEADCHAR:
+            case WM_SYSKEYDOWN:
+            case WM_SYSKEYUP:
+            case WM_SYSCHAR:
+            case WM_SYSDEADCHAR:
+#ifdef WM_UNICHAR
+            case WM_UNICHAR:
+#endif
+            case WM_HOTKEY:
+            case WM_IME_STARTCOMPOSITION:
+            case WM_IME_ENDCOMPOSITION:
+            case WM_IME_COMPOSITION:
+            case WM_COMMAND:
+            case WM_SYSCOMMAND:
+
+            case WM_IME_SETCONTEXT:
+            case WM_IME_NOTIFY:
+            case WM_IME_CONTROL:
+            case WM_IME_COMPOSITIONFULL:
+            case WM_IME_SELECT:
+            case WM_IME_CHAR:
+            case WM_IME_KEYDOWN:
+            case WM_IME_KEYUP:
+
+            case WM_MOUSEHOVER:
+#ifdef WM_NCMOUSELEAVE
+            case WM_NCMOUSELEAVE:
+#endif
+            case WM_MOUSELEAVE:
+
+            case WM_CUT:
+            case WM_COPY:
+            case WM_PASTE:
+            case WM_CLEAR:
+            case WM_UNDO:
+
+            case WM_MOUSEMOVE:
+            case WM_LBUTTONDOWN:
+            case WM_LBUTTONUP:
+            case WM_LBUTTONDBLCLK:
+            case WM_RBUTTONDOWN:
+            case WM_RBUTTONUP:
+            case WM_RBUTTONDBLCLK:
+            case WM_MBUTTONDOWN:
+            case WM_MBUTTONUP:
+            case WM_MBUTTONDBLCLK:
+            case WM_MOUSEWHEEL:
+                cat = wxEVT_CATEGORY_USER_INPUT;
+                break;
+
+            case WM_TIMER:
+                cat = wxEVT_CATEGORY_TIMER;
+                break;
+
+            default:
+                if (msg.message < WM_USER)
+                {
+                    // 0;WM_USER-1 is the range of message IDs reserved for use
+                    // by the system.
+
+                    // there are too many of these types of messages to handle
+                    // them in this switch
+                    cat = wxEVT_CATEGORY_UI;
+                }
+                else
+                    cat = wxEVT_CATEGORY_UNKNOWN;
+        }
+
+        // should we process this event now?
+        if (cat & eventsToProcess)
+        {
+            if ( !wxTheApp->Dispatch() )
+                break;
+        }
+        else
+        {
+            // remove the message and store it
+            ::GetMessage(&msg, NULL, 0, 0);
+            m_arrMSG.Add(msg);
+        }
+    }
+
+    // if there are pending events, we must process them.
+    ProcessPendingEvents();
+
+    // put back unprocessed events in the queue
+    DWORD id = GetCurrentThreadId();
+    for (size_t i=0; i<m_arrMSG.GetCount(); i++)
+    {
+        PostThreadMessage(id, m_arrMSG[i].message,
+                          m_arrMSG[i].wParam, m_arrMSG[i].lParam);
+    }
+
+    m_arrMSG.Clear();
+
+    return true;
+}
+
+
 #else // !wxUSE_GUI
 
 
index ed071ed89e885fe936d027e3293d65abc9b0e101..c60a8ed3d62b8f4f8917d93132743dc826c6bd07 100644 (file)
@@ -504,66 +504,6 @@ void wxApp::OnQueryEndSession( wxCloseEvent& rEvent )
     }
 } // end of wxApp::OnQueryEndSession
 
-//
-// Yield to incoming messages
-//
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( _T("wxYield() called recursively") );
-        }
-
-        return false;
-    }
-
-    HAB vHab = 0;
-    QMSG vMsg;
-
-    //
-    // Disable log flushing from here because a call to wxYield() shouldn't
-    // normally result in message boxes popping up &c
-    //
-    wxLog::Suspend();
-
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-    //
-    // We want to go back to the main message loop
-    // if we see a WM_QUIT. (?)
-    //
-    wxEventLoopGuarantor dummyLoopIfNeeded;
-    while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
-    {
-        // TODO: implement event filtering using the eventsToProcess mask
-
-#if wxUSE_THREADS
-        wxMutexGuiLeaveOrEnter();
-#endif // wxUSE_THREADS
-        if (!wxTheApp->Dispatch())
-            break;
-    }
-
-    //
-    // If they are pending events, we must process them.
-    //
-    if (wxTheApp)
-        wxTheApp->ProcessPendingEvents();
-
-    HandleSockets();
-
-    //
-    // Let the logs be flashed again
-    //
-    wxLog::Resume();
-    m_isInsideYield = false;
-
-    return true;
-} // end of wxYield
-
 int wxApp::AddSocketHandler(int handle, int mask,
                             void (*callback)(void*), void * gsock)
 {
index b054bfce488b331ce75910771848b08c0fd354d6..9399da2c82629d16e1222a975e62e8d4d163e035 100644 (file)
@@ -365,3 +365,52 @@ bool wxGUIEventLoop::Dispatch()
 
     return true;
 }
+
+//
+// Yield to incoming messages
+//
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+    HAB vHab = 0;
+    QMSG vMsg;
+
+    //
+    // Disable log flushing from here because a call to wxYield() shouldn't
+    // normally result in message boxes popping up &c
+    //
+    wxLog::Suspend();
+
+    m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
+
+    //
+    // We want to go back to the main message loop
+    // if we see a WM_QUIT. (?)
+    //
+    while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
+    {
+        // TODO: implement event filtering using the eventsToProcess mask
+
+#if wxUSE_THREADS
+        wxMutexGuiLeaveOrEnter();
+#endif // wxUSE_THREADS
+        if (!wxTheApp->Dispatch())
+            break;
+    }
+
+    //
+    // If they are pending events, we must process them.
+    //
+    if (wxTheApp)
+        wxTheApp->ProcessPendingEvents();
+
+    HandleSockets();
+
+    //
+    // Let the logs be flashed again
+    //
+    wxLog::Resume();
+    m_isInsideYield = false;
+
+    return true;
+} // end of wxYield
index b1f8a3d30fbdea773337a97206bb05e26a028e53..8b98b53d7ee97ff62a8db2bce1fc245fc523c196 100644 (file)
@@ -285,13 +285,6 @@ int wxApp::GetComCtl32Version()
     return 0;
 }
 
-// Yield to incoming messages
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    return true;
-}
-
 #if wxUSE_EXCEPTIONS
 
 // ----------------------------------------------------------------------------
index 5835fb3df8e3f9f21ee216c6058b7f504361edae..d9d22bd8812cffc58cef63e6915f5fb1a84f9625 100644 (file)
@@ -144,3 +144,8 @@ void wxGUIEventLoop::WakeUp()
     return;
 }
 
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+    return true;
+}
+
index e37d35ad289238cb92ba20807db52b360c8098ec..e1a396c53f0e9d38a5c000d01b33b975d1018169 100644 (file)
@@ -767,52 +767,6 @@ void wxApp::Exit()
     wxAppConsole::Exit();
 }
 
-// Yield to other processes
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    // Sometimes only 2 yields seem
-    // to do the trick, e.g. in the
-    // progress dialog
-    int i;
-    for (i = 0; i < 2; i++)
-    {
-        if ( m_isInsideYield )
-        {
-            if ( !onlyIfNeeded )
-            {
-                wxFAIL_MSG( wxT("wxYield called recursively" ) );
-            }
-
-            return false;
-        }
-
-        m_isInsideYield = true;
-        m_eventsToProcessInsideYield = eventsToProcess;
-
-        // Make sure we have an event loop object,
-        // or Pending/Dispatch will fail
-        wxEventLoopGuarantor dummyLoopIfNeeded;
-
-        // Call dispatch at least once so that sockets
-        // can be tested
-        wxTheApp->Dispatch();
-
-        // TODO: implement event filtering using the eventsToProcess mask
-        while (wxTheApp && wxTheApp->Pending())
-            wxTheApp->Dispatch();
-
-#if wxUSE_TIMER
-        wxGenericTimerImpl::NotifyTimers();
-#endif
-        ProcessIdle();
-
-        m_isInsideYield = false;
-    }
-
-    return true;
-}
-
 #ifdef __WXDEBUG__
 
 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
index eab9042841002696f901b3471fe326e8d5b77c4e..bfcf4917afa6d0f7e7c43dfe25b88a0ab72c240d 100644 (file)
@@ -243,3 +243,33 @@ bool wxGUIEventLoop::Dispatch()
     (void) m_impl->ProcessEvent( &event );
     return true;
 }
+
+bool wxGUIEventLoop::YieldFor(long eventsToProcess)
+{
+    // Sometimes only 2 yields seem
+    // to do the trick, e.g. in the
+    // progress dialog
+    int i;
+    for (i = 0; i < 2; i++)
+    {
+        m_isInsideYield = true;
+        m_eventsToProcessInsideYield = eventsToProcess;
+
+        // Call dispatch at least once so that sockets
+        // can be tested
+        wxTheApp->Dispatch();
+
+        // TODO: implement event filtering using the eventsToProcess mask
+        while (wxTheApp && wxTheApp->Pending())
+            wxTheApp->Dispatch();
+
+#if wxUSE_TIMER
+        wxGenericTimerImpl::NotifyTimers();
+#endif
+        ProcessIdle();
+
+        m_isInsideYield = false;
+    }
+
+    return true;
+}