Skip to content

Commit

Permalink
Added JMorril's BorderlessWindowBehaviour
Browse files Browse the repository at this point in the history
Added said behaviour to the demo app, as well as merging all the styles.
  • Loading branch information
aeoth committed Jan 29, 2011
1 parent c36e797 commit 849b1d2
Show file tree
Hide file tree
Showing 9 changed files with 345 additions and 35 deletions.
Binary file added Lib/System.Windows.Interactivity.dll
Binary file not shown.
305 changes: 305 additions & 0 deletions MahApps.Metro/Behaviours/BorderlessWindowBehavior.cs
@@ -0,0 +1,305 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Interop;

namespace MahApps.Metro.Behaviours
{

/// <summary>
/// http://gallery.expression.microsoft.com/ZuneWindowBehavior/
/// Published: 10/18/2010
/// Created by: jmorrill
/// Supporting Url: http://jmorrill.hjtcentral.com
/// Tags: Behavior, WPF, Zune
/// License Information:
/// This contribution is licensed to you under Creative Commons by its owner, not Microsoft. Microsoft does not guarantee the contribution or purport to grant rights to it.
/// </summary>
///
public class BorderlessWindowBehavior : Behavior<Window>
{
#region NativeStuffs
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int leftWidth;
public int rightWidth;
public int topHeight;
public int bottomHeight;
}

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

/// <summary>
/// POINT aka POINTAPI
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
/// <summary>
/// x coordinate of point.
/// </summary>
public int x;
/// <summary>
/// y coordinate of point.
/// </summary>
public int y;

/// <summary>
/// Construct a point of coordinates (x,y).
/// </summary>
public POINT(int x, int y)
{
this.x = x;
this.y = y;
}
}

[StructLayout(LayoutKind.Sequential)]
public struct MINMAXINFO
{
public POINT ptReserved;
public POINT ptMaxSize;
public POINT ptMaxPosition;
public POINT ptMinTrackSize;
public POINT ptMaxTrackSize;
};

/// <summary>
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MONITORINFO
{
/// <summary>
/// </summary>
public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));

/// <summary>
/// </summary>
public RECT rcMonitor = new RECT();

/// <summary>
/// </summary>
public RECT rcWork = new RECT();

/// <summary>
/// </summary>
public int dwFlags = 0;
}


/// <summary> Win32 </summary>
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct RECT
{
/// <summary> Win32 </summary>
public int left;
/// <summary> Win32 </summary>
public int top;
/// <summary> Win32 </summary>
public int right;
/// <summary> Win32 </summary>
public int bottom;

/// <summary> Win32 </summary>
public static readonly RECT Empty = new RECT();

/// <summary> Win32 </summary>
public int Width
{
get { return Math.Abs(right - left); } // Abs needed for BIDI OS
}
/// <summary> Win32 </summary>
public int Height
{
get { return bottom - top; }
}

/// <summary> Win32 </summary>
public RECT(int left, int top, int right, int bottom)
{
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}


/// <summary> Win32 </summary>
public RECT(RECT rcSrc)
{
this.left = rcSrc.left;
this.top = rcSrc.top;
this.right = rcSrc.right;
this.bottom = rcSrc.bottom;
}

/// <summary> Win32 </summary>
public bool IsEmpty
{
get
{
// BUGBUG : On Bidi OS (hebrew arabic) left > right
return left >= right || top >= bottom;
}
}
/// <summary> Return a user friendly representation of this struct </summary>
public override string ToString()
{
if (this == RECT.Empty) { return "RECT {Empty}"; }
return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }";
}

/// <summary> Determine if 2 RECT are equal (deep compare) </summary>
public override bool Equals(object obj)
{
if (!(obj is Rect)) { return false; }
return (this == (RECT)obj);
}

/// <summary>Return the HashCode for this struct (not garanteed to be unique)</summary>
public override int GetHashCode()
{
return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode();
}


/// <summary> Determine if 2 RECT are equal (deep compare)</summary>
public static bool operator ==(RECT rect1, RECT rect2)
{
return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom);
}

/// <summary> Determine if 2 RECT are different(deep compare)</summary>
public static bool operator !=(RECT rect1, RECT rect2)
{
return !(rect1 == rect2);
}


}

[DllImport("user32")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);

/// <summary>
///
/// </summary>
[DllImport("User32")]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);

private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
{

MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

// Adjust the maximized size and position to fit the work area of the correct monitor
int MONITOR_DEFAULTTONEAREST = 0x00000002;
System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

if (monitor != System.IntPtr.Zero)
{

MONITORINFO monitorInfo = new MONITORINFO();
GetMonitorInfo(monitor, monitorInfo);
RECT rcWorkArea = monitorInfo.rcWork;
RECT rcMonitorArea = monitorInfo.rcMonitor;
mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left);
mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top);
mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left);
mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
}

Marshal.StructureToPtr(mmi, lParam, true);
}

[DllImport("user32.dll")]
public static extern IntPtr DefWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);

#endregion

private const int WM_NCCALCSIZE = 0x83;
private const int WM_NCPAINT = 0x85;
private const int WM_NCACTIVATE = 0x86;
private const int WM_GETMINMAXINFO = 0x24;

private HwndSource m_hwndSource;
private IntPtr m_hwnd;

protected override void OnAttached()
{
if (AssociatedObject.IsInitialized)
AddHwndHook();
else
AssociatedObject.SourceInitialized += AssociatedObject_SourceInitialized;

AssociatedObject.WindowStyle = WindowStyle.None;
AssociatedObject.ResizeMode = ResizeMode.CanResizeWithGrip;
base.OnAttached();
}

protected override void OnDetaching()
{
RemoveHwndHook();
base.OnDetaching();
}

private void AddHwndHook()
{
m_hwndSource = HwndSource.FromVisual(AssociatedObject) as HwndSource;
m_hwndSource.AddHook(HwndHook);
m_hwnd = new WindowInteropHelper(AssociatedObject).Handle;
}

private void RemoveHwndHook()
{
AssociatedObject.SourceInitialized -= AssociatedObject_SourceInitialized;
m_hwndSource.RemoveHook(HwndHook);
}

private void AssociatedObject_SourceInitialized(object sender, EventArgs e)
{
AddHwndHook();
}

private IntPtr HwndHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
{
IntPtr returnval = IntPtr.Zero;
switch (message)
{
case WM_NCCALCSIZE:
/* Hides the border */
handled = true;
break;
case WM_NCPAINT:
{
if (Environment.OSVersion.Version.Major >= 6)
{
var m = new MARGINS { bottomHeight = 1, leftWidth = 1, rightWidth = 1, topHeight = 1 };
DwmExtendFrameIntoClientArea(m_hwnd, ref m);
}
handled = true;
}
break;
case WM_NCACTIVATE:
{
/* As per http://msdn.microsoft.com/en-us/library/ms632633(VS.85).aspx , "-1" lParam
* "does not repaint the nonclient area to reflect the state change." */
returnval = DefWindowProc(hWnd, message, wParam, new IntPtr(-1));
handled = true;
}
break;
case WM_GETMINMAXINFO:
/* From Lester's Blog (thanks @aeoth):
* http://blogs.msdn.com/b/llobo/archive/2006/08/01/maximizing-window-_2800_with-windowstyle_3d00_none_2900_-considering-taskbar.aspx */
WmGetMinMaxInfo(hWnd, lParam);
handled = true;
break;
}

return returnval;
}
}
}
8 changes: 4 additions & 4 deletions MahApps.Metro/MahApps.Metro.csproj
Expand Up @@ -36,6 +36,9 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Interactivity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\Lib\System.Windows.Interactivity.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
Expand All @@ -49,6 +52,7 @@
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="Behaviours\BorderlessWindowBehavior.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
Expand All @@ -73,10 +77,6 @@
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Page Include="Merged.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Styles\Colours.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down
8 changes: 0 additions & 8 deletions MahApps.Metro/Merged.xaml

This file was deleted.

4 changes: 2 additions & 2 deletions MahApps.Metro/Styles/Colours.xaml
Expand Up @@ -190,8 +190,8 @@

<SolidColorBrush x:Key="TextBoxBorderBrush" Color="{StaticResource Gray1}" />
<SolidColorBrush x:Key="ControlBorderBrush" Color="{StaticResource Gray1}" />
<SolidColorBrush x:Key="TextBoxMouseOverBorderBrush" Color="{StaticResource HighlightDarkColor}" />
<SolidColorBrush x:Key="TextBoxMouseOverInnerBorderBrush" Color="{StaticResource HighlightLightColor}" />
<SolidColorBrush x:Key="TextBoxMouseOverBorderBrush" Color="{DynamicResource HighlightDarkColor}" />
<SolidColorBrush x:Key="TextBoxMouseOverInnerBorderBrush" Color="{DynamicResource HighlightLightColor}" />

<SolidColorBrush x:Key="CheckBoxBrush" Color="{StaticResource Gray2}" />
<SolidColorBrush x:Key="CheckBoxMouseOverBrush" Color="{StaticResource Gray3}" />
Expand Down
13 changes: 12 additions & 1 deletion MetroDemo/App.xaml
Expand Up @@ -3,6 +3,17 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>

<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml"/>


</ResourceDictionary.MergedDictionaries>

<!--<Color x:Key="HighlightDarkColor">Red</Color>
<Color x:Key="HighlightLightColor">Red</Color>-->
</ResourceDictionary>
</Application.Resources>
</Application>
10 changes: 7 additions & 3 deletions MetroDemo/MainWindow.xaml
@@ -1,8 +1,12 @@
<Window x:Class="MetroDemo.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">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:behaviours="clr-namespace:MahApps.Metro.Behaviours;assembly=MahApps.Metro" Title="MainWindow" Height="350" Width="525"
MouseDown="WindowMouseDown">
<i:Interaction.Behaviors>
<behaviours:BorderlessWindowBehavior/>
</i:Interaction.Behaviors>

<Grid>

<Button Content="oh hai" Width="50" Height="50" />
</Grid>
</Window>

0 comments on commit 849b1d2

Please sign in to comment.