diff options
-rw-r--r-- | configure.ac | 51 | ||||
-rw-r--r-- | vcl/CustomTarget_kde4_moc.mk | 3 | ||||
-rw-r--r-- | vcl/Library_vclplug_kde4.mk | 2 | ||||
-rw-r--r-- | vcl/unx/kde4/KDE4FilePicker.cxx | 8 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEData.cxx | 2 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalInstance.cxx | 10 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEXLib.cxx | 30 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEXLib.hxx | 2 | ||||
-rw-r--r-- | vcl/unx/kde4/tst_exclude_socket_notifiers.hxx | 126 |
9 files changed, 212 insertions, 22 deletions
diff --git a/configure.ac b/configure.ac index 92ca7dd700ab..cbe3f3b41eb4 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 0846b0b7f261..9e417548da4b 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 c72fe004d727..18ffa02dc183 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 467e8d871093..4f819fb4c0a1 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 ccbbd9998320..0e87c6209cf6 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 9670172e216e..023d79051741 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 5c4cd10f01e3..820d39aa661e 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 f26948d48e14..a88258c5985e 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 000000000000..0c874fd7147d --- /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; +} + |