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