[Libreoffice-commits] core.git: 3 commits - include/vcl vcl/headless vcl/inc vcl/osx vcl/source vcl/unx vcl/win
Luboš Luňák
l.lunak at collabora.com
Wed Feb 4 06:45:16 PST 2015
include/vcl/timer.hxx | 5 -
vcl/headless/svpinst.cxx | 5 -
vcl/inc/saltimer.hxx | 4
vcl/inc/salwtype.hxx | 2
vcl/inc/unx/gtk/gtkdata.hxx | 2
vcl/inc/unx/saldata.hxx | 2
vcl/inc/unx/saldisp.hxx | 1
vcl/inc/unx/salframe.h | 1
vcl/osx/salinst.cxx | 3
vcl/osx/salnstimer.mm | 3
vcl/osx/saltimer.cxx | 3
vcl/source/app/svapp.cxx | 4
vcl/source/app/timer.cxx | 4
vcl/unx/generic/app/saldata.cxx | 23 +++++
vcl/unx/generic/app/saltimer.cxx | 4
vcl/unx/generic/window/salframe.cxx | 147 ++++++++++++++++++++++++++++--------
vcl/unx/gtk/app/gtkdata.cxx | 14 ++-
vcl/unx/kde4/KDEXLib.cxx | 9 +-
vcl/unx/kde4/KDEXLib.hxx | 1
vcl/win/source/app/saltimer.cxx | 3
20 files changed, 189 insertions(+), 51 deletions(-)
New commits:
commit fc29d34dc60dda5ddbc8f0444684bd2f4eb3668e
Author: Luboš Luňák <l.lunak at collabora.com>
Date: Wed Feb 4 15:25:03 2015 +0100
discard excessive (X11) autorepeat keyboard events if they overload LO
If e.g. a document is slow to redraw, scrolling it by holding down a key such
as PageDown can make LO lag behind and continue processing the queued up
input events even (long) after the key has been released. Since with autorepeat
keyboard events the normal user expectations are to hold it until something
happens and the exact number of the events doesn't matter, simply discard
excessive autorepeat keyboard events if LO can't keep up with them.
Change-Id: I45acdc9aa5033647fb80760991437dddfcb6591c
diff --git a/vcl/inc/unx/salframe.h b/vcl/inc/unx/salframe.h
index d7ce0c2..af89ba8 100644
--- a/vcl/inc/unx/salframe.h
+++ b/vcl/inc/unx/salframe.h
@@ -77,7 +77,6 @@ class VCLPLUG_GEN_PUBLIC X11SalFrame : public SalFrame, public X11WindowProvider
X11SalGraphics *pGraphics_; // current frame graphics
X11SalGraphics *pFreeGraphics_; // first free frame graphics
- Time nReleaseTime_; // timestamp of last key release
sal_uInt16 nKeyCode_; // last key code
sal_uInt16 nKeyState_; // last key state
int nCompose_; // compose state
diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx
index 9dee672..77e70e7 100644
--- a/vcl/unx/generic/window/salframe.cxx
+++ b/vcl/unx/generic/window/salframe.cxx
@@ -778,7 +778,6 @@ X11SalFrame::X11SalFrame( SalFrame *pParent, sal_uLong nSalFrameStyle,
hCursor_ = None;
nCaptured_ = 0;
- nReleaseTime_ = 0;
nKeyCode_ = 0;
nKeyState_ = 0;
nCompose_ = -1;
@@ -3157,6 +3156,66 @@ bool X11SalFrame::endUnicodeSequence()
long X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
{
+ if( pEvent->type == KeyRelease )
+ {
+ // Ignore autorepeat keyrelease events. If there is a series of keypress+keyrelease+keypress events
+ // generated by holding down a key, and if these are from autorepeat (keyrelease and the following keypress
+ // have the same timestamp), drop the autorepeat keyrelease event. Not exactly sure why this is done
+ // (possibly hiding differences between platforms, or just making it more sensible, because technically
+ // the key has not been released at all).
+ bool ignore = false;
+ // Discard queued excessive autorepeat events.
+ // If the user presses and holds down a key, the autorepeating keypress events
+ // may overload LO (e.g. if the key is PageDown and the LO cannot keep up scrolling).
+ // Reduce the load by simply discarding such excessive events (so for a KeyRelease event,
+ // check if it's followed by matching KeyPress+KeyRelease pair(s) and discard those).
+ // This shouldn't have any negative effects - unlike with normal (non-autorepeat
+ // events), the user is unlikely to rely on the exact number of resulting actions
+ // (since autorepeat generates keypress events rather quickly and it's hard to estimate
+ // how many exactly) and the idea should be just keeping the key pressed until something
+ // happens (in which case more events that just lag LO shouldn't make a difference).
+ Display* dpy = pEvent->display;
+ XKeyEvent previousRelease = *pEvent;
+ while( XPending( dpy ))
+ {
+ XEvent nextEvent1;
+ bool discard1 = false;
+ XNextEvent( dpy, &nextEvent1 );
+ if( nextEvent1.type == KeyPress && nextEvent1.xkey.time == previousRelease.time
+ && !nextEvent1.xkey.send_event && nextEvent1.xkey.window == previousRelease.window
+ && nextEvent1.xkey.state == previousRelease.state && nextEvent1.xkey.keycode == previousRelease.keycode )
+ { // This looks like another autorepeat keypress.
+ ignore = true;
+ if( XPending( dpy ))
+ {
+ XEvent nextEvent2;
+ XNextEvent( dpy, &nextEvent2 );
+ if( nextEvent2.type == KeyRelease && nextEvent2.xkey.time <= ( previousRelease.time + 100 )
+ && !nextEvent2.xkey.send_event && nextEvent2.xkey.window == previousRelease.window
+ && nextEvent2.xkey.state == previousRelease.state && nextEvent2.xkey.keycode == previousRelease.keycode )
+ { // And the matching keyrelease -> drop them both.
+ discard1 = true;
+ previousRelease = nextEvent2.xkey;
+ ignore = false; // There either will be another autorepeating keypress that'll lead to discarding
+ // the pEvent keyrelease, it this discarding makes that keyrelease the last one.
+ }
+ else
+ {
+ XPutBackEvent( dpy, &nextEvent2 );
+ break;
+ }
+ }
+ }
+ if( !discard1 )
+ { // Unrelated event, put back and stop compressing.
+ XPutBackEvent( dpy, &nextEvent1 );
+ break;
+ }
+ }
+ if( ignore ) // This autorepeating keyrelease is followed by another keypress.
+ return 0;
+ }
+
KeySym nKeySym;
KeySym nUnmodifiedKeySym;
int nLen = 2048;
@@ -4019,24 +4078,6 @@ long X11SalFrame::HandleClientMessage( XClientMessageEvent *pEvent )
return 0;
}
-extern "C"
-{
-Bool call_checkKeyReleaseForRepeat( Display* pDisplay, XEvent* pCheck, XPointer pX11SalFrame )
-{
- return X11SalFrame::checkKeyReleaseForRepeat( pDisplay, pCheck, pX11SalFrame );
-}
-}
-
-Bool X11SalFrame::checkKeyReleaseForRepeat( Display*, XEvent* pCheck, XPointer pX11SalFrame )
-{
- X11SalFrame* pThis = reinterpret_cast<X11SalFrame*>(pX11SalFrame);
- return
- pCheck->type == KeyPress &&
- pCheck->xkey.state == pThis->nKeyState_ &&
- pCheck->xkey.keycode == pThis->nKeyCode_ &&
- pCheck->xkey.time == pThis->nReleaseTime_ ? True : False;
-}
-
long X11SalFrame::Dispatch( XEvent *pEvent )
{
long nRet = 0;
@@ -4062,14 +4103,7 @@ long X11SalFrame::Dispatch( XEvent *pEvent )
case KeyRelease:
if( -1 == nCompose_ )
- {
- nReleaseTime_ = pEvent->xkey.time;
- XEvent aEvent;
- if( XCheckIfEvent( pEvent->xkey.display, &aEvent, call_checkKeyReleaseForRepeat, reinterpret_cast<XPointer>(this) ) )
- XPutBackEvent( pEvent->xkey.display, &aEvent );
- else
- nRet = HandleKeyEvent( &pEvent->xkey );
- }
+ nRet = HandleKeyEvent( &pEvent->xkey );
break;
case ButtonPress:
commit 847513d409b146400515d7796d196b8b2a142036
Author: Luboš Luňák <l.lunak at collabora.com>
Date: Mon Feb 2 16:38:18 2015 +0100
compress (X11) mouse wheel events
There is one event per wheel step, so wheeling more can create a number
of wheel events, and LO processed those one by one. If processing one took
long (e.g. the repaint was complicated), the scrolling visibly lagged.
This commit works only for X11 VCL backend (and by extension, KDE3/4 backends).
Change-Id: I5eff7446da16167ec75925e75243314c68bc81a4
diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx
index a018b5b..9dee672 100644
--- a/vcl/unx/generic/window/salframe.cxx
+++ b/vcl/unx/generic/window/salframe.cxx
@@ -2718,6 +2718,51 @@ void X11SalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
vcl_sal::getSalDisplay(GetGenericData())->SimulateKeyPress(nKeyCode);
}
+namespace
+{
+struct CompressWheelEventsData
+{
+ XEvent* firstEvent;
+ bool ignore;
+ int count; // number of compressed events
+};
+
+static Bool compressWheelEvents( Display*, XEvent* event, XPointer p )
+{
+ CompressWheelEventsData* data = reinterpret_cast< CompressWheelEventsData* >( p );
+ if( data->ignore )
+ return False; // we're already after the events to compress
+ if( event->type == ButtonPress || event->type == ButtonRelease )
+ {
+ const unsigned int mask = Button1Mask << ( event->xbutton.button - Button1 );
+ if( event->xbutton.button == data->firstEvent->xbutton.button
+ && event->xbutton.window == data->firstEvent->xbutton.window
+ && event->xbutton.x == data->firstEvent->xbutton.x
+ && event->xbutton.y == data->firstEvent->xbutton.y
+ && ( event->xbutton.state | mask ) == ( data->firstEvent->xbutton.state | mask ))
+ {
+ // Count if it's another press (i.e. wheel start event).
+ if( event->type == ButtonPress )
+ ++data->count;
+ return True; // And remove the event from the queue.
+ }
+ }
+ // Non-matching event, skip certain events that cannot possibly affect input processing,
+ // but otherwise ignore all further events.
+ switch( event->type )
+ {
+ case Expose:
+ case NoExpose:
+ break;
+ default:
+ data->ignore = true;
+ break;
+ }
+ return False;
+}
+
+} // namespace
+
long X11SalFrame::HandleMouseEvent( XEvent *pEvent )
{
SalMouseEvent aMouseEvt = {0, 0, 0, 0, 0};
@@ -2936,13 +2981,23 @@ long X11SalFrame::HandleMouseEvent( XEvent *pEvent )
nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
}
+ // Compress consecutive wheel events (way too fine scrolling may cause lags if one scrolling steps takes long).
+ CompressWheelEventsData data;
+ data.firstEvent = pEvent;
+ data.count = 1;
+ XEvent dummy;
+ do
+ {
+ data.ignore = false;
+ } while( XCheckIfEvent( pEvent->xany.display, &dummy, compressWheelEvents, reinterpret_cast< XPointer >( &data )));
+
SalWheelMouseEvent aWheelEvt;
aWheelEvt.mnTime = pEvent->xbutton.time;
aWheelEvt.mnX = pEvent->xbutton.x;
aWheelEvt.mnY = pEvent->xbutton.y;
- aWheelEvt.mnDelta = bIncrement ? 120 : -120;
+ aWheelEvt.mnDelta = ( bIncrement ? 120 : -120 ) * data.count;
aWheelEvt.mnNotchDelta = bIncrement ? 1 : -1;
- aWheelEvt.mnScrollLines = nLines;
+ aWheelEvt.mnScrollLines = nLines * data.count;
aWheelEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
aWheelEvt.mbHorz = bHoriz;
commit 06d731428ef6cf93c7333e8228bfb6088853b52f
Author: Luboš Luňák <l.lunak at collabora.com>
Date: Sat Jan 31 17:40:48 2015 +0100
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
diff --git a/include/vcl/timer.hxx b/include/vcl/timer.hxx
index 8da2381..d93e7c0 100644
--- a/include/vcl/timer.hxx
+++ b/include/vcl/timer.hxx
@@ -61,8 +61,11 @@ public:
Timer& operator=( const Timer& rTimer );
+ /// @internal
static void ImplDeInitTimer();
- static void ImplTimerCallbackProc();
+ /// @internal
+ /// @p idle - allow also idle timers
+ static void ImplTimerCallbackProc( bool idle );
/// Process all pending idle tasks ahead of time in priority order.
static void ProcessAllIdleHandlers();
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
index 1325e3f..7523dfd 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 3bdfbc3..1e1a941 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 8055813..7a14df0 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 9c2c76e..e270204 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 2c58231..0dba4c9 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 63b8bae..aa63565 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 a531dbd..91bfa14 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 bad2f4e..fe0e907 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 17c4d80..6c83af7 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 19890e7..e393978 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 529c8b5..5742191 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 317c16e..2a90eb7 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 19b4495..fc55afb 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 8e20f62..cdbfd0a 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 dc357dd..0b15fbe 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 1f2a2dd..0a1aec3 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 9b545a1..18f666c 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
More information about the Libreoffice-commits
mailing list