4

I would like to get a semi-transparent blurred window in QML on Windows 10 similar to the Fluent Design guidelines (example). I know you can make a transparent window:

Window{
    visible: true
    color: "transparent"
}

but this doesn't achieve the blur effect I am looking at. I am also aware that one can blur elements inside the windows using QtGraphicalEffects like FastBlur but I would like to blur the entire window itself. Is there a way to achieve this? I have also tried using the QtWinExtras module and call QtWin::enableBlurBehindWindow but this doesn't work either:

    QObject *root = engine.rootObjects()[0];
    QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
    if (!window) {
        qFatal("Error: Your root item has to be a window.");
        return -1;
    }
    QtWin::enableBlurBehindWindow(window);
reckless
  • 741
  • 12
  • 53
  • Maybe [this](https://forum.qt.io/topic/51055/enableblurbehindwindow-not-working/3) will help to solve your problem – BrutalWizard Aug 23 '19 at 18:57
  • That seems to apply to QWidgets and QWindows – reckless Aug 23 '19 at 19:44
  • Is [this](https://imgur.com/o1h1g50) and [this](https://imgur.com/gZUT8BE), what're you expecting? (It can be more blured or more transparet) – BrutalWizard Aug 23 '19 at 21:45
  • Not really, I think what you did was make a window transparent and applied a semi transparent rectangle with a gradient on it. I am looking for what Microsoft calls "Acrylic Material" – reckless Aug 23 '19 at 22:41

1 Answers1

5

Ok so I found a solution that turned out to be easier than I thought it would be. Officially Microsoft does not provide an API to achieve what I was looking for. I stumbled across this thread and I found this. From there I adapted the code to my needs, I created a header file containing:

#ifndef STRUCTS_H
#define STRUCTS_H
#include <windef.h>
#pragma once

typedef enum _WINDOWCOMPOSITIONATTRIB
{
    WCA_UNDEFINED = 0,
    WCA_NCRENDERING_ENABLED = 1,
    WCA_NCRENDERING_POLICY = 2,
    WCA_TRANSITIONS_FORCEDISABLED = 3,
    WCA_ALLOW_NCPAINT = 4,
    WCA_CAPTION_BUTTON_BOUNDS = 5,
    WCA_NONCLIENT_RTL_LAYOUT = 6,
    WCA_FORCE_ICONIC_REPRESENTATION = 7,
    WCA_EXTENDED_FRAME_BOUNDS = 8,
    WCA_HAS_ICONIC_BITMAP = 9,
    WCA_THEME_ATTRIBUTES = 10,
    WCA_NCRENDERING_EXILED = 11,
    WCA_NCADORNMENTINFO = 12,
    WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
    WCA_VIDEO_OVERLAY_ACTIVE = 14,
    WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
    WCA_DISALLOW_PEEK = 16,
    WCA_CLOAK = 17,
    WCA_CLOAKED = 18,
    WCA_ACCENT_POLICY = 19,
    WCA_FREEZE_REPRESENTATION = 20,
    WCA_EVER_UNCLOAKED = 21,
    WCA_VISUAL_OWNER = 22,
    WCA_HOLOGRAPHIC = 23,
    WCA_EXCLUDED_FROM_DDA = 24,
    WCA_PASSIVEUPDATEMODE = 25,
    WCA_LAST = 26
} WINDOWCOMPOSITIONATTRIB;

typedef struct _WINDOWCOMPOSITIONATTRIBDATA
{
    WINDOWCOMPOSITIONATTRIB Attrib;
    PVOID pvData;
    SIZE_T cbData;
} WINDOWCOMPOSITIONATTRIBDATA;

typedef enum _ACCENT_STATE
{
    ACCENT_DISABLED = 0,
    ACCENT_ENABLE_GRADIENT = 1,
    ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
    ACCENT_ENABLE_BLURBEHIND = 3,
    ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
    ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809
    ACCENT_INVALID_STATE = 6
} ACCENT_STATE;

typedef struct _ACCENT_POLICY
{
    ACCENT_STATE AccentState;
    DWORD AccentFlags;
    DWORD GradientColor;
    DWORD AnimationId;
} ACCENT_POLICY;

typedef BOOL (WINAPI *pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*);

typedef BOOL (WINAPI *pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*);
#endif // STRUCTS_H

And then in my main.cpp:

#ifdef Q_OS_WIN
#include <QQuickWindow>
#include <windows.h>
#include <WinUser.h>
#include "structs.h" // my header file
#endif

#ifdef Q_OS_WIN
    QObject *root = engine.rootObjects()[0];
    QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
    if (!window) {
        qFatal("Error: Your root item has to be a window.");
        return -1;
    }
    HWND hwnd = (HWND)window->winId();
    HMODULE hUser = GetModuleHandle(L"user32.dll");
    if (hUser)
    {
        pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute");
        if (setWindowCompositionAttribute)
        {
            ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 };
            WINDOWCOMPOSITIONATTRIBDATA data;
            data.Attrib = WCA_ACCENT_POLICY;
            data.pvData = &accent;
            data.cbData = sizeof(accent);
            setWindowCompositionAttribute(hwnd, &data);
        }
    }
#endif

This enables the "Acrylic Material" effect I was looking for (in QML you have to set the window color to "transparent").

reckless
  • 741
  • 12
  • 53
  • actually, I believe this is "glass" material, not "acrylic" since you're not using ACCENT_ENABLE_ACRYLICBLURBEHIND but ACCENT_ENABLE_BLURBEHIND – Simon Mourier May 03 '20 at 08:33
  • @SimonMourier While what you're saying is correct. `ACCENT_ACRYLICBLURBEHIND` has significant performance disadvantages, doing it this way. In this case `BLURBEHIND` is preferred. – Peter Jan 21 '22 at 14:59