Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF glass window with no border and no resize out of focus

I am trying to create a Aero glass borderless and non-resizable WPF window using the DwmEnableBlurBehindWindow method from the DmwAPI. However, for some strange reason the glass color of this window appears as if the window is out of focus. As you can see in the next three images, the normal windows with borders (e.g figure 1 and 2) work just fine and react as expected (dark blue in focus, whitish when out of focus (= non active)).

DwmEnableBlurBehindWindow with ToolWindowDwmEnableBlurBehindWindow with ToolWindow out of focus

The borderless window with resizing allowed, shows the same behavior:

DwmEnableBlurBehindWindow with borderless but resizable window

The non-resizable borderless window however will always look as if it is out of focus (as you can see in the last figure 3) both when it is active and non-active. It always looks whitish:

DwmEnableBlurBehindWindow with borderless and non-resizable window

This is some example code of how I set the glass style:

public MainWindow()
{
    InitializeComponent();

    WindowStyle = WindowStyle.None;
    ResizeMode = ResizeMode.NoResize;

    Height = 200;

    Background = Brushes.Transparent;
    Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    var windowInteropHelper = new WindowInteropHelper(this);
    var handle = windowInteropHelper.Handle;
    var mainWindowSrc = HwndSource.FromHwnd(handle);

    if (mainWindowSrc != null)
        if (mainWindowSrc.CompositionTarget != null)
            mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);
    var glassParams = new DwmApi.DwmBlurbehind
    {
        dwFlags = DwmApi.DwmBlurbehind.DWM_BB_ENABLE,
        fEnable = true,
        hRegionBlur = IntPtr.Zero
    };

    IntPtr dis = new IntPtr(2);
    DwmApi.DwmSetWindowAttribute(mainWindowSrc.Handle,
                DwmApi.DwmWindowAttribute.DWMWA_LAST,
                dis,
                sizeof(uint));

    DwmApi.DwmEnableBlurBehindWindow(
        handle,
        glassParams
        );
}

I tried focusing the window, but that doesn't seem to affect the behavior. Any ideas or pointers on how to solve this?

like image 668
dsfgsho Avatar asked Jun 22 '13 00:06

dsfgsho


1 Answers

I haven't worked much in dwm apis so I may be wrong but I think the default dwm rendering policy is using WindowStyle to figure out rendering. If you disable that policy, it behaves as you'd expect it to.

Add the following bit to fix your blues xD

const int DWMWA_NCRENDERING_POLICY = 2;
int DWMNCRP_DISABLED = 2;

DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, ref DWMNCRP_DISABLED, sizeof(int));

For details of this voodoo, please check the following resources:

DwmSetWindowAttribute function

DWMWINDOWATTRIBUTE enumeration

MainWindow.xaml

<Window x:Class="dwm.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"/>

MainWindow.xaml.cs

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace dwm
{
    public partial class MainWindow
    {
        [DllImport("dwmapi.dll", PreserveSig = false)]
        public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DwmBlurbehind blurBehind);

        [DllImport("dwmapi.dll", PreserveSig = true)]
        private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);

        public MainWindow()
        {
            InitializeComponent();
        }

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);

            var bb = new DwmBlurbehind
            {
                dwFlags = CoreNativeMethods.DwmBlurBehindDwFlags.DwmBbEnable,
                Enabled = true
            };

            WindowStartupLocation = WindowStartupLocation.CenterScreen;
            Background = Brushes.Transparent;
            ResizeMode = ResizeMode.NoResize;
            WindowStyle = WindowStyle.None;

            Focus();

            var hwnd = new WindowInteropHelper(this).Handle;

            HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent;

            DwmEnableBlurBehindWindow(hwnd, ref bb);

            const int dwmwaNcrenderingPolicy = 2;
            var dwmncrpDisabled = 2;

            DwmSetWindowAttribute(hwnd, dwmwaNcrenderingPolicy, ref dwmncrpDisabled, sizeof(int));
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DwmBlurbehind
        {
            public CoreNativeMethods.DwmBlurBehindDwFlags dwFlags;
            public bool Enabled;
            public IntPtr BlurRegion;
            public bool TransitionOnMaximized;
        }

        public static class CoreNativeMethods
        {
            public enum DwmBlurBehindDwFlags
            {
                DwmBbEnable = 1,
                DwmBbBlurRegion = 2,
                DwmBbTransitionOnMaximized = 4
            }
        }
    }
}

Screenshot with focus

Screenshot with focus

Screenshot without focus

Screenoshot without focus

Test Environment

OS: Windows 8 - x64

Theme: Standard windows

like image 75
Maverik Avatar answered Oct 17 '22 00:10

Maverik