diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2015-01-31 17:40:48 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2015-02-04 15:44:09 +0100 |
commit | 06d731428ef6cf93c7333e8228bfb6088853b52f (patch) | |
tree | dbdcbed014fdbc7f1369e888a5903e493b3aabcb /vcl | |
parent | e6a58b5e69b83e01b5291b1d8629927e05447797 (diff) |
make idle timers actually activate only when idle
Without this, they can activate after any call to the event processing,
so they may activate in cases such as when updating progressbar while
loading a document, or on repeated user input (so things like showing
spellchecking get updated when the app is busy redrawing). This change
makes idle timers activate only when there's nothing more for the event
loop to process. It's a bit of a question if this doesn't break something
that happens to expect idle timers to be not-really-idle timers, but oh well.
No change for non-X11 platforms, as there's I don't know how to check
the event queues.
Change-Id: I074a88f2f5eeb4b456a11916a0ec2ad6f54dfbab
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/headless/svpinst.cxx | 5 | ||||
-rw-r--r-- | vcl/inc/saltimer.hxx | 4 | ||||
-rw-r--r-- | vcl/inc/salwtype.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkdata.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/unx/saldata.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/unx/saldisp.hxx | 1 | ||||
-rw-r--r-- | vcl/osx/salinst.cxx | 3 | ||||
-rw-r--r-- | vcl/osx/salnstimer.mm | 3 | ||||
-rw-r--r-- | vcl/osx/saltimer.cxx | 3 | ||||
-rw-r--r-- | vcl/source/app/svapp.cxx | 4 | ||||
-rw-r--r-- | vcl/source/app/timer.cxx | 4 | ||||
-rw-r--r-- | vcl/unx/generic/app/saldata.cxx | 23 | ||||
-rw-r--r-- | vcl/unx/generic/app/saltimer.cxx | 4 | ||||
-rw-r--r-- | vcl/unx/gtk/app/gtkdata.cxx | 14 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEXLib.cxx | 9 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEXLib.hxx | 1 | ||||
-rw-r--r-- | vcl/win/source/app/saltimer.cxx | 3 |
17 files changed, 67 insertions, 20 deletions
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 1325e3ff45c5..7523dfd36368 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -186,7 +186,10 @@ bool SvpSalInstance::CheckTimeout( bool bExecuteTimers ) // notify ImplSVData* pSVData = ImplGetSVData(); if( pSVData->mpSalTimer ) - pSVData->mpSalTimer->CallCallback(); + { + bool idle = true; // TODO + pSVData->mpSalTimer->CallCallback( idle ); + } } } } diff --git a/vcl/inc/saltimer.hxx b/vcl/inc/saltimer.hxx index 3bdfbc358da6..1e1a941c1287 100644 --- a/vcl/inc/saltimer.hxx +++ b/vcl/inc/saltimer.hxx @@ -47,10 +47,10 @@ public: m_pProc = pProc; } - void CallCallback() + void CallCallback( bool idle ) { if( m_pProc ) - m_pProc(); + m_pProc( idle ); } }; diff --git a/vcl/inc/salwtype.hxx b/vcl/inc/salwtype.hxx index 805581316504..7a14df0ee103 100644 --- a/vcl/inc/salwtype.hxx +++ b/vcl/inc/salwtype.hxx @@ -281,7 +281,7 @@ struct SalInputContext sal_uLong mnOptions; }; -typedef void (*SALTIMERPROC)(); +typedef void (*SALTIMERPROC)( bool idle ); #endif // INCLUDED_VCL_INC_SALWTYPE_HXX diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx index 9c2c76eaa4d3..e2702049d67d 100644 --- a/vcl/inc/unx/gtk/gtkdata.hxx +++ b/vcl/inc/unx/gtk/gtkdata.hxx @@ -99,6 +99,7 @@ class GtkData : public SalGenericData GSource *m_pUserEvent; oslMutex m_aDispatchMutex; oslCondition m_aDispatchCondition; + bool blockIdleTimeout; public: GtkData( SalInstance *pInstance ); @@ -120,6 +121,7 @@ public: virtual bool ErrorTrapPop( bool bIgnoreError ) SAL_OVERRIDE; inline GtkSalDisplay *GetGtkDisplay() const; + bool BlockIdleTimeout() const { return blockIdleTimeout; } }; class GtkSalFrame; diff --git a/vcl/inc/unx/saldata.hxx b/vcl/inc/unx/saldata.hxx index 2c5823177217..0dba4c960c9e 100644 --- a/vcl/inc/unx/saldata.hxx +++ b/vcl/inc/unx/saldata.hxx @@ -77,7 +77,7 @@ public: void StartTimer( sal_uLong nMS ); inline void StopTimer(); - void Timeout() const; + void Timeout( bool idle ) const; // X errors virtual void ErrorTrapPush() SAL_OVERRIDE; diff --git a/vcl/inc/unx/saldisp.hxx b/vcl/inc/unx/saldisp.hxx index 63b8bae33ede..aa635650186a 100644 --- a/vcl/inc/unx/saldisp.hxx +++ b/vcl/inc/unx/saldisp.hxx @@ -157,6 +157,7 @@ protected: timeval m_aTimeout; sal_uLong m_nTimeoutMS; int m_pTimeoutFDS[2]; + bool blockIdleTimeout; int nFDs_; fd_set aReadFDS_; diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index a531dbd82e7c..91bfa143a43a 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -646,7 +646,8 @@ void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) { // this cause crashes on MacOSX 10.4 // [AquaSalTimer::pRunningTimer fire]; - ImplGetSVData()->mpSalTimer->CallCallback(); + bool idle = true; // TODO + ImplGetSVData()->mpSalTimer->CallCallback( idle ); } } diff --git a/vcl/osx/salnstimer.mm b/vcl/osx/salnstimer.mm index bad2f4e51ff7..fe0e907cbda5 100644 --- a/vcl/osx/salnstimer.mm +++ b/vcl/osx/salnstimer.mm @@ -35,7 +35,8 @@ if( pSVData->mpSalTimer ) { YIELD_GUARD; - pSVData->mpSalTimer->CallCallback(); + bool idle = true; // TODO + pSVData->mpSalTimer->CallCallback( idle ); // NSTimer does not end nextEventMatchingMask of NSApplication // so we need to wakeup a waiting Yield to inform it something happened diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx index 17c4d80ac3c0..6c83af7c77c5 100644 --- a/vcl/osx/saltimer.cxx +++ b/vcl/osx/saltimer.cxx @@ -91,7 +91,8 @@ void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent ) { YIELD_GUARD; // timer already elapsed since event posted - pSVData->mpSalTimer->CallCallback(); + bool idle = true; // TODO + pSVData->mpSalTimer->CallCallback( idle ); } ImplSalStartTimer( sal_uLong( [pEvent data1] ) ); } diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 19890e7c1e2a..e3939787b3c7 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -344,7 +344,7 @@ inline void ImplYield( bool i_bWait, bool i_bAllEvents ) // run timers that have timed out if ( !pSVData->mbNoCallTimer ) while ( pSVData->mbNotAllTimerCalled ) - Timer::ImplTimerCallbackProc(); + Timer::ImplTimerCallbackProc( !i_bWait ); pSVData->maAppData.mnDispatchLevel++; // do not wait for events if application was already quit; in that @@ -366,7 +366,7 @@ inline void ImplYield( bool i_bWait, bool i_bAllEvents ) { do { - Timer::ImplTimerCallbackProc(); + Timer::ImplTimerCallbackProc( !i_bWait ); } while( pSVData->mbNotAllTimerCalled ); } diff --git a/vcl/source/app/timer.cxx b/vcl/source/app/timer.cxx index 529c8b53d881..5742191a4a42 100644 --- a/vcl/source/app/timer.cxx +++ b/vcl/source/app/timer.cxx @@ -129,7 +129,7 @@ static void ImplStartTimer( ImplSVData* pSVData, sal_uLong nMS ) } } -void Timer::ImplTimerCallbackProc() +void Timer::ImplTimerCallbackProc( bool idle ) { ImplSVData* pSVData = ImplGetSVData(); ImplTimerData* pTimerData; @@ -151,7 +151,7 @@ void Timer::ImplTimerCallbackProc() // If the timer is not new, was not deleted, and if it is not in the timeout handler, then // call the handler as soon as the time is up. if ( (pTimerData->mnTimerUpdate < pSVData->mnTimerUpdate) && - !pTimerData->mbDelete && !pTimerData->mbInTimeout ) + !pTimerData->mbDelete && !pTimerData->mbInTimeout && (!pTimerData->mpTimer->mbIdle || idle) ) { // time has expired if ( pTimerData->GetDeadline() <= nTime ) diff --git a/vcl/unx/generic/app/saldata.cxx b/vcl/unx/generic/app/saldata.cxx index 317c16e16452..2a90eb7dc49d 100644 --- a/vcl/unx/generic/app/saldata.cxx +++ b/vcl/unx/generic/app/saldata.cxx @@ -336,6 +336,7 @@ void X11SalData::PopXErrorLevel() } SalXLib::SalXLib() + : blockIdleTimeout( false ) { m_aTimeout.tv_sec = 0; m_aTimeout.tv_usec = 0; @@ -646,8 +647,20 @@ bool SalXLib::CheckTimeout( bool bExecuteTimers ) * timers are being dispatched. */ m_aTimeout += m_nTimeoutMS; + // Determine if the app is idle (for idle timers). If there's user input pending, + // if there's IO pending or if we're called inside a temporary yield (=blockIdleTimeout), + // then the app is not idle. + bool idle = true; + if( blockIdleTimeout || XPending( vcl_sal::getSalDisplay(GetGenericData())->GetDisplay())) + idle = false; + for ( int nFD = 0; idle && nFD < nFDs_; nFD++ ) + { + YieldEntry* pEntry = &(yieldTable[nFD]); + if ( pEntry->fd && pEntry->HasPendingEvent()) + idle = false; + } // notify - GetX11SalData()->Timeout(); + GetX11SalData()->Timeout( idle ); } } } @@ -656,6 +669,7 @@ bool SalXLib::CheckTimeout( bool bExecuteTimers ) void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) { + blockIdleTimeout = !bWait; // check for timeouts here if you want to make screenshots static char* p_prioritize_timer = getenv ("SAL_HIGHPRIORITY_REPAINT"); if (p_prioritize_timer != NULL) @@ -674,7 +688,10 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) { pEntry->HandleNextEvent(); if( ! bHandleAllCurrentEvents ) + { + blockIdleTimeout = false; return; + } } } } @@ -746,7 +763,10 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) // someone-else has done the job for us if (nFound == 0) + { + blockIdleTimeout = false; return; + } for ( int nFD = 0; nFD < nFDs_; nFD++ ) { @@ -772,6 +792,7 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) } } } + blockIdleTimeout = false; } void SalXLib::Wakeup() diff --git a/vcl/unx/generic/app/saltimer.cxx b/vcl/unx/generic/app/saltimer.cxx index 19b44955cfe0..fc55afb85c48 100644 --- a/vcl/unx/generic/app/saltimer.cxx +++ b/vcl/unx/generic/app/saltimer.cxx @@ -29,11 +29,11 @@ #include <unx/saltimer.h> #include <unx/salinst.h> -void X11SalData::Timeout() const +void X11SalData::Timeout( bool idle ) const { ImplSVData* pSVData = ImplGetSVData(); if( pSVData->mpSalTimer ) - pSVData->mpSalTimer->CallCallback(); + pSVData->mpSalTimer->CallCallback( idle ); } void SalXLib::StopTimer() diff --git a/vcl/unx/gtk/app/gtkdata.cxx b/vcl/unx/gtk/app/gtkdata.cxx index 8e20f62c14ee..cdbfd0a1b7c7 100644 --- a/vcl/unx/gtk/app/gtkdata.cxx +++ b/vcl/unx/gtk/app/gtkdata.cxx @@ -502,6 +502,7 @@ GtkData::GtkData( SalInstance *pInstance ) #else : SalGenericData( SAL_DATA_GTK, pInstance ) #endif + , blockIdleTimeout( false ) { m_pUserEvent = NULL; m_aDispatchMutex = osl_createMutex(); @@ -551,6 +552,7 @@ void GtkData::Dispose() void GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents ) { + blockIdleTimeout = !bWait; /* #i33212# only enter g_main_context_iteration in one thread at any one * time, else one of them potentially will never end as long as there is * another thread in there. Having only one yieldin thread actually dispatch @@ -564,7 +566,10 @@ void GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents ) if( osl_tryToAcquireMutex( m_aDispatchMutex ) ) bDispatchThread = true; else if( ! bWait ) + { + blockIdleTimeout = false; return; // someone else is waiting already, return + } if( bDispatchThread ) { @@ -596,6 +601,7 @@ void GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents ) if( bWasEvent ) osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields } + blockIdleTimeout = false; } void GtkData::Init() @@ -822,7 +828,7 @@ extern "C" { if( !pTSource->pInstance ) return FALSE; - SalData *pSalData = GetSalData(); + GtkData *pSalData = static_cast< GtkData* >( GetSalData()); osl::Guard< comphelper::SolarMutex > aGuard( pSalData->m_pInstance->GetYieldMutex() ); @@ -830,7 +836,11 @@ extern "C" { ImplSVData* pSVData = ImplGetSVData(); if( pSVData->mpSalTimer ) - pSVData->mpSalTimer->CallCallback(); + { + // TODO: context_pending should be probably checked too, but it causes locking assertion failures + bool idle = !pSalData->BlockIdleTimeout() && /*!g_main_context_pending( NULL ) &&*/ !gdk_events_pending(); + pSVData->mpSalTimer->CallCallback( idle ); + } return TRUE; } diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx index dc357dd695bc..0b15fbea8dd8 100644 --- a/vcl/unx/kde4/KDEXLib.cxx +++ b/vcl/unx/kde4/KDEXLib.cxx @@ -54,7 +54,7 @@ KDEXLib::KDEXLib() : SalXLib(), m_bStartupDone(false), m_pApplication(0), m_pFreeCmdLineArgs(0), m_pAppCmdLineArgs(0), m_nFakeCmdLineArgs( 0 ), m_frameWidth( -1 ), m_isGlibEventLoopType(false), - m_allowKdeDialogs(false) + m_allowKdeDialogs(false), blockIdleTimeout(false) { // the timers created here means they belong to the main thread. // As the timeoutTimer runs the LO event queue, which may block on a dialog, @@ -309,6 +309,7 @@ void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) void KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents ) { + blockIdleTimeout = !bWait; QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread()); bool wasEvent = false; for( int cnt = bHandleAllCurrentEvents ? 100 : 1; @@ -321,6 +322,7 @@ void KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents ) } if( bWait && !wasEvent ) dispatcher->processEvents( QEventLoop::WaitForMoreEvents ); + blockIdleTimeout = false; } void KDEXLib::StartTimer( sal_uLong nMS ) @@ -360,7 +362,10 @@ void KDEXLib::timeoutActivated() SalKDEDisplay::self()->DispatchInternalEvent(); X11SalData *pData = static_cast<X11SalData*>(ImplGetSVData()->mpSalData); - pData->Timeout(); + // QGuiEventDispatcherGlib makes glib watch also X11 fd, but its hasPendingEvents() + // doesn't check X11, so explicitly check XPending() here. + bool idle = QApplication::hasPendingEvents() && !blockIdleTimeout && !XPending( QX11Info::display()); + pData->Timeout( idle ); // QTimer is not single shot, so will be restarted immediatelly } diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx index 1f2a2dd1f436..0a1aec3f7ea0 100644 --- a/vcl/unx/kde4/KDEXLib.hxx +++ b/vcl/unx/kde4/KDEXLib.hxx @@ -54,6 +54,7 @@ class KDEXLib : public QObject, public SalXLib int m_frameWidth; bool m_isGlibEventLoopType; bool m_allowKdeDialogs; + bool blockIdleTimeout; private: void setupEventLoop(); diff --git a/vcl/win/source/app/saltimer.cxx b/vcl/win/source/app/saltimer.cxx index 9b545a121a37..18f666c66dfa 100644 --- a/vcl/win/source/app/saltimer.cxx +++ b/vcl/win/source/app/saltimer.cxx @@ -147,7 +147,8 @@ void EmitTimerCallback() // try this a short time later again. if (pSVData->mpSalTimer && ImplSalYieldMutexTryToAcquire()) { - pSVData->mpSalTimer->CallCallback(); + bool idle = true; // TODO + pSVData->mpSalTimer->CallCallback( idle ); ImplSalYieldMutexRelease(); // Run the timer in the correct time, if we started this |