Friday, 25 November 2011

How to extend the Aero Glass into the Client area

ass into the Client area

Introduction

Windows Vista has a new default theme called Aero glass. In Aero glass, the title bar of a window and the frame is drawn transculent. This gives the UI a clean and lightweight look. This nice feaure is provided by a service that is called the desktop window manager (DWM).

Extending the Glass

By default the blurry glass effect is only on the title bar and the frame, but the client area is drawn opaque. But there is a simple way to extend the glass into the client area by using the DWM's API.
First thing you need to do is to include some Win32 functions from the dwmapi.dll library.
 
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows;
 
[StructLayout(LayoutKind.Sequential)]
struct MARGINS
{
    public int cxLeftWidth;
    public int cxRightWidth;
    public int cyTopHeight;
    public int cyBottomHeight;
}
 
[DllImport("dwmapi.dll")]
static extern int 
   DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
 
[DllImport("dwmapi.dll")]
extern static int DwmIsCompositionEnabled(ref int en);
 
 
 
I have written a helper method that does all the stuff to extend the glass by the specified amount of pixels on each border of the window.
 
 
/// <summary>
/// Extends the glass area into the client area of the window
/// </summary>
/// <param name="window"></param>
/// <param name="top"></param>
public static void ExtendGlass(Window window, Thickness thikness)
{
    try
    {
        int isGlassEnabled = 0;
        DwmIsCompositionEnabled(ref isGlassEnabled);
        if (Environment.OSVersion.Version.Major > 5 && isGlassEnabled > 0)
        {
            // Get the window handle
            WindowInteropHelper helper = new WindowInteropHelper(window);
            HwndSource mainWindowSrc = (HwndSource)HwndSource.
                FromHwnd(helper.Handle);
            mainWindowSrc.CompositionTarget.BackgroundColor = 
                Colors.Transparent;
 
            // Get the dpi of the screen
            System.Drawing.Graphics desktop = 
               System.Drawing.Graphics.FromHwnd(mainWindowSrc.Handle);
            float dpiX = desktop.DpiX / 96;
            float dpiY = desktop.DpiY / 96;
 
            // Set Margins
            MARGINS margins = new MARGINS();
            margins.cxLeftWidth = (int)(thikness.Left * dpiX);
            margins.cxRightWidth = (int)(thikness.Right * dpiX);
            margins.cyBottomHeight = (int)(thikness.Bottom * dpiY);
            margins.cyTopHeight = (int)(thikness.Top * dpiY);
 
            window.Background = Brushes.Transparent;
 
            int hr = DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, 
                        ref margins);
        }
        else
        {
            window.Background = SystemColors.WindowBrush;
        }
    }
    catch (DllNotFoundException)
    {
 
    }
}
 
 
Next thing you need to do is calling the ExtendGlass in the OnSourceInitialized callback. Because that is the time the window handle has been created.
 
 
protected override void OnSourceInitialized(EventArgs e)
{
   base.OnSourceInitialized(e);
   GlassHelper.ExtendGlass(this, LayoutRoot.Margin);
}
 
 
 
Since the user (or the system) can enable or disable the glass effect while the application is running, we need to hook up a callback in the WndProc to undo or initialize the glass extension dynamically.
 
 
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, 
  IntPtr lParam, ref bool handled)
{
    if (msg == GlassHelper.WM_DWMCOMPOSITIONCHANGED)
    {
        GlassHelper.ExtendGlass(this, LayoutRoot.Margin);
        handled = true;
    }
    return IntPtr.Zero;
}
 
 

No comments:

Post a Comment