KDE update system loop integration

This updates the system loop integration to be on par with the
other backends. This includes:

1. Process LO user events before other LO events
2. Correctly handle elapsed QTimer events
3. Don't wait-yield in the main thread from a non-main thread

Change-Id: Ia17be032ae39dc4c7bfa44cadd22d85a1b9c4fbd
Reviewed-on: https://gerrit.libreoffice.org/43198
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
This commit is contained in:
Jan-Marek Glogowski 2017-10-05 18:19:32 +02:00
parent 53da556c60
commit 0d24dd25e6
8 changed files with 64 additions and 32 deletions

View file

@ -47,7 +47,7 @@ public:
void SendInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent = SalEvent::UserEvent );
void CancelInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent );
bool DispatchInternalEvent();
bool DispatchInternalEvent( bool bHandleAllCurrentEvent = false );
bool MouseCaptured( const SalFrame *pFrameData ) const
{ return m_pCapture == pFrameData; }

View file

@ -179,7 +179,7 @@ public:
virtual void StartTimer( sal_uLong nMS );
virtual void StopTimer();
bool CheckTimeout( bool bExecuteTimers = true );
virtual bool CheckTimeout( bool bExecuteTimers = true );
SalI18N_InputMethod* GetInputMethod() const { return m_pInputMethod; }
Display* GetDisplay() const { return m_pDisplay; }

View file

@ -51,6 +51,7 @@ bool SalUserEventList::DispatchUserEvents( bool bHandleAllCurrentEvents )
{
osl::MutexGuard aGuard( m_aUserEventsMutex );
assert( m_aProcessingUserEvents.empty() );
if( ! m_aUserEvents.empty() )
{
if( bHandleAllCurrentEvents )

View file

@ -47,9 +47,9 @@ void SalGenericDisplay::emitDisplayChanged()
pAnyFrame->CallCallback( SalEvent::DisplayChanged, nullptr );
}
bool SalGenericDisplay::DispatchInternalEvent()
bool SalGenericDisplay::DispatchInternalEvent( bool bHandleAllCurrentEvent )
{
return DispatchUserEvents( false );
return DispatchUserEvents( bHandleAllCurrentEvent );
}
void SalGenericDisplay::SendInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent )

View file

@ -147,7 +147,8 @@ bool X11SalInstance::AnyInput(VclInputFlags nType)
if( (nType & VclInputFlags::TIMER) && (mpXLib && mpXLib->CheckTimeout(false)) )
bRet = true;
else if (XPending(pDisplay) )
if( !bRet && XPending(pDisplay) )
{
PredicateReturn aInput;
XEvent aEvent;

View file

@ -47,9 +47,6 @@ SalKDEDisplay::~SalKDEDisplay()
void SalKDEDisplay::Yield()
{
if( DispatchInternalEvent() )
return;
// Prevent blocking from Drag'n'Drop events, which may have already have processed the event
if (XEventsQueued( pDisp_, QueuedAfterReading ) == 0)
return;

View file

@ -53,6 +53,7 @@ KDEXLib::KDEXLib() :
m_nFakeCmdLineArgs( 0 ),
m_isGlibEventLoopType(false), m_allowKdeDialogs(false),
m_timerEventId( -1 ), m_postUserEventId( -1 )
, m_bTimedOut( false )
{
m_timerEventId = QEvent::registerEventType();
m_postUserEventId = QEvent::registerEventType();
@ -269,22 +270,24 @@ void KDEXLib::socketNotifierActivated( int fd )
bool KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
{
bool bWasEvent = false;
if( !m_isGlibEventLoopType )
{
bool wasEvent = false;
if( qApp->thread() == QThread::currentThread())
{
// even if we use the LO event loop, still process Qt's events,
// otherwise they can remain unhandled for quite a long while
wasEvent = processYield( false, bHandleAllCurrentEvents );
bWasEvent = processYield( false, bHandleAllCurrentEvents );
}
return SalXLib::Yield(bWait, bHandleAllCurrentEvents) || wasEvent;
return SalXLib::Yield(bWait, bHandleAllCurrentEvents) || bWasEvent;
}
// if we are the main thread (which is where the event processing is done),
// good, just do it
if( qApp->thread() == QThread::currentThread())
{
return processYield( bWait, bHandleAllCurrentEvents );
bWasEvent = processYield( bWait, bHandleAllCurrentEvents );
if ( bWasEvent )
m_aWaitingYieldCond.set();
}
else
{
@ -292,23 +295,40 @@ bool KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
// release the yield lock to prevent deadlock with the main thread
// (it's ok to release it here, since even normal processYield() would
// temporarily do it while checking for new events)
SolarMutexReleaser aReleaser;
return Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents );
{
SolarMutexReleaser aReleaser;
bWasEvent = Q_EMIT processYieldSignal( false, bHandleAllCurrentEvents );
}
if ( !bWasEvent && bWait )
{
m_aWaitingYieldCond.reset();
SolarMutexReleaser aReleaser;
m_aWaitingYieldCond.wait();
bWasEvent = true;
}
}
return bWasEvent;
}
/**
* Quoting the Qt docs: [QAbstractEventDispatcher::processEvents] processes
* pending events that match flags until there are no more events to process.
*/
bool KDEXLib::processYield( bool bWait, bool )
bool KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents )
{
QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread());
bool wasEvent = false;
if ( bWait )
if ( m_isGlibEventLoopType )
{
wasEvent = SalKDEDisplay::self()->DispatchInternalEvent( bHandleAllCurrentEvents );
if ( !bHandleAllCurrentEvents && wasEvent )
return true;
}
/**
* Quoting the Qt docs: [QAbstractEventDispatcher::processEvents] processes
* pending events that match flags until there are no more events to process.
*/
QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread());
if ( bWait && !wasEvent )
wasEvent = dispatcher->processEvents( QEventLoop::WaitForMoreEvents );
else
wasEvent = dispatcher->processEvents( QEventLoop::AllEvents );
wasEvent = dispatcher->processEvents( QEventLoop::AllEvents ) || wasEvent;
return wasEvent;
}
@ -336,18 +356,28 @@ void KDEXLib::StopTimer()
timeoutTimer.stop();
}
bool KDEXLib::CheckTimeout( bool bExecuteTimers )
{
if( !m_isGlibEventLoopType )
return SalXLib::CheckTimeout( bExecuteTimers );
assert( !bExecuteTimers );
return m_bTimedOut;
}
void KDEXLib::timeoutActivated()
{
// don't potentially wait in timeout, as QTimer is non-recursive
m_bTimedOut = true;
QApplication::postEvent(this, new QEvent(QEvent::Type( m_timerEventId )));
}
void KDEXLib::customEvent(QEvent* e)
{
if( e->type() == m_timerEventId )
{
m_bTimedOut = false;
X11SalData::Timeout();
else if( e->type() == m_postUserEventId )
SalKDEDisplay::self()->DispatchInternalEvent();
}
}
void KDEXLib::Wakeup()

View file

@ -30,13 +30,14 @@
#include <QtCore/QTimer>
#include <unx/salinst.h>
#include <osl/conditn.hxx>
class VCLKDEApplication;
class KDEXLib : public QObject, public SalXLib
{
Q_OBJECT
private:
bool m_bStartupDone;
std::unique_ptr<VCLKDEApplication> m_pApplication;
std::unique_ptr<char*[]> m_pFreeCmdLineArgs;
@ -56,23 +57,24 @@ class KDEXLib : public QObject, public SalXLib
bool m_allowKdeDialogs;
int m_timerEventId;
int m_postUserEventId;
osl::Condition m_aWaitingYieldCond;
bool m_bTimedOut;
private:
void setupEventLoop();
void setupEventLoop();
private Q_SLOTS:
private Q_SLOTS:
void socketNotifierActivated( int fd );
void timeoutActivated();
void startTimeoutTimer();
static bool processYield( bool bWait, bool bHandleAllCurrentEvents );
bool processYield( bool bWait, bool bHandleAllCurrentEvents );
Q_SIGNALS:
Q_SIGNALS:
void startTimeoutTimerSignal();
bool processYieldSignal( bool bWait, bool bHandleAllCurrentEvents );
css::uno::Reference< css::ui::dialogs::XFilePicker2 >
createFilePickerSignal( const css::uno::Reference< css::uno::XComponentContext >& );
public:
public:
KDEXLib();
virtual ~KDEXLib() override;
@ -82,6 +84,7 @@ class KDEXLib : public QObject, public SalXLib
virtual void Remove( int fd ) override;
virtual void StartTimer( sal_uLong nMS ) override;
virtual void StopTimer() override;
virtual bool CheckTimeout( bool bExecuteTimers = true ) override;
virtual void Wakeup() override;
void TriggerUserEventProcessing();
@ -90,7 +93,7 @@ class KDEXLib : public QObject, public SalXLib
virtual void customEvent(QEvent* e) override;
public Q_SLOTS:
public Q_SLOTS:
css::uno::Reference< css::ui::dialogs::XFilePicker2 >
createFilePicker( const css::uno::Reference< css::uno::XComponentContext >& );
};