Add wxEventLoop::ScheduleExit().
This method allows to request exiting from the given event loop even if it's not the currently active one, unlike Exit() which would assert in this case. With it, it becomes possible to ask the loop to terminate as soon as possible even if a nested loop is currently running. See #10258. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74335 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
e77dc839af
commit
d3ad22bdb3
@ -584,6 +584,7 @@ All:
|
||||
- Add new wxFSW_EVENT_ATTRIB and wxFSW_EVENT_UNMOUNT flags (David Hart).
|
||||
- Add separate read/written bytes counters and per-direction NOWAIT and WAITALL
|
||||
flags to wxSocket (Rob Bresalier).
|
||||
- Add wxEventLoop::ScheduleExit() (Rob Bresalier).
|
||||
- Add wxProcess::SetPriority() (Marian Meravy).
|
||||
- Add wxDir::Close() method (Silverstorm82).
|
||||
- Fix wxDateTime::GetWeekOfYear() for the last week of year (aimo).
|
||||
|
@ -20,7 +20,7 @@ class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
|
||||
public:
|
||||
wxGUIEventLoop() { m_exitcode = 0; }
|
||||
|
||||
virtual void Exit(int rc = 0);
|
||||
virtual void ScheduleExit(int rc = 0);
|
||||
virtual bool Pending() const;
|
||||
virtual bool Dispatch();
|
||||
virtual int DispatchTimeout(unsigned long timeout);
|
||||
|
@ -100,7 +100,15 @@ public:
|
||||
bool IsRunning() const;
|
||||
|
||||
// exit from the loop with the given exit code
|
||||
virtual void Exit(int rc = 0) = 0;
|
||||
//
|
||||
// this can be only used to exit the currently running loop, use
|
||||
// ScheduleExit() if this might not be the case
|
||||
virtual void Exit(int rc = 0);
|
||||
|
||||
// ask the event loop to exit with the given exit code, can be used even if
|
||||
// this loop is not running right now but the loop must have been started,
|
||||
// i.e. Run() should have been already called
|
||||
virtual void ScheduleExit(int rc = 0) = 0;
|
||||
|
||||
// return true if any events are available
|
||||
virtual bool Pending() const = 0;
|
||||
@ -180,6 +188,12 @@ protected:
|
||||
// an exception thrown from inside the loop)
|
||||
virtual void OnExit();
|
||||
|
||||
// Return true if we're currently inside our Run(), even if another nested
|
||||
// event loop is currently running, unlike IsRunning() (which should have
|
||||
// been really called IsActive() but it's too late to change this now).
|
||||
bool IsInsideRun() const { return m_isInsideRun; }
|
||||
|
||||
|
||||
// the pointer to currently active loop
|
||||
static wxEventLoopBase *ms_activeLoop;
|
||||
|
||||
@ -190,6 +204,10 @@ protected:
|
||||
bool m_isInsideYield;
|
||||
long m_eventsToProcessInsideYield;
|
||||
|
||||
private:
|
||||
// this flag is set on entry into Run() and reset before leaving it
|
||||
bool m_isInsideRun;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
|
||||
};
|
||||
|
||||
@ -206,7 +224,7 @@ public:
|
||||
|
||||
// sets the "should exit" flag and wakes up the loop so that it terminates
|
||||
// soon
|
||||
virtual void Exit(int rc = 0);
|
||||
virtual void ScheduleExit(int rc = 0);
|
||||
|
||||
protected:
|
||||
// enters a loop calling OnNextIteration(), Pending() and Dispatch() and
|
||||
@ -291,7 +309,7 @@ public:
|
||||
}
|
||||
#endif // wxUSE_EVENTLOOP_SOURCE
|
||||
|
||||
virtual void Exit(int rc = 0);
|
||||
virtual void ScheduleExit(int rc = 0);
|
||||
virtual bool Pending() const;
|
||||
virtual bool Dispatch();
|
||||
virtual int DispatchTimeout(unsigned long timeout)
|
||||
|
@ -22,7 +22,7 @@ class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
|
||||
public:
|
||||
wxGUIEventLoop();
|
||||
|
||||
virtual void Exit(int rc = 0);
|
||||
virtual void ScheduleExit(int rc = 0);
|
||||
virtual bool Pending() const;
|
||||
virtual bool Dispatch();
|
||||
virtual int DispatchTimeout(unsigned long timeout);
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
|
||||
// sets the "should exit" flag and wakes up the loop so that it terminates
|
||||
// soon
|
||||
virtual void Exit(int rc = 0);
|
||||
virtual void ScheduleExit(int rc = 0);
|
||||
|
||||
// return true if any events are available
|
||||
virtual bool Pending() const;
|
||||
|
@ -23,6 +23,19 @@
|
||||
You can create your own event loop if you need, provided that you restore
|
||||
the main event loop once yours is destroyed (see wxEventLoopActivator).
|
||||
|
||||
Notice that there can be more than one event loop at any given moment, e.g.
|
||||
an event handler called from the main loop can show a modal dialog, which
|
||||
starts its own loop resulting in two nested loops, with the modal dialog
|
||||
being the active one (its IsRunning() returns @true). And a handler for a
|
||||
button inside the modal dialog can, of course, create another modal dialog
|
||||
with its own event loop and so on. So in general event loops form a stack
|
||||
and only the event loop at the top of the stack is considered to be active.
|
||||
It is also the only loop that can be directly asked to terminate by calling
|
||||
Exit() (which is done by wxDialog::EndModal()), an outer event loop can't
|
||||
be stopped while an inner one is still running. It is however possible to
|
||||
ask an outer event loop to terminate as soon as all its nested loops exit
|
||||
and the control returns back to it by using ScheduleExit().
|
||||
|
||||
@library{wxbase}
|
||||
@category{appmanagement}
|
||||
|
||||
@ -90,9 +103,32 @@ public:
|
||||
virtual bool IsOk() const;
|
||||
|
||||
/**
|
||||
Exit from the loop with the given exit code.
|
||||
Exit the currently running loop with the given exit code.
|
||||
|
||||
The loop will exit, i.e. its Run() method will return, during the next
|
||||
event loop iteration.
|
||||
|
||||
Notice that this method can only be used if this event loop is the
|
||||
currently running one, i.e. its IsRunning() returns @true. If this is
|
||||
not the case, an assert failure is triggered and nothing is done as
|
||||
outer event loops can't be exited from immediately. Use ScheduleExit()
|
||||
if you'd like to exit this loop even if it doesn't run currently.
|
||||
*/
|
||||
virtual void Exit(int rc = 0) = 0;
|
||||
virtual void Exit(int rc = 0);
|
||||
|
||||
/**
|
||||
Schedule an exit from the loop with the given exit code.
|
||||
|
||||
This method is similar to Exit() but can be called even if this event
|
||||
loop is not the currently running one -- and if it is the active loop,
|
||||
then it works in exactly the same way as Exit().
|
||||
|
||||
The loop will exit as soon as the control flow returns to it, i.e.
|
||||
after any nested loops terminate.
|
||||
|
||||
@since 2.9.5
|
||||
*/
|
||||
virtual void ScheduleExit(int rc = 0) = 0;
|
||||
|
||||
/**
|
||||
Return true if any events are available.
|
||||
|
@ -39,9 +39,9 @@ int wxGUIEventLoop::DoRun()
|
||||
return m_exitcode;
|
||||
}
|
||||
|
||||
void wxGUIEventLoop::Exit(int rc)
|
||||
void wxGUIEventLoop::ScheduleExit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsRunning(), wxT("can't call Exit() if not running") );
|
||||
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
|
||||
|
||||
m_exitcode = rc;
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "wx/app.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/scopeguard.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxEventLoopBase
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -30,6 +32,7 @@ wxEventLoopBase *wxEventLoopBase::ms_activeLoop = NULL;
|
||||
|
||||
wxEventLoopBase::wxEventLoopBase()
|
||||
{
|
||||
m_isInsideRun = false;
|
||||
m_shouldExit = false;
|
||||
|
||||
m_isInsideYield = false;
|
||||
@ -55,7 +58,7 @@ void wxEventLoopBase::SetActive(wxEventLoopBase* loop)
|
||||
int wxEventLoopBase::Run()
|
||||
{
|
||||
// event loops are not recursive, you need to create another loop!
|
||||
wxCHECK_MSG( !IsRunning(), -1, wxT("can't reenter a message loop") );
|
||||
wxCHECK_MSG( !IsInsideRun(), -1, wxT("can't reenter a message loop") );
|
||||
|
||||
// ProcessIdle() and ProcessEvents() below may throw so the code here should
|
||||
// be exception-safe, hence we must use local objects for all actions we
|
||||
@ -66,10 +69,21 @@ int wxEventLoopBase::Run()
|
||||
// reset this flag.
|
||||
m_shouldExit = false;
|
||||
|
||||
// Set this variable to true for the duration of this method.
|
||||
m_isInsideRun = true;
|
||||
wxON_BLOCK_EXIT_SET(m_isInsideRun, false);
|
||||
|
||||
// Finally really run the loop.
|
||||
return DoRun();
|
||||
}
|
||||
|
||||
void wxEventLoopBase::Exit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsRunning(), wxS("Use ScheduleExit() on not running loop") );
|
||||
|
||||
ScheduleExit(rc);
|
||||
}
|
||||
|
||||
void wxEventLoopBase::OnExit()
|
||||
{
|
||||
if (wxTheApp)
|
||||
@ -231,9 +245,9 @@ int wxEventLoopManual::DoRun()
|
||||
return m_exitcode;
|
||||
}
|
||||
|
||||
void wxEventLoopManual::Exit(int rc)
|
||||
void wxEventLoopManual::ScheduleExit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsRunning(), wxT("can't call Exit() if not running") );
|
||||
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not running") );
|
||||
|
||||
m_exitcode = rc;
|
||||
m_shouldExit = true;
|
||||
|
@ -52,19 +52,41 @@ wxGUIEventLoop::wxGUIEventLoop()
|
||||
|
||||
int wxGUIEventLoop::DoRun()
|
||||
{
|
||||
gtk_main();
|
||||
guint loopLevel = gtk_main_level();
|
||||
|
||||
// This is placed inside of a loop to take into account nested
|
||||
// event loops. For example, inside this event loop, we may receive
|
||||
// Exit() for a different event loop (which we are currently inside of)
|
||||
// That Exit() will cause this gtk_main() to exit so we need to re-enter it.
|
||||
while ( !m_shouldExit )
|
||||
{
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
// Force the enclosing event loop to also exit to see if it is done in case
|
||||
// that event loop had Exit() called inside of the just ended loop. If it
|
||||
// is not time yet for that event loop to exit, it will be executed again
|
||||
// due to the while() loop on m_shouldExit().
|
||||
//
|
||||
// This is unnecessary if we are the top level loop, i.e. loop of level 0.
|
||||
if ( loopLevel )
|
||||
{
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
OnExit();
|
||||
|
||||
return m_exitcode;
|
||||
}
|
||||
|
||||
void wxGUIEventLoop::Exit(int rc)
|
||||
void wxGUIEventLoop::ScheduleExit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsRunning(), "can't call Exit() if not running" );
|
||||
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
|
||||
|
||||
m_exitcode = rc;
|
||||
|
||||
m_shouldExit = true;
|
||||
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,27 @@ int wxGUIEventLoop::DoRun()
|
||||
{
|
||||
m_impl = new wxEventLoopImpl;
|
||||
|
||||
gtk_main();
|
||||
guint loopLevel = gtk_main_level();
|
||||
|
||||
// This is placed inside of a loop to take into account nested
|
||||
// event loops. For example, inside this event loop, we may recieve
|
||||
// Exit() for a different event loop (which we are currently inside of)
|
||||
// That Exit() will cause this gtk_main() to exit so we need to re-enter it.
|
||||
while ( !m_shouldExit )
|
||||
{
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
// Force the enclosing event loop to also exit to see if it is done
|
||||
// in case that event loop ended inside of this one. If it is not time
|
||||
// yet for that event loop to exit, it will be executed again due to
|
||||
// the while() loop on m_shouldExit().
|
||||
//
|
||||
// This is unnecessary if we are the top level loop, i.e. loop of level 0.
|
||||
if ( loopLevel )
|
||||
{
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
OnExit();
|
||||
|
||||
@ -79,12 +99,14 @@ int wxGUIEventLoop::DoRun()
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
void wxGUIEventLoop::Exit(int rc)
|
||||
void wxGUIEventLoop::ScheduleExit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsRunning(), wxT("can't call Exit() if not running") );
|
||||
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
|
||||
|
||||
m_impl->SetExitCode(rc);
|
||||
|
||||
m_shouldExit = true;
|
||||
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
|
@ -121,9 +121,9 @@ int wxGUIEventLoop::DoRun()
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
void wxGUIEventLoop::Exit(int rc)
|
||||
void wxGUIEventLoop::SchduleExit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsRunning(), wxT("can't call Exit() if not running") );
|
||||
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
|
||||
|
||||
m_impl->SetExitCode(rc);
|
||||
m_impl->SetKeepGoing( false );
|
||||
|
@ -96,7 +96,15 @@ void wxGUIEventLoop::WakeUp()
|
||||
void wxGUIEventLoop::OSXDoRun()
|
||||
{
|
||||
wxMacAutoreleasePool autoreleasepool;
|
||||
RunApplicationEventLoop();
|
||||
|
||||
while (!m_shouldExit)
|
||||
{
|
||||
RunApplicationEventLoop();
|
||||
}
|
||||
|
||||
// Force enclosing event loop to temporarily exit and check
|
||||
// if it should be stopped.
|
||||
QuitApplicationEventLoop();
|
||||
}
|
||||
|
||||
void wxGUIEventLoop::OSXDoStop()
|
||||
|
@ -32,6 +32,7 @@
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/log.h"
|
||||
#include "wx/scopeguard.h"
|
||||
|
||||
#include "wx/osx/private.h"
|
||||
|
||||
@ -240,17 +241,113 @@ int wxGUIEventLoop::DoDispatchTimeout(unsigned long timeout)
|
||||
}
|
||||
}
|
||||
|
||||
static int gs_loopNestingLevel = 0;
|
||||
|
||||
void wxGUIEventLoop::OSXDoRun()
|
||||
{
|
||||
wxMacAutoreleasePool autoreleasepool;
|
||||
[NSApp run];
|
||||
/*
|
||||
In order to properly nest GUI event loops in Cocoa, it is important to
|
||||
have [NSApp run] only as the main/outermost event loop. There are many
|
||||
problems if [NSApp run] is used as an inner event loop. The main issue
|
||||
is that a call to [NSApp stop] is needed to exit an [NSApp run] event
|
||||
loop. But the [NSApp stop] has some side effects that we do not want -
|
||||
such as if there was a modal dialog box with a modal event loop running,
|
||||
that event loop would also get exited, and the dialog would be closed.
|
||||
The call to [NSApp stop] would also cause the enclosing event loop to
|
||||
exit as well.
|
||||
|
||||
webkit's webcore library uses CFRunLoopRun() for nested event loops. See
|
||||
the log of the commit log about the change in webkit's webcore module:
|
||||
http://www.mail-archive.com/webkit-changes@lists.webkit.org/msg07397.html
|
||||
|
||||
See here for the latest run loop that is used in webcore:
|
||||
https://github.com/WebKit/webkit/blob/master/Source/WebCore/platform/mac/RunLoopMac.mm
|
||||
|
||||
CFRunLoopRun() was tried for the nested event loop here but it causes a
|
||||
problem in that all user input is disabled - and there is no way to
|
||||
re-enable it. The caller of this event loop may not want user input
|
||||
disabled (such as synchronous wxExecute with wxEXEC_NODISABLE flag).
|
||||
|
||||
In order to have an inner event loop where user input can be enabled,
|
||||
the old wxCocoa code that used the [NSApp nextEventMatchingMask] was
|
||||
borrowed but changed to use blocking instead of polling. By specifying
|
||||
'distantFuture' in 'untildate', we can have it block until the next
|
||||
event. Then we can keep looping on each new event until m_shouldExit is
|
||||
raised to exit the event loop.
|
||||
*/
|
||||
gs_loopNestingLevel++;
|
||||
wxON_BLOCK_EXIT_SET(gs_loopNestingLevel, gs_loopNestingLevel - 1);
|
||||
|
||||
while ( !m_shouldExit )
|
||||
{
|
||||
// By putting this inside the loop, we can drain it in each
|
||||
// loop iteration.
|
||||
wxMacAutoreleasePool autoreleasepool;
|
||||
|
||||
if ( gs_loopNestingLevel == 1 )
|
||||
{
|
||||
// Use -[NSApplication run] for the main run loop.
|
||||
[NSApp run];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We use this blocking call to [NSApp nextEventMatchingMask:...]
|
||||
// because the other methods (such as CFRunLoopRun() and [runLoop
|
||||
// runMode:beforeDate] were always disabling input to the windows
|
||||
// (even if we wanted it enabled).
|
||||
//
|
||||
// Here are the other run loops which were tried, but always left
|
||||
// user input disabled:
|
||||
//
|
||||
// [runLoop runMode:NSDefaultRunLoopMode beforeDate:date];
|
||||
// CFRunLoopRun();
|
||||
// CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10 , true);
|
||||
//
|
||||
// Using [NSApp nextEventMatchingMask:...] would leave windows
|
||||
// enabled if we wanted them to be, so that is why it is used.
|
||||
NSEvent *event = [NSApp
|
||||
nextEventMatchingMask:NSAnyEventMask
|
||||
untilDate:[NSDate distantFuture]
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue: YES];
|
||||
|
||||
[NSApp sendEvent: event];
|
||||
|
||||
/**
|
||||
The NSApplication documentation states that:
|
||||
|
||||
"
|
||||
This method is invoked automatically in the main event loop
|
||||
after each event when running in NSDefaultRunLoopMode or
|
||||
NSModalRunLoopMode. This method is not invoked automatically
|
||||
when running in NSEventTrackingRunLoopMode.
|
||||
"
|
||||
|
||||
So to be safe, we also invoke it here in this event loop.
|
||||
|
||||
See: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html
|
||||
*/
|
||||
[NSApp updateWindows];
|
||||
}
|
||||
}
|
||||
|
||||
// Wake up the enclosing loop so that it can check if it also needs
|
||||
// to exit.
|
||||
WakeUp();
|
||||
}
|
||||
|
||||
void wxGUIEventLoop::OSXDoStop()
|
||||
{
|
||||
// only calling stop: is not enough when called from a runloop-observer,
|
||||
// therefore add a dummy event, to make sure the runloop gets another round
|
||||
[NSApp stop:0];
|
||||
// We should only stop the top level event loop.
|
||||
if ( gs_loopNestingLevel <= 1 )
|
||||
{
|
||||
[NSApp stop:0];
|
||||
}
|
||||
|
||||
// For the top level loop only calling stop: is not enough when called from
|
||||
// a runloop-observer, therefore add a dummy event, to make sure the
|
||||
// runloop gets another round. And for the nested loops we need to wake it
|
||||
// up to notice that it should exit, so do this unconditionally.
|
||||
WakeUp();
|
||||
}
|
||||
|
||||
|
@ -440,7 +440,7 @@ int wxCFEventLoop::DoRun()
|
||||
|
||||
// sets the "should exit" flag and wakes up the loop so that it terminates
|
||||
// soon
|
||||
void wxCFEventLoop::Exit(int rc)
|
||||
void wxCFEventLoop::ScheduleExit(int rc)
|
||||
{
|
||||
m_exitcode = rc;
|
||||
m_shouldExit = true;
|
||||
|
@ -162,7 +162,7 @@ int wxGUIEventLoop::DoRun()
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
void wxGUIEventLoop::Exit(int rc)
|
||||
void wxGUIEventLoop::ScheduleExit(int rc)
|
||||
{
|
||||
if ( m_impl )
|
||||
{
|
||||
|
@ -65,6 +65,7 @@ TEST_OBJECTS = \
|
||||
test_regconf.o \
|
||||
test_datetimetest.o \
|
||||
test_evthandler.o \
|
||||
test_evtlooptest.o \
|
||||
test_evtsource.o \
|
||||
test_stopwatch.o \
|
||||
test_timertest.o \
|
||||
@ -208,6 +209,7 @@ TEST_GUI_OBJECTS = \
|
||||
test_gui_windowtest.o \
|
||||
test_gui_dialogtest.o \
|
||||
test_gui_clone.o \
|
||||
test_gui_evtlooptest.o \
|
||||
test_gui_propagation.o \
|
||||
test_gui_keyboard.o \
|
||||
test_gui_fonttest.o \
|
||||
@ -476,6 +478,9 @@ test_datetimetest.o: $(srcdir)/datetime/datetimetest.cpp $(TEST_ODEP)
|
||||
test_evthandler.o: $(srcdir)/events/evthandler.cpp $(TEST_ODEP)
|
||||
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/events/evthandler.cpp
|
||||
|
||||
test_evtlooptest.o: $(srcdir)/events/evtlooptest.cpp $(TEST_ODEP)
|
||||
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/events/evtlooptest.cpp
|
||||
|
||||
test_evtsource.o: $(srcdir)/events/evtsource.cpp $(TEST_ODEP)
|
||||
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/events/evtsource.cpp
|
||||
|
||||
@ -881,6 +886,9 @@ test_gui_dialogtest.o: $(srcdir)/controls/dialogtest.cpp $(TEST_GUI_ODEP)
|
||||
test_gui_clone.o: $(srcdir)/events/clone.cpp $(TEST_GUI_ODEP)
|
||||
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/events/clone.cpp
|
||||
|
||||
test_gui_evtlooptest.o: $(srcdir)/events/evtlooptest.cpp $(TEST_GUI_ODEP)
|
||||
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/events/evtlooptest.cpp
|
||||
|
||||
test_gui_propagation.o: $(srcdir)/events/propagation.cpp $(TEST_GUI_ODEP)
|
||||
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/events/propagation.cpp
|
||||
|
||||
|
128
tests/events/evtlooptest.cpp
Normal file
128
tests/events/evtlooptest.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: tests/events/evtloop.cpp
|
||||
// Purpose: Tests for the event loop classes
|
||||
// Author: Rob Bresalier
|
||||
// Created: 2013-05-02
|
||||
// RCS-ID: $Id$
|
||||
// Copyright: (c) 2013 Rob Bresalier
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "testprec.h"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "wx/timer.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Use two arbitrary but different return codes for the two loops.
|
||||
const int EXIT_CODE_OUTER_LOOP = 99;
|
||||
const int EXIT_CODE_INNER_LOOP = 55;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// test class
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class EvtloopTestCase : public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
EvtloopTestCase() { }
|
||||
|
||||
private:
|
||||
CPPUNIT_TEST_SUITE( EvtloopTestCase );
|
||||
CPPUNIT_TEST( TestExit );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
void TestExit();
|
||||
|
||||
DECLARE_NO_COPY_CLASS(EvtloopTestCase)
|
||||
};
|
||||
|
||||
// register in the unnamed registry so that these tests are run by default
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION( EvtloopTestCase );
|
||||
|
||||
// also include in its own registry so that these tests can be run alone
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtloopTestCase, "EvtloopTestCase" );
|
||||
|
||||
|
||||
// Helper class to schedule exit of the given event loop after the specified
|
||||
// delay.
|
||||
class ScheduleLoopExitTimer : public wxTimer
|
||||
{
|
||||
public:
|
||||
ScheduleLoopExitTimer(wxEventLoop& loop, int rc)
|
||||
: m_loop(loop),
|
||||
m_rc(rc)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Notify()
|
||||
{
|
||||
m_loop.ScheduleExit(m_rc);
|
||||
}
|
||||
|
||||
private:
|
||||
wxEventLoop& m_loop;
|
||||
const int m_rc;
|
||||
};
|
||||
|
||||
// Another helper which runs a nested loop and schedules exiting both the outer
|
||||
// and the inner loop after the specified delays.
|
||||
class RunNestedAndExitBothLoopsTimer : public wxTimer
|
||||
{
|
||||
public:
|
||||
RunNestedAndExitBothLoopsTimer(wxTimer& timerOuter,
|
||||
int loopOuterDuration,
|
||||
int loopInnerDuration)
|
||||
: m_timerOuter(timerOuter),
|
||||
m_loopOuterDuration(loopOuterDuration),
|
||||
m_loopInnerDuration(loopInnerDuration)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Notify()
|
||||
{
|
||||
wxEventLoop loopInner;
|
||||
ScheduleLoopExitTimer timerInner(loopInner, EXIT_CODE_INNER_LOOP);
|
||||
|
||||
m_timerOuter.StartOnce(m_loopOuterDuration);
|
||||
timerInner.StartOnce(m_loopInnerDuration);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( EXIT_CODE_INNER_LOOP, loopInner.Run() );
|
||||
}
|
||||
|
||||
private:
|
||||
wxTimer& m_timerOuter;
|
||||
const int m_loopOuterDuration;
|
||||
const int m_loopInnerDuration;
|
||||
};
|
||||
|
||||
void EvtloopTestCase::TestExit()
|
||||
{
|
||||
// Test that simply exiting the loop works.
|
||||
wxEventLoop loopOuter;
|
||||
ScheduleLoopExitTimer timerExit(loopOuter, EXIT_CODE_OUTER_LOOP);
|
||||
timerExit.StartOnce(1);
|
||||
CPPUNIT_ASSERT_EQUAL( EXIT_CODE_OUTER_LOOP, loopOuter.Run() );
|
||||
|
||||
// Test that exiting the outer loop before the inner loop (outer duration
|
||||
// parameter less than inner duration in the timer ctor below) works.
|
||||
ScheduleLoopExitTimer timerExitOuter(loopOuter, EXIT_CODE_OUTER_LOOP);
|
||||
RunNestedAndExitBothLoopsTimer timerRun(timerExitOuter, 5, 10);
|
||||
timerRun.StartOnce(1);
|
||||
CPPUNIT_ASSERT_EQUAL( EXIT_CODE_OUTER_LOOP, loopOuter.Run() );
|
||||
|
||||
// Test that exiting the inner loop before the outer one works too.
|
||||
ScheduleLoopExitTimer timerExitOuter2(loopOuter, EXIT_CODE_OUTER_LOOP);
|
||||
RunNestedAndExitBothLoopsTimer timerRun2(timerExitOuter, 10, 5);
|
||||
timerRun2.StartOnce(1);
|
||||
CPPUNIT_ASSERT_EQUAL( EXIT_CODE_OUTER_LOOP, loopOuter.Run() );
|
||||
}
|
@ -50,6 +50,7 @@ TEST_OBJECTS = \
|
||||
$(OBJS)\test_regconf.obj \
|
||||
$(OBJS)\test_datetimetest.obj \
|
||||
$(OBJS)\test_evthandler.obj \
|
||||
$(OBJS)\test_evtlooptest.obj \
|
||||
$(OBJS)\test_evtsource.obj \
|
||||
$(OBJS)\test_stopwatch.obj \
|
||||
$(OBJS)\test_timertest.obj \
|
||||
@ -194,6 +195,7 @@ TEST_GUI_OBJECTS = \
|
||||
$(OBJS)\test_gui_windowtest.obj \
|
||||
$(OBJS)\test_gui_dialogtest.obj \
|
||||
$(OBJS)\test_gui_clone.obj \
|
||||
$(OBJS)\test_gui_evtlooptest.obj \
|
||||
$(OBJS)\test_gui_propagation.obj \
|
||||
$(OBJS)\test_gui_keyboard.obj \
|
||||
$(OBJS)\test_gui_fonttest.obj \
|
||||
@ -531,6 +533,9 @@ $(OBJS)\test_datetimetest.obj: .\datetime\datetimetest.cpp
|
||||
$(OBJS)\test_evthandler.obj: .\events\evthandler.cpp
|
||||
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\events\evthandler.cpp
|
||||
|
||||
$(OBJS)\test_evtlooptest.obj: .\events\evtlooptest.cpp
|
||||
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\events\evtlooptest.cpp
|
||||
|
||||
$(OBJS)\test_evtsource.obj: .\events\evtsource.cpp
|
||||
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\events\evtsource.cpp
|
||||
|
||||
@ -939,6 +944,9 @@ $(OBJS)\test_gui_dialogtest.obj: .\controls\dialogtest.cpp
|
||||
$(OBJS)\test_gui_clone.obj: .\events\clone.cpp
|
||||
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\clone.cpp
|
||||
|
||||
$(OBJS)\test_gui_evtlooptest.obj: .\events\evtlooptest.cpp
|
||||
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\evtlooptest.cpp
|
||||
|
||||
$(OBJS)\test_gui_propagation.obj: .\events\propagation.cpp
|
||||
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\propagation.cpp
|
||||
|
||||
|
@ -43,6 +43,7 @@ TEST_OBJECTS = \
|
||||
$(OBJS)\test_regconf.o \
|
||||
$(OBJS)\test_datetimetest.o \
|
||||
$(OBJS)\test_evthandler.o \
|
||||
$(OBJS)\test_evtlooptest.o \
|
||||
$(OBJS)\test_evtsource.o \
|
||||
$(OBJS)\test_stopwatch.o \
|
||||
$(OBJS)\test_timertest.o \
|
||||
@ -188,6 +189,7 @@ TEST_GUI_OBJECTS = \
|
||||
$(OBJS)\test_gui_windowtest.o \
|
||||
$(OBJS)\test_gui_dialogtest.o \
|
||||
$(OBJS)\test_gui_clone.o \
|
||||
$(OBJS)\test_gui_evtlooptest.o \
|
||||
$(OBJS)\test_gui_propagation.o \
|
||||
$(OBJS)\test_gui_keyboard.o \
|
||||
$(OBJS)\test_gui_fonttest.o \
|
||||
@ -520,6 +522,9 @@ $(OBJS)\test_datetimetest.o: ./datetime/datetimetest.cpp
|
||||
$(OBJS)\test_evthandler.o: ./events/evthandler.cpp
|
||||
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
||||
|
||||
$(OBJS)\test_evtlooptest.o: ./events/evtlooptest.cpp
|
||||
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
||||
|
||||
$(OBJS)\test_evtsource.o: ./events/evtsource.cpp
|
||||
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
||||
|
||||
@ -928,6 +933,9 @@ $(OBJS)\test_gui_dialogtest.o: ./controls/dialogtest.cpp
|
||||
$(OBJS)\test_gui_clone.o: ./events/clone.cpp
|
||||
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
|
||||
|
||||
$(OBJS)\test_gui_evtlooptest.o: ./events/evtlooptest.cpp
|
||||
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
|
||||
|
||||
$(OBJS)\test_gui_propagation.o: ./events/propagation.cpp
|
||||
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
|
||||
|
||||
|
@ -44,6 +44,7 @@ TEST_OBJECTS = \
|
||||
$(OBJS)\test_regconf.obj \
|
||||
$(OBJS)\test_datetimetest.obj \
|
||||
$(OBJS)\test_evthandler.obj \
|
||||
$(OBJS)\test_evtlooptest.obj \
|
||||
$(OBJS)\test_evtsource.obj \
|
||||
$(OBJS)\test_stopwatch.obj \
|
||||
$(OBJS)\test_timertest.obj \
|
||||
@ -191,6 +192,7 @@ TEST_GUI_OBJECTS = \
|
||||
$(OBJS)\test_gui_windowtest.obj \
|
||||
$(OBJS)\test_gui_dialogtest.obj \
|
||||
$(OBJS)\test_gui_clone.obj \
|
||||
$(OBJS)\test_gui_evtlooptest.obj \
|
||||
$(OBJS)\test_gui_propagation.obj \
|
||||
$(OBJS)\test_gui_keyboard.obj \
|
||||
$(OBJS)\test_gui_fonttest.obj \
|
||||
@ -671,6 +673,9 @@ $(OBJS)\test_datetimetest.obj: .\datetime\datetimetest.cpp
|
||||
$(OBJS)\test_evthandler.obj: .\events\evthandler.cpp
|
||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\events\evthandler.cpp
|
||||
|
||||
$(OBJS)\test_evtlooptest.obj: .\events\evtlooptest.cpp
|
||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\events\evtlooptest.cpp
|
||||
|
||||
$(OBJS)\test_evtsource.obj: .\events\evtsource.cpp
|
||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\events\evtsource.cpp
|
||||
|
||||
@ -1079,6 +1084,9 @@ $(OBJS)\test_gui_dialogtest.obj: .\controls\dialogtest.cpp
|
||||
$(OBJS)\test_gui_clone.obj: .\events\clone.cpp
|
||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\clone.cpp
|
||||
|
||||
$(OBJS)\test_gui_evtlooptest.obj: .\events\evtlooptest.cpp
|
||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\evtlooptest.cpp
|
||||
|
||||
$(OBJS)\test_gui_propagation.obj: .\events\propagation.cpp
|
||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\propagation.cpp
|
||||
|
||||
|
@ -319,6 +319,7 @@ TEST_OBJECTS = &
|
||||
$(OBJS)\test_regconf.obj &
|
||||
$(OBJS)\test_datetimetest.obj &
|
||||
$(OBJS)\test_evthandler.obj &
|
||||
$(OBJS)\test_evtlooptest.obj &
|
||||
$(OBJS)\test_evtsource.obj &
|
||||
$(OBJS)\test_stopwatch.obj &
|
||||
$(OBJS)\test_timertest.obj &
|
||||
@ -463,6 +464,7 @@ TEST_GUI_OBJECTS = &
|
||||
$(OBJS)\test_gui_windowtest.obj &
|
||||
$(OBJS)\test_gui_dialogtest.obj &
|
||||
$(OBJS)\test_gui_clone.obj &
|
||||
$(OBJS)\test_gui_evtlooptest.obj &
|
||||
$(OBJS)\test_gui_propagation.obj &
|
||||
$(OBJS)\test_gui_keyboard.obj &
|
||||
$(OBJS)\test_gui_fonttest.obj &
|
||||
@ -580,6 +582,9 @@ $(OBJS)\test_datetimetest.obj : .AUTODEPEND .\datetime\datetimetest.cpp
|
||||
$(OBJS)\test_evthandler.obj : .AUTODEPEND .\events\evthandler.cpp
|
||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
||||
|
||||
$(OBJS)\test_evtlooptest.obj : .AUTODEPEND .\events\evtlooptest.cpp
|
||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
||||
|
||||
$(OBJS)\test_evtsource.obj : .AUTODEPEND .\events\evtsource.cpp
|
||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
||||
|
||||
@ -988,6 +993,9 @@ $(OBJS)\test_gui_dialogtest.obj : .AUTODEPEND .\controls\dialogtest.cpp
|
||||
$(OBJS)\test_gui_clone.obj : .AUTODEPEND .\events\clone.cpp
|
||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
|
||||
|
||||
$(OBJS)\test_gui_evtlooptest.obj : .AUTODEPEND .\events\evtlooptest.cpp
|
||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
|
||||
|
||||
$(OBJS)\test_gui_propagation.obj : .AUTODEPEND .\events\propagation.cpp
|
||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
config/regconf.cpp
|
||||
datetime/datetimetest.cpp
|
||||
events/evthandler.cpp
|
||||
events/evtlooptest.cpp
|
||||
events/evtsource.cpp
|
||||
events/stopwatch.cpp
|
||||
events/timertest.cpp
|
||||
@ -189,6 +190,10 @@
|
||||
controls/windowtest.cpp
|
||||
controls/dialogtest.cpp
|
||||
events/clone.cpp
|
||||
<!--
|
||||
Duplicate this file here to test GUI event loops too.
|
||||
-->
|
||||
events/evtlooptest.cpp
|
||||
events/propagation.cpp
|
||||
events/keyboard.cpp
|
||||
font/fonttest.cpp
|
||||
|
@ -205,6 +205,10 @@ SOURCE=.\events\evthandler.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\events\evtlooptest.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\events\evtsource.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -229,6 +229,10 @@ SOURCE=.\graphics\ellipsization.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\events\evtlooptest.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\font\fonttest.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -370,6 +370,9 @@
|
||||
<File
|
||||
RelativePath=".\events\evthandler.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtlooptest.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtsource.cpp">
|
||||
</File>
|
||||
|
@ -388,6 +388,9 @@
|
||||
<File
|
||||
RelativePath=".\graphics\ellipsization.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtlooptest.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\font\fonttest.cpp">
|
||||
</File>
|
||||
|
@ -529,6 +529,10 @@
|
||||
RelativePath=".\events\evthandler.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtlooptest.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtsource.cpp"
|
||||
>
|
||||
|
@ -553,6 +553,10 @@
|
||||
RelativePath=".\graphics\ellipsization.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtlooptest.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\font\fonttest.cpp"
|
||||
>
|
||||
|
@ -515,6 +515,10 @@
|
||||
RelativePath=".\events\evthandler.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtlooptest.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtsource.cpp"
|
||||
>
|
||||
|
@ -539,6 +539,10 @@
|
||||
RelativePath=".\graphics\ellipsization.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\events\evtlooptest.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\font\fonttest.cpp"
|
||||
>
|
||||
|
Loading…
Reference in New Issue
Block a user