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:
Vadim Zeitlin 2013-07-03 00:26:13 +00:00
parent e77dc839af
commit d3ad22bdb3
30 changed files with 450 additions and 29 deletions

View File

@ -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).

View File

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

View File

@ -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)

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

@ -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();
}

View File

@ -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();
}

View File

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

View File

@ -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()

View File

@ -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();
}

View File

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

View File

@ -162,7 +162,7 @@ int wxGUIEventLoop::DoRun()
return exitcode;
}
void wxGUIEventLoop::Exit(int rc)
void wxGUIEventLoop::ScheduleExit(int rc)
{
if ( m_impl )
{

View File

@ -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

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

View File

@ -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

View File

@ -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) $<

View File

@ -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

View File

@ -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) $<

View File

@ -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

View File

@ -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

View 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

View File

@ -370,6 +370,9 @@
<File
RelativePath=".\events\evthandler.cpp">
</File>
<File
RelativePath=".\events\evtlooptest.cpp">
</File>
<File
RelativePath=".\events\evtsource.cpp">
</File>

View File

@ -388,6 +388,9 @@
<File
RelativePath=".\graphics\ellipsization.cpp">
</File>
<File
RelativePath=".\events\evtlooptest.cpp">
</File>
<File
RelativePath=".\font\fonttest.cpp">
</File>

View File

@ -529,6 +529,10 @@
RelativePath=".\events\evthandler.cpp"
>
</File>
<File
RelativePath=".\events\evtlooptest.cpp"
>
</File>
<File
RelativePath=".\events\evtsource.cpp"
>

View File

@ -553,6 +553,10 @@
RelativePath=".\graphics\ellipsization.cpp"
>
</File>
<File
RelativePath=".\events\evtlooptest.cpp"
>
</File>
<File
RelativePath=".\font\fonttest.cpp"
>

View File

@ -515,6 +515,10 @@
RelativePath=".\events\evthandler.cpp"
>
</File>
<File
RelativePath=".\events\evtlooptest.cpp"
>
</File>
<File
RelativePath=".\events\evtsource.cpp"
>

View File

@ -539,6 +539,10 @@
RelativePath=".\graphics\ellipsization.cpp"
>
</File>
<File
RelativePath=".\events\evtlooptest.cpp"
>
</File>
<File
RelativePath=".\font\fonttest.cpp"
>