[Libreoffice-commits] core.git: 6 commits - configure.ac vcl/CustomTarget_kde4_moc.mk vcl/Library_vclplug_kde4.mk vcl/unx

Jan-Marek Glogowski glogow at fbihome.de
Fri Mar 14 15:47:24 PDT 2014


 configure.ac                                  |   51 +++++++++-
 vcl/CustomTarget_kde4_moc.mk                  |    3 
 vcl/Library_vclplug_kde4.mk                   |    2 
 vcl/unx/kde4/KDE4FilePicker.cxx               |   15 +--
 vcl/unx/kde4/KDE4FilePicker.hxx               |    5 -
 vcl/unx/kde4/KDEData.cxx                      |    2 
 vcl/unx/kde4/KDESalDisplay.cxx                |   24 +---
 vcl/unx/kde4/KDESalInstance.cxx               |   10 +-
 vcl/unx/kde4/KDEXLib.cxx                      |  104 ++++++++-------------
 vcl/unx/kde4/KDEXLib.hxx                      |    6 -
 vcl/unx/kde4/tst_exclude_socket_notifiers.hxx |  126 ++++++++++++++++++++++++++
 11 files changed, 242 insertions(+), 106 deletions(-)

New commits:
commit 6c7374f071d998f726cd4a5b67baf54e357d096b
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Fri Mar 14 21:02:16 2014 +0100

    KDE4: prevent blocking in Display::Yield
    
    SalX11Display registers a Yield handler, which splits check and
    and processing into two functions, which both lock the yield mutex.
    
    Normally this no problem, but during a Drag'n'Drop operation the
    D'n'D thread also checks and processes XEvents (for D'n'D). So the
    XNextEvent in Display::Yield will actually block, if the seen XEvent
    was for D'n'D and was already processed.
    
    Change-Id: I9f8d96d4f9986997cbe150a2b66bc767b4bbc2f1

diff --git a/vcl/unx/kde4/KDESalDisplay.cxx b/vcl/unx/kde4/KDESalDisplay.cxx
index 21440fc..650b266 100644
--- a/vcl/unx/kde4/KDESalDisplay.cxx
+++ b/vcl/unx/kde4/KDESalDisplay.cxx
@@ -51,6 +51,10 @@ 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;
+
     DBG_ASSERT( static_cast<SalYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())->GetThreadId() ==
                 osl::Thread::getCurrentIdentifier(),
                 "will crash soon since solar mutex not locked in SalKDEDisplay::Yield" );
commit cc8d566d74a2e0b969b92d9cf22cc95a3bf31a98
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Mar 10 15:05:22 2014 +0000

    KDE4: add Qt4 glib ExcludeSocket runtime check
    
    Add a runtime check and configure warning to disable KDE4 native
    file pickers, if the Qt4 glib dispatcher doesn't honor the
    QEventLoop::ExcludeSocketNotifiers flag.
    
    This way polling the QClipboard using the event loop won't
    crash LibreOffice with recursive paint events,
    
    See https://bugreports.qt-project.org/browse/QTBUG-37380
    
    Change-Id: I5cad30ead74571e49a075c084cca7a19acff7523

diff --git a/configure.ac b/configure.ac
index 92ca7dd..cbe3f3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11050,7 +11050,7 @@ if test "$test_kde4" = "yes" -a "$ENABLE_KDE4" = "TRUE"; then
     fi
 
     qt_test_include="Qt/qobject.h"
-    qt_test_library="libQtCore.so"
+    qt_test_library="libQtNetwork.so"
     kde_test_include="kwindowsystem.h"
     kde_test_library="libsolid.so"
 
@@ -11137,8 +11137,9 @@ the root of your Qt installation by exporting QT4DIR before running "configure".
         AC_MSG_ERROR([KDE4 libraries not found.  Please specify the root of your KDE4 installation by exporting KDE4DIR before running "configure".])
     fi
 
-    KDE4_CFLAGS="`pkg-config --cflags QtCore` `pkg-config --cflags QtGui` -I$kde_incdir -DQT_CLEAN_NAMESPACE -DQT_THREAD_SUPPORT"
-    KDE4_LIBS="-L$kde_libdir -L$qt_lib_dir -lkio -lkfile -lkdeui -lkdecore -lQtCore -lQtGui"
+    PKG_CHECK_MODULES([QT4],[QtNetwork QtGui])
+    KDE4_CFLAGS="-I$kde_incdir $QT4_CFLAGS -DQT_CLEAN_NAMESPACE -DQT_THREAD_SUPPORT"
+    KDE4_LIBS="-L$kde_libdir -lkio -lkfile -lkdeui -lkdecore -L$qt_lib_dir $QT4_LIBS"
     KDE4_CFLAGS=$(printf '%s' "$KDE4_CFLAGS" | sed -e "s/-I/${ISYSTEM?}/g")
 
     AC_LANG_PUSH([C++])
@@ -11160,11 +11161,47 @@ int main(int argc, char **argv) {
     # Sets also KDE_GLIB_CFLAGS/KDE_GLIB_LIBS if successful.
     PKG_CHECK_MODULES(KDE_GLIB,[glib-2.0 >= 2.4],
         [
-        KDE_HAVE_GLIB=1
-        AC_DEFINE(KDE_HAVE_GLIB,1)
-        KDE_GLIB_CFLAGS=$(printf '%s' "$KDE_GLIB_CFLAGS" | sed -e "s/-I/${ISYSTEM?}/g")
+            KDE_HAVE_GLIB=1
+            AC_DEFINE(KDE_HAVE_GLIB,1)
+            KDE_GLIB_CFLAGS=$(printf '%s' "$KDE_GLIB_CFLAGS" | sed -e "s/-I/${ISYSTEM?}/g")
+
+            AC_LANG_PUSH([C++])
+            save_CXXFLAGS=$CXXFLAGS
+            CXXFLAGS="$CXXFLAGS $KDE4_CFLAGS"
+            save_LIBS=$LIBS
+            LIBS="$LIBS $KDE4_LIBS"
+            AC_MSG_CHECKING([whether Qt has fixed ExcludeSocketNotifiers])
+
+            # Prepare meta object data
+            TSTBASE="tst_exclude_socket_notifiers"
+            TSTMOC="${SRC_ROOT}/vcl/unx/kde4/${TSTBASE}"
+            ln -fs "${TSTMOC}.hxx"
+            $MOC4 "${TSTBASE}.hxx" -o "${TSTBASE}.moc"
+
+            AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include "tst_exclude_socket_notifiers.moc"
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication app(argc, argv);
+    exit(tst_processEventsExcludeSocket());
+    return 0;
+}
+            ]])],[
+                AC_MSG_RESULT([yes])
+            ],[
+                AC_MSG_RESULT([no])
+                AC_MSG_WARN([native KDE4 file pickers will be disabled at runtime - fix your Qt4 library!])
+            ])
+
+            # Remove meta object data
+            rm -f "${TSTBASE}."*
+
+            LIBS=$save_LIBS
+            CXXFLAGS=$save_CXXFLAGS
+            AC_LANG_POP([C++])
         ],
-        AC_MSG_WARN([[No Glib found, KDE4 support will not integrate with Qt's Glib event loop support]]))
+        AC_MSG_WARN([[No Glib found, KDE4 support will not use native file pickers!]]))
 fi
 AC_SUBST(KDE4_CFLAGS)
 AC_SUBST(KDE4_LIBS)
diff --git a/vcl/CustomTarget_kde4_moc.mk b/vcl/CustomTarget_kde4_moc.mk
index 0846b0b..9e41754 100644
--- a/vcl/CustomTarget_kde4_moc.mk
+++ b/vcl/CustomTarget_kde4_moc.mk
@@ -11,7 +11,8 @@ $(eval $(call gb_CustomTarget_CustomTarget,vcl/unx/kde4))
 
 $(call gb_CustomTarget_get_target,vcl/unx/kde4) : \
 	$(call gb_CustomTarget_get_workdir,vcl/unx/kde4)/KDEXLib.moc \
-	$(call gb_CustomTarget_get_workdir,vcl/unx/kde4)/KDE4FilePicker.moc
+	$(call gb_CustomTarget_get_workdir,vcl/unx/kde4)/KDE4FilePicker.moc \
+	$(call gb_CustomTarget_get_workdir,vcl/unx/kde4)/tst_exclude_socket_notifiers.moc
 
 $(call gb_CustomTarget_get_workdir,vcl/unx/kde4)/%.moc : \
 		$(SRCDIR)/vcl/unx/kde4/%.hxx \
diff --git a/vcl/Library_vclplug_kde4.mk b/vcl/Library_vclplug_kde4.mk
index c72fe00..18ffa02 100644
--- a/vcl/Library_vclplug_kde4.mk
+++ b/vcl/Library_vclplug_kde4.mk
@@ -76,7 +76,7 @@ endif
 
 $(eval $(call gb_Library_add_exception_objects,vclplug_kde4,\
     vcl/unx/kde4/KDEData \
-	vcl/unx/kde4/KDE4FilePicker \
+    vcl/unx/kde4/KDE4FilePicker \
     vcl/unx/kde4/KDESalDisplay \
     vcl/unx/kde4/KDESalFrame \
     vcl/unx/kde4/KDESalGraphics \
diff --git a/vcl/unx/kde4/KDE4FilePicker.cxx b/vcl/unx/kde4/KDE4FilePicker.cxx
index 467e8d8..4f819fb 100644
--- a/vcl/unx/kde4/KDE4FilePicker.cxx
+++ b/vcl/unx/kde4/KDE4FilePicker.cxx
@@ -261,8 +261,12 @@ sal_Int16 SAL_CALL KDE4FilePicker::execute()
     _dialog->filterWidget()->setEditable(false);
 
     // We're entering a nested loop.
-    // Release the yield mutex to prevent deadlocks.
-    int result = _dialog->exec();
+    int result;
+    {
+        // Release the yield mutex to prevent deadlocks.
+        SalYieldMutexReleaser aReleaser;
+        result = _dialog->exec();
+    }
 
     // HACK: KFileDialog uses KConfig("kdeglobals") for saving some settings
     // (such as the auto-extension flag), but that doesn't update KGlobal::config()
diff --git a/vcl/unx/kde4/KDEData.cxx b/vcl/unx/kde4/KDEData.cxx
index ccbbd99..0e87c62 100644
--- a/vcl/unx/kde4/KDEData.cxx
+++ b/vcl/unx/kde4/KDEData.cxx
@@ -27,6 +27,7 @@
 #include "KDEData.hxx"
 
 #include "KDEXLib.hxx"
+#include "KDESalDisplay.hxx"
 
 
 KDEData::~KDEData()
@@ -37,6 +38,7 @@ void KDEData::Init()
 {
     pXLib_ = new KDEXLib();
     pXLib_->Init();
+    SetDisplay( SalKDEDisplay::self() );
 }
 
 void KDEData::initNWF()
diff --git a/vcl/unx/kde4/KDESalInstance.cxx b/vcl/unx/kde4/KDESalInstance.cxx
index 9670172..023d790 100644
--- a/vcl/unx/kde4/KDESalInstance.cxx
+++ b/vcl/unx/kde4/KDESalInstance.cxx
@@ -32,10 +32,14 @@ SalFrame* KDESalInstance::CreateFrame( SalFrame *pParent, sal_uLong nState )
 }
 
 uno::Reference< ui::dialogs::XFilePicker2 > KDESalInstance::createFilePicker(
-        const uno::Reference< uno::XComponentContext >& xMSF )
+    const uno::Reference< uno::XComponentContext >& xMSF )
 {
-    return uno::Reference< ui::dialogs::XFilePicker2 >(
-        static_cast<KDEXLib*>( mpXLib )->createFilePicker(xMSF) );
+    KDEXLib* kdeXLib = static_cast<KDEXLib*>( mpXLib );
+    if (kdeXLib->haveQt4SocketExcludeFix())
+        return uno::Reference< ui::dialogs::XFilePicker2 >(
+            kdeXLib->createFilePicker(xMSF) );
+    else
+        return X11SalInstance::createFilePicker( xMSF );
 }
 
 int KDESalInstance::getFrameWidth()
diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx
index 5c4cd10..820d39a 100644
--- a/vcl/unx/kde4/KDEXLib.cxx
+++ b/vcl/unx/kde4/KDEXLib.cxx
@@ -19,7 +19,6 @@
 
 #include "VCLKDEApplication.hxx"
 
-#include "KDE4FilePicker.hxx"
 #include "KDESalInstance.hxx"
 
 #include <kapplication.h>
@@ -45,15 +44,17 @@
 
 #include <config_kde4.h>
 
+#if KDE_HAVE_GLIB
+#include "KDE4FilePicker.hxx"
+#include "tst_exclude_socket_notifiers.moc"
+#endif
+
 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_frameWidth( -1 ), m_isGlibEventLoopType(false),
+    m_haveQt4SocketExcludeFix(false)
 {
-#if KDE_HAVE_GLIB
-    m_isGlibEventLoopType = QAbstractEventDispatcher::instance()->inherits( "QEventDispatcherGlib" );
-#endif
-
     // 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,
     // the timer has to use a Qt::QueuedConnection, otherwise the nested event
@@ -168,6 +169,14 @@ void KDEXLib::Init()
     m_pApplication = new VCLKDEApplication();
     kapp->disableSessionManagement();
     KApplication::setQuitOnLastWindowClosed(false);
+
+#if KDE_HAVE_GLIB
+    m_isGlibEventLoopType = QAbstractEventDispatcher::instance()->inherits( "QEventDispatcherGlib" );
+    if (m_isGlibEventLoopType && (0 == tst_processEventsExcludeSocket()))
+        // See http://bugreports.qt.nokia.com/browse/QTBUG-37380
+        m_haveQt4SocketExcludeFix = true;
+#endif
+
     setupEventLoop();
 
     Display* pDisp = QX11Info::display();
@@ -188,9 +197,8 @@ void KDEXLib::Init()
 #include <glib.h>
 
 static GPollFunc old_gpoll = NULL;
-static gint gpoll_wrapper( GPollFD*, guint, gint );
 
-gint gpoll_wrapper( GPollFD* ufds, guint nfds, gint timeout )
+static gint gpoll_wrapper( GPollFD* ufds, guint nfds, gint timeout )
 {
     SalYieldMutexReleaser release; // release YieldMutex (and re-acquire at block end)
     return old_gpoll( ufds, nfds, timeout );
@@ -215,6 +223,8 @@ void KDEXLib::setupEventLoop()
     {
         old_gpoll = g_main_context_get_poll_func( NULL );
         g_main_context_set_poll_func( NULL, gpoll_wrapper );
+        if( m_haveQt4SocketExcludeFix )
+            m_pApplication->clipboard()->setProperty( "useEventLoopWhenWaiting", true );
         return;
     }
 #endif
@@ -367,11 +377,15 @@ using namespace com::sun::star;
 uno::Reference< ui::dialogs::XFilePicker2 > KDEXLib::createFilePicker(
         const uno::Reference< uno::XComponentContext >& xMSF )
 {
+#if KDE_HAVE_GLIB
     if( qApp->thread() != QThread::currentThread()) {
         SalYieldMutexReleaser aReleaser;
         return Q_EMIT createFilePickerSignal( xMSF );
     }
     return uno::Reference< ui::dialogs::XFilePicker2 >( new KDE4FilePicker( xMSF ) );
+#else
+    return NULL;
+#endif
 }
 
 #define Region QtXRegion
diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx
index f26948d..a88258c 100644
--- a/vcl/unx/kde4/KDEXLib.hxx
+++ b/vcl/unx/kde4/KDEXLib.hxx
@@ -53,6 +53,7 @@ class KDEXLib : public QObject, public SalXLib
         QTimer userEventTimer;
         int m_frameWidth;
         bool m_isGlibEventLoopType;
+        bool m_haveQt4SocketExcludeFix;
 
     private:
         void setupEventLoop();
@@ -87,6 +88,7 @@ class KDEXLib : public QObject, public SalXLib
         virtual void PostUserEvent();
 
         void doStartup();
+        bool haveQt4SocketExcludeFix() { return m_haveQt4SocketExcludeFix; }
 
     public Q_SLOTS:
         com::sun::star::uno::Reference< com::sun::star::ui::dialogs::XFilePicker2 >
diff --git a/vcl/unx/kde4/tst_exclude_socket_notifiers.hxx b/vcl/unx/kde4/tst_exclude_socket_notifiers.hxx
new file mode 100644
index 0000000..0c874fd
--- /dev/null
+++ b/vcl/unx/kde4/tst_exclude_socket_notifiers.hxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ *
+ * This code is based on the SocketEventsTester from the Qt4 test suite.
+ */
+
+#pragma once
+
+#include <qcoreapplication.h>
+#include <qeventloop.h>
+#include <qthread.h>
+#include <qtimer.h>
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qtcpsocket.h>
+
+class SocketEventsTester: public QObject
+{
+    Q_OBJECT
+public:
+    SocketEventsTester()
+    {
+        socket = 0;
+        server = 0;
+        dataSent = false;
+        testResult = false;
+        dataArrived = false;
+    }
+    ~SocketEventsTester()
+    {
+        delete socket;
+        delete server;
+    }
+    bool init()
+    {
+        bool ret = false;
+        server = new QTcpServer();
+        socket = new QTcpSocket();
+        connect(server, SIGNAL(newConnection()), this, SLOT(sendHello()));
+        connect(socket, SIGNAL(readyRead()), this, SLOT(sendAck()), Qt::DirectConnection);
+        if((ret = server->listen(QHostAddress::LocalHost, 0))) {
+            socket->connectToHost(server->serverAddress(), server->serverPort());
+            socket->waitForConnected();
+        }
+        return ret;
+    }
+
+    QTcpSocket *socket;
+    QTcpServer *server;
+    bool dataSent;
+    bool testResult;
+    bool dataArrived;
+public slots:
+    void sendAck()
+    {
+        dataArrived = true;
+    }
+    void sendHello()
+    {
+        char data[10] ="HELLO";
+        qint64 size = sizeof(data);
+
+        QTcpSocket *serverSocket = server->nextPendingConnection();
+        serverSocket->write(data, size);
+        dataSent = serverSocket->waitForBytesWritten(-1);
+        QEventLoop loop;
+        //allow the TCP/IP stack time to loopback the data, so our socket is ready to read
+        QTimer::singleShot(200, &loop, SLOT(quit()));
+        loop.exec(QEventLoop::ExcludeSocketNotifiers);
+        testResult = dataArrived;
+        //check the deferred event is processed
+        QTimer::singleShot(200, &loop, SLOT(quit()));
+        loop.exec();
+        serverSocket->close();
+        QThread::currentThread()->exit(0);
+    }
+};
+
+class SocketTestThread : public QThread
+{
+    Q_OBJECT
+public:
+    SocketTestThread():QThread(0),testResult(false){};
+    void run()
+    {
+        SocketEventsTester *tester = new SocketEventsTester();
+        if (tester->init())
+            exec();
+        dataSent = tester->dataSent;
+        testResult = tester->testResult;
+        dataArrived = tester->dataArrived;
+        delete tester;
+    }
+    bool dataSent;
+    bool testResult;
+    bool dataArrived;
+};
+
+#define QVERIFY(a) \
+    if (!a) return 1;
+
+static int tst_processEventsExcludeSocket()
+{
+    SocketTestThread thread;
+    thread.start();
+    QVERIFY(thread.wait());
+    QVERIFY(thread.dataSent);
+    QVERIFY(!thread.testResult);
+    QVERIFY(thread.dataArrived);
+    return 0;
+}
+
commit 516a8dedac9c3cb77cd26a740cf793b1cab920d0
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Fri Mar 14 15:16:11 2014 +0100

    KDE4: change eventLoopType enum to glib bool
    
    Just check for glib; it's the default in later Qt4 versions on unix.
    
    Change-Id: Ia99466e9010eb835bea0c3c4420da3c8b3cd4671

diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx
index e936c69..5c4cd10 100644
--- a/vcl/unx/kde4/KDEXLib.cxx
+++ b/vcl/unx/kde4/KDEXLib.cxx
@@ -45,21 +45,15 @@
 
 #include <config_kde4.h>
 
-#if KDE_HAVE_GLIB
-#define GLIB_EVENT_LOOP_SUPPORT 1
-#else
-#define GLIB_EVENT_LOOP_SUPPORT 0
-#endif
-
-#if GLIB_EVENT_LOOP_SUPPORT
-#include <glib-2.0/glib.h>
-#endif
-
 KDEXLib::KDEXLib() :
     SalXLib(),  m_bStartupDone(false), m_pApplication(0),
     m_pFreeCmdLineArgs(0), m_pAppCmdLineArgs(0), m_nFakeCmdLineArgs( 0 ),
-    eventLoopType( LibreOfficeEventLoop ), m_frameWidth( -1 )
+    m_frameWidth( -1 ), m_isGlibEventLoopType(false)
 {
+#if KDE_HAVE_GLIB
+    m_isGlibEventLoopType = QAbstractEventDispatcher::instance()->inherits( "QEventDispatcherGlib" );
+#endif
+
     // 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,
     // the timer has to use a Qt::QueuedConnection, otherwise the nested event
@@ -190,9 +184,17 @@ void KDEXLib::Init()
 // needs to be unlocked shortly before entering the main sleep (e.g. select()) and locked
 // immediatelly after. So we need to know which event loop implementation is used and
 // hook accordingly.
-#if GLIB_EVENT_LOOP_SUPPORT
+#if KDE_HAVE_GLIB
+#include <glib.h>
+
 static GPollFunc old_gpoll = NULL;
 static gint gpoll_wrapper( GPollFD*, guint, gint );
+
+gint gpoll_wrapper( GPollFD* ufds, guint nfds, gint timeout )
+{
+    SalYieldMutexReleaser release; // release YieldMutex (and re-acquire at block end)
+    return old_gpoll( ufds, nfds, timeout );
+}
 #endif
 
 static bool ( *old_qt_event_filter )( void* );
@@ -208,35 +210,19 @@ static bool qt_event_filter( void* m )
 void KDEXLib::setupEventLoop()
 {
     old_qt_event_filter = QAbstractEventDispatcher::instance()->setEventFilter( qt_event_filter );
-#if GLIB_EVENT_LOOP_SUPPORT
-// Glib is simple, it has g_main_context_set_poll_func() for wrapping the sleep call.
-// The catch is that Qt has a bug that allows triggering timers even when they should
-// not be, leading to crashes caused by QClipboard re-entering the event loop.
-// (http://bugreports.qt.nokia.com/browse/QTBUG-14461), so enable only with Qt>=4.8.0,
-// where it is fixed.
-#if QT_VERSION >= QT_VERSION_CHECK( 4, 8, 0 )
-    if( QAbstractEventDispatcher::instance()->inherits( "QEventDispatcherGlib" ))
+#if KDE_HAVE_GLIB
+    if( m_isGlibEventLoopType )
     {
-        eventLoopType = GlibEventLoop;
         old_gpoll = g_main_context_get_poll_func( NULL );
         g_main_context_set_poll_func( NULL, gpoll_wrapper );
         return;
     }
 #endif
-#endif
-}
-
-#if GLIB_EVENT_LOOP_SUPPORT
-gint gpoll_wrapper( GPollFD* ufds, guint nfds, gint timeout )
-{
-    SalYieldMutexReleaser release; // release YieldMutex (and re-acquire at block end)
-    return old_gpoll( ufds, nfds, timeout );
 }
-#endif
 
 void KDEXLib::Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, YieldFunc handle )
 {
-    if( eventLoopType == LibreOfficeEventLoop )
+    if( !m_isGlibEventLoopType )
         return SalXLib::Insert( fd, data, pending, queued, handle );
     SocketData sdata;
     sdata.data = data;
@@ -251,7 +237,7 @@ void KDEXLib::Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, Y
 
 void KDEXLib::Remove( int fd )
 {
-    if( eventLoopType == LibreOfficeEventLoop )
+    if( !m_isGlibEventLoopType )
         return SalXLib::Remove( fd );
     SocketData sdata = socketData.take( fd );// according to SalXLib::Remove() this should be safe
     delete sdata.notifier;
@@ -265,7 +251,7 @@ void KDEXLib::socketNotifierActivated( int fd )
 
 void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
 {
-    if( eventLoopType == LibreOfficeEventLoop )
+    if( !m_isGlibEventLoopType )
     {
         if( qApp->thread() == QThread::currentThread())
         {
@@ -307,7 +293,7 @@ void KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents )
 
 void KDEXLib::StartTimer( sal_uLong nMS )
 {
-    if( eventLoopType == LibreOfficeEventLoop )
+    if( !m_isGlibEventLoopType )
         return SalXLib::StartTimer( nMS );
     timeoutTimer.setInterval( nMS );
     // QTimer's can be started only in their thread (main thread here)
@@ -324,7 +310,7 @@ void KDEXLib::startTimeoutTimer()
 
 void KDEXLib::StopTimer()
 {
-    if( eventLoopType == LibreOfficeEventLoop )
+    if( !m_isGlibEventLoopType )
         return SalXLib::StopTimer();
     timeoutTimer.stop();
 }
@@ -338,14 +324,14 @@ void KDEXLib::timeoutActivated()
 
 void KDEXLib::Wakeup()
 {
-    if( eventLoopType == LibreOfficeEventLoop )
+    if( !m_isGlibEventLoopType )
         return SalXLib::Wakeup();
     QAbstractEventDispatcher::instance( qApp->thread())->wakeUp(); // main thread event loop
 }
 
 void KDEXLib::PostUserEvent()
 {
-    if( eventLoopType == LibreOfficeEventLoop )
+    if( !m_isGlibEventLoopType )
         return SalXLib::PostUserEvent();
     if( qApp->thread() == QThread::currentThread())
         startUserEventTimer();
diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx
index 1d307a0..f26948d 100644
--- a/vcl/unx/kde4/KDEXLib.hxx
+++ b/vcl/unx/kde4/KDEXLib.hxx
@@ -51,8 +51,8 @@ class KDEXLib : public QObject, public SalXLib
         QHash< int, SocketData > socketData; // key is fd
         QTimer timeoutTimer;
         QTimer userEventTimer;
-        enum { LibreOfficeEventLoop, GlibEventLoop, QtUnixEventLoop } eventLoopType;
         int m_frameWidth;
+        bool m_isGlibEventLoopType;
 
     private:
         void setupEventLoop();
commit daf011870efae282244c0298494820d9a0c6d3bc
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Thu Mar 13 21:55:31 2014 +0100

    Revert "Rewrite Qt4 based nested yield mutex locking."
    
    This reverts the unx/kde4/KDEXLib.cxx part of
    
    commit 13a34f4c6307d1bd2443cbf3fbd83bfdd8cdbafb.
    
    Conflicts:
    
    	vcl/unx/kde4/KDE4FilePicker.cxx
    	vcl/unx/kde4/KDEXLib.cxx
    
    Change-Id: Ica8a0f678f080ae7d763bb7da7761d20ceec328c

diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx
index a31c7e0..e936c69 100644
--- a/vcl/unx/kde4/KDEXLib.cxx
+++ b/vcl/unx/kde4/KDEXLib.cxx
@@ -265,9 +265,6 @@ void KDEXLib::socketNotifierActivated( int fd )
 
 void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
 {
-    // Nested yield loop counter.
-    static int loop_depth = 0;
-
     if( eventLoopType == LibreOfficeEventLoop )
     {
         if( qApp->thread() == QThread::currentThread())
@@ -281,21 +278,13 @@ void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
 
     // if we are the main thread (which is where the event processing is done),
     // good, just do it
-    if( qApp->thread() == QThread::currentThread()) {
-        // Release the yield lock before entering a nested loop.
-        if (loop_depth > 0)
-            SalYieldMutexReleaser aReleaser;
-        loop_depth++;
+    if( qApp->thread() == QThread::currentThread())
         processYield( bWait, bHandleAllCurrentEvents );
-        loop_depth--;
-    }
-    else {
+    else
+    {
         // we were called from another thread;
         // release the yield lock to prevent deadlock.
         SalYieldMutexReleaser aReleaser;
-
-        // if this deadlocks, event processing needs to go into a separate
-        // thread or some other solution needs to be found
         Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents );
     }
 }
commit 69e7f4491ec78384c46653d3cd8870c97cc9218a
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Mar 10 14:54:58 2014 +0000

    Revert "fdo#67011: Run Display::Yield through KDEXLib::Yield."
    
    This reverts commit 95f60222e75486336b6569afa8f34d60b51c94ad.

diff --git a/vcl/unx/kde4/KDESalDisplay.cxx b/vcl/unx/kde4/KDESalDisplay.cxx
index ee330e7..21440fc 100644
--- a/vcl/unx/kde4/KDESalDisplay.cxx
+++ b/vcl/unx/kde4/KDESalDisplay.cxx
@@ -25,8 +25,6 @@
 #include <assert.h>
 #include <unx/saldata.hxx>
 
-#include <qthread.h>
-
 SalKDEDisplay* SalKDEDisplay::selfptr = NULL;
 
 SalKDEDisplay::SalKDEDisplay( Display* pDisp )
@@ -50,26 +48,18 @@ SalKDEDisplay::~SalKDEDisplay()
 
 void SalKDEDisplay::Yield()
 {
-    // We yield the display throught the main Qt thread.
-    // Actually this Yield may call the Display::Yield, which results in an
-    // unlimited cycle.
-    static bool break_cyclic_yield_recursion = false;
-    bool is_qt_gui_thread = ( qApp->thread() == QThread::currentThread() );
-
-    if( DispatchInternalEvent() || break_cyclic_yield_recursion )
+    if( DispatchInternalEvent() )
         return;
 
-    if( is_qt_gui_thread )
-        break_cyclic_yield_recursion = true;
-
     DBG_ASSERT( static_cast<SalYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())->GetThreadId() ==
                 osl::Thread::getCurrentIdentifier(),
                 "will crash soon since solar mutex not locked in SalKDEDisplay::Yield" );
 
-    static_cast<KDEXLib*>(GetXLib())->Yield( true, false );
-
-    if( is_qt_gui_thread )
-        break_cyclic_yield_recursion = false;
+    XEvent event;
+    XNextEvent( pDisp_, &event );
+    if( checkDirectInputEvent( &event ))
+        return;
+    qApp->x11ProcessEvent( &event );
 }
 
 // HACK: When using Qt event loop, input methods (japanese, etc.) will get broken because
commit 52a2bde753fdf62cd8bb8498ef92abcce86e6c12
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Mar 10 14:57:10 2014 +0000

    Revert "KDE4: sleep in yield for native file picker"
    
    This reverts commit 380f3b4b6cbbe8e82b58ddf55e95c5005307b51f.
    
    Conflicts:
    
    	vcl/unx/kde4/KDEXLib.cxx
    	vcl/unx/kde4/KDEXLib.hxx
    
    Change-Id: I8a201c89be63cebab7401124002261be23e049c7

diff --git a/vcl/unx/kde4/KDE4FilePicker.cxx b/vcl/unx/kde4/KDE4FilePicker.cxx
index c94f248..467e8d8 100644
--- a/vcl/unx/kde4/KDE4FilePicker.cxx
+++ b/vcl/unx/kde4/KDE4FilePicker.cxx
@@ -38,7 +38,6 @@
 
 #include "KDE4FilePicker.hxx"
 #include "FPServiceInfo.hxx"
-#include "KDEXLib.hxx"
 
 /* ********* Hack, but needed because of conflicting types... */
 #define Region QtXRegion
@@ -114,11 +113,10 @@ QString toQString(const OUString& s)
 // KDE4FilePicker
 
 
-KDE4FilePicker::KDE4FilePicker( const uno::Reference<uno::XComponentContext>&, KDEXLib *xlib )
+KDE4FilePicker::KDE4FilePicker( const uno::Reference<uno::XComponentContext>& )
     : KDE4FilePicker_Base(_helperMutex)
     , _resMgr( ResMgr::CreateResMgr("fps_office") )
     , allowRemoteUrls( false )
-    , _mXLib( xlib )
 {
     _extraControls = new QWidget();
     _layout = new QGridLayout(_extraControls);
@@ -263,11 +261,8 @@ sal_Int16 SAL_CALL KDE4FilePicker::execute()
     _dialog->filterWidget()->setEditable(false);
 
     // We're entering a nested loop.
-    // Prevent yield calls, which would crash LO.
-
-    _mXLib->freezeYield( true );
+    // Release the yield mutex to prevent deadlocks.
     int result = _dialog->exec();
-    _mXLib->freezeYield( false );
 
     // HACK: KFileDialog uses KConfig("kdeglobals") for saving some settings
     // (such as the auto-extension flag), but that doesn't update KGlobal::config()
diff --git a/vcl/unx/kde4/KDE4FilePicker.hxx b/vcl/unx/kde4/KDE4FilePicker.hxx
index 79d80dc..3cde3cf 100644
--- a/vcl/unx/kde4/KDE4FilePicker.hxx
+++ b/vcl/unx/kde4/KDE4FilePicker.hxx
@@ -40,7 +40,6 @@
 class KFileDialog;
 class QWidget;
 class QLayout;
-class KDEXLib;
 
 class ResMgr;
 
@@ -83,10 +82,8 @@ protected:
 
     bool allowRemoteUrls;
 
-    KDEXLib* _mXLib;
-
 public:
-    KDE4FilePicker( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >&, KDEXLib* );
+    KDE4FilePicker( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& );
     virtual ~KDE4FilePicker();
 
     // XFilePickerNotifier
diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx
index 29797a1..a31c7e0 100644
--- a/vcl/unx/kde4/KDEXLib.cxx
+++ b/vcl/unx/kde4/KDEXLib.cxx
@@ -58,8 +58,7 @@
 KDEXLib::KDEXLib() :
     SalXLib(),  m_bStartupDone(false), m_pApplication(0),
     m_pFreeCmdLineArgs(0), m_pAppCmdLineArgs(0), m_nFakeCmdLineArgs( 0 ),
-    eventLoopType( LibreOfficeEventLoop ),
-    m_bYieldFrozen( false ), m_frameWidth( -1 )
+    eventLoopType( LibreOfficeEventLoop ), m_frameWidth( -1 )
 {
     // 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,
@@ -221,7 +220,6 @@ void KDEXLib::setupEventLoop()
         eventLoopType = GlibEventLoop;
         old_gpoll = g_main_context_get_poll_func( NULL );
         g_main_context_set_poll_func( NULL, gpoll_wrapper );
-        m_pApplication->clipboard()->setProperty( "useEventLoopWhenWaiting", true );
         return;
     }
 #endif
@@ -281,17 +279,6 @@ void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
         return SalXLib::Yield( bWait, bHandleAllCurrentEvents );
     }
 
-    if( m_bYieldFrozen ) {
-        if( qApp->thread() != QThread::currentThread() ) {
-            QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread() );
-            if( dispatcher->hasPendingEvents() ) {
-                struct timespec delay = {0, ( 1000000 )};
-                nanosleep(&delay, NULL);
-            }
-        }
-        return;
-    }
-
     // if we are the main thread (which is where the event processing is done),
     // good, just do it
     if( qApp->thread() == QThread::currentThread()) {
@@ -409,7 +396,7 @@ uno::Reference< ui::dialogs::XFilePicker2 > KDEXLib::createFilePicker(
         SalYieldMutexReleaser aReleaser;
         return Q_EMIT createFilePickerSignal( xMSF );
     }
-    return uno::Reference< ui::dialogs::XFilePicker2 >( new KDE4FilePicker( xMSF, this ) );
+    return uno::Reference< ui::dialogs::XFilePicker2 >( new KDE4FilePicker( xMSF ) );
 }
 
 #define Region QtXRegion
diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx
index dd7f83f..1d307a0 100644
--- a/vcl/unx/kde4/KDEXLib.hxx
+++ b/vcl/unx/kde4/KDEXLib.hxx
@@ -52,7 +52,6 @@ class KDEXLib : public QObject, public SalXLib
         QTimer timeoutTimer;
         QTimer userEventTimer;
         enum { LibreOfficeEventLoop, GlibEventLoop, QtUnixEventLoop } eventLoopType;
-        bool m_bYieldFrozen;
         int m_frameWidth;
 
     private:
@@ -87,7 +86,6 @@ class KDEXLib : public QObject, public SalXLib
         virtual void Wakeup();
         virtual void PostUserEvent();
 
-        void freezeYield(bool freeze) { m_bYieldFrozen = freeze; }
         void doStartup();
 
     public Q_SLOTS:


More information about the Libreoffice-commits mailing list