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:
@@ -261,6 +261,8 @@ Deprecated methods and their replacements
|
|||||||
- wxDos2UnixFilename, wxUnix2DosFilename, wxStripExtension, wxGetTempFileName,
|
- wxDos2UnixFilename, wxUnix2DosFilename, wxStripExtension, wxGetTempFileName,
|
||||||
wxExpandPath, wxContractPath, wxRealPath, wxCopyAbsolutePath, wxSplitPath
|
wxExpandPath, wxContractPath, wxRealPath, wxCopyAbsolutePath, wxSplitPath
|
||||||
were deprecated in favour of wxFileName methods. See docs for more info.
|
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
|
Major new features in this release
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@@ -472,6 +474,9 @@ All (GUI):
|
|||||||
- Added wxIMAGE_OPTION_PNG_FILTER and many wxIMAGE_OPTION_PNG_COMPRESSION_* options
|
- 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
|
to wxImage and wxPNGHandler to allow for custom compression levels when saving PNGs
|
||||||
- Added GetValue(), GetRange(), GetMessage() functions to wxProgressDialog
|
- 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:
|
wxGTK:
|
||||||
|
|
||||||
|
119
include/wx/app.h
119
include/wx/app.h
@@ -221,6 +221,10 @@ public:
|
|||||||
// had been already processed or won't be processed at all, respectively
|
// had been already processed or won't be processed at all, respectively
|
||||||
virtual int FilterEvent(wxEvent& event);
|
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
|
#if wxUSE_EXCEPTIONS
|
||||||
// execute the functor to handle the given event
|
// 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
|
// exit, if you need to really handle the exceptions you need to override
|
||||||
// OnExceptionInMainLoop()
|
// OnExceptionInMainLoop()
|
||||||
virtual void OnUnhandledException();
|
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
|
// Function called if an uncaught exception is caught inside the main
|
||||||
// event loop: it may return true to continue running the event loop or
|
// 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
|
// false to stop it (in the latter case it may rethrow the exception as
|
||||||
// well)
|
// well)
|
||||||
virtual bool OnExceptionInMainLoop();
|
virtual bool OnExceptionInMainLoop();
|
||||||
|
|
||||||
#endif // wxUSE_EXCEPTIONS
|
#endif // wxUSE_EXCEPTIONS
|
||||||
|
|
||||||
// Yield-related hooks
|
|
||||||
// -------------------
|
|
||||||
|
|
||||||
// process all currently pending events right now
|
// wxEventLoop redirections
|
||||||
//
|
// ------------------------
|
||||||
// it is an error to call Yield() recursively unless the value of
|
|
||||||
// onlyIfNeeded is true
|
virtual void SuspendProcessingOfPendingEvents();
|
||||||
//
|
virtual void ResumeProcessingOfPendingEvents();
|
||||||
// WARNING: this function is dangerous as it can lead to unexpected
|
virtual void ProcessPendingEvents();
|
||||||
// reentrancies (i.e. when called from an event handler it
|
bool HasPendingEvents() const;
|
||||||
// may result in calling the same event handler again), use
|
|
||||||
// with _extreme_ care or, better, don't use at all!
|
virtual bool Pending();
|
||||||
// NOTE: in wxConsoleBase it doesn't do anything, just a hook for GUI wxApp
|
virtual bool Dispatch();
|
||||||
bool Yield(bool onlyIfNeeded = false)
|
|
||||||
{ return DoYield(onlyIfNeeded, wxEVT_CATEGORY_ALL); }
|
virtual int MainLoop();
|
||||||
bool YieldFor(long eventsToProcess)
|
virtual void ExitMainLoop();
|
||||||
{ return DoYield(true, eventsToProcess); }
|
|
||||||
virtual bool IsYielding() const
|
bool Yield(bool onlyIfNeeded = false);
|
||||||
{ return false; }
|
|
||||||
virtual bool IsEventAllowedInsideYield(wxEventCategory WXUNUSED(cat)) const
|
virtual void WakeUpIdle();
|
||||||
{ return true; }
|
virtual bool ProcessIdle();
|
||||||
// no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
|
|
||||||
|
|
||||||
|
|
||||||
// debugging support
|
// debugging support
|
||||||
@@ -395,10 +346,6 @@ protected:
|
|||||||
// for the first time
|
// for the first time
|
||||||
virtual wxAppTraits *CreateTraits();
|
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
|
// function used for dynamic wxApp creation
|
||||||
static wxAppInitializerFunction ms_appInitFn;
|
static wxAppInitializerFunction ms_appInitFn;
|
||||||
|
|
||||||
@@ -424,13 +371,6 @@ protected:
|
|||||||
// been started yet or has already terminated)
|
// been started yet or has already terminated)
|
||||||
wxEventLoopBase *m_mainLoop;
|
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;
|
friend class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
|
||||||
|
|
||||||
// the application object is a singleton anyhow, there is no sense in
|
// 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 SafeYield(wxWindow *win, bool onlyIfNeeded);
|
||||||
virtual bool SafeYieldFor(wxWindow *win, long eventsToProcess);
|
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
|
// this virtual function is called in the GUI mode when the application
|
||||||
// becomes idle and normally just sends wxIdleEvent to all interested
|
// becomes idle and normally just sends wxIdleEvent to all interested
|
||||||
// parties
|
// parties
|
||||||
@@ -627,10 +558,6 @@ protected:
|
|||||||
// does any of our windows have focus?
|
// does any of our windows have focus?
|
||||||
bool m_isActive;
|
bool m_isActive;
|
||||||
|
|
||||||
// Yield() helpers:
|
|
||||||
bool m_isInsideYield;
|
|
||||||
long m_eventsToProcessInsideYield;
|
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxAppBase);
|
wxDECLARE_NO_COPY_CLASS(wxAppBase);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -57,7 +57,6 @@ public:
|
|||||||
// Implement wxAppBase pure virtuals
|
// Implement wxAppBase pure virtuals
|
||||||
virtual void Exit();
|
virtual void Exit();
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
virtual void WakeUpIdle();
|
virtual void WakeUpIdle();
|
||||||
|
|
||||||
virtual bool Initialize(int& argc, wxChar **argv);
|
virtual bool Initialize(int& argc, wxChar **argv);
|
||||||
|
@@ -26,6 +26,7 @@ public:
|
|||||||
virtual bool Dispatch();
|
virtual bool Dispatch();
|
||||||
virtual int DispatchTimeout(unsigned long timeout);
|
virtual int DispatchTimeout(unsigned long timeout);
|
||||||
virtual void WakeUp() { }
|
virtual void WakeUp() { }
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int m_exitcode;
|
int m_exitcode;
|
||||||
|
@@ -39,8 +39,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
wxVideoMode m_videoMode;
|
wxVideoMode m_videoMode;
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
DECLARE_DYNAMIC_CLASS(wxApp)
|
DECLARE_DYNAMIC_CLASS(wxApp)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -25,14 +25,12 @@ class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxConsoleEventLoop
|
|||||||
public:
|
public:
|
||||||
wxGUIEventLoop();
|
wxGUIEventLoop();
|
||||||
|
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
// returns DirectFB event buffer used by wx
|
// returns DirectFB event buffer used by wx
|
||||||
static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer();
|
static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// wxYield implementation: iterate the loop as long as there are any
|
|
||||||
// pending events
|
|
||||||
void Yield();
|
|
||||||
|
|
||||||
static void InitBuffer();
|
static void InitBuffer();
|
||||||
static void CleanUp();
|
static void CleanUp();
|
||||||
|
|
||||||
|
@@ -772,7 +772,7 @@ enum wxEventPropagation
|
|||||||
};
|
};
|
||||||
|
|
||||||
// The different categories for a wxEvent; see wxEvent::GetEventCategory.
|
// 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
|
enum wxEventCategory
|
||||||
{
|
{
|
||||||
// this is the category for those events which are generated to update
|
// this is the category for those events which are generated to update
|
||||||
@@ -802,10 +802,10 @@ enum wxEventCategory
|
|||||||
|
|
||||||
// implementation only
|
// implementation only
|
||||||
|
|
||||||
// used in the implementations of DoYield()
|
// used in the implementations of wxEventLoopBase::YieldFor
|
||||||
wxEVT_CATEGORY_UNKNOWN = 32,
|
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
|
// 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)
|
// (native events will be processed but the wxEvents they generate will be queued)
|
||||||
wxEVT_CATEGORY_CLIPBOARD = 64,
|
wxEVT_CATEGORY_CLIPBOARD = 64,
|
||||||
@@ -817,7 +817,7 @@ enum wxEventCategory
|
|||||||
// events of the native toolkit and which typically are not-"delayable".
|
// events of the native toolkit and which typically are not-"delayable".
|
||||||
wxEVT_CATEGORY_NATIVE_EVENTS = wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT,
|
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_ALL =
|
||||||
wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
|
wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
|
||||||
wxEVT_CATEGORY_TIMER|wxEVT_CATEGORY_THREAD
|
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)
|
// for them wouldn't work (it needs to do a copy of the event)
|
||||||
virtual wxEvent *Clone() const = 0;
|
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
|
// NOTE: by default it returns wxEVT_CATEGORY_UI just because the major
|
||||||
// part of wxWidgets events belong to that category.
|
// part of wxWidgets events belong to that category.
|
||||||
virtual wxEventCategory GetEventCategory() const
|
virtual wxEventCategory GetEventCategory() const
|
||||||
@@ -1120,7 +1120,7 @@ public:
|
|||||||
return ev;
|
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:
|
// gets processed when this is unwanted:
|
||||||
virtual wxEventCategory GetEventCategory() const
|
virtual wxEventCategory GetEventCategory() const
|
||||||
{ return wxEVT_CATEGORY_THREAD; }
|
{ return wxEVT_CATEGORY_THREAD; }
|
||||||
@@ -3985,24 +3985,6 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
|
|||||||
// Thread events
|
// Thread events
|
||||||
#define EVT_THREAD(id, func) wx__DECLARE_EVT1(wxEVT_COMMAND_THREAD, id, wxThreadEventHandler(func))
|
#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
|
// Helper functions
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@@ -14,6 +14,36 @@
|
|||||||
|
|
||||||
#include "wx/utils.h"
|
#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
|
// wxEventLoopBase: interface for wxEventLoop
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -22,7 +52,7 @@ class WXDLLIMPEXP_BASE wxEventLoopBase
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// trivial, but needed (because of wxEventLoopBase) ctor
|
// trivial, but needed (because of wxEventLoopBase) ctor
|
||||||
wxEventLoopBase() { }
|
wxEventLoopBase();
|
||||||
|
|
||||||
// dtor
|
// dtor
|
||||||
virtual ~wxEventLoopBase() { }
|
virtual ~wxEventLoopBase() { }
|
||||||
@@ -32,9 +62,18 @@ public:
|
|||||||
virtual bool IsOk() const { return true; }
|
virtual bool IsOk() const { return true; }
|
||||||
|
|
||||||
|
|
||||||
|
// dispatch&processing
|
||||||
|
// -------------------
|
||||||
|
|
||||||
// start the event loop, return the exit code when it is finished
|
// start the event loop, return the exit code when it is finished
|
||||||
virtual int Run() = 0;
|
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
|
// exit from the loop with the given exit code
|
||||||
virtual void Exit(int rc = 0) = 0;
|
virtual void Exit(int rc = 0) = 0;
|
||||||
|
|
||||||
@@ -49,6 +88,86 @@ public:
|
|||||||
// exit the loop or -1 if timeout expired
|
// exit the loop or -1 if timeout expired
|
||||||
virtual int DispatchTimeout(unsigned long timeout) = 0;
|
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
|
// return currently active (running) event loop, may be NULL
|
||||||
static wxEventLoopBase *GetActive() { return ms_activeLoop; }
|
static wxEventLoopBase *GetActive() { return ms_activeLoop; }
|
||||||
@@ -56,15 +175,6 @@ public:
|
|||||||
// set currently active (running) event loop
|
// set currently active (running) event loop
|
||||||
static void SetActive(wxEventLoopBase* loop) { ms_activeLoop = 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:
|
protected:
|
||||||
// this function should be called before the event loop terminates, whether
|
// this function should be called before the event loop terminates, whether
|
||||||
@@ -72,10 +182,25 @@ protected:
|
|||||||
// an exception thrown from inside the loop)
|
// an exception thrown from inside the loop)
|
||||||
virtual void OnExit() { }
|
virtual void OnExit() { }
|
||||||
|
|
||||||
|
|
||||||
// the pointer to currently active loop
|
// the pointer to currently active loop
|
||||||
static wxEventLoopBase *ms_activeLoop;
|
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);
|
wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,6 +286,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void WakeUp() { }
|
virtual void WakeUp() { }
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// the pointer to the port specific implementation class
|
// the pointer to the port specific implementation class
|
||||||
|
@@ -78,10 +78,6 @@ public:
|
|||||||
bool EventsPending();
|
bool EventsPending();
|
||||||
bool DoIdle();
|
bool DoIdle();
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// true if we're inside an assert modal dialog
|
// true if we're inside an assert modal dialog
|
||||||
#ifdef __WXDEBUG__
|
#ifdef __WXDEBUG__
|
||||||
|
@@ -26,11 +26,16 @@ public:
|
|||||||
virtual bool Dispatch();
|
virtual bool Dispatch();
|
||||||
virtual int DispatchTimeout(unsigned long timeout);
|
virtual int DispatchTimeout(unsigned long timeout);
|
||||||
virtual void WakeUp();
|
virtual void WakeUp();
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// the exit code of this event loop
|
// the exit code of this event loop
|
||||||
int m_exitcode;
|
int m_exitcode;
|
||||||
|
|
||||||
|
// used to temporarily store events in DoYield()
|
||||||
|
wxArrayPtrVoid m_arrGdkEvents;
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
|
wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -70,8 +70,6 @@ private:
|
|||||||
bool m_isInAssert;
|
bool m_isInAssert;
|
||||||
#endif // __WXDEBUG__
|
#endif // __WXDEBUG__
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
DECLARE_DYNAMIC_CLASS(wxApp)
|
DECLARE_DYNAMIC_CLASS(wxApp)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -51,8 +51,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
DECLARE_DYNAMIC_CLASS(wxApp)
|
DECLARE_DYNAMIC_CLASS(wxApp)
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
wxVideoMode m_displayMode;
|
wxVideoMode m_displayMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -65,7 +65,6 @@ public:
|
|||||||
// Implementation
|
// Implementation
|
||||||
virtual bool Initialize(int& argc, wxChar **argv);
|
virtual bool Initialize(int& argc, wxChar **argv);
|
||||||
virtual void CleanUp();
|
virtual void CleanUp();
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
// Motif-specific
|
// Motif-specific
|
||||||
WXAppContext GetAppContext() const { return m_appContext; }
|
WXAppContext GetAppContext() const { return m_appContext; }
|
||||||
|
@@ -78,8 +78,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
|
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// unregister any window classes registered by GetRegisteredClassName()
|
// unregister any window classes registered by GetRegisteredClassName()
|
||||||
static void UnregisterWindowClasses();
|
static void UnregisterWindowClasses();
|
||||||
|
@@ -40,6 +40,8 @@ protected:
|
|||||||
|
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
|
|
||||||
|
WX_DECLARE_OBJARRAY(MSG, wxMSGArray);
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxMSWEventLoopBase
|
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxMSWEventLoopBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -72,6 +74,7 @@ public:
|
|||||||
virtual bool Dispatch();
|
virtual bool Dispatch();
|
||||||
virtual int DispatchTimeout(unsigned long timeout);
|
virtual int DispatchTimeout(unsigned long timeout);
|
||||||
virtual void WakeUp();
|
virtual void WakeUp();
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnNextIteration();
|
virtual void OnNextIteration();
|
||||||
@@ -81,6 +84,8 @@ private:
|
|||||||
// non NULL)
|
// non NULL)
|
||||||
static bool IsChildOfCriticalWindow(wxWindowMSW *win);
|
static bool IsChildOfCriticalWindow(wxWindowMSW *win);
|
||||||
|
|
||||||
|
// array of messages used for temporary storage by YieldFor()
|
||||||
|
wxMSGArray m_arrMSG;
|
||||||
|
|
||||||
// critical window or NULL
|
// critical window or NULL
|
||||||
static wxWindowMSW *ms_winCritical;
|
static wxWindowMSW *ms_winCritical;
|
||||||
|
@@ -110,8 +110,6 @@ public:
|
|||||||
// Implementation
|
// Implementation
|
||||||
static bool RegisterWindowClasses(HAB vHab);
|
static bool RegisterWindowClasses(HAB vHab);
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int m_nCmdShow;
|
int m_nCmdShow;
|
||||||
HMQ m_hMq;
|
HMQ m_hMq;
|
||||||
|
@@ -66,7 +66,6 @@ public:
|
|||||||
// Implementation
|
// Implementation
|
||||||
virtual bool Initialize(int& argc, wxChar **argv);
|
virtual bool Initialize(int& argc, wxChar **argv);
|
||||||
virtual void CleanUp();
|
virtual void CleanUp();
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
// the installed application event handler
|
// the installed application event handler
|
||||||
WXEVENTHANDLERREF MacGetEventHandler() { return m_macEventHandler ; }
|
WXEVENTHANDLERREF MacGetEventHandler() { return m_macEventHandler ; }
|
||||||
|
@@ -26,6 +26,7 @@ public:
|
|||||||
virtual int DispatchTimeout(unsigned long timeout);
|
virtual int DispatchTimeout(unsigned long timeout);
|
||||||
|
|
||||||
virtual void WakeUp();
|
virtual void WakeUp();
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// dispatch an event and release it
|
// dispatch an event and release it
|
||||||
|
@@ -22,6 +22,7 @@ public:
|
|||||||
virtual int DispatchTimeout(unsigned long timeout);
|
virtual int DispatchTimeout(unsigned long timeout);
|
||||||
|
|
||||||
virtual void WakeUp();
|
virtual void WakeUp();
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_sleepTime;
|
double m_sleepTime;
|
||||||
|
@@ -51,8 +51,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
|
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
|
||||||
|
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Implementation
|
// Implementation
|
||||||
static bool RegisterWindowClasses();
|
static bool RegisterWindowClasses();
|
||||||
|
@@ -28,6 +28,7 @@ public:
|
|||||||
virtual bool Dispatch();
|
virtual bool Dispatch();
|
||||||
virtual int DispatchTimeout(unsigned long timeout);
|
virtual int DispatchTimeout(unsigned long timeout);
|
||||||
virtual bool IsRunning() const;
|
virtual bool IsRunning() const;
|
||||||
|
virtual bool YieldFor(long eventsToProcess);
|
||||||
|
|
||||||
// MSW-specific methods
|
// MSW-specific methods
|
||||||
// --------------------
|
// --------------------
|
||||||
|
@@ -37,6 +37,7 @@ public:
|
|||||||
virtual int DispatchTimeout(unsigned long timeout);
|
virtual int DispatchTimeout(unsigned long timeout);
|
||||||
virtual void WakeUp();
|
virtual void WakeUp();
|
||||||
virtual bool IsOk() const { return m_dispatcher != NULL; }
|
virtual bool IsOk() const { return m_dispatcher != NULL; }
|
||||||
|
virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnNextIteration();
|
virtual void OnNextIteration();
|
||||||
|
@@ -63,7 +63,6 @@ public:
|
|||||||
// Implementation
|
// Implementation
|
||||||
virtual bool Initialize(int& argc, wxChar **argv);
|
virtual bool Initialize(int& argc, wxChar **argv);
|
||||||
virtual void CleanUp();
|
virtual void CleanUp();
|
||||||
virtual bool DoYield(bool onlyIfNeeded, long eventsToProcess);
|
|
||||||
|
|
||||||
WXWindow GetTopLevelWidget() const { return m_topLevelWidget; }
|
WXWindow GetTopLevelWidget() const { return m_topLevelWidget; }
|
||||||
WXColormap GetMainColormap(WXDisplay* display);
|
WXColormap GetMainColormap(WXDisplay* display);
|
||||||
|
@@ -57,31 +57,26 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
@name Event-handling
|
@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.
|
Called by wxWidgets on creation of the application. Override this if you wish
|
||||||
Blocks until an event appears if there are none currently
|
to provide your own (environment-dependent) main loop.
|
||||||
(use Pending() if this is not wanted).
|
|
||||||
|
|
||||||
This can be used for programming event loops, e.g.
|
@return 0 under X, and the wParam of the WM_QUIT message under Windows.
|
||||||
|
|
||||||
@code
|
|
||||||
while (app.Pending())
|
|
||||||
Dispatch();
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@return @false if the event loop should stop and @true otherwise.
|
|
||||||
|
|
||||||
@see Pending(), wxEventLoopBase
|
|
||||||
*/
|
*/
|
||||||
virtual bool Dispatch();
|
virtual int MainLoop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Call this to explicitly exit the main message (event) loop.
|
Call this to explicitly exit the main message (event) loop.
|
||||||
You should normally exit the main loop (and the application) by deleting
|
You should normally exit the main loop (and the application) by deleting
|
||||||
the top window.
|
the top window.
|
||||||
|
|
||||||
|
This function simply calls wxEvtLoopBase::Exit() on the active loop.
|
||||||
*/
|
*/
|
||||||
virtual void ExitMainLoop();
|
virtual void ExitMainLoop();
|
||||||
|
|
||||||
@@ -108,81 +103,6 @@ public:
|
|||||||
wxEventFunction func,
|
wxEventFunction func,
|
||||||
wxEvent& event) const;
|
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;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ enum wxEventPropagation
|
|||||||
/**
|
/**
|
||||||
The different categories for a wxEvent; see wxEvent::GetEventCategory.
|
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
|
enum wxEventCategory
|
||||||
{
|
{
|
||||||
@@ -58,8 +58,8 @@ enum wxEventCategory
|
|||||||
wxEVT_CATEGORY_THREAD = 16,
|
wxEVT_CATEGORY_THREAD = 16,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This mask is used in wxApp::Yield to specify that all event categories should
|
This mask is used in wxEventLoopBase::YieldFor to specify that all event
|
||||||
be processed.
|
categories should be processed.
|
||||||
*/
|
*/
|
||||||
wxEVT_CATEGORY_ALL =
|
wxEVT_CATEGORY_ALL =
|
||||||
wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
|
wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_SOCKET| \
|
||||||
@@ -148,7 +148,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
Returns a generic category for this event.
|
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;
|
virtual wxEventCategory GetEventCategory() const;
|
||||||
|
|
||||||
@@ -2537,7 +2537,7 @@ public:
|
|||||||
@library{wxcore}
|
@library{wxcore}
|
||||||
@category{events}
|
@category{events}
|
||||||
|
|
||||||
@see @ref overview_thread, wxApp::YieldFor
|
@see @ref overview_thread, wxEventLoopBase::YieldFor
|
||||||
*/
|
*/
|
||||||
class wxThreadEvent : public wxCommandEvent
|
class wxThreadEvent : public wxCommandEvent
|
||||||
{
|
{
|
||||||
@@ -2558,7 +2558,7 @@ public:
|
|||||||
Returns @c wxEVT_CATEGORY_THREAD.
|
Returns @c wxEVT_CATEGORY_THREAD.
|
||||||
|
|
||||||
This is important to avoid unwanted processing of thread events
|
This is important to avoid unwanted processing of thread events
|
||||||
when calling wxApp::YieldFor().
|
when calling wxEventLoopBase::YieldFor().
|
||||||
*/
|
*/
|
||||||
virtual wxEventCategory GetEventCategory() const;
|
virtual wxEventCategory GetEventCategory() const;
|
||||||
};
|
};
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
@library{wxbase}
|
@library{wxbase}
|
||||||
@category{appmanagement}
|
@category{appmanagement}
|
||||||
|
|
||||||
@see wxApp
|
@see wxApp, wxEventLoopActivator
|
||||||
*/
|
*/
|
||||||
class wxEventLoopBase
|
class wxEventLoopBase
|
||||||
{
|
{
|
||||||
@@ -42,10 +42,9 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Use this to check whether the event loop was successfully created
|
@name Dispatch and processing
|
||||||
before using it
|
|
||||||
*/
|
*/
|
||||||
virtual bool IsOk() const;
|
//@{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Start the event loop, return the exit code when it is finished.
|
Start the event loop, return the exit code when it is finished.
|
||||||
@@ -60,6 +59,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual int Run() = 0;
|
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.
|
Exit from the loop with the given exit code.
|
||||||
*/
|
*/
|
||||||
@@ -73,12 +87,20 @@ public:
|
|||||||
virtual bool Pending() const = 0;
|
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
|
This can be used for programming event loops, e.g.
|
||||||
becomes available.
|
|
||||||
|
|
||||||
@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;
|
virtual bool Dispatch() = 0;
|
||||||
|
|
||||||
@@ -100,21 +122,139 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual int DispatchTimeout(unsigned long timeout) = 0;
|
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
|
Called by wxWidgets to wake up the event loop even if it is currently
|
||||||
blocked inside Dispatch().
|
blocked inside Dispatch().
|
||||||
*/
|
*/
|
||||||
virtual void WakeUp() = 0;
|
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:
|
protected:
|
||||||
/**
|
/**
|
||||||
This function is called before the event loop terminates, whether this
|
This function is called before the event loop terminates, whether this
|
||||||
|
@@ -162,11 +162,6 @@ bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc), wxChar **argv)
|
|||||||
GetTraits()->SetLocale();
|
GetTraits()->SetLocale();
|
||||||
#endif // wxUSE_INTL
|
#endif // wxUSE_INTL
|
||||||
|
|
||||||
#if wxUSE_THREADS
|
|
||||||
wxHandlersWithPendingEventsLocker = new wxCriticalSection;
|
|
||||||
wxHandlersWithPendingDelayedEvents = new wxList;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __WXPALMOS__
|
#ifndef __WXPALMOS__
|
||||||
if ( m_appName.empty() && argv && argv[0] )
|
if ( m_appName.empty() && argv && argv[0] )
|
||||||
{
|
{
|
||||||
@@ -190,17 +185,6 @@ void wxAppConsoleBase::CleanUp()
|
|||||||
delete m_mainLoop;
|
delete m_mainLoop;
|
||||||
m_mainLoop = NULL;
|
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()
|
int wxAppConsoleBase::MainLoop()
|
||||||
@@ -331,81 +315,37 @@ bool wxAppConsoleBase::Dispatch()
|
|||||||
|
|
||||||
bool wxAppConsoleBase::HasPendingEvents() const
|
bool wxAppConsoleBase::HasPendingEvents() const
|
||||||
{
|
{
|
||||||
wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
|
|
||||||
bool has = wxHandlersWithPendingEvents && !wxHandlersWithPendingEvents->IsEmpty();
|
return loop && loop->HasPendingEvents();
|
||||||
|
|
||||||
wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
|
|
||||||
|
|
||||||
return has;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
|
void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
|
||||||
{
|
{
|
||||||
wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
|
|
||||||
|
if (loop) loop->SuspendProcessingOfPendingEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
|
void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
|
||||||
{
|
{
|
||||||
wxLEAVE_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
if (loop) loop->ResumeProcessingOfPendingEvents();
|
||||||
bool wxAppConsoleBase::IsMainLoopRunning()
|
|
||||||
{
|
|
||||||
const wxAppConsole * const app = GetInstance();
|
|
||||||
|
|
||||||
return app && app->m_mainLoop != NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppConsoleBase::ProcessPendingEvents()
|
void wxAppConsoleBase::ProcessPendingEvents()
|
||||||
{
|
{
|
||||||
#if wxUSE_THREADS
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
if ( !wxHandlersWithPendingEventsLocker )
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wxENTER_CRIT_SECT( *wxHandlersWithPendingEventsLocker );
|
if (loop) loop->ProcessPendingEvents();
|
||||||
|
}
|
||||||
|
|
||||||
wxCHECK_RET( wxHandlersWithPendingDelayedEvents->IsEmpty(),
|
bool wxAppConsoleBase::Yield(bool onlyIfNeeded)
|
||||||
"this helper list should be empty" );
|
{
|
||||||
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
|
|
||||||
if (wxHandlersWithPendingEvents)
|
return loop && loop->Yield(onlyIfNeeded);
|
||||||
{
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxAppConsoleBase::WakeUpIdle()
|
void wxAppConsoleBase::WakeUpIdle()
|
||||||
@@ -416,14 +356,21 @@ void wxAppConsoleBase::WakeUpIdle()
|
|||||||
|
|
||||||
bool wxAppConsoleBase::ProcessIdle()
|
bool wxAppConsoleBase::ProcessIdle()
|
||||||
{
|
{
|
||||||
// process pending wx events before sending idle events
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
ProcessPendingEvents();
|
|
||||||
|
|
||||||
wxIdleEvent event;
|
return loop && loop->ProcessIdle();
|
||||||
|
}
|
||||||
|
|
||||||
event.SetEventObject(this);
|
// ----------------------------------------------------------------------------
|
||||||
ProcessEvent(event);
|
// events
|
||||||
return event.MoreRequested();
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
bool wxAppConsoleBase::IsMainLoopRunning()
|
||||||
|
{
|
||||||
|
const wxAppConsole * const app = GetInstance();
|
||||||
|
|
||||||
|
return app && app->m_mainLoop != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event))
|
int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event))
|
||||||
@@ -603,7 +550,6 @@ bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature,
|
|||||||
// normally wxLogFatalError doesn't return
|
// normally wxLogFatalError doesn't return
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#undef wxCMP
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
#include "wx/msgout.h"
|
#include "wx/msgout.h"
|
||||||
#include "wx/thread.h"
|
#include "wx/thread.h"
|
||||||
#include "wx/vidmode.h"
|
#include "wx/vidmode.h"
|
||||||
|
#include "wx/evtloop.h"
|
||||||
|
|
||||||
#ifdef __WXDEBUG__
|
#ifdef __WXDEBUG__
|
||||||
#if wxUSE_STACKWALKER
|
#if wxUSE_STACKWALKER
|
||||||
@@ -78,9 +79,6 @@ wxAppBase::wxAppBase()
|
|||||||
|
|
||||||
m_isActive = true;
|
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
|
// 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
|
// 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.
|
// 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);
|
(void)ProcessEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxAppBase::IsEventAllowedInsideYield(wxEventCategory cat) const
|
|
||||||
{
|
|
||||||
return (m_eventsToProcessInsideYield & cat) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
|
bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
|
||||||
{
|
{
|
||||||
wxWindowDisabler wd(win);
|
wxWindowDisabler wd(win);
|
||||||
|
|
||||||
return Yield(onlyIfNeeded);
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
|
|
||||||
|
return loop && loop->Yield(onlyIfNeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
|
bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
|
||||||
{
|
{
|
||||||
wxWindowDisabler wd(win);
|
wxWindowDisabler wd(win);
|
||||||
|
|
||||||
return YieldFor(eventsToProcess);
|
wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
|
||||||
|
|
||||||
|
return loop && loop->YieldFor(eventsToProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -145,16 +145,6 @@ IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule)
|
|||||||
// global variables
|
// 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
|
// common event types are defined here, other event types are defined by the
|
||||||
// components which use them
|
// components which use them
|
||||||
|
|
||||||
@@ -1037,10 +1027,6 @@ void wxEventHashTable::GrowEventTypeTable()
|
|||||||
// wxEvtHandler
|
// wxEvtHandler
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
|
||||||
* Event handler
|
|
||||||
*/
|
|
||||||
|
|
||||||
wxEvtHandler::wxEvtHandler()
|
wxEvtHandler::wxEvtHandler()
|
||||||
{
|
{
|
||||||
m_nextHandler = NULL;
|
m_nextHandler = NULL;
|
||||||
@@ -1085,41 +1071,16 @@ wxEvtHandler::~wxEvtHandler()
|
|||||||
delete entry;
|
delete entry;
|
||||||
}
|
}
|
||||||
delete m_dynamicEvents;
|
delete m_dynamicEvents;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (m_pendingEvents)
|
if (m_pendingEvents)
|
||||||
m_pendingEvents->DeleteContents(true);
|
m_pendingEvents->DeleteContents(true);
|
||||||
delete m_pendingEvents;
|
delete m_pendingEvents;
|
||||||
|
|
||||||
// Remove us from wxHandlersWithPendingEvents if necessary.
|
// Remove us from the list of the pending events if necessary.
|
||||||
if ( wxHandlersWithPendingEvents )
|
wxEventLoopBase *loop = wxEventLoopBase::GetActive();
|
||||||
{
|
if (loop)
|
||||||
#if wxUSE_THREADS
|
loop->RemovePendingEventHandler(this);
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// we only delete object data, not untyped
|
// we only delete object data, not untyped
|
||||||
if ( m_clientDataType == wxClientData_Object )
|
if ( m_clientDataType == wxClientData_Object )
|
||||||
@@ -1165,6 +1126,15 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
|
|||||||
{
|
{
|
||||||
wxCHECK_RET( event, "NULL event can't be posted" );
|
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
|
// 1) Add this event to our list of pending events
|
||||||
wxENTER_CRIT_SECT( m_pendingEventsLock );
|
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
|
// 2) Add this event handler to list of event handlers that
|
||||||
// have pending events.
|
// have pending events.
|
||||||
|
|
||||||
wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
|
loop->AppendPendingEventHandler(this);
|
||||||
|
|
||||||
if ( !wxHandlersWithPendingEvents )
|
|
||||||
wxHandlersWithPendingEvents = new wxList;
|
|
||||||
if ( !wxHandlersWithPendingEvents->Find(this) )
|
|
||||||
wxHandlersWithPendingEvents->Append(this);
|
|
||||||
|
|
||||||
wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
|
|
||||||
|
|
||||||
// only release m_pendingEventsLock now because otherwise there is a race
|
// only release m_pendingEventsLock now because otherwise there is a race
|
||||||
// condition as described in the ticket #9093: we could process the event
|
// condition as described in the ticket #9093: we could process the event
|
||||||
@@ -1200,6 +1163,15 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
|
|||||||
|
|
||||||
void wxEvtHandler::ProcessPendingEvents()
|
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
|
// we need to process only a single pending event in this call because
|
||||||
// each call to ProcessEvent() could result in the destruction of this
|
// each call to ProcessEvent() could result in the destruction of this
|
||||||
// same event handler (see the comment at the end of this function)
|
// 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());
|
wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
|
||||||
|
|
||||||
// find the first event which can be processed now:
|
// 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();
|
node = node->GetNext();
|
||||||
pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
|
pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
|
||||||
@@ -1226,19 +1199,11 @@ void wxEvtHandler::ProcessPendingEvents()
|
|||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
// all our events are NOT processable now... signal this:
|
// all our events are NOT processable now... signal this:
|
||||||
#if wxUSE_THREADS
|
loop->DelayPendingEventHandler(this);
|
||||||
if (wxHandlersWithPendingEventsLocker)
|
|
||||||
wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
|
// see the comment at the beginning of evtloop.h header for the
|
||||||
#endif
|
// logic behind YieldFor() and behind DelayPendingEventHandler()
|
||||||
// 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 );
|
wxLEAVE_CRIT_SECT( m_pendingEventsLock );
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -1252,19 +1217,11 @@ void wxEvtHandler::ProcessPendingEvents()
|
|||||||
// same event again.
|
// same event again.
|
||||||
m_pendingEvents->Erase(node);
|
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 ( m_pendingEvents->IsEmpty() )
|
||||||
{
|
{
|
||||||
#if wxUSE_THREADS
|
// if there are no more pending events left, we don't need to
|
||||||
if (wxHandlersWithPendingEventsLocker)
|
// stay in this list
|
||||||
wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
|
loop->RemovePendingEventHandler(this);
|
||||||
#endif
|
|
||||||
wxHandlersWithPendingEvents->DeleteObject(this);
|
|
||||||
#if wxUSE_THREADS
|
|
||||||
if (wxHandlersWithPendingEventsLocker)
|
|
||||||
wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLEAVE_CRIT_SECT( m_pendingEventsLock );
|
wxLEAVE_CRIT_SECT( m_pendingEventsLock );
|
||||||
|
@@ -36,6 +36,154 @@
|
|||||||
|
|
||||||
wxEventLoopBase *wxEventLoopBase::ms_activeLoop = NULL;
|
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
|
// wxEventLoopManual is unused in the other ports
|
||||||
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && wxUSE_BASE)
|
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && wxUSE_BASE)
|
||||||
|
|
||||||
|
@@ -162,46 +162,3 @@ void wxApp::WakeUpIdle()
|
|||||||
wxMutexGuiLeave();
|
wxMutexGuiLeave();
|
||||||
#endif
|
#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;
|
|
||||||
}
|
|
||||||
|
@@ -202,8 +202,20 @@ wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
|
|||||||
// events dispatch and loop handling
|
// 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
|
// TODO: implement event filtering using the eventsToProcess mask
|
||||||
|
|
||||||
// process all pending events:
|
// process all pending events:
|
||||||
@@ -212,4 +224,17 @@ void wxGUIEventLoop::Yield()
|
|||||||
|
|
||||||
// handle timers, sockets etc.
|
// handle timers, sockets etc.
|
||||||
OnNextIteration();
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "wx/progdlg.h"
|
#include "wx/progdlg.h"
|
||||||
|
#include "wx/evtloop.h"
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// macros
|
// macros
|
||||||
@@ -402,7 +403,7 @@ wxProgressDialog::Update(int value, const wxString& newmsg, bool *skip)
|
|||||||
m_msg->SetLabel(_("Done."));
|
m_msg->SetLabel(_("Done."));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
|
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
|
||||||
|
|
||||||
(void)ShowModal();
|
(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
|
// 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
|
// 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();
|
Update();
|
||||||
|
|
||||||
@@ -671,7 +672,7 @@ void wxProgressDialog::UpdateMessage(const wxString &newmsg)
|
|||||||
|
|
||||||
Fit(); // adapt to the new label size
|
Fit(); // adapt to the new label size
|
||||||
|
|
||||||
wxTheApp->YieldFor(wxEVT_CATEGORY_UI);
|
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
171
src/gtk/app.cpp
171
src/gtk/app.cpp
@@ -44,167 +44,6 @@
|
|||||||
wxFORCE_LINK_MODULE(gnome_vfs)
|
wxFORCE_LINK_MODULE(gnome_vfs)
|
||||||
#endif
|
#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
|
// local functions
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -324,12 +163,14 @@ bool wxApp::DoIdle()
|
|||||||
|
|
||||||
GtkWidget* wxGetRootWindow()
|
GtkWidget* wxGetRootWindow()
|
||||||
{
|
{
|
||||||
if (gs_RootWindow == NULL)
|
static GtkWidget *s_RootWindow = NULL;
|
||||||
|
|
||||||
|
if (s_RootWindow == NULL)
|
||||||
{
|
{
|
||||||
gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
|
s_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
|
||||||
gtk_widget_realize( gs_RootWindow );
|
gtk_widget_realize( s_RootWindow );
|
||||||
}
|
}
|
||||||
return gs_RootWindow;
|
return s_RootWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "wx/scopedarray.h"
|
#include "wx/scopedarray.h"
|
||||||
#include "wx/scopeguard.h"
|
#include "wx/scopeguard.h"
|
||||||
|
#include "wx/evtloop.h"
|
||||||
|
|
||||||
#include "wx/gtk/private.h"
|
#include "wx/gtk/private.h"
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ public:
|
|||||||
~wxClipboardSync()
|
~wxClipboardSync()
|
||||||
{
|
{
|
||||||
while (ms_clipboard)
|
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
|
// this method must be called by GTK+ callbacks to indicate that we got the
|
||||||
|
@@ -36,6 +36,8 @@
|
|||||||
// wxEventLoop implementation
|
// wxEventLoop implementation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
extern GtkWidget *wxGetRootWindow();
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxEventLoop running and exiting
|
// wxEventLoop running and exiting
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -126,4 +128,146 @@ int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
|
|||||||
return !quit;
|
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;
|
||||||
|
}
|
||||||
|
@@ -99,64 +99,6 @@ void wxapp_install_idle_handler();
|
|||||||
static wxMutex gs_idleTagsMutex;
|
static wxMutex gs_idleTagsMutex;
|
||||||
#endif
|
#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
|
// wxWakeUpIdle
|
||||||
|
@@ -117,3 +117,52 @@ bool wxGUIEventLoop::Dispatch()
|
|||||||
|
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
@@ -44,56 +44,6 @@ void wxApp::Exit()
|
|||||||
exit(0);
|
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
|
// wxWakeUpIdle
|
||||||
|
@@ -184,3 +184,39 @@ bool wxGUIEventLoop::Dispatch()
|
|||||||
return m_impl->GetKeepLooping();
|
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;
|
||||||
|
}
|
||||||
|
@@ -468,32 +468,6 @@ void wxApp::SetTopLevelRealizedWidget(WXDisplay* display, WXWidget widget)
|
|||||||
.m_topLevelRealizedWidget = (Widget)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
|
// accessors for C modules
|
||||||
|
@@ -137,6 +137,20 @@ void wxGUIEventLoop::Exit(int rc)
|
|||||||
::wxBreakDispatch();
|
::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
|
// wxEventLoop message processing dispatching
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
171
src/msw/app.cpp
171
src/msw/app.cpp
@@ -1011,177 +1011,6 @@ int wxApp::GetShell32Version()
|
|||||||
|
|
||||||
#endif // !__WXWINCE__
|
#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
|
#if wxUSE_EXCEPTIONS
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
#include "wx/thread.h"
|
#include "wx/thread.h"
|
||||||
#include "wx/except.h"
|
#include "wx/except.h"
|
||||||
#include "wx/msw/private.h"
|
#include "wx/msw/private.h"
|
||||||
|
#include "wx/scopeguard.h"
|
||||||
|
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
#include "wx/tooltip.h"
|
#include "wx/tooltip.h"
|
||||||
@@ -358,6 +359,164 @@ void wxGUIEventLoop::WakeUp()
|
|||||||
::PostMessage(NULL, WM_NULL, 0, 0);
|
::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
|
#else // !wxUSE_GUI
|
||||||
|
|
||||||
|
|
||||||
|
@@ -504,66 +504,6 @@ void wxApp::OnQueryEndSession( wxCloseEvent& rEvent )
|
|||||||
}
|
}
|
||||||
} // end of wxApp::OnQueryEndSession
|
} // 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,
|
int wxApp::AddSocketHandler(int handle, int mask,
|
||||||
void (*callback)(void*), void * gsock)
|
void (*callback)(void*), void * gsock)
|
||||||
{
|
{
|
||||||
|
@@ -365,3 +365,52 @@ bool wxGUIEventLoop::Dispatch()
|
|||||||
|
|
||||||
return true;
|
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
|
||||||
|
@@ -285,13 +285,6 @@ int wxApp::GetComCtl32Version()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yield to incoming messages
|
|
||||||
|
|
||||||
bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if wxUSE_EXCEPTIONS
|
#if wxUSE_EXCEPTIONS
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@@ -144,3 +144,8 @@ void wxGUIEventLoop::WakeUp()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxGUIEventLoop::YieldFor(long eventsToProcess)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -767,52 +767,6 @@ void wxApp::Exit()
|
|||||||
wxAppConsole::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__
|
#ifdef __WXDEBUG__
|
||||||
|
|
||||||
void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
|
void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
|
||||||
|
@@ -243,3 +243,33 @@ bool wxGUIEventLoop::Dispatch()
|
|||||||
(void) m_impl->ProcessEvent( &event );
|
(void) m_impl->ProcessEvent( &event );
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user