vcl: re-introduce idle handling.

The idea here is that we should process 'idle' events - like re-paint
after we have processed any OS messages - such as key/mouse input,
window re-size events etc.

The previous approach wasn't achieving this - it was processing a single
idle event each time around the main-loop iteration; urk.

Lubos implemented something -like- this, the vestiges of it need cleaning
up and removing in: 06d731428ef6cf93c7333e8228bfb6088853b52f but it was
disabled (most likely because it broke gtk in tdf#91727, which was itself
broken by using silly values for timeouts in the scheduler (now fixed))

Tested on Windows, gtk, kde4, unx-generic.

Change-Id: I7756bca874779c00f72b372cacb7745d0f189f66
Reviewed-on: https://gerrit.libreoffice.org/20158
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
Tested-by: Michael Meeks <michael.meeks@collabora.com>
diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx
index be9df9e..5771f3a 100644
--- a/include/vcl/scheduler.hxx
+++ b/include/vcl/scheduler.hxx
@@ -94,7 +94,7 @@
    // Process one pending Timer with highhest priority
    static void CallbackTaskScheduling( bool ignore );
    /// Calculate minimum timeout - and return its value.
    static sal_uInt64 CalculateMinimumTimeout();
    static sal_uInt64 CalculateMinimumTimeout( bool &bHasActiveIdles );
    /// Process one pending task ahead of time with highhest priority.
    static void       ProcessTaskScheduling( bool bTimer );
};
diff --git a/vcl/source/app/idle.cxx b/vcl/source/app/idle.cxx
index 5ce5361..bba2d05 100644
--- a/vcl/source/app/idle.cxx
+++ b/vcl/source/app/idle.cxx
@@ -48,10 +48,7 @@

bool Idle::ReadyForSchedule( bool bTimer ) const
{
    // 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
    return !bTimer;
}

sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 /* nTime */ ) const
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index b5e64e2..743de91 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -153,7 +153,7 @@
{
    // this function is for the saltimer callback
    (void)ignore;
    Scheduler::ProcessTaskScheduling( true );
    Scheduler::ProcessTaskScheduling( false );
}

void Scheduler::ProcessTaskScheduling( bool bTimerOnly )
@@ -168,7 +168,7 @@
    }
}

sal_uInt64 Scheduler::CalculateMinimumTimeout()
sal_uInt64 Scheduler::CalculateMinimumTimeout( bool &bHasActiveIdles )
{
    // process all pending Tasks
    // if bTimer True, only handle timer
@@ -181,13 +181,11 @@
    pSchedulerData = pSVData->mpFirstSchedulerData;
    while ( pSchedulerData )
    {
        if( pSchedulerData->mbInScheduler )
        {
            pPrevSchedulerData = pSchedulerData;
            pSchedulerData = pSchedulerData->mpNext;
        }
        ImplSchedulerData *pNext = pSchedulerData->mpNext;

        // Should Task be released from scheduling?
        else if ( pSchedulerData->mbDelete )
        if ( !pSchedulerData->mbInScheduler &&
              pSchedulerData->mbDelete )
        {
            if ( pPrevSchedulerData )
                pPrevSchedulerData->mpNext = pSchedulerData->mpNext;
@@ -195,19 +193,24 @@
                pSVData->mpFirstSchedulerData = pSchedulerData->mpNext;
            if ( pSchedulerData->mpScheduler )
                pSchedulerData->mpScheduler->mpSchedulerData = nullptr;
            ImplSchedulerData* pTempSchedulerData = pSchedulerData;
            pSchedulerData = pSchedulerData->mpNext;
            delete pTempSchedulerData;
            pNext = pSchedulerData->mpNext;
            delete pSchedulerData;
        }
        else
        {
            nMinPeriod = pSchedulerData->mpScheduler->UpdateMinPeriod( nMinPeriod, nTime );
            if (!pSchedulerData->mbInScheduler)
            {
                if ( pSchedulerData->mpScheduler->ReadyForSchedule( true ) )
                    nMinPeriod = pSchedulerData->mpScheduler->UpdateMinPeriod( nMinPeriod, nTime );
                else
                    bHasActiveIdles = true;
            }
            pPrevSchedulerData = pSchedulerData;
            pSchedulerData = pSchedulerData->mpNext;
        }
        pSchedulerData = pNext;
    }

    // delete clock if no more timers available
    // delete clock if no more timers available,
    if ( !pSVData->mpFirstSchedulerData )
    {
        if ( pSVData->mpSalTimer )
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index 734b5de..808e743 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -477,18 +477,25 @@
{
    ImplSVData* pSVData = ImplGetSVData();

    bool bHasActiveIdles = false;
    sal_uInt64 nMinTimeout = 0;
    if (nReleased == 0) // else thread doesn't have SolarMutex so avoid race
        nMinTimeout = Scheduler::CalculateMinimumTimeout();
        nMinTimeout = Scheduler::CalculateMinimumTimeout(bHasActiveIdles);

    // FIXME: should use returned value as param to DoYield
    (void)nMinTimeout;

    // If we have idles, don't wait for the timeout; check for events
    // and come back as quick as possible.
    if (bHasActiveIdles)
        i_bWait = false;

    // TODO: there's a data race here on WNT only because ImplYield may be
    // called without SolarMutex; if we can get rid of LazyDelete (with VclPtr)
    // then the only remaining use of mnDispatchLevel is in OSX specific code
    // so that would effectively eliminate the race on WNT
    pSVData->maAppData.mnDispatchLevel++;

    // do not wait for events if application was already quit; in that
    // case only dispatch events already available
    // do not wait for events either if the app decided that it is too busy for timers