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 SetCoverTaskbarWhenMaximized(bool enable)
{
//Not supported
}
public void Invalidate(Rect rect)
{
if (Holder?.Surface?.IsValid == true) base.Invalidate();

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

@ -35,6 +35,11 @@ namespace Avalonia.Platform
/// </summary>
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>
/// Sets the icon of this window.
/// </summary>

21
src/Avalonia.Controls/Window.cs

@ -64,6 +64,13 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
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>
/// Defines the <see cref="Title"/> property.
/// </summary>
@ -89,6 +96,10 @@ namespace Avalonia.Controls
TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue));
HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
(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));
}
@ -157,6 +168,16 @@ namespace Avalonia.Controls
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>
/// Gets or sets the minimized/maximized state of the window.
/// </summary>

5
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();

21
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,

107
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);
}
}
}
}

5
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;

Loading…
Cancel
Save