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>
This commit is contained in:
parent
c0963486ce
commit
ea757da436
src/plugins/platforms/windows
@ -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
|
||||
|
@ -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
|
||||
|
116
src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
Normal file
116
src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user