- 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).
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);
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;
// 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;
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);
};
// 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
}
#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)
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);
// 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;
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}
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);
+
+ /**
+ 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 Exit(int rc = 0) = 0;
+ virtual void ScheduleExit(int rc = 0) = 0;
/**
Return true if any events are available.
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;
#include "wx/app.h"
#endif //WX_PRECOMP
+#include "wx/scopeguard.h"
+
// ----------------------------------------------------------------------------
// wxEventLoopBase
// ----------------------------------------------------------------------------
wxEventLoopBase::wxEventLoopBase()
{
+ m_isInsideRun = false;
m_shouldExit = false;
m_isInsideYield = false;
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
// 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)
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;
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();
}
{
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();
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();
}
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 );
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()
#endif // WX_PRECOMP
#include "wx/log.h"
+#include "wx/scopeguard.h"
#include "wx/osx/private.h"
}
}
+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();
}
// 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;
return exitcode;
}
-void wxGUIEventLoop::Exit(int rc)
+void wxGUIEventLoop::ScheduleExit(int rc)
{
if ( m_impl )
{
test_regconf.o \
test_datetimetest.o \
test_evthandler.o \
+ test_evtlooptest.o \
test_evtsource.o \
test_stopwatch.o \
test_timertest.o \
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 \
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
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
--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// 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() );
+}
$(OBJS)\test_regconf.obj \\r
$(OBJS)\test_datetimetest.obj \\r
$(OBJS)\test_evthandler.obj \\r
+ $(OBJS)\test_evtlooptest.obj \
$(OBJS)\test_evtsource.obj \\r
$(OBJS)\test_stopwatch.obj \\r
$(OBJS)\test_timertest.obj \\r
$(OBJS)\test_gui_windowtest.obj \\r
$(OBJS)\test_gui_dialogtest.obj \\r
$(OBJS)\test_gui_clone.obj \\r
+ $(OBJS)\test_gui_evtlooptest.obj \
$(OBJS)\test_gui_propagation.obj \\r
$(OBJS)\test_gui_keyboard.obj \\r
$(OBJS)\test_gui_fonttest.obj \\r
$(OBJS)\test_evthandler.obj: .\events\evthandler.cpp\r
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\events\evthandler.cpp\r
\r
+$(OBJS)\test_evtlooptest.obj: .\events\evtlooptest.cpp
+ $(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\events\evtlooptest.cpp
+
$(OBJS)\test_evtsource.obj: .\events\evtsource.cpp\r
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\events\evtsource.cpp\r
\r
$(OBJS)\test_gui_clone.obj: .\events\clone.cpp\r
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\clone.cpp\r
\r
+$(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\r
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\propagation.cpp\r
\r
$(OBJS)\test_regconf.o \\r
$(OBJS)\test_datetimetest.o \\r
$(OBJS)\test_evthandler.o \\r
+ $(OBJS)\test_evtlooptest.o \
$(OBJS)\test_evtsource.o \\r
$(OBJS)\test_stopwatch.o \\r
$(OBJS)\test_timertest.o \\r
$(OBJS)\test_gui_windowtest.o \\r
$(OBJS)\test_gui_dialogtest.o \\r
$(OBJS)\test_gui_clone.o \\r
+ $(OBJS)\test_gui_evtlooptest.o \
$(OBJS)\test_gui_propagation.o \\r
$(OBJS)\test_gui_keyboard.o \\r
$(OBJS)\test_gui_fonttest.o \\r
$(OBJS)\test_evthandler.o: ./events/evthandler.cpp\r
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<\r
\r
+$(OBJS)\test_evtlooptest.o: ./events/evtlooptest.cpp
+ $(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
+
$(OBJS)\test_evtsource.o: ./events/evtsource.cpp\r
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<\r
\r
$(OBJS)\test_gui_clone.o: ./events/clone.cpp\r
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<\r
\r
+$(OBJS)\test_gui_evtlooptest.o: ./events/evtlooptest.cpp
+ $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
+
$(OBJS)\test_gui_propagation.o: ./events/propagation.cpp\r
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<\r
\r
$(OBJS)\test_regconf.obj \\r
$(OBJS)\test_datetimetest.obj \\r
$(OBJS)\test_evthandler.obj \\r
+ $(OBJS)\test_evtlooptest.obj \
$(OBJS)\test_evtsource.obj \\r
$(OBJS)\test_stopwatch.obj \\r
$(OBJS)\test_timertest.obj \\r
$(OBJS)\test_gui_windowtest.obj \\r
$(OBJS)\test_gui_dialogtest.obj \\r
$(OBJS)\test_gui_clone.obj \\r
+ $(OBJS)\test_gui_evtlooptest.obj \
$(OBJS)\test_gui_propagation.obj \\r
$(OBJS)\test_gui_keyboard.obj \\r
$(OBJS)\test_gui_fonttest.obj \\r
$(OBJS)\test_evthandler.obj: .\events\evthandler.cpp\r
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\events\evthandler.cpp\r
\r
+$(OBJS)\test_evtlooptest.obj: .\events\evtlooptest.cpp
+ $(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\events\evtlooptest.cpp
+
$(OBJS)\test_evtsource.obj: .\events\evtsource.cpp\r
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\events\evtsource.cpp\r
\r
$(OBJS)\test_gui_clone.obj: .\events\clone.cpp\r
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\clone.cpp\r
\r
+$(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\r
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\propagation.cpp\r
\r
$(OBJS)\test_regconf.obj &\r
$(OBJS)\test_datetimetest.obj &\r
$(OBJS)\test_evthandler.obj &\r
+ $(OBJS)\test_evtlooptest.obj &
$(OBJS)\test_evtsource.obj &\r
$(OBJS)\test_stopwatch.obj &\r
$(OBJS)\test_timertest.obj &\r
$(OBJS)\test_gui_windowtest.obj &\r
$(OBJS)\test_gui_dialogtest.obj &\r
$(OBJS)\test_gui_clone.obj &\r
+ $(OBJS)\test_gui_evtlooptest.obj &
$(OBJS)\test_gui_propagation.obj &\r
$(OBJS)\test_gui_keyboard.obj &\r
$(OBJS)\test_gui_fonttest.obj &\r
$(OBJS)\test_evthandler.obj : .AUTODEPEND .\events\evthandler.cpp\r
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<\r
\r
+$(OBJS)\test_evtlooptest.obj : .AUTODEPEND .\events\evtlooptest.cpp
+ $(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
+
$(OBJS)\test_evtsource.obj : .AUTODEPEND .\events\evtsource.cpp\r
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<\r
\r
$(OBJS)\test_gui_clone.obj : .AUTODEPEND .\events\clone.cpp\r
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<\r
\r
+$(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\r
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<\r
\r
config/regconf.cpp
datetime/datetimetest.cpp
events/evthandler.cpp
+ events/evtlooptest.cpp
events/evtsource.cpp
events/stopwatch.cpp
events/timertest.cpp
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
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\events\evtlooptest.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\events\evtsource.cpp\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\events\evtlooptest.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\font\fonttest.cpp\r
# End Source File\r
# Begin Source File\r
<File\r
RelativePath=".\events\evthandler.cpp">\r
</File>\r
+ <File\r
+ RelativePath=".\events\evtlooptest.cpp">\r
+ </File>\r
<File\r
RelativePath=".\events\evtsource.cpp">\r
</File>\r
<File\r
RelativePath=".\graphics\ellipsization.cpp">\r
</File>\r
+ <File\r
+ RelativePath=".\events\evtlooptest.cpp">\r
+ </File>\r
<File\r
RelativePath=".\font\fonttest.cpp">\r
</File>\r
RelativePath=".\events\evthandler.cpp"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\events\evtlooptest.cpp"\r
+ >\r
+ </File>\r
<File\r
RelativePath=".\events\evtsource.cpp"\r
>\r
RelativePath=".\graphics\ellipsization.cpp"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\events\evtlooptest.cpp"\r
+ >\r
+ </File>\r
<File\r
RelativePath=".\font\fonttest.cpp"\r
>\r
RelativePath=".\events\evthandler.cpp"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\events\evtlooptest.cpp"\r
+ >\r
+ </File>\r
<File\r
RelativePath=".\events\evtsource.cpp"\r
>\r
RelativePath=".\graphics\ellipsization.cpp"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\events\evtlooptest.cpp"\r
+ >\r
+ </File>\r
<File\r
RelativePath=".\font\fonttest.cpp"\r
>\r