Kaydet (Commit) 48c2815d authored tarafından Michael Meeks's avatar Michael Meeks

tdf#91727 - Unwind non-dispatch of idle handlers.

This clobbers the functionality from commit:

    06d73142

    make idle timers actually activate only when idle

Since now all rendering and re-sizing is done in idle handlers it
does effectively the opposite of what was intended. A better solution
would allow special-casing the processing of just rendering,
re-sizing and window management to spin for eg. progress bar
rendering.

Also add helpful debugging labels to the idle & timeouts.

Also cleanup the Idle vs. Scheduler handling.

Also ensure that starting an Idle triggers a mainloop wakeup.

Also add a unit test.

Change-Id: Ifb0756714378fdb790be599b93c7a3ac1f9209e6
üst ef4fd9c5
......@@ -123,7 +123,9 @@ public:
{ return (nTime <= rTime.nTime); }
static Time GetUTCOffset();
static sal_uInt64 GetSystemTicks(); // Elapsed time
/// Elapsed time since epoch in milliseconds
static sal_uInt64 GetSystemTicks();
void ConvertToUTC() { *this -= Time::GetUTCOffset(); }
void ConvertToLocalTime() { *this += Time::GetUTCOffset(); }
......
......@@ -29,14 +29,18 @@ protected:
Link<Idle *, void> maIdleHdl; // Callback Link
public:
Idle();
Idle( const sal_Char *pDebugName = NULL );
Idle( const Idle& rIdle );
virtual void Start();
/// Make it possible to associate a callback with this idle handler
/// of course, you can also sub-class and override 'Invoke'
void SetIdleHdl( const Link<Idle *, void>& rLink ) { maIdleHdl = rLink; }
const Link<Idle *, void>& GetIdleHdl() const { return maIdleHdl; }
virtual void Invoke() SAL_OVERRIDE;
virtual void Invoke() SAL_OVERRIDE;
virtual bool ReadyForSchedule( bool bTimer ) SAL_OVERRIDE;
virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) SAL_OVERRIDE;
Idle& operator=( const Idle& rIdle );
};
......
......@@ -52,23 +52,27 @@ enum class SchedulerPriority {
class VCL_DLLPUBLIC Scheduler
{
protected:
ImplSchedulerData* mpSchedulerData; // Pointer to element in scheduler list
SchedulerPriority mePriority; // Scheduler priority
bool mbActive; // Currently in the scheduler
ImplSchedulerData* mpSchedulerData; /// Pointer to element in scheduler list
const sal_Char *mpDebugName; /// Useful for debugging
SchedulerPriority mePriority; /// Scheduler priority
bool mbActive; /// Currently in the scheduler
friend struct ImplSchedulerData;
virtual void SetDeletionFlags();
virtual bool ReadyForSchedule( bool bTimer ) { return !bTimer; }
virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime );
virtual bool ReadyForSchedule( bool bTimer ) = 0;
virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) = 0;
public:
Scheduler();
Scheduler( const sal_Char *pDebugName = NULL );
Scheduler( const Scheduler& rScheduler );
virtual ~Scheduler();
void SetPriority( SchedulerPriority ePriority );
SchedulerPriority GetPriority() const { return mePriority; }
void SetDebugName( const sal_Char *pDebugName ) { mpDebugName = pDebugName; }
const sal_Char *GetDebugName() { return mpDebugName; }
// Call handler
virtual void Invoke() = 0;
......
......@@ -38,7 +38,7 @@ private:
static void InitSystemTimer();
public:
Timer();
Timer( const sal_Char *pDebugName = NULL );
Timer( const Timer& rTimer );
/// Make it possible to associate a callback with this timer handler
......
......@@ -805,6 +805,7 @@ void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const
}
GraphicCache::GraphicCache( sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) :
maReleaseTimer ( "GraphicCache maReleaseTimer" ),
mnReleaseTimeoutSeconds ( 0UL ),
mnMaxDisplaySize ( nDisplayCacheSize ),
mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ),
......
......@@ -102,6 +102,7 @@ OLEObjCache::OLEObjCache()
pTimer->SetTimeoutHdl(aLink);
pTimer->SetTimeout(20000);
pTimer->Start();
pTimer->SetDebugName("OLEObjCache pTimer UnloadCheck");
aLink.Call(pTimer);
}
......
......@@ -18,6 +18,10 @@
#include <vcl/timer.hxx>
#include <vcl/idle.hxx>
#include <vcl/svapp.hxx>
#include "svdata.hxx"
#include "salinst.hxx"
// #define TEST_WATCHDOG
/// Avoid our timer tests just wedging the build if they fail.
class WatchDog : public osl::Thread
......@@ -47,6 +51,7 @@ class TimerTest : public test::BootstrapFixture
public:
TimerTest() : BootstrapFixture(true, false) {}
void testIdleMainloop();
void testIdle();
#ifdef TEST_WATCHDOG
void testWatchdog();
......@@ -58,6 +63,7 @@ public:
CPPUNIT_TEST_SUITE(TimerTest);
CPPUNIT_TEST(testIdle);
CPPUNIT_TEST(testIdleMainloop);
#ifdef TEST_WATCHDOG
CPPUNIT_TEST(testWatchdog);
#endif
......@@ -105,7 +111,25 @@ void TimerTest::testIdle()
bool bTriggered = false;
IdleBool aTest( bTriggered );
Scheduler::ProcessTaskScheduling(false);
CPPUNIT_ASSERT_MESSAGE("watchdog triggered", bTriggered);
CPPUNIT_ASSERT_MESSAGE("idle triggered", bTriggered);
}
// tdf#91727
void TimerTest::testIdleMainloop()
{
bool bTriggered = false;
IdleBool aTest( bTriggered );
while (!bTriggered)
{
ImplSVData* pSVData = ImplGetSVData();
// can't test this via Application::Yield since this
// also processes all tasks directly via the scheduler.
pSVData->maAppData.mnDispatchLevel++;
pSVData->mpDefInst->Yield( true, false );
pSVData->maAppData.mnDispatchLevel--;
}
CPPUNIT_ASSERT_MESSAGE("mainloop idle triggered", bTriggered);
}
// --------------------------------------------------------------------
......
......@@ -18,6 +18,8 @@
*/
#include <vcl/idle.hxx>
#include <vcl/timer.hxx>
#include "svdata.hxx"
void Idle::Invoke()
{
......@@ -31,7 +33,7 @@ Idle& Idle::operator=( const Idle& rIdle )
return *this;
}
Idle::Idle() : Scheduler()
Idle::Idle( const sal_Char *pDebugName ) : Scheduler( pDebugName )
{
}
......@@ -40,4 +42,25 @@ Idle::Idle( const Idle& rIdle ) : Scheduler(rIdle)
maIdleHdl = rIdle.maIdleHdl;
}
void Idle::Start()
{
Scheduler::Start();
ImplSVData* pSVData = ImplGetSVData();
Timer::ImplStartTimer( pSVData, 0 );
}
bool Idle::ReadyForSchedule( bool bTimer )
{
// tdf#91727 - We need to re-work this to allow only UI idle handlers
// and not timeouts to be processed in some limited scenarios
(void)bTimer;
return true; // !bTimer
}
sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nMinPeriod */, sal_uInt64 /* nTime */ )
{
return 1;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -120,6 +120,7 @@ void Scheduler::ProcessTaskScheduling( bool bTimer )
sal_uInt64 nMinPeriod = MAX_TIMER_PERIOD;
pSVData->mnUpdateStack++;
// tdf#91727 - NB. bTimer is ultimately not used
if ((pSchedulerData = ImplSchedulerData::GetMostImportantTask(bTimer)))
{
pSchedulerData->mnUpdateTime = nTime;
......@@ -164,18 +165,12 @@ void Scheduler::ProcessTaskScheduling( bool bTimer )
pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
}
else
{
Timer::ImplStartTimer( pSVData, nMinPeriod );
}
pSVData->mnUpdateStack--;
}
sal_uInt64 Scheduler::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime )
{
// this period is only useful for timer
// so in this implementation it' only a pass through
(void)nTime;
return nMinPeriod;
}
void Scheduler::SetPriority( SchedulerPriority ePriority )
{
mePriority = ePriority;
......@@ -235,8 +230,9 @@ Scheduler& Scheduler::operator=( const Scheduler& rScheduler )
return *this;
}
Scheduler::Scheduler():
Scheduler::Scheduler(const sal_Char *pDebugName):
mpSchedulerData(NULL),
mpDebugName(pDebugName),
mePriority(SchedulerPriority::HIGH),
mbActive(false)
{
......@@ -244,6 +240,7 @@ Scheduler::Scheduler():
Scheduler::Scheduler( const Scheduler& rScheduler ):
mpSchedulerData(NULL),
mpDebugName(rScheduler.mpDebugName),
mePriority(rScheduler.mePriority),
mbActive(false)
{
......
......@@ -98,7 +98,7 @@ void Timer::InitSystemTimer()
}
}
Timer::Timer() : Scheduler()
Timer::Timer(const sal_Char *pDebugName) : Scheduler(pDebugName)
{
mnTimeout = 1;
mbAuto = false;
......
......@@ -1058,9 +1058,11 @@ void Window::ImplInit( vcl::Window* pParent, WinBits nStyle, SystemParentData* p
{
mpWindowImpl->mpFrameData->maPaintIdle.SetPriority( SchedulerPriority::REPAINT );
mpWindowImpl->mpFrameData->maPaintIdle.SetIdleHdl( LINK( this, Window, ImplHandlePaintHdl ) );
mpWindowImpl->mpFrameData->maPaintIdle.SetDebugName( "vcl::Window maPaintIdle" );
}
mpWindowImpl->mpFrameData->maResizeIdle.SetPriority( SchedulerPriority::RESIZE );
mpWindowImpl->mpFrameData->maResizeIdle.SetIdleHdl( LINK( this, Window, ImplHandleResizeTimerHdl ) );
mpWindowImpl->mpFrameData->maResizeIdle.SetDebugName( "vcl::Window maResizeIdle" );
mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = false;
if ( pRealParent && IsTopWindow() )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment