Blurring the background of a semi-transparent form (like Aero glass)
Asked Answered
F

2

12

I have a borderless, non-resizable WPF form (WindowStyle=None, AllowsTransparency=True, ResizeMode=NoResize) with a semi-transparent background. Here's a picture of how the form, a semi-transparent red rectangle, looks right now, running on top of Notepad:

the form as it currently appears on top of Notepad

However, I'd like the background to be blurred, like how Aero glass does it, except without all the fancy window borders and colored background with stripes - I'd like to handle that myself. Here's a mockup of how I want it to look like:

the form as I want it to be - blur anything that's below it

How can I achieve this in the most efficient way possible?

WinForms or WPF is fine by me. Hopefully it should use the same thing Aero glass uses (I'm fine with it working only with Aero enabled), instead of something crazy like capturing the screen region below as a bitmap and blurring that.

Here is a picture of what I DON'T want:

I don't want the entire Aero glass window chrome

I know this is possible and I know how to do it, but I DON'T want the entire Aero glass window chrome, or the borders and title bar, or the window to have the user-set Aero glass color, JUST the effect of blurring whatever is below the window/form.

Further answered 8/7, 2012 at 20:29 Comment(7)
Have you seen https://mcmap.net/q/730316/-blurred-opacity?Ketty
Yes, and that's blurring INSIDE the form. I want the form itself to blur other windows below it.Woodwork
Have you tried this: #7815778Quentin
Again, that's blurring INSIDE the form. I want the form itself to blur other windows below it.Woodwork
@FutureMillennium Do you want to blur any application in the background or only windows of your application? If the format, you may have to screen capture w/o your window, copy that image to your window and blur it.Thigpen
@Thigpen I want to blur anything that's below the application's window, be it other windows, the desktop or anything else. And yes, blurring a screen capture is exactly what want to avoid, that's not how Aero does it.Woodwork
@FutureMillennium id you know how Aero does it, can you use that method?Thigpen
S
10

If you want to use the Aero blur then you can use the DwmEnableBlurBehindWindow api. Here's an example derived Window that utilizes this.

public class BlurWindow : Window
{
    #region Constants

    private const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
    private const int DWM_BB_ENABLE = 0x1; 

    #endregion //Constants

    #region Structures
    [StructLayout( LayoutKind.Sequential )]
    private struct DWM_BLURBEHIND
    {
        public int dwFlags;
        public bool fEnable;
        public IntPtr hRgnBlur;
        public bool fTransitionOnMaximized;
    }

    [StructLayout( LayoutKind.Sequential )]
    private struct MARGINS
    {
        public int cxLeftWidth;
        public int cxRightWidth;
        public int cyTopHeight;
        public int cyBottomHeight;
    } 
    #endregion //Structures

    #region APIs

    [DllImport( "dwmapi.dll", PreserveSig = false )]
    private static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);

    [DllImport( "dwmapi.dll" )]
    private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMargins);

    [DllImport( "dwmapi.dll", PreserveSig = false )]
    private static extern bool DwmIsCompositionEnabled(); 

    #endregion //APIs

    #region Constructor
    public BlurWindow()
    {
        this.WindowStyle = System.Windows.WindowStyle.None;
        this.ResizeMode = System.Windows.ResizeMode.NoResize;
        this.Background = Brushes.Transparent;
    } 
    #endregion //Constructor

    #region Base class overrides
    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized( e );

        if ( Environment.OSVersion.Version.Major >= 6 )
        {
            var hwnd = new WindowInteropHelper( this ).Handle;
            var hs = HwndSource.FromHwnd( hwnd );
            hs.CompositionTarget.BackgroundColor = Colors.Transparent;

            hs.AddHook( new HwndSourceHook( this.WndProc ) );
            this.InitializeGlass( hwnd );
        }
    } 
    #endregion //Base class overrides

    #region Methods

    #region InitializeGlass
    private void InitializeGlass(IntPtr hwnd)
    {
        if ( !DwmIsCompositionEnabled() )
            return;

        // fill the background with glass
        var margins = new MARGINS();
        margins.cxLeftWidth = margins.cxRightWidth = margins.cyBottomHeight = margins.cyTopHeight = -1;
        DwmExtendFrameIntoClientArea( hwnd, ref margins );

        // initialize blur for the window
        DWM_BLURBEHIND bbh = new DWM_BLURBEHIND();
        bbh.fEnable = true;
        bbh.dwFlags = DWM_BB_ENABLE;
        DwmEnableBlurBehindWindow( hwnd, ref bbh );
    }
    #endregion //InitializeGlass

    #region WndProc
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if ( msg == WM_DWMCOMPOSITIONCHANGED )
        {
            this.InitializeGlass( hwnd );
            handled = false;
        }

        return IntPtr.Zero;
    } 
    #endregion //WndProc 

    #endregion //Methods
}

And here's a snippet of using the BlurWindow.

var w = new BlurWindow();
w.Width = 100;
w.Height = 100;
w.MouseLeftButtonDown += (s1, e1) => {
    ((Window)s1).DragMove();
    e1.Handled = true;
};
w.Background = new SolidColorBrush( Color.FromArgb( 75, 255, 0, 0 ) );
w.Show();
Scolopendrid answered 23/10, 2012 at 17:45 Comment(1)
That's probably because aero glass is disabled in Windows 8. I think there are hacks to re-enable it but it's not something MS is really supporting.Scolopendrid
M
1

I did something similar once but I didn't need the following:

  1. I didn't need to move my form much.
  2. No movement took place under my form.

What I did:

  1. I used to minimize my form window for a moment (programmatically).
  2. Form used to capture the image snip of it's size and at the same coordinates.
  3. Set that image as it's background after applying the BlurBitmapEffect.

Not a great answer I presume, but I'm just writing what I did!

If you're interested in this approach this article will help you: http://www.codeproject.com/Articles/91487/Screen-Capture-in-WPF-WinForms-Application

Marieann answered 9/7, 2012 at 10:3 Comment(1)
Thanks, but that's what I'm trying to avoid. Aero is a compositing window manager and you shouldn't have to manually screencap a part of the screen and then blur that as a bitmap. Not only is it costly, but it's not hardware accelerated, unlike how Aero does it.Woodwork

© 2022 - 2024 — McMap. All rights reserved.