summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2015-01-31 17:40:48 +0100
committerLuboš Luňák <l.lunak@collabora.com>2015-02-04 15:44:09 +0100
commit06d731428ef6cf93c7333e8228bfb6088853b52f (patch)
treedbdcbed014fdbc7f1369e888a5903e493b3aabcb /vcl
parente6a58b5e69b83e01b5291b1d8629927e05447797 (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.cxx5
-rw-r--r--vcl/inc/saltimer.hxx4
-rw-r--r--vcl/inc/salwtype.hxx2
-rw-r--r--vcl/inc/unx/gtk/gtkdata.hxx2
-rw-r--r--vcl/inc/unx/saldata.hxx2
-rw-r--r--vcl/inc/unx/saldisp.hxx1
-rw-r--r--vcl/osx/salinst.cxx3
-rw-r--r--vcl/osx/salnstimer.mm3
-rw-r--r--vcl/osx/saltimer.cxx3
-rw-r--r--vcl/source/app/svapp.cxx4
-rw-r--r--vcl/source/app/timer.cxx4
-rw-r--r--vcl/unx/generic/app/saldata.cxx23
-rw-r--r--vcl/unx/generic/app/saltimer.cxx4
-rw-r--r--vcl/unx/gtk/app/gtkdata.cxx14
-rw-r--r--vcl/unx/kde4/KDEXLib.cxx9
-rw-r--r--vcl/unx/kde4/KDEXLib.hxx1
-rw-r--r--vcl/win/source/app/saltimer.cxx3
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