]> git.saurik.com Git - wxWidgets.git/commitdiff
check in the 'selective yield' patch (see ticket #10320):
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Wed, 4 Feb 2009 17:42:28 +0000 (17:42 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Wed, 4 Feb 2009 17:42:28 +0000 (17:42 +0000)
- implements YieldFor() with event filtering for wxMSW and wxGTK,
  adds TODO markers in other ports;
- replaces wxYield() in GTK's clipboard code with a wxTheApp->YieldFor() call, thus fixing possible reentrancies
(and modifies clipboard sample to test synchronous IsSupported calls)
- replaces wxYieldIfNeeded() calls in wxProgressDialog with wxTheApp->YieldFor() calls, so that it processes only
UI/user-input events, thus fixing the race condition visible in the "thread" sample
- documents the new functions

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58654 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

39 files changed:
include/wx/app.h
include/wx/cocoa/app.h
include/wx/dfb/app.h
include/wx/event.h
include/wx/gtk/app.h
include/wx/gtk1/app.h
include/wx/list.h
include/wx/mgl/app.h
include/wx/motif/app.h
include/wx/msw/app.h
include/wx/os2/app.h
include/wx/osx/app.h
include/wx/palmos/app.h
include/wx/socket.h
include/wx/timer.h
include/wx/x11/app.h
interface/wx/app.h
interface/wx/event.h
samples/clipboard/clipboard.cpp
samples/thread/thread.cpp
src/cocoa/app.mm
src/common/appbase.cpp
src/common/appcmn.cpp
src/common/event.cpp
src/common/init.cpp
src/dfb/app.cpp
src/dfb/evtloop.cpp
src/generic/progdlgg.cpp
src/gtk/app.cpp
src/gtk/clipbrd.cpp
src/gtk1/app.cpp
src/mgl/app.cpp
src/motif/app.cpp
src/msw/app.cpp
src/msw/evtloop.cpp
src/os2/app.cpp
src/osx/carbon/app.cpp
src/palmos/app.cpp
src/x11/app.cpp

index d4ff10377945d3f4367abcefc7143ff415fe4af3..9113fbd6e10fff018e7756d37bd936928fc57cd0 100644 (file)
@@ -32,6 +32,7 @@ class WXDLLIMPEXP_FWD_BASE wxMessageOutput;
 
 #if wxUSE_GUI
     struct WXDLLIMPEXP_FWD_CORE wxVideoMode;
+    class WXDLLIMPEXP_FWD_CORE wxWindow;
 #endif
 
 // ----------------------------------------------------------------------------
@@ -254,6 +255,13 @@ public:
     // (already) be dispatched
     static bool IsMainLoopRunning();
 
+    // 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
@@ -263,9 +271,6 @@ public:
     // check if there are pending events on global pending event list
     bool HasPendingEvents() const;
 
-    // doesn't do anything in this class, just a hook for GUI wxApp
-    virtual bool Yield(bool WXUNUSED(onlyIfNeeded) = false) { return true; }
-
     // make sure that idle events are sent again
     virtual void WakeUpIdle();
 
@@ -300,6 +305,30 @@ public:
     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
     // -----------------
 
@@ -366,6 +395,9 @@ 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;
@@ -392,6 +424,15 @@ 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_BASE wxEvtHandler;
+
     // the application object is a singleton anyhow, there is no sense in
     // copying it
     DECLARE_NO_COPY_CLASS(wxAppConsoleBase)
@@ -451,23 +492,19 @@ public:
     // the worker functions - usually not used directly by the user code
     // -----------------------------------------------------------------
 
-
-
-        // 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!
-    virtual bool Yield(bool onlyIfNeeded = false) = 0;
+        // safer alternatives to Yield(), using wxWindowDisabler
+    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
-    bool IsYielding() const
+    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
@@ -590,7 +627,9 @@ protected:
     // does any of our windows have focus?
     bool m_isActive;
 
+    // Yield() helpers:
     bool m_isInsideYield;
+    long m_eventsToProcessInsideYield;
 
     DECLARE_NO_COPY_CLASS(wxAppBase)
 };
@@ -660,7 +699,7 @@ protected:
 // Force an exit from main loop
 WXDLLIMPEXP_BASE void wxExit();
 
-// avoid redeclaring this function here if it had been already declated by
+// avoid redeclaring this function here if it had been already declared by
 // wx/utils.h, this results in warnings from g++ with -Wredundant-decls
 #ifndef wx_YIELD_DECLARED
 #define wx_YIELD_DECLARED
index bed4a07c7f3873066e78485da99400282e2800f4..7285f71e65fd1c7d7db0fa1dc4e59abc4f92f1bf 100644 (file)
@@ -57,14 +57,14 @@ public:
     // Implement wxAppBase pure virtuals
     virtual void Exit();
 
-    virtual bool Yield(bool onlyIfNeeded = FALSE);
+    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
     virtual void WakeUpIdle();
-    
+
     virtual bool Initialize(int& argc, wxChar **argv);
     virtual void CleanUp();
     virtual bool CallOnInit();
 
-    
+
     virtual bool OnInit();
     virtual bool OnInitGui();
 
index 80e7dfcb088e6dd7d95f04fea347065615ac4e47..b76af79ce3a693b334b49017cde09ff4a5aa5710 100644 (file)
@@ -32,7 +32,6 @@ public:
     virtual void CleanUp();
 
     virtual void WakeUpIdle();
-    virtual bool Yield(bool onlyIfNeeded = false);
 
     virtual wxVideoMode GetDisplayMode() const;
     virtual bool SetDisplayMode(const wxVideoMode& mode);
@@ -40,6 +39,8 @@ public:
 private:
     wxVideoMode m_videoMode;
 
+    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
     DECLARE_DYNAMIC_CLASS(wxApp)
 };
 
index 6b0f093f309fa0ea4d777eb68a156315297138c3..b92e213cd6a10248dd67cb38ac21157d0ab48be1 100644 (file)
@@ -574,6 +574,9 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TOOL_RCLICKED, wxComman
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED, wxCommandEvent)
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TOOL_ENTER, wxCommandEvent)
 
+    // Thread events
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_THREAD, wxCommandEvent)
+
     // Mouse event types
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_LEFT_DOWN, wxMouseEvent)
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_LEFT_UP, wxMouseEvent)
@@ -718,9 +721,14 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_DETAILED_HELP, wxHelpEvent)
 // still, any new code using it should include wx/textctrl.h explicitly
 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEvent)
 
+
+// ----------------------------------------------------------------------------
+// wxEvent(-derived) classes
+// ----------------------------------------------------------------------------
+
 // the predefined constants for the number of times we propagate event
 // upwards window child-parent chain
-enum Propagation_state
+enum wxEventPropagation
 {
     // don't propagate it at all
     wxEVENT_PROPAGATE_NONE = 0,
@@ -729,6 +737,58 @@ enum Propagation_state
     wxEVENT_PROPAGATE_MAX = INT_MAX
 };
 
+// The different categories for a wxEvent; see wxEvent::GetEventCategory.
+// NOTE: they are used as OR-combinable flags by wxApp::Yield
+enum wxEventCategory
+{
+    // this is the category for those events which are generated to update
+    // the appearance of the GUI but which (usually) do not comport data
+    // processing, i.e. which do not provide input or output data
+    // (e.g. size events, scroll events, etc).
+    // They are events NOT directly generated by the user's input devices.
+    wxEVT_CATEGORY_UI = 1,
+
+    // this category groups those events which are generated directly from the
+    // user through input devices like mouse and keyboard and usually result in
+    // data to be processed from the application.
+    // (e.g. mouse clicks, key presses, etc)
+    wxEVT_CATEGORY_USER_INPUT = 2,
+
+    // this category is for wxSocketEvent
+    wxEVT_CATEGORY_SOCKET = 4,
+
+    // this category is for wxTimerEvent
+    wxEVT_CATEGORY_TIMER = 8,
+
+    // this category is for any event used to send notifications from the
+    // secondary threads to the main one or in general for notifications among
+    // different threads (which may or may not be user-generated)
+    wxEVT_CATEGORY_THREAD = 16,
+
+
+    // implementation only
+
+    // used in the implementations of DoYield()
+    wxEVT_CATEGORY_UNKNOWN = 32,
+
+    // a special category used as an argument to wxApp::Yield() 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,
+
+
+    // shortcut masks
+
+    // this category groups those events which are emitted in response to
+    // 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:
+    wxEVT_CATEGORY_ALL =
+        wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
+        wxEVT_CATEGORY_TIMER|wxEVT_CATEGORY_THREAD
+};
+
 /*
  * wxWidgets events, covering all interesting things that might happen
  * (button clicking, resizing, setting text in widgets, etc.).
@@ -748,10 +808,13 @@ public:
 
     void SetEventType(wxEventType typ) { m_eventType = typ; }
     wxEventType GetEventType() const { return m_eventType; }
+
     wxObject *GetEventObject() const { return m_eventObject; }
     void SetEventObject(wxObject *obj) { m_eventObject = obj; }
+
     long GetTimestamp() const { return m_timeStamp; }
     void SetTimestamp(long ts = 0) { m_timeStamp = ts; }
+
     int GetId() const { return m_id; }
     void SetId(int Id) { m_id = Id; }
 
@@ -767,6 +830,12 @@ 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
+    // NOTE: by default it returns wxEVT_CATEGORY_UI just because the major
+    //       part of wxWidgets events belong to that category.
+    virtual wxEventCategory GetEventCategory() const
+        { return wxEVT_CATEGORY_UI; }
+
     // Implementation only: this test is explicitly anti OO and this function
     // exists only for optimization purposes.
     bool IsCommandEvent() const { return m_isCommandEvent; }
@@ -818,9 +887,6 @@ public:
 protected:
     // the propagation level: while it is positive, we propagate the event to
     // the parent window (if any)
-    //
-    // this one doesn't have to be public, we don't have to worry about
-    // backwards compatibility as it is new
     int               m_propagationLevel;
 
     bool              m_skipped;
@@ -956,6 +1022,7 @@ public:
     int GetInt() const { return m_commandInt; }
 
     virtual wxEvent *Clone() const { return new wxCommandEvent(*this); }
+    virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_USER_INPUT; }
 
 protected:
     wxString          m_cmdString;     // String event argument
@@ -999,6 +1066,36 @@ private:
     DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxNotifyEvent)
 };
 
+
+// Thread event
+
+class WXDLLIMPEXP_BASE wxThreadEvent : public wxCommandEvent
+{
+public:
+    wxThreadEvent(int id = wxID_ANY)
+        : wxCommandEvent(wxEVT_COMMAND_THREAD, id)
+        { }
+
+    virtual wxEvent *Clone() const
+    {
+        // make sure our string member (which uses COW aka refcounting) is not
+        // shared by other string instances:
+        const_cast<wxThreadEvent*>(this)->SetString(GetString().c_str());
+
+        return new wxThreadEvent(*this);
+    }
+
+    // this is important to avoid that calling wxApp::Yield() thread events
+    // gets processed when this is unwanted:
+    virtual wxEventCategory GetEventCategory() const
+        { return wxEVT_CATEGORY_THREAD; }
+
+private:
+    DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxThreadEvent)
+};
+
+
+
 // Scroll event class, derived form wxCommandEvent. wxScrollEvents are
 // sent by wxSlider and wxScrollBar.
 /*
@@ -1067,6 +1164,8 @@ private:
     DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxScrollWinEvent)
 };
 
+
+
 // Mouse event class
 
 /*
@@ -1247,6 +1346,7 @@ public:
     bool IsPageScroll() const { return ((unsigned int)m_linesPerAction == UINT_MAX); }
 
     virtual wxEvent *Clone() const { return new wxMouseEvent(*this); }
+    virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_USER_INPUT; }
 
     wxMouseEvent& operator=(const wxMouseEvent& event)
     {
@@ -1370,6 +1470,7 @@ public:
     wxCoord GetY() const { return m_y; }
 
     virtual wxEvent *Clone() const { return new wxKeyEvent(*this); }
+    virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_USER_INPUT; }
 
     // we do need to copy wxKeyEvent sometimes (in wxTreeCtrl code, for
     // example)
@@ -2537,6 +2638,7 @@ private:
 */
 
 
+
 // ============================================================================
 // event handler and related classes
 // ============================================================================
@@ -3217,6 +3319,8 @@ private:
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler)
 };
 
+WX_DEFINE_EXPORTED_ARRAY_PTR(wxEvtHandler*, wxEvtHandlerArray);
+
 // ----------------------------------------------------------------------------
 // wxEventConnectionRef represents all connections between two event handlers
 // and enables automatic disconnect when an event handler sink goes out of
@@ -3322,6 +3426,7 @@ protected:
 };
 
 typedef void (wxEvtHandler::*wxCommandEventFunction)(wxCommandEvent&);
+typedef void (wxEvtHandler::*wxThreadEventFunction)(wxThreadEvent&);
 typedef void (wxEvtHandler::*wxScrollEventFunction)(wxScrollEvent&);
 typedef void (wxEvtHandler::*wxScrollWinEventFunction)(wxScrollWinEvent&);
 typedef void (wxEvtHandler::*wxSizeEventFunction)(wxSizeEvent&);
@@ -3361,6 +3466,8 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
 
 #define wxCommandEventHandler(func) \
     wxEVENT_HANDLER_CAST(wxCommandEventFunction, func)
+#define wxThreadEventHandler(func) \
+    wxEVENT_HANDLER_CAST(wxThreadEventFunction, func)
 #define wxScrollEventHandler(func) \
     wxEVENT_HANDLER_CAST(wxScrollEventFunction, func)
 #define wxScrollWinEventHandler(func) \
@@ -3840,6 +3947,9 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
 #define EVT_TEXT_COPY(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_TEXT_COPY, winid, wxClipboardTextEventHandler(func))
 #define EVT_TEXT_PASTE(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_TEXT_PASTE, winid, wxClipboardTextEventHandler(func))
 
+// Thread events
+#define EVT_THREAD(id, func)  wx__DECLARE_EVT1(wxEVT_COMMAND_THREAD, id, wxThreadEventHandler(func))
+
 // ----------------------------------------------------------------------------
 // Global data
 // ----------------------------------------------------------------------------
@@ -3848,10 +3958,16 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
 //
 // 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 ce6da5421e6b319d73a229f42cfb608a4dae6aa6..87a2ff8c437e26157ed1fd2289293fcc0fd8cd64 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        wx/gtk/app.h
-// Purpose:
+// Purpose:     wxApp definition for wxGTK
 // Author:      Robert Roebling
 // Id:          $Id$
 // Copyright:   (c) 1998 Robert Roebling, Julian Smart
@@ -40,7 +40,6 @@ public:
     virtual bool OnInitGui();
 
     // override base class (pure) virtuals
-    virtual bool Yield(bool onlyIfNeeded = FALSE);
     virtual void WakeUpIdle();
 
     virtual bool Initialize(int& argc, wxChar **argv);
@@ -79,6 +78,10 @@ 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 db2d753e3d09f93a91f56c5a26021bfd05986ca8..32ef7416a0b2817300506f9e572b80ed730279aa 100644 (file)
@@ -38,7 +38,6 @@ public:
     virtual bool OnInitGui();
 
     // override base class (pure) virtuals
-    virtual bool Yield(bool onlyIfNeeded = FALSE);
     virtual void WakeUpIdle();
 
     virtual bool Initialize(int& argc, wxChar **argv);
@@ -71,6 +70,8 @@ private:
     bool m_isInAssert;
 #endif // __WXDEBUG__
 
+    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
     DECLARE_DYNAMIC_CLASS(wxApp)
 };
 
index 950156d4f821667159acf276271e95d89d3699e3..4a55c64134475d11e8d8aa1d6ef8d4b683d70626 100644 (file)
@@ -1277,4 +1277,15 @@ public:
         (list).clear();                                                      \
     }
 
+// append all element of one list to another one
+#define WX_APPEND_LIST(list, other)                                           \
+    {                                                                         \
+        wxList::compatibility_iterator node = other->GetFirst();              \
+        while ( node )                                                        \
+        {                                                                     \
+            (list)->push_back(node->GetData());                               \
+            node = node->GetNext();                                           \
+        }                                                                     \
+    }
+
 #endif // _WX_LISTH__
index 686137a5a2bd9a03033d29a29e452015ee0686dc..d771014e8d4d3b9b222446d04d474bf989ad58e6 100644 (file)
@@ -44,7 +44,6 @@ public:
 
     virtual void Exit();
     virtual void WakeUpIdle();
-    virtual bool Yield(bool onlyIfNeeded = FALSE);
 
     virtual wxVideoMode GetDisplayMode() const { return m_displayMode; }
     virtual bool SetDisplayMode(const wxVideoMode& mode);
@@ -52,6 +51,8 @@ public:
 private:
     DECLARE_DYNAMIC_CLASS(wxApp)
 
+    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
     wxVideoMode m_displayMode;
 };
 
index eef7c9e05429d2ae196d7191857c668150be780b..8879381460d0d245d93efea91629567dc862a152 100644 (file)
@@ -53,7 +53,6 @@ public:
 
     virtual void Exit();
 
-    virtual bool Yield(bool onlyIfNeeded = false);
     virtual void WakeUpIdle(); // implemented in motif/evtloop.cpp
 
     // implementation from now on
@@ -66,6 +65,7 @@ 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 62c6668f1aa408bb11967638407e11b2bb8b79f4..d7175118e1cb4fda605e8c869162a541671fbb3b 100644 (file)
@@ -33,7 +33,6 @@ public:
     virtual bool Initialize(int& argc, wxChar **argv);
     virtual void CleanUp();
 
-    virtual bool Yield(bool onlyIfNeeded = false);
     virtual void WakeUpIdle();
 
     virtual void SetPrintMode(int mode) { m_printMode = mode; }
@@ -79,6 +78,8 @@ 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 6c811e3a1f7bee6a0cddd2f1045e8b111e261e51..26716011af35f795c3d835a65815b6df0da983e5 100644 (file)
@@ -75,7 +75,6 @@ public:
 
     virtual bool OnInitGui(void);
 
-    virtual bool Yield(bool onlyIfNeeded = false);
     virtual void WakeUpIdle(void);
 
     virtual void SetPrintMode(int mode) { m_nPrintMode = mode; }
@@ -111,6 +110,8 @@ public:
     // Implementation
     static bool  RegisterWindowClasses(HAB vHab);
 
+    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
 public:
     int                             m_nCmdShow;
     HMQ                             m_hMq;
index 2ebb72cc1a2577cae47f3d47ec1d7ee178733a79..ad80d008a5f1be8cee2352f441832b1b6fd313b0 100644 (file)
@@ -38,7 +38,6 @@ class WXDLLIMPEXP_CORE wxApp: public wxAppBase
     wxApp();
     virtual ~wxApp() {}
 
-    virtual bool Yield(bool onlyIfNeeded = FALSE);
     virtual void WakeUpIdle();
 
     virtual void SetPrintMode(int mode) { m_printMode = mode; }
@@ -67,6 +66,7 @@ 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 ; }
@@ -88,7 +88,7 @@ public:
 private:
     // mac specifics
     virtual bool        DoInitGui();
-    virtual void        DoCleanUp();  
+    virtual void        DoCleanUp();
 
     WXEVENTHANDLERREF     m_macEventHandler ;
     WXEVENTHANDLERCALLREF m_macCurrentEventHandlerCallRef ;
index c2f4fa6e93f2d8f13d84435d23ab31ffd5bea51b..84d740ea64689da1f9f760bdb1ebdc9e17f7753c 100644 (file)
@@ -35,7 +35,6 @@ public:
     virtual bool Initialize(int& argc, wxChar **argv);
     virtual void CleanUp();
 
-    virtual bool Yield(bool onlyIfNeeded = false);
     virtual void WakeUpIdle();
 
     virtual void SetPrintMode(int mode) { m_printMode = mode; }
@@ -52,6 +51,8 @@ public:
 protected:
     int    m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
 
+    virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
+
 public:
     // Implementation
     static bool RegisterWindowClasses();
index 628605f606453aa52a913350f09ddcfc64a9c6b4..94818bed03a3c58def05d241f5f24cdc2f1fe5af 100644 (file)
@@ -382,6 +382,7 @@ public:
     void *GetClientData() const { return m_clientData; }
 
     virtual wxEvent *Clone() const { return new wxSocketEvent(*this); }
+    virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_SOCKET; }
 
 public:
     wxSocketNotify  m_event;
index 87ac6b9e065f7615861e3332e7a048ba562e2493..2677cab68462d12755bdb535a301e9e1f5ba4c5b 100644 (file)
@@ -172,6 +172,7 @@ public:
 
     // implement the base class pure virtual
     virtual wxEvent *Clone() const { return new wxTimerEvent(*this); }
+    virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; }
 
 private:
     wxTimer* m_timer;
index 02bea53fffc4340a6ed0da5b0fb8f37393b55b9a..588d62242d74b2292b2510a2ecd938fa9eb6f2f9 100644 (file)
@@ -45,7 +45,6 @@ public:
 
     virtual void Exit();
 
-    virtual bool Yield(bool onlyIfNeeded = FALSE);
     virtual void WakeUpIdle();
 
     virtual bool OnInitGui();
@@ -64,6 +63,7 @@ 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 893ee20c6c16e3684e12121dae6fd4f7a87b47c2..ad5ef7b621482e73b2ac5d604c765f171afcb20b 100644 (file)
@@ -162,7 +162,26 @@ public:
         @a onlyIfNeeded parameter is @true, the method will just silently
         return @false instead.
     */
-    virtual bool Yield(bool onlyIfNeeded = false);
+    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;
 
     //@}
 
@@ -180,7 +199,7 @@ public:
 
     /**
         Returns the one and only global application object.
-        Usually wxTheApp is used instead.
+        Usually ::wxTheApp is used instead.
 
         @see SetInstance()
     */
@@ -621,6 +640,25 @@ public:
     */
     virtual bool IsActive() const;
 
+    /**
+        This function is similar to wxYield(), except that it disables the user
+        input to all program windows before calling wxAppConsole::Yield and re-enables it
+        again afterwards. If @a win is not @NULL, this window will remain enabled,
+        allowing the implementation of some limited user interaction.
+        Returns the result of the call to wxAppConsole::Yield.
+
+        @see wxSafeYield
+    */
+    virtual bool SafeYield(wxWindow *win, bool onlyIfNeeded);
+
+    /**
+        Works like SafeYield() with @e onlyIfNeeded == @true except that
+        it allows the caller to specify a mask of events to be processed.
+
+        See wxAppConsole::YieldFor for more info.
+    */
+    virtual bool SafeYieldFor(wxWindow *win, long eventsToProcess);
+
     /**
         Windows-only function for processing a message. This function is called
         from the main message loop, checking for windows that may wish to process it.
@@ -857,22 +895,18 @@ void wxUninitialize();
 void wxWakeUpIdle();
 
 /**
-    Calls wxApp::Yield.
+    Calls wxAppConsole::Yield.
 
     @deprecated
     This function is kept only for backwards compatibility. Please use
-    the wxApp::Yield method instead in any new code.
+    the wxAppConsole::Yield method instead in any new code.
 
     @header{wx/app.h}
 */
 bool wxYield();
 
 /**
-    This function is similar to wxYield(), except that it disables the user
-    input to all program windows before calling wxYield() and re-enables it
-    again afterwards. If @a win is not @NULL, this window will remain enabled,
-    allowing the implementation of some limited user interaction.
-    Returns the result of the call to ::wxYield.
+    Calls wxApp::SafeYield.
 
     @header{wx/app.h}
 */
index 638b185ee2fa6050dfa17709d0a50633c607fd57..f4ff7a77c508981a350d55eee5742c80a3fc6fcd 100644 (file)
@@ -7,6 +7,64 @@
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
+/**
+    The predefined constants for the number of times we propagate event
+    upwards window child-parent chain.
+*/
+enum wxEventPropagation
+{
+    /// don't propagate it at all
+    wxEVENT_PROPAGATE_NONE = 0,
+
+    /// propagate it until it is processed
+    wxEVENT_PROPAGATE_MAX = INT_MAX
+};
+
+/**
+    The different categories for a wxEvent; see wxEvent::GetEventCategory.
+
+    @note They are used as OR-combinable flags by wxApp::Yield.
+*/
+enum wxEventCategory
+{
+    /**
+        This is the category for those events which are generated to update
+        the appearance of the GUI but which (usually) do not comport data
+        processing, i.e. which do not provide input or output data
+        (e.g. size events, scroll events, etc).
+        They are events NOT directly generated by the user's input devices.
+    */
+    wxEVT_CATEGORY_UI = 1,
+
+    /**
+        This category groups those events which are generated directly from the
+        user through input devices like mouse and keyboard and usually result in
+        data to be processed from the application
+        (e.g. mouse clicks, key presses, etc).
+    */
+    wxEVT_CATEGORY_USER_INPUT = 2,
+
+    /// This category is for wxSocketEvent
+    wxEVT_CATEGORY_SOCKET = 4,
+
+    /// This category is for wxTimerEvent
+    wxEVT_CATEGORY_TIMER = 8,
+
+    /**
+        This category is for any event used to send notifications from the
+        secondary threads to the main one or in general for notifications among
+        different threads (which may or may not be user-generated).
+    */
+    wxEVT_CATEGORY_THREAD = 16,
+
+    /**
+        This mask is used in wxApp::Yield to specify that 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
+};
 
 /**
     @class wxEvent
@@ -87,6 +145,13 @@ public:
     */
     wxEventType GetEventType() const;
 
+    /**
+        Returns a generic category for this event.
+
+        This function is used to selectively process events in wxApp::Yield.
+    */
+    virtual wxEventCategory GetEventCategory() const;
+
     /**
         Returns the identifier associated with this event, such as a button command id.
     */
@@ -2463,18 +2528,45 @@ public:
 };
 
 
+/**
+    @class wxThreadEvent
 
+    This class adds some simple functionalities to wxCommandEvent coinceived
+    for inter-threads communications.
 
-enum wxHelpEventOrigin
+    @library{wxcore}
+    @category{events}
+
+    @see @ref overview_thread, wxApp::YieldFor
+*/
+class wxThreadEvent : public wxCommandEvent
 {
-    wxHE_ORIGIN_UNKNOWN = -1,
-    wxHE_ORIGIN_KEYBOARD,
+public:
+    /**
+        Constructor.
+
+        Initializes the event type to @c wxEVT_THREAD (but you can change it
+        using wxEvent::SetEventType.
+    */
+    wxThreadEvent(int id = wxID_ANY);
 
-    /** event generated by wxContextHelp or from the [?] button on
-        the title bar (Windows). */
-    wxHE_ORIGIN_HELPBUTTON
+    /**
+        Clones this event making sure that all internal members which use
+        COW (only @c m_commandString for now; see @ref overview_refcount)
+        are unshared (see wxObject::UnShare).
+    */
+    virtual wxEvent *Clone() const;
+
+    /**
+        Returns @c wxEVT_CATEGORY_THREAD.
+
+        This is important to avoid that calling wxApp::Yield() thread events
+        gets processed when this is unwanted:
+    */
+    virtual wxEventCategory GetEventCategory() const;
 };
 
+
 /**
     @class wxHelpEvent
 
index 3843e7ab2c35ae0ee7dcd79de8852a866220fc3b..be9b0f9433cf98bb0c0d1633a4d0cd9f19cd95c7 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        clipboard.cpp
-// Purpose:     clipbaord wxWidgets sample
+// Purpose:     clipboard wxWidgets sample
 // Author:      Robert Roebling
 // RCS-ID:      $Id: minimal.cpp 53461 2008-05-05 23:30:33Z VZ $
 // Copyright:   (c) Robert Roebling
@@ -9,7 +9,7 @@
 
 // For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
+
 #ifdef __BORLANDC__
     #pragma hdrstop
 #endif
@@ -27,7 +27,7 @@
 #endif
 
 
-#define USE_ASYNCHRONOUS_CLIPBOARD_REQUEST 1
+#define USE_ASYNCHRONOUS_CLIPBOARD_REQUEST  0
 
 class MyApp : public wxApp
 {
@@ -94,7 +94,7 @@ bool MyApp::OnInit()
 
     MyFrame *frame = new MyFrame("wxClipboard sample");
     frame->Show(true);
-    
+
     return true;
 }
 
@@ -103,7 +103,7 @@ MyFrame::MyFrame(const wxString& title)
 {
     // set the frame icon
     SetIcon(wxICON(sample));
-    
+
 #if USE_ASYNCHRONOUS_CLIPBOARD_REQUEST
     m_request = Idle;
     m_clipboardSupportsText = false;
@@ -129,7 +129,7 @@ MyFrame::MyFrame(const wxString& title)
 #endif // wxUSE_MENUS
 
     wxPanel *panel = new wxPanel( this, -1 );
-    
+
     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
     main_sizer->Add( new wxButton( panel, ID_Write, "Get clipboard text" ) );
     m_textctrl = new wxTextCtrl( panel, ID_Text, "", wxDefaultPosition,
@@ -148,7 +148,7 @@ void MyFrame::OnWriteClipboardContents(wxCommandEvent& WXUNUSED(event))
             wxTheClipboard->GetData( data );
             m_textctrl->Clear();
             m_textctrl->SetValue( data.GetText() );
-            
+
         }
         wxTheClipboard->Close();
    }
@@ -175,7 +175,7 @@ void MyFrame::OnUpdateUI(wxUpdateUIEvent&event)
         }
         m_request = Waiting;
         event.Enable( m_clipboardSupportsText ); // not yet known, assume last value
-    } 
+    }
     else if (m_request == Waiting)
     {
         event.Enable( m_clipboardSupportsText ); // not yet known, assume last value
@@ -198,6 +198,7 @@ void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
 {
+    wxMessageBox("Clipboard sample", "About clipboard", wxOK|wxICON_INFORMATION, this);
 }
 
 
index ad2ca592200c4b95fc52062e2be4ad00376bd826..2bcdbb87ea2c980819cb216240d77df6040924fd 100644 (file)
@@ -105,7 +105,7 @@ private:
     void OnResumeThread(wxCommandEvent& event);
 
     void OnStartWorker(wxCommandEvent& event);
-    void OnWorkerEvent(wxCommandEvent& event);
+    void OnWorkerEvent(wxThreadEvent& event);
     void OnUpdateWorker(wxUpdateUIEvent& event);
 
     void OnExecMain(wxCommandEvent& event);
@@ -169,7 +169,7 @@ enum
 
     THREAD_SHOWCPUS,
 
-    WORKER_EVENT    // this one gets sent from the worker thread
+    WORKER_EVENT = wxID_HIGHEST+1   // this one gets sent from the worker thread
 };
 
 // ----------------------------------------------------------------------------
@@ -292,8 +292,22 @@ void MyWorkerThread::OnExit()
 {
 }
 
+#define TEST_YIELD_RACE_CONDITION       1
+
 void *MyWorkerThread::Entry()
 {
+#if TEST_YIELD_RACE_CONDITION
+    if ( TestDestroy() )
+        return NULL;
+
+    wxThreadEvent event( WORKER_EVENT );
+
+    event.SetInt( 50 );
+    wxQueueEvent( m_frame, new wxThreadEvent(event) );
+
+    event.SetInt(-1);
+    wxQueueEvent( m_frame, new wxThreadEvent(event) );
+#else
     for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ )
     {
         // check if we were asked to exit
@@ -301,18 +315,19 @@ void *MyWorkerThread::Entry()
             break;
 
         // create any type of command event here
-        wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
+        wxThreadEvent event( WORKER_EVENT );
         event.SetInt( m_count );
 
         // send in a thread-safe way
-        wxQueueEvent( m_frame, new wxCommandEvent(event) );
+        wxQueueEvent( m_frame, new wxThreadEvent(event) );
 
         wxMilliSleep(200);
     }
 
-    wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
+    wxThreadEvent event( WORKER_EVENT );
     event.SetInt(-1); // that's all
-    wxQueueEvent( m_frame, new wxCommandEvent(event) );
+    wxQueueEvent( m_frame, new wxThreadEvent(event) );
+#endif
 
     return NULL;
 }
@@ -360,7 +375,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
 
     EVT_UPDATE_UI(THREAD_START_WORKER, MyFrame::OnUpdateWorker)
     EVT_MENU(THREAD_START_WORKER, MyFrame::OnStartWorker)
-    EVT_MENU(WORKER_EVENT, MyFrame::OnWorkerEvent)
+
+    EVT_THREAD(WORKER_EVENT, MyFrame::OnWorkerEvent)
 
     EVT_IDLE(MyFrame::OnIdle)
 END_EVENT_TABLE()
@@ -442,7 +458,6 @@ MyFrame::MyFrame(wxFrame *frame, const wxString& title,
 
     m_txtctrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxPoint(0, 0), wxSize(0, 0),
                                wxTE_MULTILINE | wxTE_READONLY);
-
 }
 
 MyFrame::~MyFrame()
@@ -758,7 +773,7 @@ void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event))
     thread->Run();
 }
 
-void MyFrame::OnWorkerEvent(wxCommandEvent& event)
+void MyFrame::OnWorkerEvent(wxThreadEvent& event)
 {
     int n = event.GetInt();
     if ( n == -1 )
index 662859f0912fb5b66fc9e3dc36534877357ce51e..7cde079e142917a574313be12d6a5faead69f77f 100644 (file)
@@ -295,7 +295,7 @@ void wxApp::Exit()
 }
 
 // Yield to other processes
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
 #if wxUSE_LOG
     // disable log flushing from here because a call to wxYield() shouldn't
@@ -314,10 +314,13 @@ bool wxApp::Yield(bool onlyIfNeeded)
     }
 
     m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
 
     // Run the event loop until it is out of events
     while(1)
     {
+        // TODO: implement event filtering using the eventsToProcess mask
+
         wxAutoNSAutoreleasePool pool;
         /*  NOTE: It may be better to use something like
             NSEventTrackingRunLoopMode since we don't necessarily want all
index 30c7f093b2eeb4649610622bdcfc8c685659f2fd..d159c9bdd8eb71738a15fa4b43e776ff77318fa0 100644 (file)
@@ -164,6 +164,7 @@ bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc), wxChar **argv)
 
 #if wxUSE_THREADS
     wxHandlersWithPendingEventsLocker = new wxCriticalSection;
+    wxHandlersWithPendingDelayedEvents = new wxList;
 #endif
 
 #ifndef __WXPALMOS__
@@ -193,6 +194,9 @@ void wxAppConsoleBase::CleanUp()
     delete wxHandlersWithPendingEvents;
     wxHandlersWithPendingEvents = NULL;
 
+    delete wxHandlersWithPendingDelayedEvents;
+    wxHandlersWithPendingDelayedEvents = NULL;
+
 #if wxUSE_THREADS
     delete wxHandlersWithPendingEventsLocker;
     wxHandlersWithPendingEventsLocker = NULL;
@@ -336,6 +340,16 @@ bool wxAppConsoleBase::HasPendingEvents() const
     return has;
 }
 
+void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
+{
+    wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+}
+
+void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
+{
+    wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
+}
+
 /* static */
 bool wxAppConsoleBase::IsMainLoopRunning()
 {
@@ -353,6 +367,9 @@ void wxAppConsoleBase::ProcessPendingEvents()
 
     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
@@ -360,7 +377,7 @@ void wxAppConsoleBase::ProcessPendingEvents()
         wxList::compatibility_iterator node = wxHandlersWithPendingEvents->GetFirst();
         while (node)
         {
-            // In ProcessPendingEvents(), new handlers might be add
+            // In ProcessPendingEvents(), new handlers might be added
             // and we can safely leave the critical section here.
             wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
 
@@ -374,6 +391,20 @@ void wxAppConsoleBase::ProcessPendingEvents()
         }
     }
 
+    // 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;
+
+        WX_APPEND_LIST(wxHandlersWithPendingEvents, wxHandlersWithPendingDelayedEvents);
+        wxHandlersWithPendingDelayedEvents->Clear();
+    }
+
     wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
 }
 
index afb51d63c8579d817d742f4f6c4208b9bed3a089..95da92def714e2316dd39e54cadf551fb62e35d8 100644 (file)
@@ -79,6 +79,7 @@ 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
@@ -325,6 +326,26 @@ void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
     (void)ProcessEvent(event);
 }
 
+bool wxAppBase::IsEventAllowedInsideYield(wxEventCategory cat) const
+{
+    return m_eventsToProcessInsideYield & cat;
+}
+
+bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
+{
+    wxWindowDisabler wd(win);
+
+    return Yield(onlyIfNeeded);
+}
+
+bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
+{
+    wxWindowDisabler wd(win);
+
+    return YieldFor(eventsToProcess);
+}
+
+
 // ----------------------------------------------------------------------------
 // idle handling
 // ----------------------------------------------------------------------------
index a3cce6f3f38dfb114129b7c8680bfd21247074eb..13adaf0aaa2027011b15f9e7ceb12a18a37aee50 100644 (file)
@@ -65,6 +65,7 @@
 
 #if wxUSE_GUI
     IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent)
+    IMPLEMENT_DYNAMIC_CLASS(wxThreadEvent, wxEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent)
@@ -147,6 +148,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule)
 // 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
@@ -316,6 +318,9 @@ wxDEFINE_EVENT( wxEVT_COMMAND_ENTER, wxCommandEvent )
 wxDEFINE_EVENT( wxEVT_HELP, wxHelpEvent )
 wxDEFINE_EVENT( wxEVT_DETAILED_HELP, wxHelpEvent )
 
+// Thread event
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_THREAD)
+
 #endif // wxUSE_GUI
 
 #if wxUSE_BASE
@@ -350,15 +355,14 @@ wxEventFunctor::~wxEventFunctor()
 // ----------------------------------------------------------------------------
 
 /*
- * General wxWidgets events, covering
- * all interesting things that might happen (button clicking, resizing,
- * setting text in widgets, etc.).
+ * General wxWidgets events, covering all interesting things that might happen
+ * (button clicking, resizing, setting text in widgets, etc.).
  *
  * For each completely new event type, derive a new event class.
  *
  */
 
-wxEvent::wxEvent(int theId, wxEventType commandType )
+wxEvent::wxEvent(int theId, wxEventType commandType)
 {
     m_eventType = commandType;
     m_eventObject = NULL;
@@ -1103,6 +1107,14 @@ wxEvtHandler::~wxEvtHandler()
         }
         //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);
@@ -1188,6 +1200,10 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
 
 void wxEvtHandler::ProcessPendingEvents()
 {
+    // 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)
+
     wxENTER_CRIT_SECT( m_pendingEventsLock );
 
     // this method is only called by wxApp if this handler does have
@@ -1196,7 +1212,40 @@ void wxEvtHandler::ProcessPendingEvents()
                  "should have pending events if called" );
 
     wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
-    wxEventPtr event(static_cast<wxEvent *>(node->GetData()));
+    wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
+
+    // find the first event which can be processed now:
+    if (wxTheApp && wxTheApp->IsYielding())
+    {
+        while (node && pEvent && !wxTheApp->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
+        {
+            node = node->GetNext();
+            pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
+        }
+
+        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
+            wxLEAVE_CRIT_SECT( m_pendingEventsLock );
+
+            return;
+        }
+    }
+
+    wxEventPtr event(pEvent);
 
     // it's important we remove event from list before processing it, else a
     // nested event loop, for example from a modal dialog, might process the
@@ -1306,6 +1355,27 @@ bool wxEvtHandler::ProcessEvent(wxEvent& event)
     {
         if ( wxTheApp )
         {
+/*
+    CANNOT ENABLE: ProcessEvent() must always immediately process the event!
+
+            if (wxTheApp->IsYielding() &&
+                !wxTheApp->IsEventAllowedInsideYield(event.GetEventCategory()))
+            {
+                wxEvent* queuedEv = event.Clone();
+
+                // queue this event rather than processing it now
+                QueueEvent(queuedEv);
+                    // the wxWakeUpIdle call shouldn't probably be done
+                    // in this context (there's wxYield in the call stack)
+
+                return true;
+                    // it's not completely true that the event was processed;
+                    // but we cannot even say it was skipped or discarded...
+            }
+            //else: either we're not inside a wxYield() call or if we are,
+            //      we can process this event immediately.
+*/
+
             int rc = wxTheApp->FilterEvent(event);
             if ( rc != -1 )
             {
index 91e0abaf70e25e6e35a2732dd968a71e67625ab9..2450ec403360c6d2c595b54a0b63d6e3b0450aeb 100644 (file)
@@ -63,6 +63,7 @@ public:
     wxDummyConsoleApp() { }
 
     virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; }
+    virtual bool DoYield(bool, long) { return true; }
 
     DECLARE_NO_COPY_CLASS(wxDummyConsoleApp)
 };
index c95912e53866c75d74b0b69b56ac506831b9838f..141bd1a031dbc8dec32542ae02c8875880732870 100644 (file)
@@ -163,8 +163,7 @@ void wxApp::WakeUpIdle()
 #endif
 }
 
-
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
 #if wxUSE_THREADS
     if ( !wxThread::IsMain() )
@@ -182,6 +181,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
     }
 
     m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
 
 #if wxUSE_LOG
     wxLog::Suspend();
index 89d0f753880406f67ee9b26e92e8d17c3b954d1e..d18b73a2515c2ec75ab20897e9f10b429f445f90 100644 (file)
@@ -204,6 +204,8 @@ wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
 
 void wxGUIEventLoop::Yield()
 {
+    // TODO: implement event filtering using the eventsToProcess mask
+
     // process all pending events:
     while ( Pending() )
         Dispatch();
index 2f77e37bf08978e656160e3db1156310909c2930..114f32071c674d47e5dde9d7daa7436a6daa7892 100644 (file)
@@ -401,7 +401,7 @@ wxProgressDialog::Update(int value, const wxString& newmsg, bool *skip)
                 m_msg->SetLabel(_("Done."));
             }
 
-            wxYieldIfNeeded();
+            wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
 
             (void)ShowModal();
         }
@@ -451,7 +451,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
-    wxYieldIfNeeded();
+    wxTheApp->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT);
 
     Update();
 
@@ -670,7 +670,7 @@ void wxProgressDialog::UpdateMessage(const wxString &newmsg)
 
         Fit();   // adapt to the new label size
 
-        wxYieldIfNeeded() ;
+        wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
     }
 }
 
index e982ec4ab0bf41859b2493ed984aeb363589e09b..a7c984dd3bdc1746228868bc6d204431b8a69cbb 100644 (file)
 //-----------------------------------------------------------------------------
 
 static GtkWidget *gs_RootWindow = NULL;
+static wxArrayPtrVoid g_arrGdkEvents;
 
 //-----------------------------------------------------------------------------
 // wxYield
 //-----------------------------------------------------------------------------
 
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
     if ( m_isInsideYield )
     {
@@ -75,6 +76,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
 #endif // wxUSE_THREADS
 
     m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
 
 #if wxUSE_LOG
     // disable log flushing from here because a call to wxYield() shouldn't
@@ -82,16 +84,116 @@ bool wxApp::Yield(bool onlyIfNeeded)
     wxLog::Suspend();
 #endif
 
-    while (EventsPending())
-        gtk_main_iteration();
+    // 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
 
-    // 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();
+    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
index 3ab24136a84f1e78611bc05d136b5548817814ca..a6f6718be144f12e0ab9af397928e007b829b18d 100644 (file)
@@ -73,8 +73,8 @@ public:
 
     ~wxClipboardSync()
     {
-        while ( ms_clipboard )
-            gtk_main_iteration();
+        while (ms_clipboard)
+            wxTheApp->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
     }
 
     // this method must be called by GTK+ callbacks to indicate that we got the
@@ -359,10 +359,10 @@ async_targets_selection_received( GtkWidget *WXUNUSED(widget),
 
     if (!clipboard->m_sink)
         return;
-        
+
     wxClipboardEvent *event = new wxClipboardEvent(wxEVT_CLIPBOARD_CHANGED);
     event->SetEventObject( clipboard );
-    
+
     if ( !selection_data || selection_data->length <= 0 )
     {
         clipboard->m_sink->QueueEvent( event );
@@ -404,7 +404,7 @@ async_targets_selection_received( GtkWidget *WXUNUSED(widget),
 
         event->AddFormat( format );
     }
-    
+
     clipboard->m_sink->QueueEvent( event );
     clipboard->m_sink.Release();
 }
@@ -438,7 +438,7 @@ wxClipboard::wxClipboard()
     g_signal_connect (m_targetsWidget, "selection_received",
                       G_CALLBACK (targets_selection_received), this);
 
-    // we use m_targetsWidgetAsync to query what formats asynchronously
+    // we use m_targetsWidgetAsync to query what formats are available asynchronously
     m_targetsWidgetAsync = gtk_window_new( GTK_WINDOW_POPUP );
     gtk_widget_realize( m_targetsWidgetAsync );
 
@@ -525,15 +525,15 @@ bool wxClipboard::IsSupportedAsync(wxEvtHandler *sink)
 {
     if (m_sink.get())
         return false;  // currently busy, come back later
-        
+
     wxCHECK_MSG( sink, false, wxT("no sink given") );
-      
+
     m_sink = sink;
     gtk_selection_convert( m_targetsWidgetAsync,
                            GTKGetClipboardAtom(),
                            g_targetsAtom,
                            (guint32) GDK_CURRENT_TIME );
-                           
+
     return true;
 }
 
index 449a0f2a0b37dba5b9144317bc899052abdb14ea..17aa4029004d25ab6b783ed23bea973f8f0c74fc 100644 (file)
@@ -103,7 +103,7 @@ static wxMutex gs_idleTagsMutex;
 // wxYield
 //-----------------------------------------------------------------------------
 
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
     if ( m_isInsideYield )
     {
@@ -124,6 +124,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
 #endif // wxUSE_THREADS
 
     m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
 
     // We need to remove idle callbacks or the loop will
     // never finish.
@@ -135,6 +136,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
     wxLog::Suspend();
 #endif
 
+    // TODO: implement event filtering using the eventsToProcess mask
     while (gtk_events_pending())
         gtk_main_iteration();
 
index 0c0a1ac7d46e077d3ba741f1a4e37a2978baf672..a43beb61f1f54b016f1fa82d8d5d2ba87bbd1ab1 100644 (file)
@@ -48,7 +48,7 @@ void wxApp::Exit()
 // wxYield
 //-----------------------------------------------------------------------------
 
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
     if ( m_isInsideYield )
     {
@@ -69,12 +69,15 @@ bool wxApp::Yield(bool onlyIfNeeded)
 #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();
     }
index 6f85268d7515bea251e2dc755fb23f7b0ac91431..11d8129d7026b508d1815abdb660d62a54b06b97 100644 (file)
@@ -470,7 +470,7 @@ void wxApp::SetTopLevelRealizedWidget(WXDisplay* display, WXWidget widget)
 
 // Yield to other processes
 
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
     if ( m_isInsideYield )
     {
@@ -483,9 +483,11 @@ bool wxApp::Yield(bool onlyIfNeeded)
     }
 
     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;
index eccd8787f485a0a28cd61aab925bb9d47287fc6b..d15abf2186747812098f5db7b3cd1664c411b612 100644 (file)
@@ -1015,7 +1015,14 @@ int wxApp::GetShell32Version()
 // Yield to incoming messages
 // ----------------------------------------------------------------------------
 
-bool wxApp::Yield(bool onlyIfNeeded)
+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 )
     {
@@ -1029,8 +1036,9 @@ bool wxApp::Yield(bool onlyIfNeeded)
 
     // set the flag and don't forget to reset it before returning
     m_isInsideYield = true;
-    wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
+    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
@@ -1041,7 +1049,6 @@ bool wxApp::Yield(bool onlyIfNeeded)
     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;
@@ -1053,13 +1060,105 @@ bool wxApp::Yield(bool onlyIfNeeded)
         wxMutexGuiLeaveOrEnter();
 #endif // wxUSE_THREADS
 
-        if ( !wxTheApp->Dispatch() )
-            break;
+        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_KEYFIRST:
+        case WM_KEYDOWN:
+        case WM_KEYUP:
+        case WM_CHAR:
+        case WM_DEADCHAR:
+        case WM_SYSKEYDOWN:
+        case WM_SYSKEYUP:
+        case WM_SYSCHAR:
+        case WM_SYSDEADCHAR:
+        case WM_KEYLAST:
+        case WM_HOTKEY:
+        case WM_IME_STARTCOMPOSITION:
+        case WM_IME_ENDCOMPOSITION:
+        case WM_IME_COMPOSITION:
+        case WM_IME_KEYLAST:
+        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:
+        case WM_NCMOUSELEAVE:
+        case WM_MOUSELEAVE:
+
+        case WM_CUT:
+        case WM_COPY:
+        case WM_PASTE:
+        case WM_CLEAR:
+        case WM_UNDO:
+
+        case WM_MOUSEFIRST:
+        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_MOUSELAST:
+        case WM_MOUSEWHEEL:
+            cat = wxEVT_CATEGORY_USER_INPUT;
+
+        case WM_TIMER:
+            cat = wxEVT_CATEGORY_TIMER;
+
+        default:
+            // there are too many of these types of messages to handle them in this switch
+            cat = wxEVT_CATEGORY_UI;
+        }
+
+        if (cat & eventsToProcess)
+        {
+            if ( !wxTheApp->Dispatch() )
+                break;
+        }
+        else
+        {
+            // remove the message and store it
+            PeekMessage(&msg, (HWND)0, 0, 0, PM_REMOVE)
+            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;
 }
 
index 78d4ee212e3f026fa314a7d87f72a2a6439d01a3..96e618066449a292e439f4a5c4a59c53f190c374 100644 (file)
@@ -360,6 +360,11 @@ void wxGUIEventLoop::WakeUp()
 
 #else // !wxUSE_GUI
 
+
+// ============================================================================
+// wxConsoleEventLoop implementation
+// ============================================================================
+
 #if wxUSE_CONSOLE_EVENTLOOP
 
 void wxConsoleEventLoop::WakeUp()
index 097b323973b9a93d52f664dcf8b53490ff05f366..ed071ed89e885fe936d027e3293d65abc9b0e101 100644 (file)
@@ -507,7 +507,7 @@ void wxApp::OnQueryEndSession( wxCloseEvent& rEvent )
 //
 // Yield to incoming messages
 //
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
     if ( m_isInsideYield )
     {
@@ -529,6 +529,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
     wxLog::Suspend();
 
     m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
 
     //
     // We want to go back to the main message loop
@@ -537,6 +538,8 @@ bool wxApp::Yield(bool onlyIfNeeded)
     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
index 3ad2d09ab0d92e83708c77d67a2d4cc722e4bcac..2b8c675d3dd1fcdc2df09c1cfa15a11ea06873b1 100644 (file)
@@ -1119,7 +1119,7 @@ void wxCYield()
 
 // Yield to other processes
 
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
 #if wxUSE_THREADS
     // Yielding from a non-gui thread needs to bail out, otherwise we end up
@@ -1141,6 +1141,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
     }
 
     m_isInsideYield = true;
+    m_eventsToProcessInsideYield = eventsToProcess;
 
 #if wxUSE_LOG
     // disable log flushing from here because a call to wxYield() shouldn't
index 6accd4a64f3e11bc325d990324dadd8957ba8fbf..b1f8a3d30fbdea773337a97206bb05e26a028e53 100644 (file)
@@ -287,7 +287,7 @@ int wxApp::GetComCtl32Version()
 
 // Yield to incoming messages
 
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
     return true;
 }
index 772abba8c6003fd25eb740631f56cfc291efe511..e37d35ad289238cb92ba20807db52b360c8098ec 100644 (file)
@@ -769,7 +769,7 @@ void wxApp::Exit()
 
 // Yield to other processes
 
-bool wxApp::Yield(bool onlyIfNeeded)
+bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
 {
     // Sometimes only 2 yields seem
     // to do the trick, e.g. in the
@@ -788,6 +788,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
         }
 
         m_isInsideYield = true;
+        m_eventsToProcessInsideYield = eventsToProcess;
 
         // Make sure we have an event loop object,
         // or Pending/Dispatch will fail
@@ -797,6 +798,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
         // can be tested
         wxTheApp->Dispatch();
 
+        // TODO: implement event filtering using the eventsToProcess mask
         while (wxTheApp && wxTheApp->Pending())
             wxTheApp->Dispatch();