1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QWINDOWSXPSTYLE_P_P_H
41 #define QWINDOWSXPSTYLE_P_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists for the convenience
48 // of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp.  This header
49 // file may change from version to version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtWidgets/private/qtwidgetsglobal_p.h>
55 #include "qwindowsxpstyle_p.h"
56 #include <QtWidgets/private/qwindowsstyle_p_p.h>
57 #include <qmap.h>
58 #include <qt_windows.h>
59 
60 #include <uxtheme.h>
61 #include <vssym32.h>
62 
63 #include <limits.h>
64 
65 QT_BEGIN_NAMESPACE
66 
67 class QDebug;
68 
69 // TMT_TEXTSHADOWCOLOR is wrongly defined in mingw
70 #if TMT_TEXTSHADOWCOLOR != 3818
71 #undef TMT_TEXTSHADOWCOLOR
72 #define TMT_TEXTSHADOWCOLOR 3818
73 #endif
74 #ifndef TST_NONE
75 #  define TST_NONE 0
76 #endif
77 
78 // These defines are missing from the tmschema, but still exist as
79 // states for their parts
80 #ifndef MINBS_INACTIVE
81 #define MINBS_INACTIVE 5
82 #endif
83 #ifndef MAXBS_INACTIVE
84 #define MAXBS_INACTIVE 5
85 #endif
86 #ifndef RBS_INACTIVE
87 #define RBS_INACTIVE 5
88 #endif
89 #ifndef HBS_INACTIVE
90 #define HBS_INACTIVE 5
91 #endif
92 #ifndef CBS_INACTIVE
93 #define CBS_INACTIVE 5
94 #endif
95 
96 // Uncomment define below to build debug assisting code, and output
97 // #define DEBUG_XP_STYLE
98 
99 // Declarations -----------------------------------------------------------------------------------
100 class XPThemeData
101 {
102 public:
103     explicit XPThemeData(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
104                          int part = 0, int state = 0, const QRect &r = QRect())
widget(w)105         : widget(w), painter(p), theme(themeIn), partId(part), stateId(state),
106           mirrorHorizontally(false), mirrorVertically(false), noBorder(false),
107           noContent(false), rect(r)
108     {}
109 
110     HRGN mask(QWidget *widget);
111     HTHEME handle();
112 
113     static RECT toRECT(const QRect &qr);
114     bool isValid();
115 
116     QSizeF size();
117     QMarginsF margins(const QRect &rect, int propId = TMT_CONTENTMARGINS);
118     QMarginsF margins(int propId = TMT_CONTENTMARGINS);
119 
120     static QSizeF themeSize(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1, int part = 0, int state = 0);
121     static QMarginsF themeMargins(const QRect &rect, const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
122                                   int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
123     static QMarginsF themeMargins(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
124                                   int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
125 
126     const QWidget *widget;
127     QPainter *painter;
128 
129     int theme;
130     HTHEME htheme = nullptr;
131     int partId;
132     int stateId;
133 
134     uint mirrorHorizontally : 1;
135     uint mirrorVertically : 1;
136     uint noBorder : 1;
137     uint noContent : 1;
138     uint rotate = 0;
139     QRect rect;
140 };
141 
142 struct ThemeMapKey {
143     int theme = 0;
144     int partId = -1;
145     int stateId = -1;
146     bool noBorder = false;
147     bool noContent = false;
148 
149     ThemeMapKey() = default;
ThemeMapKeyThemeMapKey150     ThemeMapKey(const XPThemeData &data)
151         : theme(data.theme), partId(data.partId), stateId(data.stateId),
152         noBorder(data.noBorder), noContent(data.noContent) {}
153 
154 };
155 
qHash(const ThemeMapKey & key)156 inline uint qHash(const ThemeMapKey &key)
157 { return key.theme ^ key.partId ^ key.stateId; }
158 
159 inline bool operator==(const ThemeMapKey &k1, const ThemeMapKey &k2)
160 {
161     return k1.theme == k2.theme
162            && k1.partId == k2.partId
163            && k1.stateId == k2.stateId;
164 }
165 
166 enum AlphaChannelType {
167     UnknownAlpha = -1,          // Alpha of part & state not yet known
168     NoAlpha,                    // Totally opaque, no need to touch alpha (RGB)
169     MaskAlpha,                  // Alpha channel must be fixed            (ARGB)
170     RealAlpha                   // Proper alpha values from Windows       (ARGB_Premultiplied)
171 };
172 
173 struct ThemeMapData {
174     AlphaChannelType alphaType = UnknownAlpha; // Which type of alpha on part & state
175 
176     bool dataValid         : 1; // Only used to detect if hash value is ok
177     bool partIsTransparent : 1;
178     bool hasAlphaChannel   : 1; // True =  part & state has real Alpha
179     bool wasAlphaSwapped   : 1; // True =  alpha channel needs to be swapped
180     bool hadInvalidAlpha   : 1; // True =  alpha channel contained invalid alpha values
181 
ThemeMapDataThemeMapData182     ThemeMapData() : dataValid(false), partIsTransparent(false),
183                      hasAlphaChannel(false), wasAlphaSwapped(false), hadInvalidAlpha(false) {}
184 };
185 
186 #ifndef QT_NO_DEBUG_STREAM
187 QDebug operator<<(QDebug d, const XPThemeData &t);
188 QDebug operator<<(QDebug d, const ThemeMapKey &k);
189 QDebug operator<<(QDebug d, const ThemeMapData &td);
190 #endif
191 
192 class QWindowsXPStylePrivate : public QWindowsStylePrivate
193 {
194     Q_DECLARE_PUBLIC(QWindowsXPStyle)
195 public:
196     enum Theme {
197         ButtonTheme,
198         ComboboxTheme,
199         EditTheme,
200         HeaderTheme,
201         ListViewTheme,
202         MenuTheme,
203         ProgressTheme,
204         RebarTheme,
205         ScrollBarTheme,
206         SpinTheme,
207         TabTheme,
208         TaskDialogTheme,
209         ToolBarTheme,
210         ToolTipTheme,
211         TrackBarTheme,
212         XpTreeViewTheme, // '+'/'-' shape treeview indicators (XP)
213         WindowTheme,
214         StatusTheme,
215         VistaTreeViewTheme, // arrow shape treeview indicators (Vista) obtained from "explorer" theme.
216         NThemes
217     };
218 
QWindowsXPStylePrivate()219     QWindowsXPStylePrivate()
220     { init(); }
221 
~QWindowsXPStylePrivate()222     ~QWindowsXPStylePrivate()
223     { cleanup(); }
224 
225     static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
226     static int fixedPixelMetric(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
227 
228     static HWND winId(const QWidget *widget);
229 
230     void init(bool force = false);
231     void cleanup(bool force = false);
232     void cleanupHandleMap();
233 
234     HBITMAP buffer(int w = 0, int h = 0);
bufferHDC()235     HDC bufferHDC()
236     { return bufferDC;}
237 
238     static bool useXP(bool update = false);
239     static QRect scrollBarGripperBounds(QStyle::State flags, const QWidget *widget, XPThemeData *theme);
240 
241     bool isTransparent(XPThemeData &themeData);
242     QRegion region(XPThemeData &themeData);
243 
244     bool drawBackground(XPThemeData &themeData, qreal correctionFactor = 1);
245     bool drawBackgroundThruNativeBuffer(XPThemeData &themeData, qreal aditionalDevicePixelRatio, qreal correctionFactor);
246     bool drawBackgroundDirectly(HDC dc, XPThemeData &themeData, qreal aditionalDevicePixelRatio);
247 
248     bool hasAlphaChannel(const QRect &rect);
249     bool fixAlphaChannel(const QRect &rect);
250     bool swapAlphaChannel(const QRect &rect, bool allPixels = false);
251 
252     QRgb groupBoxTextColor = 0;
253     QRgb groupBoxTextColorDisabled = 0;
254     QRgb sliderTickColor = 0;
255     bool hasInitColors = false;
256 
257     static HTHEME createTheme(int theme, HWND hwnd);
258     static QString themeName(int theme);
hasTheme(int theme)259     static inline bool hasTheme(int theme) { return theme >= 0 && theme < NThemes && m_themes[theme]; }
260     static bool isItemViewDelegateLineEdit(const QWidget *widget);
261     static bool isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget);
262 
263     QIcon dockFloat, dockClose;
264 
265 private:
266 #ifdef DEBUG_XP_STYLE
267     void dumpNativeDIB(int w, int h);
268     void showProperties(XPThemeData &themeData);
269 #endif
270 
271     static bool initVistaTreeViewTheming();
272     static void cleanupVistaTreeViewTheming();
273 
274     static QBasicAtomicInt ref;
275     static bool use_xp;
276 
277     QHash<ThemeMapKey, ThemeMapData> alphaCache;
278     HDC bufferDC = nullptr;
279     HBITMAP bufferBitmap = nullptr;
280     HBITMAP nullBitmap = nullptr;
281     uchar *bufferPixels = nullptr;
282     int bufferW = 0;
283     int bufferH = 0;
284 
285     static HWND m_vistaTreeViewHelper;
286     static HTHEME m_themes[NThemes];
287 };
288 
size()289 inline QSizeF XPThemeData::size()
290 {
291     QSizeF result(0, 0);
292     if (isValid()) {
293         SIZE size;
294         if (SUCCEEDED(GetThemePartSize(handle(), nullptr, partId, stateId, nullptr, TS_TRUE, &size)))
295             result = QSize(size.cx, size.cy);
296     }
297     return result;
298 }
299 
margins(const QRect & qRect,int propId)300 inline QMarginsF XPThemeData::margins(const QRect &qRect, int propId)
301 {
302     QMarginsF result(0, 0, 0 ,0);
303     if (isValid()) {
304         MARGINS margins;
305         RECT rect = XPThemeData::toRECT(qRect);
306         if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, &rect, &margins)))
307             result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
308     }
309     return result;
310 }
311 
margins(int propId)312 inline QMarginsF XPThemeData::margins(int propId)
313 {
314     QMarginsF result(0, 0, 0 ,0);
315     if (isValid()) {
316         MARGINS margins;
317         if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, nullptr, &margins)))
318             result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
319     }
320     return result;
321 }
322 
themeSize(const QWidget * w,QPainter * p,int themeIn,int part,int state)323 inline QSizeF XPThemeData::themeSize(const QWidget *w, QPainter *p, int themeIn, int part, int state)
324 {
325     XPThemeData theme(w, p, themeIn, part, state);
326     return theme.size();
327 }
328 
themeMargins(const QRect & rect,const QWidget * w,QPainter * p,int themeIn,int part,int state,int propId)329 inline QMarginsF XPThemeData::themeMargins(const QRect &rect, const QWidget *w, QPainter *p, int themeIn,
330                                            int part, int state, int propId)
331 {
332     XPThemeData theme(w, p, themeIn, part, state);
333     return theme.margins(rect, propId);
334 }
335 
themeMargins(const QWidget * w,QPainter * p,int themeIn,int part,int state,int propId)336 inline QMarginsF XPThemeData::themeMargins(const QWidget *w, QPainter *p, int themeIn,
337                                            int part, int state, int propId)
338 {
339     XPThemeData theme(w, p, themeIn, part, state);
340     return theme.margins(propId);
341 }
342 
343 QT_END_NAMESPACE
344 
345 #endif //QWINDOWSXPSTYLE_P_P_H
346