230 lines
6.7 KiB
C++
230 lines
6.7 KiB
C++
|
/****************************************************************************
|
||
|
**
|
||
|
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||
|
**
|
||
|
** Use, modification and distribution is allowed without limitation,
|
||
|
** warranty, liability or support of any kind.
|
||
|
**
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "qtwin.h"
|
||
|
#include <QLibrary>
|
||
|
#include <QApplication>
|
||
|
#include <QWidget>
|
||
|
#include <QList>
|
||
|
#include <QPointer>
|
||
|
|
||
|
#ifdef Q_WS_WIN
|
||
|
|
||
|
#include <qt_windows.h>
|
||
|
|
||
|
// Blur behind data structures
|
||
|
#define DWM_BB_ENABLE 0x00000001 // fEnable has been specified
|
||
|
#define DWM_BB_BLURREGION 0x00000002 // hRgnBlur has been specified
|
||
|
#define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 // fTransitionOnMaximized has been specified
|
||
|
#define WM_DWMCOMPOSITIONCHANGED 0x031E // Composition changed window message
|
||
|
|
||
|
typedef struct _DWM_BLURBEHIND
|
||
|
{
|
||
|
DWORD dwFlags;
|
||
|
BOOL fEnable;
|
||
|
HRGN hRgnBlur;
|
||
|
BOOL fTransitionOnMaximized;
|
||
|
} DWM_BLURBEHIND, *PDWM_BLURBEHIND;
|
||
|
|
||
|
typedef struct _MARGINS
|
||
|
{
|
||
|
int cxLeftWidth;
|
||
|
int cxRightWidth;
|
||
|
int cyTopHeight;
|
||
|
int cyBottomHeight;
|
||
|
} MARGINS, *PMARGINS;
|
||
|
|
||
|
typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL* pfEnabled);
|
||
|
typedef HRESULT (WINAPI *PtrDwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
|
||
|
typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
|
||
|
typedef HRESULT (WINAPI *PtrDwmGetColorizationColor)(DWORD *pcrColorization, BOOL *pfOpaqueBlend);
|
||
|
|
||
|
static PtrDwmIsCompositionEnabled pDwmIsCompositionEnabled= 0;
|
||
|
static PtrDwmEnableBlurBehindWindow pDwmEnableBlurBehindWindow = 0;
|
||
|
static PtrDwmExtendFrameIntoClientArea pDwmExtendFrameIntoClientArea = 0;
|
||
|
static PtrDwmGetColorizationColor pDwmGetColorizationColor = 0;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Internal helper class that notifies windows if the
|
||
|
* DWM compositing state changes and updates the widget
|
||
|
* flags correspondingly.
|
||
|
*/
|
||
|
class WindowNotifier : public QWidget
|
||
|
{
|
||
|
public:
|
||
|
WindowNotifier() { winId(); }
|
||
|
void addWidget(QWidget *widget) { widgets.append(widget); }
|
||
|
void removeWidget(QWidget *widget) { widgets.removeAll(widget); }
|
||
|
bool winEvent(MSG *message, long *result);
|
||
|
|
||
|
private:
|
||
|
QWidgetList widgets;
|
||
|
};
|
||
|
|
||
|
static bool resolveLibs()
|
||
|
{
|
||
|
if (!pDwmIsCompositionEnabled) {
|
||
|
QLibrary dwmLib(QString::fromAscii("dwmapi"));
|
||
|
pDwmIsCompositionEnabled =(PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled");
|
||
|
pDwmExtendFrameIntoClientArea = (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea");
|
||
|
pDwmEnableBlurBehindWindow = (PtrDwmEnableBlurBehindWindow)dwmLib.resolve("DwmEnableBlurBehindWindow");
|
||
|
pDwmGetColorizationColor = (PtrDwmGetColorizationColor)dwmLib.resolve("DwmGetColorizationColor");
|
||
|
}
|
||
|
return pDwmIsCompositionEnabled != 0;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*!
|
||
|
* Chekcs and returns true if Windows DWM composition
|
||
|
* is currently enabled on the system.
|
||
|
*
|
||
|
* To get live notification on the availability of
|
||
|
* this feature, you will currently have to
|
||
|
* reimplement winEvent() on your widget and listen
|
||
|
* for the WM_DWMCOMPOSITIONCHANGED event to occur.
|
||
|
*
|
||
|
*/
|
||
|
bool QtWin::isCompositionEnabled()
|
||
|
{
|
||
|
#ifdef Q_WS_WIN
|
||
|
if (resolveLibs()) {
|
||
|
HRESULT hr = S_OK;
|
||
|
BOOL isEnabled = false;
|
||
|
hr = pDwmIsCompositionEnabled(&isEnabled);
|
||
|
if (SUCCEEDED(hr))
|
||
|
return isEnabled;
|
||
|
}
|
||
|
#endif
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Enables Blur behind on a Widget.
|
||
|
*
|
||
|
* \a enable tells if the blur should be enabled or not
|
||
|
*/
|
||
|
bool QtWin::enableBlurBehindWindow(QWidget *widget, bool enable,
|
||
|
const QRegion ®ion)
|
||
|
{
|
||
|
Q_ASSERT(widget);
|
||
|
bool result = false;
|
||
|
#ifdef Q_WS_WIN
|
||
|
if (resolveLibs()) {
|
||
|
DWM_BLURBEHIND bb = {0};
|
||
|
HRESULT hr = S_OK;
|
||
|
bb.fEnable = enable;
|
||
|
bb.dwFlags = DWM_BB_ENABLE;
|
||
|
bb.hRgnBlur = NULL;
|
||
|
|
||
|
if (!region.isEmpty()) {
|
||
|
bb.dwFlags |= DWM_BB_BLURREGION;
|
||
|
bb.hRgnBlur = region.handle();
|
||
|
}
|
||
|
|
||
|
widget->setAttribute(Qt::WA_TranslucentBackground, enable);
|
||
|
widget->setAttribute(Qt::WA_NoSystemBackground, enable);
|
||
|
hr = pDwmEnableBlurBehindWindow(widget->winId(), &bb);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
result = true;
|
||
|
windowNotifier()->addWidget(widget);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* ExtendFrameIntoClientArea.
|
||
|
*
|
||
|
* This controls the rendering of the frame inside the window.
|
||
|
* Note that passing margins of -1 (the default value) will completely
|
||
|
* remove the frame from the window.
|
||
|
*
|
||
|
* \note you should not call enableBlurBehindWindow before calling
|
||
|
* this functions
|
||
|
*
|
||
|
* \a enable tells if the blur should be enabled or not
|
||
|
*/
|
||
|
bool QtWin::extendFrameIntoClientArea(QWidget *widget, int left, int top, int right, int bottom)
|
||
|
{
|
||
|
|
||
|
Q_ASSERT(widget);
|
||
|
Q_UNUSED(left);
|
||
|
Q_UNUSED(top);
|
||
|
Q_UNUSED(right);
|
||
|
Q_UNUSED(bottom);
|
||
|
|
||
|
bool result = false;
|
||
|
#ifdef Q_WS_WIN
|
||
|
if (resolveLibs()) {
|
||
|
QLibrary dwmLib(QString::fromAscii("dwmapi"));
|
||
|
HRESULT hr = S_OK;
|
||
|
MARGINS m = {left, top, right, bottom};
|
||
|
hr = pDwmExtendFrameIntoClientArea(widget->winId(), &m);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
result = true;
|
||
|
windowNotifier()->addWidget(widget);
|
||
|
}
|
||
|
widget->setAttribute(Qt::WA_TranslucentBackground, result);
|
||
|
}
|
||
|
#endif
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Returns the current colorizationColor for the window.
|
||
|
*
|
||
|
* \a enable tells if the blur should be enabled or not
|
||
|
*/
|
||
|
QColor QtWin::colorizatinColor()
|
||
|
{
|
||
|
QColor resultColor = QApplication::palette().window().color();
|
||
|
|
||
|
#ifdef Q_WS_WIN
|
||
|
if (resolveLibs()) {
|
||
|
DWORD color = 0;
|
||
|
BOOL opaque = FALSE;
|
||
|
QLibrary dwmLib(QString::fromAscii("dwmapi"));
|
||
|
HRESULT hr = S_OK;
|
||
|
hr = pDwmGetColorizationColor(&color, &opaque);
|
||
|
if (SUCCEEDED(hr))
|
||
|
resultColor = QColor(color);
|
||
|
}
|
||
|
#endif
|
||
|
return resultColor;
|
||
|
}
|
||
|
|
||
|
#ifdef Q_WS_WIN
|
||
|
WindowNotifier *QtWin::windowNotifier()
|
||
|
{
|
||
|
static WindowNotifier *windowNotifierInstance = 0;
|
||
|
if (!windowNotifierInstance)
|
||
|
windowNotifierInstance = new WindowNotifier;
|
||
|
return windowNotifierInstance;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Notify all enabled windows that the DWM state changed */
|
||
|
bool WindowNotifier::winEvent(MSG *message, long *result)
|
||
|
{
|
||
|
if (message && message->message == WM_DWMCOMPOSITIONCHANGED) {
|
||
|
bool compositionEnabled = QtWin::isCompositionEnabled();
|
||
|
foreach(QWidget * widget, widgets) {
|
||
|
if (widget) {
|
||
|
widget->setAttribute(Qt::WA_NoSystemBackground, compositionEnabled);
|
||
|
}
|
||
|
widget->update();
|
||
|
}
|
||
|
}
|
||
|
return QWidget::winEvent(message, result);
|
||
|
}
|
||
|
#endif
|