/**************************************************************************** ** ** 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 #include #include #include #include #ifdef Q_WS_WIN #include // 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; } return false; #elif !defined(HANDHELD) //! \todo TODO: Check for trsnsparency support in other OSes. return true; #else return false; #endif } /*! * Enables Blur behind on a Widget. * * \a enable tells if the blur should be enabled or not */ bool QtWin::enableBlurBehindWindow(QWidget *widget, bool enable) { Q_ASSERT(widget); Q_UNUSED(widget); Q_UNUSED(enable); 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; #endif widget->setAttribute(Qt::WA_TranslucentBackground, enable); widget->setAttribute(Qt::WA_NoSystemBackground, enable); #ifdef Q_WS_WIN 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(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