Browse Source

Merge pull request #805 from VitalElement/fixes/dont-cover-taskbar-with-system-decorations-hidden

Fixes/dont cover taskbar with system decorations hidden
pull/801/head
danwalmsley 10 years ago
committed by GitHub
parent
commit
898bec7750
  1. 6
      src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs
  2. 5
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  3. 21
      src/Avalonia.Controls/Window.cs
  4. 5
      src/Gtk/Avalonia.Gtk/WindowImplBase.cs
  5. 21
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  6. 107
      src/Windows/Avalonia.Win32/WindowImpl.cs
  7. 5
      src/iOS/Avalonia.iOS/AvaloniaView.cs

6
src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs

@ -107,6 +107,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public void SetSystemDecorations(bool enabled) public void SetSystemDecorations(bool enabled)
{ {
} }
public void SetCoverTaskbarWhenMaximized(bool enable)
{
//Not supported
}
public void Invalidate(Rect rect) public void Invalidate(Rect rect)
{ {
if (Holder?.Surface?.IsValid == true) base.Invalidate(); if (Holder?.Surface?.IsValid == true) base.Invalidate();

5
src/Avalonia.Controls/Platform/IWindowImpl.cs

@ -35,6 +35,11 @@ namespace Avalonia.Platform
/// </summary> /// </summary>
void SetSystemDecorations(bool enabled); void SetSystemDecorations(bool enabled);
/// <summary>
/// When system decorations are disabled sets if the maximized state covers the entire screen or just the working area.
/// </summary>
void SetCoverTaskbarWhenMaximized(bool enable);
/// <summary> /// <summary>
/// Sets the icon of this window. /// Sets the icon of this window.
/// </summary> /// </summary>

21
src/Avalonia.Controls/Window.cs

@ -64,6 +64,13 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> HasSystemDecorationsProperty = public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true); AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
/// <summary>
/// Sets if the window should cover the taskbar when maximized. Only applies to Windows
/// with HasSystemDecorations = false.
/// </summary>
public static readonly StyledProperty<bool> CoverTaskbarOnMaximizeProperty =
AvaloniaProperty.Register<Window, bool>(nameof(CoverTaskbarOnMaximize), true);
/// <summary> /// <summary>
/// Defines the <see cref="Title"/> property. /// Defines the <see cref="Title"/> property.
/// </summary> /// </summary>
@ -89,6 +96,10 @@ namespace Avalonia.Controls
TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue)); TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue));
HasSystemDecorationsProperty.Changed.AddClassHandler<Window>( HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue));
CoverTaskbarOnMaximizeProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl.SetCoverTaskbarWhenMaximized((bool)e.NewValue));
IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
} }
@ -157,6 +168,16 @@ namespace Avalonia.Controls
set { SetValue(HasSystemDecorationsProperty, value); } set { SetValue(HasSystemDecorationsProperty, value); }
} }
/// <summary>
/// Sets if the window should cover the taskbar when maximized. Only applies to Windows
/// with HasSystemDecorations = false.
/// </summary>
public bool CoverTaskbarOnMaximize
{
get { return GetValue(CoverTaskbarOnMaximizeProperty); }
set { SetValue(CoverTaskbarOnMaximizeProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets the minimized/maximized state of the window. /// Gets or sets the minimized/maximized state of the window.
/// </summary> /// </summary>

5
src/Gtk/Avalonia.Gtk/WindowImplBase.cs

@ -304,6 +304,11 @@ namespace Avalonia.Gtk
args.RetVal = true; args.RetVal = true;
} }
public void SetCoverTaskbarWhenMaximized(bool enable)
{
// No action neccesary on Gtk.
}
public void Dispose() public void Dispose()
{ {
_window.Hide(); _window.Hide();

21
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -850,6 +850,10 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, MONITOR dwFlags); 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)] [return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
@ -862,6 +866,23 @@ namespace Avalonia.Win32.Interop
MONITOR_DEFAULTTONEAREST = 0x00000002, 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 public enum PROCESS_DPI_AWARENESS
{ {
PROCESS_DPI_UNAWARE = 0, PROCESS_DPI_UNAWARE = 0,

107
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -15,6 +15,7 @@ using Avalonia.Input.Raw;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Win32.Input; using Avalonia.Win32.Input;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
@ -32,6 +33,7 @@ namespace Avalonia.Win32
private bool _trackingMouse; private bool _trackingMouse;
private bool _isActive; private bool _isActive;
private bool _decorated = true; private bool _decorated = true;
private bool _coverTaskBarWhenMaximized = true;
private double _scaling = 1; private double _scaling = 1;
private WindowState _showWindowState; private WindowState _showWindowState;
@ -135,7 +137,7 @@ namespace Avalonia.Win32
{ {
var placement = default(UnmanagedMethods.WINDOWPLACEMENT); var placement = default(UnmanagedMethods.WINDOWPLACEMENT);
UnmanagedMethods.GetWindowPlacement(_hwnd, ref placement); UnmanagedMethods.GetWindowPlacement(_hwnd, ref placement);
switch (placement.ShowCmd) switch (placement.ShowCmd)
{ {
case UnmanagedMethods.ShowWindowCommand.Maximize: case UnmanagedMethods.ShowWindowCommand.Maximize:
@ -184,22 +186,32 @@ namespace Avalonia.Win32
public void SetSystemDecorations(bool value) public void SetSystemDecorations(bool value)
{ {
if (value == _decorated) if (value == _decorated)
{
return; return;
var style = (UnmanagedMethods.WindowStyles) UnmanagedMethods.GetWindowLong(_hwnd, -16); }
var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16);
style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW;
if (!value) if (!value)
{
style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW;
}
UnmanagedMethods.RECT windowRect; UnmanagedMethods.RECT windowRect;
UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); UnmanagedMethods.GetWindowRect(_hwnd, out windowRect);
Rect newRect; Rect newRect;
var oldThickness = BorderThickness; var oldThickness = BorderThickness;
UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint) style); UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint)style);
if (value) if (value)
{ {
var thickness = BorderThickness; var thickness = BorderThickness;
newRect = new Rect( newRect = new Rect(
windowRect.left - thickness.Left, windowRect.left - thickness.Left,
windowRect.top - thickness.Top, windowRect.top - thickness.Top,
@ -207,19 +219,19 @@ namespace Avalonia.Win32
(windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom));
} }
else else
{
newRect = new Rect( newRect = new Rect(
windowRect.left + oldThickness.Left, windowRect.left + oldThickness.Left,
windowRect.top + oldThickness.Top, windowRect.top + oldThickness.Top,
(windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right),
(windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); (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; _decorated = value;
} }
public void Invalidate(Rect rect) public void Invalidate(Rect rect)
@ -268,7 +280,7 @@ namespace Avalonia.Win32
public void BeginMoveDrag() 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); new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero);
} }
@ -286,8 +298,8 @@ namespace Avalonia.Win32
public void BeginResizeDrag(WindowEdge edge) public void BeginResizeDrag(WindowEdge edge)
{ {
UnmanagedMethods.DefWindowProc(_hwnd, (int) UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN, UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int) EdgeDic[edge]), IntPtr.Zero); new IntPtr((int)EdgeDic[edge]), IntPtr.Zero);
} }
public Point Position public Point Position
@ -303,8 +315,8 @@ namespace Avalonia.Win32
UnmanagedMethods.SetWindowPos( UnmanagedMethods.SetWindowPos(
Handle.Handle, Handle.Handle,
IntPtr.Zero, IntPtr.Zero,
(int) value.X, (int)value.X,
(int) value.Y, (int)value.Y,
0, 0,
0, 0,
UnmanagedMethods.SetWindowPosFlags.SWP_NOSIZE | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); UnmanagedMethods.SetWindowPosFlags.SWP_NOSIZE | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE);
@ -454,7 +466,7 @@ namespace Avalonia.Win32
: RawMouseEventType.MiddleButtonDown, : RawMouseEventType.MiddleButtonDown,
DipFromLParam(lParam), GetMouseModifiers(wParam)); DipFromLParam(lParam), GetMouseModifiers(wParam));
break; break;
case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP:
case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP: case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP:
@ -462,9 +474,9 @@ namespace Avalonia.Win32
WindowsMouseDevice.Instance, WindowsMouseDevice.Instance,
timestamp, timestamp,
_owner, _owner,
msg == (int) UnmanagedMethods.WindowsMessage.WM_LBUTTONUP msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONUP
? RawMouseEventType.LeftButtonUp ? RawMouseEventType.LeftButtonUp
: msg == (int) UnmanagedMethods.WindowsMessage.WM_RBUTTONUP : msg == (int)UnmanagedMethods.WindowsMessage.WM_RBUTTONUP
? RawMouseEventType.RightButtonUp ? RawMouseEventType.RightButtonUp
: RawMouseEventType.MiddleButtonUp, : RawMouseEventType.MiddleButtonUp,
DipFromLParam(lParam), GetMouseModifiers(wParam)); DipFromLParam(lParam), GetMouseModifiers(wParam));
@ -508,7 +520,7 @@ namespace Avalonia.Win32
timestamp, timestamp,
_owner, _owner,
ScreenToClient(DipFromLParam(lParam)), ScreenToClient(DipFromLParam(lParam)),
new Vector(-(ToInt32(wParam) >> 16) / wheelDelta,0), GetMouseModifiers(wParam)); new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0), GetMouseModifiers(wParam));
break; break;
case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE: case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE:
@ -585,9 +597,9 @@ namespace Avalonia.Win32
var modifiers = WindowsKeyboardDevice.Instance.Modifiers; var modifiers = WindowsKeyboardDevice.Instance.Modifiers;
if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON)) if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
modifiers |= InputModifiers.LeftMouseButton; modifiers |= InputModifiers.LeftMouseButton;
if(keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON)) if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
modifiers |= InputModifiers.RightMouseButton; modifiers |= InputModifiers.RightMouseButton;
if(keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
modifiers |= InputModifiers.MiddleMouseButton; modifiers |= InputModifiers.MiddleMouseButton;
return modifiers; return modifiers;
} }
@ -666,23 +678,60 @@ namespace Avalonia.Win32
{ {
UnmanagedMethods.ShowWindowCommand command; UnmanagedMethods.ShowWindowCommand command;
bool maximizeFillsDesktop = false; // otherwise we cover entire screen.
switch (state) switch (state)
{ {
case WindowState.Minimized: case WindowState.Minimized:
command = UnmanagedMethods.ShowWindowCommand.Minimize; command = ShowWindowCommand.Minimize;
break; break;
case WindowState.Maximized: case WindowState.Maximized:
command = UnmanagedMethods.ShowWindowCommand.Maximize; command = ShowWindowCommand.Maximize;
if (!_decorated && !_coverTaskBarWhenMaximized)
{
maximizeFillsDesktop = true;
}
break; break;
case WindowState.Normal: case WindowState.Normal:
command = UnmanagedMethods.ShowWindowCommand.Restore; command = ShowWindowCommand.Restore;
break; break;
default: default:
throw new ArgumentException("Invalid WindowState."); throw new ArgumentException("Invalid WindowState.");
} }
UnmanagedMethods.ShowWindow(_hwnd, command); 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) public void SetIcon(IWindowIconImpl icon)
@ -699,5 +748,15 @@ namespace Avalonia.Win32
return (int)(ptr.ToInt64() & 0xffffffff); return (int)(ptr.ToInt64() & 0xffffffff);
} }
public void SetCoverTaskbarWhenMaximized(bool enable)
{
_coverTaskBarWhenMaximized = enable;
if (_showWindowState == WindowState.Maximized)
{
ShowWindow(WindowState.Maximized);
}
}
} }
} }

5
src/iOS/Avalonia.iOS/AvaloniaView.cs

@ -170,6 +170,11 @@ namespace Avalonia.iOS
//Not supported //Not supported
} }
public void SetCoverTaskbarWhenMaximized(bool enable)
{
//Not supported
}
public override void TouchesEnded(NSSet touches, UIEvent evt) public override void TouchesEnded(NSSet touches, UIEvent evt)
{ {
var touch = touches.AnyObject as UITouch; var touch = touches.AnyObject as UITouch;

Loading…
Cancel
Save