Blur behind the pretty OSD on Windows Vista and above

This commit is contained in:
David Sansome 2010-07-07 23:03:35 +00:00
parent e9525e8ec3
commit f151df00b0
6 changed files with 293 additions and 8 deletions

9
3rdparty/qtwin/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.6)
set(QTWIN-SOURCES
qtwin.cpp
)
ADD_LIBRARY(qtwin STATIC
${QTWIN-SOURCES}
)

229
3rdparty/qtwin/qtwin.cpp vendored Normal file
View File

@ -0,0 +1,229 @@
/****************************************************************************
**
** 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 &region)
{
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

38
3rdparty/qtwin/qtwin.h vendored Normal file
View File

@ -0,0 +1,38 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef QTWIN_H
#define QTWIN_H
#include <QColor>
#include <QWidget>
/**
* This is a helper class for using the Desktop Window Manager
* functionality on Windows 7 and Windows Vista. On other platforms
* these functions will simply not do anything.
*/
class WindowNotifier;
class QtWin
{
public:
static bool enableBlurBehindWindow(QWidget *widget, bool enable = true,
const QRegion& region = QRegion());
static bool extendFrameIntoClientArea(QWidget *widget,
int left = -1, int top = -1,
int right = -1, int bottom = -1);
static bool isCompositionEnabled();
static QColor colorizatinColor();
private:
static WindowNotifier *windowNotifier();
};
#endif // QTWIN_H

View File

@ -156,6 +156,7 @@ add_subdirectory(src)
if (NOT APPLE) if (NOT APPLE)
add_subdirectory(3rdparty/qxt) add_subdirectory(3rdparty/qxt)
endif (NOT APPLE) endif (NOT APPLE)
add_subdirectory(3rdparty/qtwin)
add_subdirectory(3rdparty/universalchardet) add_subdirectory(3rdparty/universalchardet)
add_subdirectory(tests) add_subdirectory(tests)
add_subdirectory(dist) add_subdirectory(dist)

View File

@ -8,6 +8,7 @@ include_directories(${SPARKLE})
include_directories(../3rdparty/gmock/gtest/include) include_directories(../3rdparty/gmock/gtest/include)
include_directories(../3rdparty/qtsingleapplication) include_directories(../3rdparty/qtsingleapplication)
include_directories(../3rdparty/qtiocompressor) include_directories(../3rdparty/qtiocompressor)
include_directories(../3rdparty/qtwin)
include_directories(../3rdparty/qxt) include_directories(../3rdparty/qxt)
include_directories(../3rdparty/libprojectm) include_directories(../3rdparty/libprojectm)
@ -516,6 +517,7 @@ add_dependencies(clementine_lib pot)
target_link_libraries(clementine_lib target_link_libraries(clementine_lib
qtsingleapplication qtsingleapplication
qtiocompressor qtiocompressor
qtwin
chardet chardet
${GOBJECT_LIBRARIES} ${GOBJECT_LIBRARIES}
${GLIB_LIBRARIES} ${GLIB_LIBRARIES}

View File

@ -17,6 +17,8 @@
#include "osdpretty.h" #include "osdpretty.h"
#include "ui_osdpretty.h" #include "ui_osdpretty.h"
#include "qtwin.h"
#include <QColor> #include <QColor>
#include <QPainter> #include <QPainter>
#include <QLayout> #include <QLayout>
@ -278,11 +280,7 @@ void OSDPretty::Reposition() {
move(qBound(0, x, geometry.right() - width()), move(qBound(0, x, geometry.right() - width()),
qBound(0, y, geometry.bottom() - height())); qBound(0, y, geometry.bottom() - height()));
// If there's no compositing window manager running then we have to set an // Create a mask for the actual area of the OSD
// XShape mask.
if (IsTransparencyAvailable())
clearMask();
else {
QBitmap mask(size()); QBitmap mask(size());
mask.clear(); mask.clear();
@ -291,8 +289,16 @@ void OSDPretty::Reposition() {
p.drawRoundedRect(BoxBorder().adjusted(-1, -1, 0, 0), kBorderRadius, kBorderRadius); p.drawRoundedRect(BoxBorder().adjusted(-1, -1, 0, 0), kBorderRadius, kBorderRadius);
p.end(); p.end();
// If there's no compositing window manager running then we have to set an
// XShape mask.
if (IsTransparencyAvailable())
clearMask();
else {
setMask(mask); setMask(mask);
} }
// On windows, enable blurbehind on the masked area
QtWin::enableBlurBehindWindow(this, true, QRegion(mask));
} }
void OSDPretty::enterEvent(QEvent *) { void OSDPretty::enterEvent(QEvent *) {