QWindowsXP/VistaStyle: Move the Vista treeview handling to QWindowsXPStylePrivate.

QWindowsXPStylePrivate maintains a list of theme handles for various
style items. The derived class QWindowsVistaStylePrivate had logic
to use a special helper window with the "explorer" window theme set to
obtain the correct treeview arrow branch indicator (arrow shape for Vista as
opposed to '+'/'-' on Windows XP) when creating the "TREEVIEW" theme.
This required calling the helper function
QWindowsVistaStylePrivate::initTreeViewTheming() before
QWindowsXPStylePrivate::createTheme(), which is prone to errors and
initialization order issues.

This could be solved by making QWindowsXPStylePrivate::createTheme()
virtual or similar, but since it the fate of QWindowsXPStylePrivate is most likely
to be merged into QWindowsVistaStylePrivate; it was decided to move
the entire special handling of the Vista treeviews into
QWindowsXPStylePrivate. The existing enumeration value
QWindowsXPStylePrivate::TreeViewTheme is renamed to
QWindowsXPStylePrivate::XpTreeViewTheme and a new value
QWindowsXPStylePrivate::VistaTreeViewTheme is added for which
QWindowsXPStylePrivate::createTheme() invokes the special handling.
This also removes the need to destroy the helper window in unpolish(),
which should save some initializations.

Task-number: QTBUG-52230
Change-Id: I0492ecf38fb3e5eabc4ecbdef70f0bf05e82e104
Reviewed-by: Adam Light <aclight@gmail.com>
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
This commit is contained in:
Friedemann Kleint 2016-04-01 09:25:45 +02:00
parent 4d10e55d4d
commit f1e0eedcf5
4 changed files with 72 additions and 76 deletions

View File

@ -420,9 +420,9 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
case PE_IndicatorBranch: case PE_IndicatorBranch:
{ {
XPThemeData theme(widget, painter, QWindowsXPStylePrivate::TreeViewTheme); XPThemeData theme(widget, painter, QWindowsXPStylePrivate::VistaTreeViewTheme);
static int decoration_size = 0; static int decoration_size = 0;
if (!decoration_size && d->initTreeViewTheming() && theme.isValid()) { if (!decoration_size && theme.isValid()) {
XPThemeData themeSize = theme; XPThemeData themeSize = theme;
themeSize.partId = TVP_HOTGLYPH; themeSize.partId = TVP_HOTGLYPH;
themeSize.stateId = GLPS_OPENED; themeSize.stateId = GLPS_OPENED;
@ -722,9 +722,9 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
QPainter pixmapPainter(&pixmap); QPainter pixmapPainter(&pixmap);
XPThemeData theme(widget, &pixmapPainter, XPThemeData theme(widget, &pixmapPainter,
QWindowsXPStylePrivate::TreeViewTheme, QWindowsXPStylePrivate::VistaTreeViewTheme,
LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height())); LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height()));
if (d->initTreeViewTheming() && theme.isValid()) { if (theme.isValid()) {
d->drawBackground(theme); d->drawBackground(theme);
} else { } else {
QWindowsXPStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget); QWindowsXPStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
@ -2351,10 +2351,6 @@ void QWindowsVistaStyle::unpolish(QWidget *widget)
QWindowsXPStyle::unpolish(widget); QWindowsXPStyle::unpolish(widget);
QWindowsVistaStylePrivate *d = d_func(); QWindowsVistaStylePrivate *d = d_func();
// Delete the tree view helper in case the XP style cleaned the
// theme handle map due to a theme or QStyle change (QProxyStyle).
if (!QWindowsXPStylePrivate::hasTheme(QWindowsXPStylePrivate::TreeViewTheme))
d->cleanupTreeViewTheming();
d->stopAnimation(widget); d->stopAnimation(widget);
@ -2420,15 +2416,10 @@ QPixmap QWindowsVistaStyle::standardPixmap(StandardPixmap standardPixmap, const
} }
QWindowsVistaStylePrivate::QWindowsVistaStylePrivate() : QWindowsVistaStylePrivate::QWindowsVistaStylePrivate() :
QWindowsXPStylePrivate(), m_treeViewHelper(0) QWindowsXPStylePrivate()
{ {
} }
QWindowsVistaStylePrivate::~QWindowsVistaStylePrivate()
{
cleanupTreeViewTheming();
}
bool QWindowsVistaStylePrivate::transitionsEnabled() const bool QWindowsVistaStylePrivate::transitionsEnabled() const
{ {
BOOL animEnabled = false; BOOL animEnabled = false;
@ -2440,58 +2431,6 @@ bool QWindowsVistaStylePrivate::transitionsEnabled() const
return false; return false;
} }
/*
* We need to set the windows "explorer" theme explicitly on a native
* window and open the "TREEVIEW" theme handle passing its window handle
* in order to get Vista-style item view themes (particulary drawBackground()
* for selected items needs this).
* We invoke a service of the native Windows interface to create
* a non-visible window handle, open the theme on it and insert it into
* the cache so that it is found by XPThemeData::handle() first.
*/
static inline HWND createTreeViewHelperWindow()
{
if (QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface()) {
void *hwnd = 0;
void *wndProc = reinterpret_cast<void *>(DefWindowProc);
if (QMetaObject::invokeMethod(ni, "createMessageWindow", Qt::DirectConnection,
Q_RETURN_ARG(void *, hwnd),
Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindowClass")),
Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindow")),
Q_ARG(void *, wndProc)) && hwnd) {
return reinterpret_cast<HWND>(hwnd);
}
}
return 0;
}
bool QWindowsVistaStylePrivate::initTreeViewTheming()
{
if (m_treeViewHelper)
return true;
m_treeViewHelper = createTreeViewHelperWindow();
if (!m_treeViewHelper) {
qWarning("Unable to create the treeview helper window.");
return false;
}
const HRESULT hr = QWindowsXPStylePrivate::pSetWindowTheme(m_treeViewHelper, L"explorer", NULL);
if (hr != S_OK) {
qErrnoWarning("SetWindowTheme() failed.");
return false;
}
return QWindowsXPStylePrivate::createTheme(QWindowsXPStylePrivate::TreeViewTheme, m_treeViewHelper);
}
void QWindowsVistaStylePrivate::cleanupTreeViewTheming()
{
if (m_treeViewHelper) {
DestroyWindow(m_treeViewHelper);
m_treeViewHelper = 0;
}
}
/*! /*!
\reimp \reimp
*/ */

View File

@ -162,16 +162,10 @@ class QWindowsVistaStylePrivate : public QWindowsXPStylePrivate
public: public:
QWindowsVistaStylePrivate(); QWindowsVistaStylePrivate();
~QWindowsVistaStylePrivate();
static int fixedPixelMetric(QStyle::PixelMetric pm); static int fixedPixelMetric(QStyle::PixelMetric pm);
static inline bool useVista(); static inline bool useVista();
bool transitionsEnabled() const; bool transitionsEnabled() const;
private:
bool initTreeViewTheming();
void cleanupTreeViewTheming();
HWND m_treeViewHelper;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -48,6 +48,8 @@
#include <qbackingstore.h> #include <qbackingstore.h>
#include <qapplication.h> #include <qapplication.h>
#include <qpixmapcache.h> #include <qpixmapcache.h>
#include <private/qapplication_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <qdesktopwidget.h> #include <qdesktopwidget.h>
#include <qtoolbutton.h> #include <qtoolbutton.h>
@ -157,7 +159,7 @@ static const wchar_t *themeNames[QWindowsXPStylePrivate::NThemes] =
L"BUTTON", L"COMBOBOX", L"EDIT", L"HEADER", L"LISTVIEW", L"BUTTON", L"COMBOBOX", L"EDIT", L"HEADER", L"LISTVIEW",
L"MENU", L"PROGRESS", L"REBAR", L"SCROLLBAR", L"SPIN", L"MENU", L"PROGRESS", L"REBAR", L"SCROLLBAR", L"SPIN",
L"TAB", L"TASKDIALOG", L"TOOLBAR", L"TOOLTIP", L"TRACKBAR", L"TAB", L"TASKDIALOG", L"TOOLBAR", L"TOOLTIP", L"TRACKBAR",
L"TREEVIEW", L"WINDOW", L"STATUS" L"TREEVIEW", L"WINDOW", L"STATUS", L"TREEVIEW"
}; };
static inline QBackingStore *backingStoreForWidget(const QWidget *widget) static inline QBackingStore *backingStoreForWidget(const QWidget *widget)
@ -238,6 +240,7 @@ HRGN XPThemeData::mask(QWidget *widget)
// QWindowsXPStylePrivate ------------------------------------------------------------------------- // QWindowsXPStylePrivate -------------------------------------------------------------------------
// Static initializations // Static initializations
QPixmap *QWindowsXPStylePrivate::tabbody = 0; QPixmap *QWindowsXPStylePrivate::tabbody = 0;
HWND QWindowsXPStylePrivate::m_vistaTreeViewHelper = 0;
HTHEME QWindowsXPStylePrivate::m_themes[NThemes]; HTHEME QWindowsXPStylePrivate::m_themes[NThemes];
bool QWindowsXPStylePrivate::use_xp = false; bool QWindowsXPStylePrivate::use_xp = false;
QBasicAtomicInt QWindowsXPStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting QBasicAtomicInt QWindowsXPStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting
@ -321,6 +324,58 @@ void QWindowsXPStylePrivate::cleanup(bool force)
tabbody = 0; tabbody = 0;
} }
/* In order to obtain the correct VistaTreeViewTheme (arrows for PE_IndicatorBranch),
* we need to set the windows "explorer" theme explicitly on a native
* window and open the "TREEVIEW" theme handle passing its window handle
* in order to get Vista-style item view themes (particulary drawBackground()
* for selected items needs this).
* We invoke a service of the native Windows interface to create
* a non-visible window handle, open the theme on it and insert it into
* the cache so that it is found by XPThemeData::handle() first.
*/
static inline HWND createTreeViewHelperWindow()
{
if (QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface()) {
void *hwnd = 0;
void *wndProc = reinterpret_cast<void *>(DefWindowProc);
if (QMetaObject::invokeMethod(ni, "createMessageWindow", Qt::DirectConnection,
Q_RETURN_ARG(void *, hwnd),
Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindowClass")),
Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindow")),
Q_ARG(void *, wndProc)) && hwnd) {
return reinterpret_cast<HWND>(hwnd);
}
}
return 0;
}
bool QWindowsXPStylePrivate::initVistaTreeViewTheming()
{
if (m_vistaTreeViewHelper)
return true;
m_vistaTreeViewHelper = createTreeViewHelperWindow();
if (!m_vistaTreeViewHelper) {
qWarning("Unable to create the treeview helper window.");
return false;
}
if (FAILED(QWindowsXPStylePrivate::pSetWindowTheme(m_vistaTreeViewHelper, L"explorer", NULL))) {
qErrnoWarning("SetWindowTheme() failed.");
cleanupVistaTreeViewTheming();
return false;
}
return true;
}
void QWindowsXPStylePrivate::cleanupVistaTreeViewTheming()
{
if (m_vistaTreeViewHelper) {
DestroyWindow(m_vistaTreeViewHelper);
m_vistaTreeViewHelper = 0;
}
}
/* \internal /* \internal
Closes all open theme data handles to ensure that we don't leak Closes all open theme data handles to ensure that we don't leak
resources, and that we don't refere to old handles when for resources, and that we don't refere to old handles when for
@ -333,6 +388,7 @@ void QWindowsXPStylePrivate::cleanupHandleMap()
pCloseThemeData(m_themes[i]); pCloseThemeData(m_themes[i]);
m_themes[i] = 0; m_themes[i] = 0;
} }
QWindowsXPStylePrivate::cleanupVistaTreeViewTheming();
} }
HTHEME QWindowsXPStylePrivate::createTheme(int theme, HWND hwnd) HTHEME QWindowsXPStylePrivate::createTheme(int theme, HWND hwnd)
@ -343,6 +399,8 @@ HTHEME QWindowsXPStylePrivate::createTheme(int theme, HWND hwnd)
} }
if (!m_themes[theme]) { if (!m_themes[theme]) {
const wchar_t *name = themeNames[theme]; const wchar_t *name = themeNames[theme];
if (theme == VistaTreeViewTheme && QWindowsXPStylePrivate::initVistaTreeViewTheming())
hwnd = QWindowsXPStylePrivate::m_vistaTreeViewHelper;
m_themes[theme] = pOpenThemeData(hwnd, name); m_themes[theme] = pOpenThemeData(hwnd, name);
if (!m_themes[theme]) if (!m_themes[theme])
qErrnoWarning("OpenThemeData() failed for theme %d (%s).", qErrnoWarning("OpenThemeData() failed for theme %d (%s).",
@ -1947,7 +2005,7 @@ case PE_Frame:
bef_v -= delta; bef_v -= delta;
aft_h += delta; aft_h += delta;
aft_v += delta; aft_v += delta;
XPThemeData theme(0, p, QWindowsXPStylePrivate::TreeViewTheme); XPThemeData theme(0, p, QWindowsXPStylePrivate::XpTreeViewTheme);
theme.rect = QRect(bef_h, bef_v, decoration_size, decoration_size); theme.rect = QRect(bef_h, bef_v, decoration_size, decoration_size);
theme.partId = TVP_GLYPH; theme.partId = TVP_GLYPH;
theme.stateId = flags & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED; theme.stateId = flags & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;

View File

@ -350,9 +350,10 @@ public:
ToolBarTheme, ToolBarTheme,
ToolTipTheme, ToolTipTheme,
TrackBarTheme, TrackBarTheme,
TreeViewTheme, XpTreeViewTheme, // '+'/'-' shape treeview indicators (XP)
WindowTheme, WindowTheme,
StatusTheme, StatusTheme,
VistaTreeViewTheme, // arrow shape treeview indicators (Vista) obtained from "explorer" theme.
NThemes NThemes
}; };
@ -413,6 +414,9 @@ private:
void showProperties(XPThemeData &themeData); void showProperties(XPThemeData &themeData);
#endif #endif
static bool initVistaTreeViewTheming();
static void cleanupVistaTreeViewTheming();
static QBasicAtomicInt ref; static QBasicAtomicInt ref;
static bool use_xp; static bool use_xp;
static QPixmap *tabbody; static QPixmap *tabbody;
@ -424,6 +428,7 @@ private:
uchar *bufferPixels; uchar *bufferPixels;
int bufferW, bufferH; int bufferW, bufferH;
static HWND m_vistaTreeViewHelper;
static HTHEME m_themes[NThemes]; static HTHEME m_themes[NThemes];
}; };