1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui 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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #ifndef QT_NO_WIZARD
43 #ifndef QT_NO_STYLE_WINDOWSVISTA
44 
45 #include "qwizard_win_p.h"
46 #include <private/qsystemlibrary_p.h>
47 #include "qwizard.h"
48 #include "qpaintengine.h"
49 #include "qapplication.h"
50 #include <QtGui/QMouseEvent>
51 #include <QtGui/QDesktopWidget>
52 
53 // Note, these tests are duplicates in qwindowsxpstyle_p.h.
54 #ifdef Q_CC_GNU
55 #  include <w32api.h>
56 #  if (__W32API_MAJOR_VERSION >= 3 || (__W32API_MAJOR_VERSION == 2 && __W32API_MINOR_VERSION >= 5))
57 #    ifdef _WIN32_WINNT
58 #      undef _WIN32_WINNT
59 #    endif
60 #    define _WIN32_WINNT 0x0501
61 #    include <commctrl.h>
62 #  endif
63 #endif
64 
65 #include <uxtheme.h>
66 
67 QT_BEGIN_NAMESPACE
68 
69 //DWM related
70 typedef struct  {       //MARGINS
71     int cxLeftWidth;    // width of left border that retains its size
72     int cxRightWidth;   // width of right border that retains its size
73     int cyTopHeight;    // height of top border that retains its size
74     int cyBottomHeight; // height of bottom border that retains its size
75 } WIZ_MARGINS;
76 typedef struct {        //DTTOPTS
77     DWORD dwSize;
78     DWORD dwFlags;
79     COLORREF crText;
80     COLORREF crBorder;
81     COLORREF crShadow;
82     int eTextShadowType;
83     POINT ptShadowOffset;
84     int iBorderSize;
85     int iFontPropId;
86     int iColorPropId;
87     int iStateId;
88     BOOL fApplyOverlay;
89     int iGlowSize;
90 } WIZ_DTTOPTS;
91 
92 typedef struct {
93     DWORD dwFlags;
94     DWORD dwMask;
95 } WIZ_WTA_OPTIONS;
96 
97 #define WIZ_WM_THEMECHANGED                 0x031A
98 #define WIZ_WM_DWMCOMPOSITIONCHANGED        0x031E
99 
100 enum WIZ_WINDOWTHEMEATTRIBUTETYPE {
101     WIZ_WTA_NONCLIENT = 1
102 };
103 
104 #define WIZ_WTNCA_NODRAWCAPTION 0x00000001
105 #define WIZ_WTNCA_NODRAWICON    0x00000002
106 
107 #define WIZ_DT_CENTER                   0x00000001 //DT_CENTER
108 #define WIZ_DT_VCENTER                  0x00000004
109 #define WIZ_DT_SINGLELINE               0x00000020
110 #define WIZ_DT_NOPREFIX                 0x00000800
111 
112 enum WIZ_NAVIGATIONPARTS {          //NAVIGATIONPARTS
113 	WIZ_NAV_BACKBUTTON = 1,
114 	WIZ_NAV_FORWARDBUTTON = 2,
115 	WIZ_NAV_MENUBUTTON = 3,
116 };
117 
118 enum WIZ_NAV_BACKBUTTONSTATES {     //NAV_BACKBUTTONSTATES
119 	WIZ_NAV_BB_NORMAL = 1,
120 	WIZ_NAV_BB_HOT = 2,
121 	WIZ_NAV_BB_PRESSED = 3,
122 	WIZ_NAV_BB_DISABLED = 4,
123 };
124 
125 #define WIZ_TMT_CAPTIONFONT (801)           //TMT_CAPTIONFONT
126 #define WIZ_DTT_COMPOSITED  (1UL << 13)     //DTT_COMPOSITED
127 #define WIZ_DTT_GLOWSIZE    (1UL << 11)     //DTT_GLOWSIZE
128 
129 #define WIZ_WM_NCMOUSELEAVE 674             //WM_NCMOUSELEAVE
130 
131 #define WIZ_WP_CAPTION             1 //WP_CAPTION
132 #define WIZ_CS_ACTIVE              1 //CS_ACTIVE
133 #define WIZ_TMT_FILLCOLORHINT   3821 //TMT_FILLCOLORHINT
134 #define WIZ_TMT_BORDERCOLORHINT 3822 //TMT_BORDERCOLORHINT
135 
136 typedef BOOL (WINAPI *PtrDwmDefWindowProc)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult);
137 typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL* pfEnabled);
138 typedef HRESULT (WINAPI *PtrDwmExtendFrameIntoClientArea)(HWND hWnd, const WIZ_MARGINS* pMarInset);
139 typedef HRESULT (WINAPI *PtrSetWindowThemeAttribute)(HWND hwnd, enum WIZ_WINDOWTHEMEATTRIBUTETYPE eAttribute, PVOID pvAttribute, DWORD cbAttribute);
140 
141 static PtrDwmDefWindowProc pDwmDefWindowProc = 0;
142 static PtrDwmIsCompositionEnabled pDwmIsCompositionEnabled = 0;
143 static PtrDwmExtendFrameIntoClientArea pDwmExtendFrameIntoClientArea = 0;
144 static PtrSetWindowThemeAttribute pSetWindowThemeAttribute = 0;
145 
146 //Theme related
147 typedef bool (WINAPI *PtrIsAppThemed)();
148 typedef bool (WINAPI *PtrIsThemeActive)();
149 typedef HANDLE (WINAPI *PtrOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
150 typedef HRESULT (WINAPI *PtrCloseThemeData)(HANDLE hTheme);
151 typedef HRESULT (WINAPI *PtrGetThemeSysFont)(HANDLE hTheme, int iFontId, LOGFONTW *plf);
152 typedef HRESULT (WINAPI *PtrDrawThemeTextEx)(HANDLE hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT pRect, const WIZ_DTTOPTS *pOptions);
153 typedef HRESULT (WINAPI *PtrDrawThemeBackground)(HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
154 typedef HRESULT (WINAPI *PtrGetThemePartSize)(HANDLE hTheme, HDC hdc, int iPartId, int iStateId, OPTIONAL RECT *prc, enum THEMESIZE eSize, OUT SIZE *psz);
155 typedef HRESULT (WINAPI *PtrGetThemeColor)(HANDLE hTheme, int iPartId, int iStateId, int iPropId, OUT COLORREF *pColor);
156 
157 static PtrIsAppThemed pIsAppThemed = 0;
158 static PtrIsThemeActive pIsThemeActive = 0;
159 static PtrOpenThemeData pOpenThemeData = 0;
160 static PtrCloseThemeData pCloseThemeData = 0;
161 static PtrGetThemeSysFont pGetThemeSysFont = 0;
162 static PtrDrawThemeTextEx pDrawThemeTextEx = 0;
163 static PtrDrawThemeBackground pDrawThemeBackground = 0;
164 static PtrGetThemePartSize pGetThemePartSize = 0;
165 static PtrGetThemeColor pGetThemeColor = 0;
166 
167 int QVistaHelper::instanceCount = 0;
168 bool QVistaHelper::is_vista = false;
169 QVistaHelper::VistaState QVistaHelper::cachedVistaState = QVistaHelper::Dirty;
170 
171 /******************************************************************************
172 ** QVistaBackButton
173 */
174 
QVistaBackButton(QWidget * widget)175 QVistaBackButton::QVistaBackButton(QWidget *widget)
176     : QAbstractButton(widget)
177 {
178     setFocusPolicy(Qt::NoFocus);
179 }
180 
sizeHint() const181 QSize QVistaBackButton::sizeHint() const
182 {
183     ensurePolished();
184     int size = int(QStyleHelper::dpiScaled(32));
185     int width = size, height = size;
186 /*
187     HANDLE theme = pOpenThemeData(0, L"Navigation");
188     SIZE size;
189     if (pGetThemePartSize(theme, 0, WIZ_NAV_BACKBUTTON, WIZ_NAV_BB_NORMAL, 0, TS_TRUE, &size) == S_OK) {
190         width = size.cx;
191         height = size.cy;
192     }
193 */
194     return QSize(width, height);
195 }
196 
enterEvent(QEvent * event)197 void QVistaBackButton::enterEvent(QEvent *event)
198 {
199     if (isEnabled())
200         update();
201     QAbstractButton::enterEvent(event);
202 }
203 
leaveEvent(QEvent * event)204 void QVistaBackButton::leaveEvent(QEvent *event)
205 {
206     if (isEnabled())
207         update();
208     QAbstractButton::leaveEvent(event);
209 }
210 
paintEvent(QPaintEvent *)211 void QVistaBackButton::paintEvent(QPaintEvent *)
212 {
213     QPainter p(this);
214     QRect r = rect();
215     HANDLE theme = pOpenThemeData(0, L"Navigation");
216     //RECT rect;
217     RECT clipRect;
218     int xoffset = QWidget::mapToParent(r.topLeft()).x() - 1;
219     int yoffset = QWidget::mapToParent(r.topLeft()).y() - 1;
220 
221     clipRect.top = r.top() + yoffset;
222     clipRect.bottom = r.bottom() + yoffset;
223     clipRect.left = r.left() + xoffset;
224     clipRect.right = r.right()  + xoffset;
225 
226     int state = WIZ_NAV_BB_NORMAL;
227     if (!isEnabled())
228         state = WIZ_NAV_BB_DISABLED;
229     else if (isDown())
230         state = WIZ_NAV_BB_PRESSED;
231     else if (underMouse())
232         state = WIZ_NAV_BB_HOT;
233 
234     WIZ_NAVIGATIONPARTS buttonType = (layoutDirection() == Qt::LeftToRight
235                                       ? WIZ_NAV_BACKBUTTON
236                                       : WIZ_NAV_FORWARDBUTTON);
237 
238    pDrawThemeBackground(theme, p.paintEngine()->getDC(), buttonType, state, &clipRect, &clipRect);
239 }
240 
241 /******************************************************************************
242 ** QVistaHelper
243 */
244 
QVistaHelper(QWizard * wizard)245 QVistaHelper::QVistaHelper(QWizard *wizard)
246     : QObject(wizard)
247     , pressed(false)
248     , wizard(wizard)
249     , backButton_(0)
250 {
251     is_vista = QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && resolveSymbols();
252     if (instanceCount++ == 0)
253         cachedVistaState = Dirty;
254     if (is_vista)
255         backButton_ = new QVistaBackButton(wizard);
256 
257     // Handle diff between Windows 7 and Vista
258     iconSpacing = QStyleHelper::dpiScaled(7);
259     textSpacing = QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7 ?
260                   iconSpacing : QStyleHelper::dpiScaled(20);
261 }
262 
~QVistaHelper()263 QVistaHelper::~QVistaHelper()
264 {
265     --instanceCount;
266 }
267 
isCompositionEnabled()268 bool QVistaHelper::isCompositionEnabled()
269 {
270     bool value = is_vista;
271     if (is_vista) {
272         HRESULT hr;
273         BOOL bEnabled;
274 
275         hr = pDwmIsCompositionEnabled(&bEnabled);
276         value = (SUCCEEDED(hr) && bEnabled);
277     }
278     return value;
279 }
280 
isThemeActive()281 bool QVistaHelper::isThemeActive()
282 {
283     return is_vista && pIsThemeActive();
284 }
285 
vistaState()286 QVistaHelper::VistaState QVistaHelper::vistaState()
287 {
288     if (instanceCount == 0 || cachedVistaState == Dirty)
289         cachedVistaState =
290             isCompositionEnabled() ? VistaAero : isThemeActive() ? VistaBasic : Classic;
291     return cachedVistaState;
292 }
293 
disconnectBackButton()294 void QVistaHelper::disconnectBackButton()
295 {
296     if (backButton_) // Leave QStyleSheetStyle's connections on destroyed() intact.
297         backButton_->disconnect(SIGNAL(clicked()));
298 }
299 
basicWindowFrameColor()300 QColor QVistaHelper::basicWindowFrameColor()
301 {
302     DWORD rgb;
303     HANDLE hTheme = pOpenThemeData(QApplication::desktop()->winId(), L"WINDOW");
304     pGetThemeColor(
305         hTheme, WIZ_WP_CAPTION, WIZ_CS_ACTIVE,
306         wizard->isActiveWindow() ? WIZ_TMT_FILLCOLORHINT : WIZ_TMT_BORDERCOLORHINT,
307         &rgb);
308     BYTE r = GetRValue(rgb);
309     BYTE g = GetGValue(rgb);
310     BYTE b = GetBValue(rgb);
311     return QColor(r, g, b);
312 }
313 
setDWMTitleBar(TitleBarChangeType type)314 bool QVistaHelper::setDWMTitleBar(TitleBarChangeType type)
315 {
316     bool value = false;
317     if (vistaState() == VistaAero) {
318         WIZ_MARGINS mar = {0};
319         if (type == NormalTitleBar)
320             mar.cyTopHeight = 0;
321         else
322             mar.cyTopHeight = titleBarSize() + topOffset();
323         HRESULT hr = pDwmExtendFrameIntoClientArea(wizard->winId(), &mar);
324         value = SUCCEEDED(hr);
325     }
326     return value;
327 }
328 
drawTitleBar(QPainter * painter)329 void QVistaHelper::drawTitleBar(QPainter *painter)
330 {
331     HDC hdc = painter->paintEngine()->getDC();
332 
333     if (vistaState() == VistaAero)
334         drawBlackRect(QRect(0, 0, wizard->width(),
335                             titleBarSize() + topOffset()), hdc);
336     Q_ASSERT(backButton_);
337     const int btnTop = backButton_->mapToParent(QPoint()).y();
338     const int btnHeight = backButton_->size().height();
339     const int verticalCenter = (btnTop + btnHeight / 2) - 1;
340 
341     const QString text = wizard->window()->windowTitle();
342     const QFont font = QApplication::font("QWorkspaceTitleBar");
343     const QFontMetrics fontMetrics(font);
344     const QRect brect = fontMetrics.boundingRect(text);
345     int textHeight = brect.height();
346     int textWidth = brect.width();
347     int glowOffset = 0;
348 
349     if (vistaState() == VistaAero) {
350         textHeight += 2 * glowSize();
351         textWidth += 2 * glowSize();
352         glowOffset = glowSize();
353     }
354 
355     const int titleLeft = (wizard->layoutDirection() == Qt::LeftToRight
356                            ? titleOffset() - glowOffset
357                            : wizard->width() - titleOffset() - textWidth + glowOffset);
358 
359     drawTitleText(
360         painter, text,
361         QRect(titleLeft, verticalCenter - textHeight / 2, textWidth, textHeight),
362         hdc);
363 
364     if (!wizard->windowIcon().isNull()) {
365         const int iconLeft = (wizard->layoutDirection() == Qt::LeftToRight
366                               ? leftMargin()
367                               : wizard->width() - leftMargin() - iconSize());
368 
369         QRect rect(iconLeft, verticalCenter - iconSize() / 2, iconSize(), iconSize());
370         HICON hIcon = wizard->windowIcon().pixmap(iconSize()).toWinHICON();
371         DrawIconEx(hdc, rect.left(), rect.top(), hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
372         DestroyIcon(hIcon);
373     }
374 }
375 
setTitleBarIconAndCaptionVisible(bool visible)376 void QVistaHelper::setTitleBarIconAndCaptionVisible(bool visible)
377 {
378     if (is_vista) {
379         WIZ_WTA_OPTIONS opt;
380         opt.dwFlags = WIZ_WTNCA_NODRAWICON | WIZ_WTNCA_NODRAWCAPTION;
381         if (visible)
382             opt.dwMask = 0;
383         else
384             opt.dwMask = WIZ_WTNCA_NODRAWICON | WIZ_WTNCA_NODRAWCAPTION;
385         pSetWindowThemeAttribute(wizard->winId(), WIZ_WTA_NONCLIENT, &opt, sizeof(WIZ_WTA_OPTIONS));
386     }
387 }
388 
winEvent(MSG * msg,long * result)389 bool QVistaHelper::winEvent(MSG* msg, long* result)
390 {
391     switch (msg->message) {
392     case WM_NCHITTEST: {
393         LRESULT lResult;
394         // Perform hit testing using DWM
395         if (pDwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lResult)) {
396             // DWM returned a hit, no further processing necessary
397             *result = lResult;
398         } else {
399             // DWM didn't return a hit, process using DefWindowProc
400             lResult = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
401             // If DefWindowProc returns a window caption button, just return HTCLIENT (client area).
402             // This avoid unnecessary hits to Windows NT style caption buttons which aren't visible but are
403             // located just under the Aero style window close button.
404             if (lResult == HTCLOSE || lResult == HTMAXBUTTON || lResult == HTMINBUTTON || lResult == HTHELP)
405                 *result = HTCLIENT;
406             else
407                 *result = lResult;
408         }
409         break;
410     }
411     case WM_NCCALCSIZE:
412         if (vistaState() == VistaAero) {
413             NCCALCSIZE_PARAMS* lpncsp = (NCCALCSIZE_PARAMS*)msg->lParam;
414             *result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
415             lpncsp->rgrc[0].top -= titleBarSize();
416         } else {
417             return false;
418         }
419         break;
420     default:
421         LRESULT lResult;
422         // Pass to DWM to handle
423         if (pDwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lResult))
424             *result = lResult;
425         // If the message wasn't handled by DWM, continue processing it as normal
426         else
427             return false;
428     }
429 
430     return true;
431 }
432 
setMouseCursor(QPoint pos)433 void QVistaHelper::setMouseCursor(QPoint pos)
434 {
435 #ifndef QT_NO_CURSOR
436     if (rtTop.contains(pos))
437         wizard->setCursor(Qt::SizeVerCursor);
438     else
439         wizard->setCursor(Qt::ArrowCursor);
440 #endif
441 }
442 
mouseEvent(QEvent * event)443 void QVistaHelper::mouseEvent(QEvent *event)
444 {
445     switch (event->type()) {
446     case QEvent::MouseMove:
447         mouseMoveEvent(static_cast<QMouseEvent *>(event));
448         break;
449     case QEvent::MouseButtonPress:
450         mousePressEvent(static_cast<QMouseEvent *>(event));
451         break;
452     case QEvent::MouseButtonRelease:
453         mouseReleaseEvent(static_cast<QMouseEvent *>(event));
454         break;
455     default:
456         break;
457     }
458 }
459 
460 // The following hack ensures that the titlebar is updated correctly
461 // when the wizard style changes to and from AeroStyle. Specifically,
462 // this function causes a Windows message of type WM_NCCALCSIZE to
463 // be triggered.
setWindowPosHack()464 void QVistaHelper::setWindowPosHack()
465 {
466     const int x = wizard->geometry().x(); // ignored by SWP_NOMOVE
467     const int y = wizard->geometry().y(); // ignored by SWP_NOMOVE
468     const int w = wizard->width();
469     const int h = wizard->height();
470     SetWindowPos(wizard->winId(), 0, x, y, w, h, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
471 }
472 
473 // The following hack allows any QWidget subclass to access
474 // QWidgetPrivate::topData() without being declared as a
475 // friend by QWidget.
476 class QHackWidget : public QWidget
477 {
478 public:
Q_DECLARE_PRIVATE(QWidget)479     Q_DECLARE_PRIVATE(QWidget)
480     QTLWExtra* topData() { return d_func()->topData(); }
481 };
482 
collapseTopFrameStrut()483 void QVistaHelper::collapseTopFrameStrut()
484 {
485     QTLWExtra *top = ((QHackWidget *)wizard)->d_func()->topData();
486     int x1, y1, x2, y2;
487     top->frameStrut.getCoords(&x1, &y1, &x2, &y2);
488     top->frameStrut.setCoords(x1, 0, x2, y2);
489 }
490 
handleWinEvent(MSG * message,long * result)491 bool QVistaHelper::handleWinEvent(MSG *message, long *result)
492 {
493     if (message->message == WIZ_WM_THEMECHANGED || message->message == WIZ_WM_DWMCOMPOSITIONCHANGED)
494         cachedVistaState = Dirty;
495 
496     bool status = false;
497     if (wizard->wizardStyle() == QWizard::AeroStyle && vistaState() == VistaAero) {
498         status = winEvent(message, result);
499         if (message->message == WM_NCCALCSIZE) {
500             if (status)
501                 collapseTopFrameStrut();
502         } else if (message->message == WM_NCPAINT) {
503             wizard->update();
504         }
505     }
506     return status;
507 }
508 
resizeEvent(QResizeEvent * event)509 void QVistaHelper::resizeEvent(QResizeEvent * event)
510 {
511     Q_UNUSED(event);
512     rtTop = QRect (0, 0, wizard->width(), frameSize());
513     int height = captionSize() + topOffset();
514     if (vistaState() == VistaBasic)
515         height -= titleBarSize();
516     rtTitle = QRect (0, frameSize(), wizard->width(), height);
517 }
518 
paintEvent(QPaintEvent * event)519 void QVistaHelper::paintEvent(QPaintEvent *event)
520 {
521     Q_UNUSED(event);
522     QPainter painter(wizard);
523     drawTitleBar(&painter);
524 }
525 
mouseMoveEvent(QMouseEvent * event)526 void QVistaHelper::mouseMoveEvent(QMouseEvent *event)
527 {
528     if (wizard->windowState() & Qt::WindowMaximized) {
529         event->ignore();
530         return;
531     }
532 
533     QRect rect = wizard->geometry();
534     if (pressed) {
535         switch (change) {
536         case resizeTop:
537             {
538                 const int dy = event->pos().y() - pressedPos.y();
539                 if ((dy > 0 && rect.height() > wizard->minimumHeight())
540                     || (dy < 0 && rect.height() < wizard->maximumHeight()))
541                     rect.setTop(rect.top() + dy);
542             }
543             break;
544         case movePosition: {
545             QPoint newPos = event->pos() - pressedPos;
546             rect.moveLeft(rect.left() + newPos.x());
547             rect.moveTop(rect.top() + newPos.y());
548             break; }
549         default:
550             break;
551         }
552         wizard->setGeometry(rect);
553 
554     } else if (vistaState() == VistaAero) {
555         setMouseCursor(event->pos());
556     }
557     event->ignore();
558 }
559 
mousePressEvent(QMouseEvent * event)560 void QVistaHelper::mousePressEvent(QMouseEvent *event)
561 {
562     change = noChange;
563 
564     if (event->button() != Qt::LeftButton || wizard->windowState() & Qt::WindowMaximized) {
565         event->ignore();
566         return;
567     }
568 
569     if (rtTitle.contains(event->pos())) {
570         change = movePosition;
571     } else if (rtTop.contains(event->pos()))
572         change = (vistaState() == VistaAero) ? resizeTop : movePosition;
573 
574     if (change != noChange) {
575         if (vistaState() == VistaAero)
576             setMouseCursor(event->pos());
577         pressed = true;
578         pressedPos = event->pos();
579     } else {
580         event->ignore();
581     }
582 }
583 
mouseReleaseEvent(QMouseEvent * event)584 void QVistaHelper::mouseReleaseEvent(QMouseEvent *event)
585 {
586     change = noChange;
587     if (pressed) {
588         pressed = false;
589         wizard->releaseMouse();
590         if (vistaState() == VistaAero)
591             setMouseCursor(event->pos());
592     }
593     event->ignore();
594 }
595 
eventFilter(QObject * obj,QEvent * event)596 bool QVistaHelper::eventFilter(QObject *obj, QEvent *event)
597 {
598     if (obj != wizard)
599         return QObject::eventFilter(obj, event);
600 
601     if (event->type() == QEvent::MouseMove) {
602         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
603         long result;
604         MSG msg;
605         msg.message = WM_NCHITTEST;
606         msg.wParam  = 0;
607         msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
608         msg.hwnd = wizard->winId();
609         winEvent(&msg, &result);
610         msg.wParam = result;
611         msg.message = WM_NCMOUSEMOVE;
612         winEvent(&msg, &result);
613      } else if (event->type() == QEvent::MouseButtonPress) {
614         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
615 
616         if (mouseEvent->button() == Qt::LeftButton) {
617             long result;
618             MSG msg;
619             msg.message = WM_NCHITTEST;
620             msg.wParam  = 0;
621             msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
622             msg.hwnd = wizard->winId();
623             winEvent(&msg, &result);
624             msg.wParam = result;
625             msg.message = WM_NCLBUTTONDOWN;
626             winEvent(&msg, &result);
627         }
628      } else if (event->type() == QEvent::MouseButtonRelease) {
629         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
630 
631         if (mouseEvent->button() == Qt::LeftButton) {
632             long result;
633             MSG msg;
634             msg.message = WM_NCHITTEST;
635             msg.wParam  = 0;
636             msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
637             msg.hwnd = wizard->winId();
638             winEvent(&msg, &result);
639             msg.wParam = result;
640             msg.message = WM_NCLBUTTONUP;
641             winEvent(&msg, &result);
642         }
643      }
644 
645      return false;
646 }
647 
getCaptionFont(HANDLE hTheme)648 HFONT QVistaHelper::getCaptionFont(HANDLE hTheme)
649 {
650     LOGFONT lf = {0};
651 
652     if (!hTheme)
653         pGetThemeSysFont(hTheme, WIZ_TMT_CAPTIONFONT, &lf);
654     else
655     {
656         NONCLIENTMETRICS ncm = {sizeof(NONCLIENTMETRICS)};
657         SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, false);
658         lf = ncm.lfMessageFont;
659     }
660     return CreateFontIndirect(&lf);
661 }
662 
drawTitleText(QPainter * painter,const QString & text,const QRect & rect,HDC hdc)663 bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const QRect &rect, HDC hdc)
664 {
665     bool value = false;
666     if (vistaState() == VistaAero) {
667         HANDLE hTheme = pOpenThemeData(QApplication::desktop()->winId(), L"WINDOW");
668         if (!hTheme) return false;
669         // Set up a memory DC and bitmap that we'll draw into
670         HDC dcMem;
671         HBITMAP bmp;
672         BITMAPINFO dib = {{0}};
673         dcMem = CreateCompatibleDC(hdc);
674 
675         dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
676         dib.bmiHeader.biWidth = rect.width();
677         dib.bmiHeader.biHeight = -rect.height();
678         dib.bmiHeader.biPlanes = 1;
679         dib.bmiHeader.biBitCount = 32;
680         dib.bmiHeader.biCompression = BI_RGB;
681 
682         bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
683 
684         // Set up the DC
685         HFONT hCaptionFont = getCaptionFont(hTheme);
686         HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp);
687         HFONT hOldFont = (HFONT)SelectObject(dcMem, (HGDIOBJ) hCaptionFont);
688 
689         // Draw the text!
690         WIZ_DTTOPTS dto = { sizeof(WIZ_DTTOPTS) };
691         const UINT uFormat = WIZ_DT_SINGLELINE|WIZ_DT_CENTER|WIZ_DT_VCENTER|WIZ_DT_NOPREFIX;
692         RECT rctext ={0,0, rect.width(), rect.height()};
693 
694         dto.dwFlags = WIZ_DTT_COMPOSITED|WIZ_DTT_GLOWSIZE;
695         dto.iGlowSize = glowSize();
696 
697         pDrawThemeTextEx(hTheme, dcMem, 0, 0, (LPCWSTR)text.utf16(), -1, uFormat, &rctext, &dto );
698         BitBlt(hdc, rect.left(), rect.top(), rect.width(), rect.height(), dcMem, 0, 0, SRCCOPY);
699         SelectObject(dcMem, (HGDIOBJ) hOldBmp);
700         SelectObject(dcMem, (HGDIOBJ) hOldFont);
701         DeleteObject(bmp);
702         DeleteObject(hCaptionFont);
703         DeleteDC(dcMem);
704         //ReleaseDC(hwnd, hdc);
705     } else if (vistaState() == VistaBasic) {
706         painter->drawText(rect, text);
707     }
708     return value;
709 }
710 
drawBlackRect(const QRect & rect,HDC hdc)711 bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
712 {
713     bool value = false;
714     if (vistaState() == VistaAero) {
715         // Set up a memory DC and bitmap that we'll draw into
716         HDC dcMem;
717         HBITMAP bmp;
718         BITMAPINFO dib = {{0}};
719         dcMem = CreateCompatibleDC(hdc);
720 
721         dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
722         dib.bmiHeader.biWidth = rect.width();
723         dib.bmiHeader.biHeight = -rect.height();
724         dib.bmiHeader.biPlanes = 1;
725         dib.bmiHeader.biBitCount = 32;
726         dib.bmiHeader.biCompression = BI_RGB;
727 
728         bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
729         HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp);
730 
731         BitBlt(hdc, rect.left(), rect.top(), rect.width(), rect.height(), dcMem, 0, 0, SRCCOPY);
732         SelectObject(dcMem, (HGDIOBJ) hOldBmp);
733 
734         DeleteObject(bmp);
735         DeleteDC(dcMem);
736     }
737     return value;
738 }
739 
740 #if !defined(_MSC_VER) || _MSC_VER < 1700
getWindowBottomMargin()741 static inline int getWindowBottomMargin()
742 {
743     return GetSystemMetrics(SM_CYSIZEFRAME);
744 }
745 #else // !_MSC_VER || _MSC_VER < 1700
746 // QTBUG-36192, GetSystemMetrics(SM_CYSIZEFRAME) returns bogus values
747 // for MSVC2012 which leads to the custom margin having no effect since
748 // that only works when removing the entire margin.
getWindowBottomMargin()749 static inline int getWindowBottomMargin()
750 {
751     RECT rect = {0, 0, 0, 0};
752     AdjustWindowRectEx(&rect, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_THICKFRAME | WS_DLGFRAME, FALSE, 0);
753     return qAbs(rect.bottom);
754 }
755 #endif // _MSC_VER >= 1700
756 
frameSize()757 int QVistaHelper::frameSize()
758 {
759     return getWindowBottomMargin();
760 }
761 
captionSize()762 int QVistaHelper::captionSize()
763 {
764     return GetSystemMetrics(SM_CYCAPTION);
765 }
766 
resolveSymbols()767 bool QVistaHelper::resolveSymbols()
768 {
769     static bool tried = false;
770     if (!tried) {
771         QSystemLibrary dwmLib(L"dwmapi");
772         pDwmIsCompositionEnabled =
773             (PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled");
774         if (pDwmIsCompositionEnabled) {
775             pDwmDefWindowProc = (PtrDwmDefWindowProc)dwmLib.resolve("DwmDefWindowProc");
776             pDwmExtendFrameIntoClientArea =
777                 (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea");
778         }
779         QSystemLibrary themeLib(L"uxtheme");
780         pIsAppThemed = (PtrIsAppThemed)themeLib.resolve("IsAppThemed");
781         if (pIsAppThemed) {
782             pDrawThemeBackground = (PtrDrawThemeBackground)themeLib.resolve("DrawThemeBackground");
783             pGetThemePartSize = (PtrGetThemePartSize)themeLib.resolve("GetThemePartSize");
784             pGetThemeColor = (PtrGetThemeColor)themeLib.resolve("GetThemeColor");
785             pIsThemeActive = (PtrIsThemeActive)themeLib.resolve("IsThemeActive");
786             pOpenThemeData = (PtrOpenThemeData)themeLib.resolve("OpenThemeData");
787             pCloseThemeData = (PtrCloseThemeData)themeLib.resolve("CloseThemeData");
788             pGetThemeSysFont = (PtrGetThemeSysFont)themeLib.resolve("GetThemeSysFont");
789             pDrawThemeTextEx = (PtrDrawThemeTextEx)themeLib.resolve("DrawThemeTextEx");
790             pSetWindowThemeAttribute = (PtrSetWindowThemeAttribute)themeLib.resolve("SetWindowThemeAttribute");
791         }
792         tried = true;
793     }
794 
795     return (
796         pDwmIsCompositionEnabled != 0
797         && pDwmDefWindowProc != 0
798         && pDwmExtendFrameIntoClientArea != 0
799         && pIsAppThemed != 0
800         && pDrawThemeBackground != 0
801         && pGetThemePartSize != 0
802         && pGetThemeColor != 0
803         && pIsThemeActive != 0
804         && pOpenThemeData != 0
805         && pCloseThemeData != 0
806         && pGetThemeSysFont != 0
807         && pDrawThemeTextEx != 0
808         && pSetWindowThemeAttribute != 0
809         );
810 }
811 
titleOffset()812 int QVistaHelper::titleOffset()
813 {
814     int iconOffset = wizard ->windowIcon().isNull() ? 0 : iconSize() + textSpacing;
815     return leftMargin() + iconOffset;
816 }
817 
topOffset()818 int QVistaHelper::topOffset()
819 {
820     if (vistaState() != VistaAero)
821         return titleBarSize() + 3;
822     static const int aeroOffset =
823         QSysInfo::WindowsVersion == QSysInfo::WV_WINDOWS7 ?
824         QStyleHelper::dpiScaled(4) : QStyleHelper::dpiScaled(13);
825     return aeroOffset + titleBarSize();
826 }
827 
828 QT_END_NAMESPACE
829 
830 #endif // QT_NO_STYLE_WINDOWSVISTA
831 
832 #endif // QT_NO_WIZARD
833