NB: THIS IS NOT A QUESTION ABOUT A BORDERLESS WINDOW.
So, I stumbled upon this program while I was exploring my Start menu the other day on Windows 7:
It's a native Windows program, called "Math Input Panel." Now, I'm curious about the window shape. I know that it's not completely drawn by DWM, because the borders and Close button look fishy and the window has no drop shadow (I have drop shadows enabled). My first guess as to how this was made would be using DwmEnableBlurBehindWindow
, but I can't imagine that works on irregular window shapes, does it? (Or is there another way to do this, or is it just completely Microsoft sorcery?)
So, unbeknownst to me, hRgn
can take an irregular shape (and DwmEnableBlurBehindWindow
takes an hRgn
, but I knew that). So, here's my solution that's (more or less) compatible with WPF:
...and source code:
MainWindow.xaml:
<Window x:Class="IrregularGlassWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="500"
Width="500"
Background="#01FFFFFF"
AllowsTransparency="True"
WindowStyle="None"
ResizeMode="NoResize">
<Window.Clip>
<PathGeometry>
<PathFigure StartPoint="250,0">
<ArcSegment Point="250,500"
RotationAngle="180"
Size="250,250"
SweepDirection="Clockwise" />
<ArcSegment Point="250,0"
RotationAngle="180"
Size="250,250"
SweepDirection="Clockwise" />
</PathFigure>
</PathGeometry>
</Window.Clip>
<Grid>
<Ellipse Margin="1"
Width="498"
Height="498"
Stroke="#8FFF"
StrokeThickness="1.25" />
<Ellipse Width="500"
Height="500"
Stroke="#C000"
StrokeThickness="1"/>
</Grid>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
this.SourceInitialized += MainWindow_SourceInitialized;
this.KeyDown += MainWindow_KeyDown;
}
void MainWindow_KeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Escape) this.Close();
}
void MainWindow_SourceInitialized(object sender, EventArgs e) {
var helper = new WindowInteropHelper(this);
var hwnd = helper.Handle;
var src = HwndSource.FromHwnd(hwnd);
src.CompositionTarget.BackgroundColor = Colors.Transparent;
WindowChrome.SetWindowChrome(this, new WindowChrome {
CaptionHeight = 500,
CornerRadius = new CornerRadius(0),
GlassFrameThickness = new Thickness(0),
NonClientFrameEdges = NonClientFrameEdges.None,
ResizeBorderThickness = new Thickness(0),
UseAeroCaptionButtons = false
});
GraphicsPath path = new GraphicsPath(FillMode.Alternate);
path.StartFigure();
path.AddArc(new RectangleF(0, 0, 500, 500), 0, 360);
path.CloseFigure();
var dbb = new DwmBlurBehind(true);
dbb.SetRegion(Graphics.FromHwnd(hwnd), new Region(path));
DwmApi.DwmEnableBlurBehindWindow(hwnd, ref dbb);
}
}
I think somebody else beat me to it, but here's how my solution works:
When the window's SourceInitialized
event is fired, that means that we have a handle for our window. So in the handler of this function, I get the window handle. Then I make a call to a function I imported from dwmapi.dll called DwmEnableBlurBehindWindow
. This basically turns transparent areas of the window into glass for a certain region. The DwmBlurBehind
struct I got from pinvoke.net, and it converts a GDI+ System.Drawing.Region
into an hRgn
. The hRgn
is passed to DwmEnableBlurBehindWindow
, and it clips the transparent parts to the Region
. In this case, I used a circle. Then the XAML is just the accent borders. It's worth noting that, for some reason, setting Window.Background
to Transparent
doesn't enable hit-testing when AllowsTransparency
is true here. No idea why, but it probably has something to do with the code-behind.