summaryrefslogtreecommitdiff
path: root/vcl/source/app
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-02-07 16:34:38 +0100
committerLuboš Luňák <l.lunak@collabora.com>2021-02-07 18:57:30 +0100
commitd3b498cc4732f964919fecb265085cefcc422469 (patch)
treeb5cc5bbc381e18a2cad621b75cbe7401db0c585c /vcl/source/app
parentf343ad6d8a78798814c9d38261043619b4e2b487 (diff)
invoke idle priority timers only when actually idle
The 'Idle' timers are misnamed. They are zero-timeout times, i.e. they are invoked immediately after returning to the main loop. But that does not necessarily mean they are invoked when idle, there may be e.g. user input pending in the system event queue. In fact, LO events are processed before system events, which means that 'Idle' timers are normally processed before user input. Besides being confused, this also leads to poor performance in some cases, such as when using mouse wheel to zoom in a large document. This results in several mouse wheel events, each of which will result in adjusting the zoom and that causing a repaint. Repaints are internally handled using a TaskPriority::REPAINT 'Idle', and so what happens is zoom->repaint->zoom->repaint->zoom->repaint instead of the more efficient zoom->zoom->zoom->repaint. This change (besides trying to clarify the confusion in the docs) delays invoking tasks with priorities TaskPriority::HIGH_IDLE and lower if there is user input or repaint events in the OS queue. That means that tasks using idle priorities actually will be invoked only when idle (barring background threads etc.). I'm reasonably certain this is a safe change, there's no guarantee when exactly tasks will be invoked (e.g. other tasks with a higher priority go first) and explicitly specifying such a priority means asking for it. I already implemented this once in 06d731428ef6cf93c7333e8228b, and it was also again done in 87199d3829257420429057336283, but apparently these have been removed. There was d348035a60361a1b9ba9e 'Drop special idle handling' with the reasoning that 'Idles are just instant timers'. Which strictly technically speaking is true due to 'Idle' being a misnomer, but the point is that some idles should be actual idles and that's why they need to be handled specially. Change-Id: I36c2b02a80ae7e1476b731f878d9b28aa87975f4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110538 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'vcl/source/app')
-rw-r--r--vcl/source/app/scheduler.cxx11
1 files changed, 11 insertions, 0 deletions
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index b325f9238a7d..57b8176521f7 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -430,6 +430,17 @@ bool Scheduler::ProcessTaskScheduling()
<< " of " << nTasks << " tasks" );
UpdateSystemTimer( rSchedCtx, nMinPeriod, true, nTime );
+ // Delay invoking tasks with idle priorities as long as there are user input or repaint events
+ // in the OS event queue. This will often effectively compress such events and repaint only
+ // once at the end, improving performance in cases such as repeated zooming with a complex document.
+ if ( pMostUrgent && pMostUrgent->mePriority >= TaskPriority::HIGH_IDLE
+ && Application::AnyInput( VclInputFlags::MOUSE | VclInputFlags::KEYBOARD | VclInputFlags::PAINT ))
+ {
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
+ << " idle priority task " << pMostUrgent << " delayed, system events pending" );
+ pMostUrgent = nullptr;
+ }
+
if ( pMostUrgent )
{
SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "