source: tspsg/src/qtwin.cpp @ 545591d1a9

appveyorimgbotreadme
Last change on this file since 545591d1a9 was 545591d1a9, checked in by Oleksii Serdiuk, 12 years ago

Made window background semi-transparent under X11.

Insted of fully transparent when translucency effects are enabled.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4**
5** Use, modification and distribution is allowed without limitation,
6** warranty, liability or support of any kind.
7**
8****************************************************************************/
9
10#include "qtwin.h"
11#include <QLibrary>
12#include <QApplication>
13#include <QWidget>
14#include <QList>
15#include <QPointer>
16
17//! \todo TODO: Detect X11 in Qt 5 more reliably
18// No Q_WS_X11 in Qt 5. Check if we're using X11 and define it.
19#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) && defined(Q_OS_UNIX) && !defined(Q_WS_X11)
20#   if !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) && !defined(Q_WS_QPA)
21#       define Q_WS_X11
22#   endif
23#endif
24
25#ifdef Q_WS_X11
26#include <X11/Xlib.h>
27#endif // Q_WS_X11
28
29#ifdef Q_OS_WIN32
30
31#include <qt_windows.h>
32
33// Blur behind data structures
34#define DWM_BB_ENABLE                 0x00000001  // fEnable has been specified
35#define DWM_BB_BLURREGION             0x00000002  // hRgnBlur has been specified
36#define DWM_BB_TRANSITIONONMAXIMIZED  0x00000004  // fTransitionOnMaximized has been specified
37#define WM_DWMCOMPOSITIONCHANGED        0x031E    // Composition changed window message
38
39typedef struct _DWM_BLURBEHIND
40{
41    DWORD dwFlags;
42    BOOL fEnable;
43    HRGN hRgnBlur;
44    BOOL fTransitionOnMaximized;
45} DWM_BLURBEHIND, *PDWM_BLURBEHIND;
46
47typedef struct _MARGINS
48{
49    int cxLeftWidth;
50    int cxRightWidth;
51    int cyTopHeight;
52    int cyBottomHeight;
53} MARGINS, *PMARGINS;
54
55typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL* pfEnabled);
56typedef HRESULT (WINAPI *PtrDwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
57typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
58typedef HRESULT (WINAPI *PtrDwmGetColorizationColor)(DWORD *pcrColorization, BOOL *pfOpaqueBlend);
59
60static PtrDwmIsCompositionEnabled pDwmIsCompositionEnabled= 0;
61static PtrDwmEnableBlurBehindWindow pDwmEnableBlurBehindWindow = 0;
62static PtrDwmExtendFrameIntoClientArea pDwmExtendFrameIntoClientArea = 0;
63static PtrDwmGetColorizationColor pDwmGetColorizationColor = 0;
64
65
66/*
67 * Internal helper class that notifies windows if the
68 * DWM compositing state changes and updates the widget
69 * flags correspondingly.
70 */
71class WindowNotifier : public QWidget
72{
73public:
74    WindowNotifier() { winId(); }
75    void addWidget(QWidget *widget) { widgets.append(widget); }
76    void removeWidget(QWidget *widget) { widgets.removeAll(widget); }
77    bool winEvent(MSG *message, long *result);
78
79private:
80    QWidgetList widgets;
81};
82
83static bool resolveLibs()
84{
85    if (!pDwmIsCompositionEnabled) {
86        QLibrary dwmLib(QString::fromAscii("dwmapi"));
87        pDwmIsCompositionEnabled =(PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled");
88        pDwmExtendFrameIntoClientArea = (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea");
89        pDwmEnableBlurBehindWindow = (PtrDwmEnableBlurBehindWindow)dwmLib.resolve("DwmEnableBlurBehindWindow");
90        pDwmGetColorizationColor = (PtrDwmGetColorizationColor)dwmLib.resolve("DwmGetColorizationColor");
91    }
92    return pDwmIsCompositionEnabled != 0;
93}
94
95#endif
96
97/*!
98  * Chekcs and returns true if Windows DWM composition
99  * is currently enabled on the system.
100  *
101  * To get live notification on the availability of
102  * this feature, you will currently have to
103  * reimplement winEvent() on your widget and listen
104  * for the WM_DWMCOMPOSITIONCHANGED event to occur.
105  *
106  */
107bool QtWin::isCompositionEnabled()
108{
109#ifdef Q_OS_WIN32
110    if (resolveLibs()) {
111        HRESULT hr = S_OK;
112        BOOL isEnabled = false;
113        hr = pDwmIsCompositionEnabled(&isEnabled);
114        if (SUCCEEDED(hr))
115            return isEnabled;
116    }
117    return false;
118#elif defined(Q_WS_X11)
119    Display *d = XOpenDisplay(NULL);
120    Atom _NET_WM_CM_S0 = XInternAtom(d, "_NET_WM_CM_S0", true);
121    bool result = (_NET_WM_CM_S0 != None);
122    if (result)
123        result = (XGetSelectionOwner(d, _NET_WM_CM_S0) != None);
124    XCloseDisplay(d);
125    return result;
126#else
127    //! \todo TODO: Check for trsnsparency support in other OSes.
128    return false;
129#endif
130}
131
132/*!
133  * Enables Blur behind on a Widget.
134  *
135  * \a enable tells if the blur should be enabled or not
136  */
137bool QtWin::enableBlurBehindWindow(QWidget *widget, bool enable)
138{
139    Q_ASSERT(widget);
140    bool result = false;
141#ifdef Q_OS_WIN32
142    if (resolveLibs()) {
143        DWM_BLURBEHIND bb = {0};
144        HRESULT hr = S_OK;
145        bb.fEnable = enable;
146        bb.dwFlags = DWM_BB_ENABLE;
147        bb.hRgnBlur = NULL;
148#endif
149        widget->setAttribute(Qt::WA_TranslucentBackground, enable);
150#ifdef Q_WS_X11
151        widget->setAttribute(Qt::WA_NoSystemBackground, false);
152        QPalette p = widget->palette();
153        QColor c = p.color(QPalette::Window);
154        if (enable)
155            c.setAlpha(160);
156        else
157            c.setAlpha(255);
158        p.setColor(QPalette::Window, c);
159        widget->setPalette(p);
160        result = true;
161#endif
162#ifdef Q_OS_WIN32
163        hr = pDwmEnableBlurBehindWindow(HWND(widget->winId()), &bb);
164        if (SUCCEEDED(hr)) {
165            result = true;
166            windowNotifier()->addWidget(widget);
167        }
168    }
169#endif
170    return result;
171}
172
173/*!
174  * ExtendFrameIntoClientArea.
175  *
176  * This controls the rendering of the frame inside the window.
177  * Note that passing margins of -1 (the default value) will completely
178  * remove the frame from the window.
179  *
180  * \note you should not call enableBlurBehindWindow before calling
181  *       this functions
182  *
183  * \a enable tells if the blur should be enabled or not
184  */
185bool QtWin::extendFrameIntoClientArea(QWidget *widget, int left, int top, int right, int bottom)
186{
187
188    Q_ASSERT(widget);
189    Q_UNUSED(widget);
190    Q_UNUSED(left);
191    Q_UNUSED(top);
192    Q_UNUSED(right);
193    Q_UNUSED(bottom);
194
195    bool result = false;
196#ifdef Q_OS_WIN32
197    if (resolveLibs()) {
198        QLibrary dwmLib(QString::fromAscii("dwmapi"));
199        HRESULT hr = S_OK;
200        MARGINS m = {left, top, right, bottom};
201        hr = pDwmExtendFrameIntoClientArea(HWND(widget->winId()), &m);
202        if (SUCCEEDED(hr)) {
203            result = true;
204            windowNotifier()->addWidget(widget);
205        }
206        widget->setAttribute(Qt::WA_TranslucentBackground, result);
207    }
208#endif
209    return result;
210}
211
212/*!
213  * Returns the current colorizationColor for the window.
214  *
215  * \a enable tells if the blur should be enabled or not
216  */
217QColor QtWin::colorizatinColor()
218{
219    QColor resultColor = QApplication::palette().window().color();
220
221#ifdef Q_OS_WIN32
222    if (resolveLibs()) {
223        DWORD color = 0;
224        BOOL opaque = FALSE;
225        QLibrary dwmLib(QString::fromAscii("dwmapi"));
226        HRESULT hr = S_OK;
227        hr = pDwmGetColorizationColor(&color, &opaque);
228        if (SUCCEEDED(hr))
229            resultColor = QColor(color);
230    }
231#endif
232    return resultColor;
233}
234
235#ifdef Q_OS_WIN32
236WindowNotifier *QtWin::windowNotifier()
237{
238    static WindowNotifier *windowNotifierInstance = 0;
239    if (!windowNotifierInstance)
240        windowNotifierInstance = new WindowNotifier;
241    return windowNotifierInstance;
242}
243
244
245/* Notify all enabled windows that the DWM state changed */
246bool WindowNotifier::winEvent(MSG *message, long *result)
247{
248    if (message && message->message == WM_DWMCOMPOSITIONCHANGED) {
249        bool compositionEnabled = QtWin::isCompositionEnabled();
250        foreach(QWidget * widget, widgets) {
251            if (widget) {
252                widget->setAttribute(Qt::WA_NoSystemBackground, compositionEnabled);
253            }
254            widget->update();
255        }
256    }
257    return QWidget::winEvent(message, result);
258}
259#endif
Note: See TracBrowser for help on using the repository browser.