Thursday, March 31, 2011

Qt Windows 7 extend frame into client area with transparency

I wanted to have something similar to these below:


Making the window transparent did not help me much. I was getting this:

I could not get rid of the margins.

After some research I figured out, and the result can be seen below:




To get merge the margins with the window frame it is enough to call DwmExtendFrameIntoClientArea with the margins value set to -1.

void ExtendFrameIntoClientArea(QWidget* widget) {
    MARGINS margins = {-1};

    DwmExtendFrameIntoClientArea(widget->winId(), &margins);
}


The transparency part is easy, it was published long time ago:

long EnableBlurBehindWidget(QWidget* widget, bool enable)
{
    HWND hwnd = widget->winId();
    HRESULT hr = S_OK;

    widget->setAttribute(Qt::WA_TranslucentBackground, enable);
    widget->setAttribute(Qt::WA_NoSystemBackground, enable);

    // Create and populate the Blur Behind structure
    DWM_BLURBEHIND bb = {0};

    bb.dwFlags = DWM_BB_ENABLE;
    bb.fEnable = enable;
    bb.hRgnBlur = NULL;

    DwmEnableBlurBehindWindow(hwnd, &bb);
    return hr;
}

I have managed to compile this using MINGW. The DwmEnableBlurBehindWindow and DwmExtendFrameIntoClientArea are loaded directly from dwmapi.dll.

#include <windows.h>

#define DWM_BB_ENABLE                 0x00000001  // fEnable has been specified

typedef struct _DWM_BLURBEHIND
{
    DWORD dwFlags;
    BOOL fEnable;
    HRGN hRgnBlur;
    BOOL fTransitionOnMaximized;
} DWM_BLURBEHIND, *PDWM_BLURBEHIND;

typedef struct _MARGINS
{
    int cxLeftWidth;      // width of left border that retains its size
    int cxRightWidth;     // width of right border that retains its size
    int cyTopHeight;      // height of top border that retains its size
    int cyBottomHeight;   // height of bottom border that retains its size
} MARGINS, *PMARGINS;

extern "C"
{
    typedef HRESULT (WINAPI *t_DwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
    typedef HRESULT (WINAPI *t_DwmExtendFrameIntoClientArea)(HWND hwnd, const MARGINS *pMarInset);
}

void DwmExtendFrameIntoClientArea(HWND hwnd, const MARGINS *pMarInset) {
    HMODULE shell;

    shell = LoadLibrary(L"dwmapi.dll");
    if (shell) {
        t_DwmExtendFrameIntoClientArea set_window_frame_into_client_area = reinterpret_cast<t_DwmExtendFrameIntoClientArea>(GetProcAddress (shell, "DwmExtendFrameIntoClientArea"));
        set_window_frame_into_client_area(hwnd, pMarInset);

        FreeLibrary (shell);
    }

}

void DwmEnableBlurBehindWindow(HWND hwnd, const DWM_BLURBEHIND* pBlurBehind) {
    HMODULE shell;

    shell = LoadLibrary(L"dwmapi.dll");
    if (shell) {
        t_DwmEnableBlurBehindWindow set_window_blur = reinterpret_cast<t_DwmEnableBlurBehindWindow>(GetProcAddress (shell, "DwmEnableBlurBehindWindow"));
        set_window_blur(hwnd, pBlurBehind);

        FreeLibrary (shell);
    }
}

The project can be downloaded from here.

8 comments:

jhon apps said...

why the coding is hidden ???

make facebook applications

Nicolae Ghimbovschi said...

All the code is available here https://github.com/xfreebird/blogstuff/tree/master/qt/qtwindow7_tweak. This link is also in the post.

nazikus said...

Thanks for your example.
But when I was trying to compile your code for some reasone I'm missing 'libgdi32.obj'. Any idea whats wrong?

LINK : fatal error LNK1181: cannot open input file 'libgdi32.obj'

Qt4.8.4, VS2010, Win7

Nicolae Ghimbovschi said...

This is a mingw project.
With VS2010 I believe you need to change the libgdi32 to gdi32 in the project file (qtwindow7_tweak.pro)

And with VS2010 you have direct access to DwmExtendFrameIntoClientArea and DwmEnableBlurBehindWindow. No need to load the directly from dwmapi.dll.

nazikus said...

indeed, switching linker to gdi32.lib helped. Thanks again

ebelcrom said...
This comment has been removed by the author.
ebelcrom said...

Great! I played around with your code and found two ugly things in my application:

1. group boxes disappears in blurred and none blurred areas/widgets
2. labels (dark by defalut) are hard to read in blurred areas/widgets

Dou you have any idea how to solve these issues?

Nicolae Ghimbovschi said...

May be you could try to change the colors for those items. I haven't experimented with that. But I think it might help.