summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2016-02-22 09:42:39 +0100
committerFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>2016-02-26 07:17:00 +0000
commitea757da43697787cfcd1c01f11bd2b0288c679fe (patch)
tree77fc7d4e9e0e873c5f6d05e30392d14708ca7929 /src
parentc0963486ce689e778d59dafd26d36d8ef9e3ee74 (diff)
QWindowsTheme: Run SHGetFileInfo() in a thread.
Windows 10: SHGetFileInfo() (as called by item views on file system models has been observed to trigger a WM_PAINT on the mainwindow for totally obscure reasons, causing a recursive repaint. Suppress this by running it via QThreadPool. Task-number: QTBUG-45298 Task-number: QTBUG-48823 Task-number: QTCREATORBUG-14888 Change-Id: I7479102b9b8fb0771681260298c3d735e66f220f Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp56
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsthreadpoolrunner.h116
-rw-r--r--src/plugins/platforms/windows/windows.pri3
4 files changed, 165 insertions, 12 deletions
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 887a217b06..ef652e6f98 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -122,6 +122,41 @@ static inline QColor getSysColor(int index)
return COLORREFToQColor(GetSysColor(index));
}
+#ifndef QT_NO_WINCE_SHELLSDK
+// QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system
+// models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the
+// behavior by running it in a thread.
+class ShGetFileInfoFunction
+{
+public:
+ explicit ShGetFileInfoFunction(const wchar_t *fn, DWORD a, SHFILEINFO *i, UINT f, bool *r) :
+ m_fileName(fn), m_attributes(a), m_flags(f), m_info(i), m_result(r) {}
+
+ void operator()() const { *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags); }
+
+private:
+ const wchar_t *m_fileName;
+ const DWORD m_attributes;
+ const UINT m_flags;
+ SHFILEINFO *const m_info;
+ bool *m_result;
+};
+
+static bool shGetFileInfoBackground(QWindowsThreadPoolRunner &r,
+ const wchar_t *fileName, DWORD attributes,
+ SHFILEINFO *info, UINT flags,
+ unsigned long timeOutMSecs = 5000)
+{
+ bool result = false;
+ if (!r.run(ShGetFileInfoFunction(fileName, attributes, info, flags, &result), timeOutMSecs)) {
+ qWarning().noquote() << "ShGetFileInfoBackground() timed out for "
+ << QString::fromWCharArray(fileName);
+ return false;
+ }
+ return result;
+}
+#endif // !QT_NO_WINCE_SHELLSDK
+
// from QStyle::standardPalette
static inline QPalette standardPalette()
{
@@ -690,23 +725,22 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
}
SHFILEINFO info;
- unsigned int flags =
+ const unsigned int flags =
#ifndef Q_OS_WINCE
SHGFI_ICON|iconSize|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX;
#else
iconSize|SHGFI_SYSICONINDEX;
#endif // Q_OS_WINCE
- unsigned long val = 0;
+
+
#if !defined(QT_NO_WINCE_SHELLSDK)
- if (cacheableDirIcon && useDefaultFolderIcon) {
- flags |= SHGFI_USEFILEATTRIBUTES;
- val = SHGetFileInfo(L"dummy",
- FILE_ATTRIBUTE_DIRECTORY,
- &info, sizeof(SHFILEINFO), flags);
- } else {
- val = SHGetFileInfo(reinterpret_cast<const wchar_t *>(filePath.utf16()), 0,
- &info, sizeof(SHFILEINFO), flags);
- }
+ const bool val = cacheableDirIcon && useDefaultFolderIcon
+ ? shGetFileInfoBackground(m_threadPoolRunner, L"dummy", FILE_ATTRIBUTE_DIRECTORY,
+ &info, flags | SHGFI_USEFILEATTRIBUTES)
+ : shGetFileInfoBackground(m_threadPoolRunner, reinterpret_cast<const wchar_t *>(filePath.utf16()), 0,
+ &info, flags);
+#else
+ const bool val = false;
#endif // !QT_NO_WINCE_SHELLSDK
// Even if GetFileInfo returns a valid result, hIcon can be empty in some cases
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index fc004b68c8..cacde98601 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -34,6 +34,7 @@
#ifndef QWINDOWSTHEME_H
#define QWINDOWSTHEME_H
+#include "qwindowsthreadpoolrunner.h"
#include <qpa/qplatformtheme.h>
QT_BEGIN_NAMESPACE
@@ -74,6 +75,7 @@ private:
static QWindowsTheme *m_instance;
QPalette *m_palettes[NPalettes];
QFont *m_fonts[NFonts];
+ mutable QWindowsThreadPoolRunner m_threadPoolRunner;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
new file mode 100644
index 0000000000..0361aa90f5
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSTHREADPOOLRUNNER_H
+#define QWINDOWSTHREADPOOLRUNNER_H
+
+#include <QtCore/QMutex>
+#include <QtCore/QRunnable>
+#include <QtCore/QThreadPool>
+#include <QtCore/QWaitCondition>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsThreadPoolRunner
+ \brief Runs a task in the global instance of QThreadPool
+
+ QThreadPool does not provide a method to wait on a single task, so this needs
+ to be done by using QWaitCondition/QMutex.
+
+ \internal
+ \ingroup qt-lighthouse-win
+*/
+class QWindowsThreadPoolRunner
+{
+ Q_DISABLE_COPY(QWindowsThreadPoolRunner)
+
+#ifndef QT_NO_THREAD
+ template <class RunnableFunction> // nested class implementing QRunnable to execute a function.
+ class Runnable : public QRunnable
+ {
+ public:
+ explicit Runnable(QMutex *m, QWaitCondition *c, RunnableFunction f)
+ : m_mutex(m), m_condition(c), m_function(f) {}
+
+ void run() Q_DECL_OVERRIDE
+ {
+ m_function();
+ m_mutex->lock();
+ m_condition->wakeAll();
+ m_mutex->unlock();
+ }
+
+ private:
+ QMutex *m_mutex;
+ QWaitCondition *m_condition;
+ RunnableFunction m_function;
+ }; // class Runnable
+
+public:
+ QWindowsThreadPoolRunner() {}
+
+ template <class Function>
+ bool run(Function f, unsigned long timeOutMSecs = 5000)
+ {
+ QThreadPool *pool = QThreadPool::globalInstance();
+ Q_ASSERT(pool);
+ Runnable<Function> *runnable = new Runnable<Function>(&m_mutex, &m_condition, f);
+ m_mutex.lock();
+ pool->start(runnable);
+ const bool ok = m_condition.wait(&m_mutex, timeOutMSecs);
+ m_mutex.unlock();
+ if (!ok)
+ pool->cancel(runnable);
+ return ok;
+ }
+
+private:
+ QMutex m_mutex;
+ QWaitCondition m_condition;
+#else // !QT_NO_THREAD
+public:
+ QWindowsThreadPoolRunner() {}
+
+ template <class Function>
+ bool run(Function f, unsigned long /* timeOutMSecs */ = 5000)
+ {
+ f();
+ return true;
+ }
+#endif // QT_NO_THREAD
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSTHREADPOOLRUNNER_H
diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri
index 67af5c03ef..eba0593d75 100644
--- a/src/plugins/platforms/windows/windows.pri
+++ b/src/plugins/platforms/windows/windows.pri
@@ -63,7 +63,8 @@ HEADERS += \
$$PWD/qplatformfunctions_wince.h \
$$PWD/qwindowsnativeimage.h \
$$PWD/qwindowsnativeinterface.h \
- $$PWD/qwindowsopengltester.h
+ $$PWD/qwindowsopengltester.h \
+ $$PWD/qwindowsthreadpoolrunner.h
INCLUDEPATH += $$PWD