diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs
index c5e3622404..0e1540b5fd 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs
@@ -107,6 +107,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public void SetSystemDecorations(bool enabled)
{
}
+
+ public void SetCoverTaskbarWhenMaximized(bool enable)
+ {
+ //Not supported
+ }
+
public void Invalidate(Rect rect)
{
if (Holder?.Surface?.IsValid == true) base.Invalidate();
diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs
index 609e9834cb..fd2feb539f 100644
--- a/src/Avalonia.Controls/Platform/IWindowImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs
@@ -35,6 +35,11 @@ namespace Avalonia.Platform
///
void SetSystemDecorations(bool enabled);
+ ///
+ /// When system decorations are disabled sets if the maximized state covers the entire screen or just the working area.
+ ///
+ void SetCoverTaskbarWhenMaximized(bool enable);
+
///
/// Sets the icon of this window.
///
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index e0d5cddc9e..6755dee073 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -64,6 +64,13 @@ namespace Avalonia.Controls
public static readonly StyledProperty HasSystemDecorationsProperty =
AvaloniaProperty.Register(nameof(HasSystemDecorations), true);
+ ///
+ /// Sets if the window should cover the taskbar when maximized. Only applies to Windows
+ /// with HasSystemDecorations = false.
+ ///
+ public static readonly StyledProperty CoverTaskbarOnMaximizeProperty =
+ AvaloniaProperty.Register(nameof(CoverTaskbarOnMaximize), true);
+
///
/// Defines the property.
///
@@ -89,6 +96,10 @@ namespace Avalonia.Controls
TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue));
HasSystemDecorationsProperty.Changed.AddClassHandler(
(s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue));
+
+ CoverTaskbarOnMaximizeProperty.Changed.AddClassHandler(
+ (s, e) => s.PlatformImpl.SetCoverTaskbarWhenMaximized((bool)e.NewValue));
+
IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
}
@@ -157,6 +168,16 @@ namespace Avalonia.Controls
set { SetValue(HasSystemDecorationsProperty, value); }
}
+ ///
+ /// Sets if the window should cover the taskbar when maximized. Only applies to Windows
+ /// with HasSystemDecorations = false.
+ ///
+ public bool CoverTaskbarOnMaximize
+ {
+ get { return GetValue(CoverTaskbarOnMaximizeProperty); }
+ set { SetValue(CoverTaskbarOnMaximizeProperty, value); }
+ }
+
///
/// Gets or sets the minimized/maximized state of the window.
///
diff --git a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs
index a9ecfa4058..8641f2f431 100644
--- a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs
+++ b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs
@@ -304,6 +304,11 @@ namespace Avalonia.Gtk
args.RetVal = true;
}
+ public void SetCoverTaskbarWhenMaximized(bool enable)
+ {
+ // No action neccesary on Gtk.
+ }
+
public void Dispose()
{
_window.Hide();
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index d115b35a23..c2785095d0 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -850,6 +850,10 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, MONITOR dwFlags);
+
+ [DllImport("user32", EntryPoint = "GetMonitorInfoW", ExactSpelling = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetMonitorInfo([In] IntPtr hMonitor, [Out] MONITORINFO lpmi);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
@@ -862,6 +866,23 @@ namespace Avalonia.Win32.Interop
MONITOR_DEFAULTTONEAREST = 0x00000002,
}
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal class MONITORINFO
+ {
+ public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
+ public RECT rcMonitor = new RECT();
+ public RECT rcWork = new RECT();
+ public int dwFlags = 0;
+
+ public enum MonitorOptions : uint
+ {
+ MONITOR_DEFAULTTONULL = 0x00000000,
+ MONITOR_DEFAULTTOPRIMARY = 0x00000001,
+ MONITOR_DEFAULTTONEAREST = 0x00000002
+ }
+ }
+
+
public enum PROCESS_DPI_AWARENESS
{
PROCESS_DPI_UNAWARE = 0,
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 5db3f69f85..2129090a64 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -15,6 +15,7 @@ using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
+using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
{
@@ -32,6 +33,7 @@ namespace Avalonia.Win32
private bool _trackingMouse;
private bool _isActive;
private bool _decorated = true;
+ private bool _coverTaskBarWhenMaximized = true;
private double _scaling = 1;
private WindowState _showWindowState;
@@ -135,7 +137,7 @@ namespace Avalonia.Win32
{
var placement = default(UnmanagedMethods.WINDOWPLACEMENT);
UnmanagedMethods.GetWindowPlacement(_hwnd, ref placement);
-
+
switch (placement.ShowCmd)
{
case UnmanagedMethods.ShowWindowCommand.Maximize:
@@ -184,22 +186,32 @@ namespace Avalonia.Win32
public void SetSystemDecorations(bool value)
{
if (value == _decorated)
+ {
return;
- var style = (UnmanagedMethods.WindowStyles) UnmanagedMethods.GetWindowLong(_hwnd, -16);
+ }
+
+ var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16);
+
style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW;
+
if (!value)
+ {
style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW;
+ }
UnmanagedMethods.RECT windowRect;
UnmanagedMethods.GetWindowRect(_hwnd, out windowRect);
+
Rect newRect;
var oldThickness = BorderThickness;
- UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint) style);
+ UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint)style);
+
if (value)
{
var thickness = BorderThickness;
+
newRect = new Rect(
windowRect.left - thickness.Left,
windowRect.top - thickness.Top,
@@ -207,19 +219,19 @@ namespace Avalonia.Win32
(windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom));
}
else
+ {
newRect = new Rect(
windowRect.left + oldThickness.Left,
windowRect.top + oldThickness.Top,
(windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right),
(windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom));
- UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int) newRect.X, (int) newRect.Y, (int) newRect.Width,
- (int) newRect.Height,
- UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE);
+ }
+ UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int)newRect.X, (int)newRect.Y, (int)newRect.Width,
+ (int)newRect.Height,
+ UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE);
_decorated = value;
-
-
}
public void Invalidate(Rect rect)
@@ -268,7 +280,7 @@ namespace Avalonia.Win32
public void BeginMoveDrag()
{
- UnmanagedMethods.DefWindowProc(_hwnd, (int) UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
+ UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero);
}
@@ -286,8 +298,8 @@ namespace Avalonia.Win32
public void BeginResizeDrag(WindowEdge edge)
{
- UnmanagedMethods.DefWindowProc(_hwnd, (int) UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
- new IntPtr((int) EdgeDic[edge]), IntPtr.Zero);
+ UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
+ new IntPtr((int)EdgeDic[edge]), IntPtr.Zero);
}
public Point Position
@@ -303,8 +315,8 @@ namespace Avalonia.Win32
UnmanagedMethods.SetWindowPos(
Handle.Handle,
IntPtr.Zero,
- (int) value.X,
- (int) value.Y,
+ (int)value.X,
+ (int)value.Y,
0,
0,
UnmanagedMethods.SetWindowPosFlags.SWP_NOSIZE | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE);
@@ -454,7 +466,7 @@ namespace Avalonia.Win32
: RawMouseEventType.MiddleButtonDown,
DipFromLParam(lParam), GetMouseModifiers(wParam));
break;
-
+
case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP:
@@ -462,9 +474,9 @@ namespace Avalonia.Win32
WindowsMouseDevice.Instance,
timestamp,
_owner,
- msg == (int) UnmanagedMethods.WindowsMessage.WM_LBUTTONUP
+ msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONUP
? RawMouseEventType.LeftButtonUp
- : msg == (int) UnmanagedMethods.WindowsMessage.WM_RBUTTONUP
+ : msg == (int)UnmanagedMethods.WindowsMessage.WM_RBUTTONUP
? RawMouseEventType.RightButtonUp
: RawMouseEventType.MiddleButtonUp,
DipFromLParam(lParam), GetMouseModifiers(wParam));
@@ -508,7 +520,7 @@ namespace Avalonia.Win32
timestamp,
_owner,
ScreenToClient(DipFromLParam(lParam)),
- new Vector(-(ToInt32(wParam) >> 16) / wheelDelta,0), GetMouseModifiers(wParam));
+ new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0), GetMouseModifiers(wParam));
break;
case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE:
@@ -585,9 +597,9 @@ namespace Avalonia.Win32
var modifiers = WindowsKeyboardDevice.Instance.Modifiers;
if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
modifiers |= InputModifiers.LeftMouseButton;
- if(keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
- modifiers |= InputModifiers.RightMouseButton;
- if(keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
+ if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
+ modifiers |= InputModifiers.RightMouseButton;
+ if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
modifiers |= InputModifiers.MiddleMouseButton;
return modifiers;
}
@@ -666,23 +678,60 @@ namespace Avalonia.Win32
{
UnmanagedMethods.ShowWindowCommand command;
+ bool maximizeFillsDesktop = false; // otherwise we cover entire screen.
+
switch (state)
{
case WindowState.Minimized:
- command = UnmanagedMethods.ShowWindowCommand.Minimize;
+ command = ShowWindowCommand.Minimize;
break;
case WindowState.Maximized:
- command = UnmanagedMethods.ShowWindowCommand.Maximize;
+ command = ShowWindowCommand.Maximize;
+
+ if (!_decorated && !_coverTaskBarWhenMaximized)
+ {
+ maximizeFillsDesktop = true;
+ }
break;
+
case WindowState.Normal:
- command = UnmanagedMethods.ShowWindowCommand.Restore;
+ command = ShowWindowCommand.Restore;
break;
+
default:
throw new ArgumentException("Invalid WindowState.");
}
UnmanagedMethods.ShowWindow(_hwnd, command);
- UnmanagedMethods.SetFocus(_hwnd);
+
+ if (maximizeFillsDesktop)
+ {
+ MaximizeWithoutCoveringTaskbar();
+ }
+
+ SetFocus(_hwnd);
+ }
+
+ private void MaximizeWithoutCoveringTaskbar()
+ {
+ IntPtr monitor = MonitorFromWindow(_hwnd, MONITOR.MONITOR_DEFAULTTONEAREST);
+
+ if (monitor != IntPtr.Zero)
+ {
+ MONITORINFO monitorInfo = new MONITORINFO();
+
+ if (GetMonitorInfo(monitor, monitorInfo))
+ {
+ RECT rcMonitorArea = monitorInfo.rcMonitor;
+
+ var x = monitorInfo.rcWork.left;
+ var y = monitorInfo.rcWork.top;
+ var cx = Math.Abs(monitorInfo.rcWork.right - x);
+ var cy = Math.Abs(monitorInfo.rcWork.bottom - y);
+
+ SetWindowPos(_hwnd, new IntPtr(-2), x, y, cx, cy, SetWindowPosFlags.SWP_SHOWWINDOW);
+ }
+ }
}
public void SetIcon(IWindowIconImpl icon)
@@ -699,5 +748,15 @@ namespace Avalonia.Win32
return (int)(ptr.ToInt64() & 0xffffffff);
}
+
+ public void SetCoverTaskbarWhenMaximized(bool enable)
+ {
+ _coverTaskBarWhenMaximized = enable;
+
+ if (_showWindowState == WindowState.Maximized)
+ {
+ ShowWindow(WindowState.Maximized);
+ }
+ }
}
}
diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.cs b/src/iOS/Avalonia.iOS/AvaloniaView.cs
index 8b14d09573..67817ef62a 100644
--- a/src/iOS/Avalonia.iOS/AvaloniaView.cs
+++ b/src/iOS/Avalonia.iOS/AvaloniaView.cs
@@ -170,6 +170,11 @@ namespace Avalonia.iOS
//Not supported
}
+ public void SetCoverTaskbarWhenMaximized(bool enable)
+ {
+ //Not supported
+ }
+
public override void TouchesEnded(NSSet touches, UIEvent evt)
{
var touch = touches.AnyObject as UITouch;