second part of #10320: move wxApp event handling functions to wxEventLoopBase (in particular move Yield() functions); add backward compatible redirections to wxApp; update docs; remove global lists wxPendingEvents and wxPendingEventsLocker

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58911 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi
2009-02-15 14:25:08 +00:00
parent 145bbf1fdf
commit dde19c2180
50 changed files with 1104 additions and 1070 deletions

View 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,87 +250,34 @@ public:
// exit, if you need to really handle the exceptions you need to override
// OnExceptionInMainLoop()
virtual void OnUnhandledException();
#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();
// 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();
// 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();
// 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 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
// wxEventLoop redirections
// ------------------------
virtual void SuspendProcessingOfPendingEvents();
virtual void ResumeProcessingOfPendingEvents();
virtual void ProcessPendingEvents();
bool HasPendingEvents() const;
virtual bool Pending();
virtual bool Dispatch();
virtual int MainLoop();
virtual void ExitMainLoop();
bool Yield(bool onlyIfNeeded = false);
virtual void WakeUpIdle();
virtual bool ProcessIdle();
// 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);
};

View 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);

View 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;

View File

@@ -39,8 +39,6 @@ public:
private:
wxVideoMode m_videoMode;
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
DECLARE_DYNAMIC_CLASS(wxApp)
};

View 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();

View 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
// ----------------------------------------------------------------------------

View File

@@ -14,6 +14,36 @@
#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

View 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__

View 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);
};

View File

@@ -70,8 +70,6 @@ private:
bool m_isInAssert;
#endif // __WXDEBUG__
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
DECLARE_DYNAMIC_CLASS(wxApp)
};

View File

@@ -51,8 +51,6 @@ public:
private:
DECLARE_DYNAMIC_CLASS(wxApp)
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
wxVideoMode m_displayMode;
};

View 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; }

View 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();

View 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;

View 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;

View 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 ; }

View 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

View File

@@ -22,6 +22,7 @@ public:
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
virtual bool YieldFor(long eventsToProcess);
private:
double m_sleepTime;

View 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();

View 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
// --------------------

View 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();

View 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);