diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 4a960d47a1..ee57f54e59 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -25,6 +25,12 @@ struct IAvnGlSurfaceRenderingSession; struct IAvnAppMenu; struct IAvnAppMenuItem; +enum SystemDecorations { + SystemDecorationsNone = 0, + SystemDecorationsBorderOnly = 1, + SystemDecorationsFull = 2, +}; + struct AvnSize { double Width, Height; @@ -236,7 +242,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase { virtual HRESULT ShowDialog (IAvnWindow* parent) = 0; virtual HRESULT SetCanResize(bool value) = 0; - virtual HRESULT SetHasDecorations(bool value) = 0; + virtual HRESULT SetHasDecorations(SystemDecorations value) = 0; virtual HRESULT SetTitle (void* utf8Title) = 0; virtual HRESULT SetTitleBarColor (AvnColor color) = 0; virtual HRESULT SetWindowState(AvnWindowState state) = 0; diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index b6ce172ffa..2c03407732 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -115,7 +115,6 @@ public: [NSApp activateIgnoringOtherApps:YES]; [Window setTitle:_lastTitle]; - [Window setTitleVisibility:NSWindowTitleVisible]; return S_OK; } @@ -411,7 +410,7 @@ class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, pub { private: bool _canResize = true; - bool _hasDecorations = true; + SystemDecorations _hasDecorations = SystemDecorationsFull; CGRect _lastUndecoratedFrame; AvnWindowState _lastWindowState; @@ -476,23 +475,26 @@ private: bool IsZoomed () { - return _hasDecorations ? [Window isZoomed] : UndecoratedIsMaximized(); + return _hasDecorations != SystemDecorationsNone ? [Window isZoomed] : UndecoratedIsMaximized(); } void DoZoom() { - if (_hasDecorations) + switch (_hasDecorations) { - [Window performZoom:Window]; - } - else - { - if (!UndecoratedIsMaximized()) - { - _lastUndecoratedFrame = [Window frame]; - } - - [Window zoom:Window]; + case SystemDecorationsNone: + if (!UndecoratedIsMaximized()) + { + _lastUndecoratedFrame = [Window frame]; + } + + [Window zoom:Window]; + break; + + case SystemDecorationsBorderOnly: + case SystemDecorationsFull: + [Window performZoom:Window]; + break; } } @@ -506,13 +508,35 @@ private: } } - virtual HRESULT SetHasDecorations(bool value) override + virtual HRESULT SetHasDecorations(SystemDecorations value) override { @autoreleasepool { _hasDecorations = value; UpdateStyle(); - + + switch (_hasDecorations) + { + case SystemDecorationsNone: + [Window setHasShadow:NO]; + [Window setTitleVisibility:NSWindowTitleHidden]; + [Window setTitlebarAppearsTransparent:YES]; + break; + + case SystemDecorationsBorderOnly: + [Window setHasShadow:YES]; + [Window setTitleVisibility:NSWindowTitleHidden]; + [Window setTitlebarAppearsTransparent:YES]; + break; + + case SystemDecorationsFull: + [Window setHasShadow:YES]; + [Window setTitleVisibility:NSWindowTitleVisible]; + [Window setTitlebarAppearsTransparent:NO]; + [Window setTitle:_lastTitle]; + break; + } + return S_OK; } } @@ -523,7 +547,6 @@ private: { _lastTitle = [NSString stringWithUTF8String:(const char*)utf8title]; [Window setTitle:_lastTitle]; - [Window setTitleVisibility:NSWindowTitleVisible]; return S_OK; } @@ -645,10 +668,26 @@ protected: virtual NSWindowStyleMask GetStyle() override { unsigned long s = NSWindowStyleMaskBorderless; - if(_hasDecorations) - s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; - if(_canResize) - s = s | NSWindowStyleMaskResizable; + + switch (_hasDecorations) + { + case SystemDecorationsNone: + break; + + case SystemDecorationsBorderOnly: + s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView; + break; + + case SystemDecorationsFull: + s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskBorderless; + if(_canResize) + { + s = s | NSWindowStyleMaskResizable; + } + + break; + } + return s; } }; diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index b95e01c5ae..f3f70719e3 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -59,10 +59,17 @@ - + + + No Decorations + Border Only + Full Decorations + + Light Dark - + + diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs index acb9bc5bc6..5f71b2ecd9 100644 --- a/samples/ControlCatalog/MainView.xaml.cs +++ b/samples/ControlCatalog/MainView.xaml.cs @@ -56,6 +56,20 @@ namespace ControlCatalog } }; Styles.Add(light); + + var decorations = this.Find("Decorations"); + decorations.SelectionChanged += (sender, e) => + { + Window window = (Window)VisualRoot; + window.SystemDecorations = (SystemDecorations)decorations.SelectedIndex; + }; + } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + var decorations = this.Find("Decorations"); + decorations.SelectedIndex = (int)((Window)VisualRoot).SystemDecorations; } } } diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 88b99cd99a..51062f1568 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -80,8 +80,12 @@ namespace Avalonia _inheritanceParent?.RemoveInheritanceChild(this); _inheritanceParent = value; - foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegisteredInherited(GetType())) + var properties = AvaloniaPropertyRegistry.Instance.GetRegisteredInherited(GetType()); + var propertiesCount = properties.Count; + + for (var i = 0; i < propertiesCount; i++) { + var property = properties[i]; if (valuestore?.IsSet(property) == true) { // If local value set there can be no change. diff --git a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs index 29ab10278b..7d3d5492b6 100644 --- a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs +++ b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs @@ -3,9 +3,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; -using Avalonia.Data; namespace Avalonia { @@ -28,8 +26,6 @@ namespace Avalonia new Dictionary>(); private readonly Dictionary> _directCache = new Dictionary>(); - private readonly Dictionary> _initializedCache = - new Dictionary>(); private readonly Dictionary> _inheritedCache = new Dictionary>(); @@ -49,7 +45,7 @@ namespace Avalonia /// /// The type. /// A collection of definitions. - public IEnumerable GetRegistered(Type type) + public IReadOnlyList GetRegistered(Type type) { Contract.Requires(type != null); @@ -83,7 +79,7 @@ namespace Avalonia /// /// The type. /// A collection of definitions. - public IEnumerable GetRegisteredAttached(Type type) + public IReadOnlyList GetRegisteredAttached(Type type) { Contract.Requires(type != null); @@ -114,7 +110,7 @@ namespace Avalonia /// /// The type. /// A collection of definitions. - public IEnumerable GetRegisteredDirect(Type type) + public IReadOnlyList GetRegisteredDirect(Type type) { Contract.Requires(type != null); @@ -145,7 +141,7 @@ namespace Avalonia /// /// The type. /// A collection of definitions. - public IEnumerable GetRegisteredInherited(Type type) + public IReadOnlyList GetRegisteredInherited(Type type) { Contract.Requires(type != null); @@ -157,16 +153,27 @@ namespace Avalonia result = new List(); var visited = new HashSet(); - foreach (var property in GetRegistered(type)) + var registered = GetRegistered(type); + var registeredCount = registered.Count; + + for (var i = 0; i < registeredCount; i++) { + var property = registered[i]; + if (property.Inherits) { result.Add(property); visited.Add(property); } } - foreach (var property in GetRegisteredAttached(type)) + + var registeredAttached = GetRegisteredAttached(type); + var registeredAttachedCount = registeredAttached.Count; + + for (var i = 0; i < registeredAttachedCount; i++) { + var property = registeredAttached[i]; + if (property.Inherits) { if (!visited.Contains(property)) @@ -185,7 +192,7 @@ namespace Avalonia /// /// The object. /// A collection of definitions. - public IEnumerable GetRegistered(IAvaloniaObject o) + public IReadOnlyList GetRegistered(IAvaloniaObject o) { Contract.Requires(o != null); @@ -229,8 +236,13 @@ namespace Avalonia throw new InvalidOperationException("Attached properties not supported."); } - foreach (AvaloniaProperty x in GetRegistered(type)) + var registered = GetRegistered(type); + var registeredCount = registered.Count; + + for (var i = 0; i < registeredCount; i++) { + AvaloniaProperty x = registered[i]; + if (x.Name == name) { return x; @@ -276,8 +288,13 @@ namespace Avalonia return property; } - foreach (var p in GetRegisteredDirect(o.GetType())) + var registeredDirect = GetRegisteredDirect(o.GetType()); + var registeredDirectCount = registeredDirect.Count; + + for (var i = 0; i < registeredDirectCount; i++) { + var p = registeredDirect[i]; + if (p == property) { return (DirectPropertyBase)p; @@ -308,8 +325,23 @@ namespace Avalonia Contract.Requires(type != null); Contract.Requires(property != null); - return Instance.GetRegistered(type).Any(x => x == property) || - Instance.GetRegisteredAttached(type).Any(x => x == property); + static bool ContainsProperty(IReadOnlyList properties, AvaloniaProperty property) + { + var propertiesCount = properties.Count; + + for (var i = 0; i < propertiesCount; i++) + { + if (properties[i] == property) + { + return true; + } + } + + return false; + } + + return ContainsProperty(Instance.GetRegistered(type), property) || + ContainsProperty(Instance.GetRegisteredAttached(type), property); } /// @@ -374,7 +406,6 @@ namespace Avalonia } _registeredCache.Clear(); - _initializedCache.Clear(); _inheritedCache.Clear(); } @@ -411,32 +442,7 @@ namespace Avalonia } _attachedCache.Clear(); - _initializedCache.Clear(); _inheritedCache.Clear(); } - - private readonly struct PropertyInitializationData - { - public AvaloniaProperty Property { get; } - public object Value { get; } - public bool IsDirect { get; } - public IDirectPropertyAccessor DirectAccessor { get; } - - public PropertyInitializationData(AvaloniaProperty property, IDirectPropertyAccessor directAccessor) - { - Property = property; - Value = null; - IsDirect = true; - DirectAccessor = directAccessor; - } - - public PropertyInitializationData(AvaloniaProperty property, IStyledPropertyAccessor styledAccessor, Type type) - { - Property = property; - Value = styledAccessor.GetDefaultValue(type); - IsDirect = false; - DirectAccessor = null; - } - } } } diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 91b895f38a..238070bbef 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -36,7 +36,7 @@ namespace Avalonia.Platform /// /// Enables or disables system window decorations (title bar, buttons, etc) /// - void SetSystemDecorations(bool enabled); + void SetSystemDecorations(SystemDecorations enabled); /// /// Sets the icon of this window. diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 943a73b427..4acfb75cb9 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -699,12 +699,12 @@ namespace Avalonia.Controls protected override void OnPointerPressed(PointerPressedEventArgs e) { - var point = e.GetPosition(_presenter); - var index = CaretIndex = _presenter.GetCaretIndex(point); var text = Text; - if (text != null && e.MouseButton == MouseButton.Left) + if (text != null && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) { + var point = e.GetPosition(_presenter); + var index = CaretIndex = _presenter.GetCaretIndex(point); switch (e.ClickCount) { case 1: @@ -730,7 +730,8 @@ namespace Avalonia.Controls protected override void OnPointerMoved(PointerEventArgs e) { - if (_presenter != null && e.Pointer.Captured == _presenter) + // selection should not change during pointer move if the user right clicks + if (_presenter != null && e.Pointer.Captured == _presenter && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) { var point = e.GetPosition(_presenter); @@ -743,6 +744,22 @@ namespace Avalonia.Controls { if (_presenter != null && e.Pointer.Captured == _presenter) { + if (e.InitialPressMouseButton == MouseButton.Right) + { + var point = e.GetPosition(_presenter); + var caretIndex = _presenter.GetCaretIndex(point); + + // see if mouse clicked inside current selection + // if it did not, we change the selection to where the user clicked + var firstSelection = Math.Min(SelectionStart, SelectionEnd); + var lastSelection = Math.Max(SelectionStart, SelectionEnd); + var didClickInSelection = SelectionStart != SelectionEnd && + caretIndex >= firstSelection && caretIndex <= lastSelection; + if (!didClickInSelection) + { + CaretIndex = SelectionEnd = SelectionStart = caretIndex; + } + } e.Pointer.Capture(null); } } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 6554237b3a..f4a3f05f03 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -2,19 +2,19 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.ComponentModel; +using System.Linq; using System.Reactive.Linq; using System.Threading.Tasks; using Avalonia.Controls.Platform; +using Avalonia.Data; using Avalonia.Input; +using Avalonia.Interactivity; using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Styling; -using System.Collections.Generic; -using System.Linq; using JetBrains.Annotations; -using System.ComponentModel; -using Avalonia.Interactivity; namespace Avalonia.Controls { @@ -45,6 +45,27 @@ namespace Avalonia.Controls WidthAndHeight = 3, } + /// + /// Determines system decorations (title bar, border, etc) for a + /// + public enum SystemDecorations + { + /// + /// No decorations + /// + None = 0, + + /// + /// Window border without titlebar + /// + BorderOnly = 1, + + /// + /// Fully decorated (default) + /// + Full = 2 + } + /// /// A top-level window. /// @@ -59,8 +80,18 @@ namespace Avalonia.Controls /// /// Enables or disables system window decorations (title bar, buttons, etc) /// - public static readonly StyledProperty HasSystemDecorationsProperty = - AvaloniaProperty.Register(nameof(HasSystemDecorations), true); + [Obsolete("Use SystemDecorationsProperty instead")] + public static readonly DirectProperty HasSystemDecorationsProperty = + AvaloniaProperty.RegisterDirect( + nameof(HasSystemDecorations), + o => o.HasSystemDecorations, + (o, v) => o.HasSystemDecorations = v); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SystemDecorationsProperty = + AvaloniaProperty.Register(nameof(SystemDecorations), SystemDecorations.Full); /// /// Enables or disables the taskbar icon @@ -124,9 +155,6 @@ namespace Avalonia.Controls { BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White); TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue)); - HasSystemDecorationsProperty.Changed.AddClassHandler( - (s, e) => s.PlatformImpl?.SetSystemDecorations((bool)e.NewValue)); - ShowInTaskbarProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue)); IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue)?.PlatformImpl)); @@ -135,12 +163,11 @@ namespace Avalonia.Controls WindowStateProperty.Changed.AddClassHandler( (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; }); - + MinWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight))); MinHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); MaxWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight))); MaxHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue))); - } /// @@ -191,11 +218,30 @@ namespace Avalonia.Controls /// /// Enables or disables system window decorations (title bar, buttons, etc) /// - /// + [Obsolete("Use SystemDecorations instead")] public bool HasSystemDecorations { - get { return GetValue(HasSystemDecorationsProperty); } - set { SetValue(HasSystemDecorationsProperty, value); } + get => SystemDecorations == SystemDecorations.Full; + set + { + var oldValue = HasSystemDecorations; + + if (oldValue != value) + { + SystemDecorations = value ? SystemDecorations.Full : SystemDecorations.None; + RaisePropertyChanged(HasSystemDecorationsProperty, oldValue, value); + } + } + } + + /// + /// Sets the system decorations (title bar, border, etc) + /// + /// + public SystemDecorations SystemDecorations + { + get { return GetValue(SystemDecorationsProperty); } + set { SetValue(SystemDecorationsProperty, value); } } /// @@ -584,5 +630,27 @@ namespace Avalonia.Controls /// event needs to be raised. /// protected virtual void OnClosing(CancelEventArgs e) => Closing?.Invoke(this, e); + + protected override void OnPropertyChanged( + AvaloniaProperty property, + Optional oldValue, + BindingValue newValue, + BindingPriority priority) + { + if (property == SystemDecorationsProperty) + { + var typedNewValue = newValue.GetValueOrDefault(); + + PlatformImpl?.SetSystemDecorations(typedNewValue); + + var o = oldValue.GetValueOrDefault() == SystemDecorations.Full; + var n = typedNewValue == SystemDecorations.Full; + + if (o != n) + { + RaisePropertyChanged(HasSystemDecorationsProperty, o, n); + } + } + } } } diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 86e34ca6d4..7480b3519c 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -96,7 +96,7 @@ namespace Avalonia.DesignerSupport.Remote { } - public void SetSystemDecorations(bool enabled) + public void SetSystemDecorations(SystemDecorations enabled) { } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 4bba5ef41b..7bf1d236bd 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -110,7 +110,7 @@ namespace Avalonia.DesignerSupport.Remote { } - public void SetSystemDecorations(bool enabled) + public void SetSystemDecorations(SystemDecorations enabled) { } diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index c757576017..73ec81ce57 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -68,9 +68,9 @@ namespace Avalonia.Native _native.CanResize = value; } - public void SetSystemDecorations(bool enabled) + public void SetSystemDecorations(Controls.SystemDecorations enabled) { - _native.HasDecorations = enabled; + _native.HasDecorations = (Interop.SystemDecorations)enabled; } public void SetTitleBarColor (Avalonia.Media.Color color) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 94f1dbc8d1..2492f5a43a 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -173,6 +173,7 @@ namespace Avalonia.X11 Surfaces = surfaces.ToArray(); UpdateMotifHints(); + UpdateSizeHints(null); _xic = XCreateIC(_x11.Xim, XNames.XNInputStyle, XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing, XNames.XNClientWindow, _handle, IntPtr.Zero); XFlush(_x11.Display); @@ -219,12 +220,16 @@ namespace Avalonia.X11 var decorations = MotifDecorations.Menu | MotifDecorations.Title | MotifDecorations.Border | MotifDecorations.Maximize | MotifDecorations.Minimize | MotifDecorations.ResizeH; - if (_popup || !_systemDecorations) + if (_popup || _systemDecorations == SystemDecorations.None) { decorations = 0; } + else if (_systemDecorations == SystemDecorations.BorderOnly) + { + decorations = MotifDecorations.Border; + } - if (!_canResize) + if (!_canResize || _systemDecorations == SystemDecorations.BorderOnly) { functions &= ~(MotifFunctions.Resize | MotifFunctions.Maximize); decorations &= ~(MotifDecorations.Maximize | MotifDecorations.ResizeH); @@ -247,7 +252,7 @@ namespace Avalonia.X11 var min = _minMaxSize.minSize; var max = _minMaxSize.maxSize; - if (!_canResize) + if (!_canResize || _systemDecorations == SystemDecorations.BorderOnly) max = min = _realSize; if (preResize.HasValue) @@ -621,7 +626,7 @@ namespace Avalonia.X11 return rv; } - private bool _systemDecorations = true; + private SystemDecorations _systemDecorations = SystemDecorations.Full; private bool _canResize = true; private const int MaxWindowDimension = 100000; @@ -777,10 +782,11 @@ namespace Avalonia.X11 (int)(point.X * Scaling + Position.X), (int)(point.Y * Scaling + Position.Y)); - public void SetSystemDecorations(bool enabled) + public void SetSystemDecorations(SystemDecorations enabled) { _systemDecorations = enabled; UpdateMotifHints(); + UpdateSizeHints(null); } diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 904e122382..50b568cab2 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1298,7 +1298,17 @@ namespace Avalonia.Win32.Interop [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)] internal static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, out int finalEffect); + [DllImport("dwmapi.dll")] + public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); + [StructLayout(LayoutKind.Sequential)] + internal struct MARGINS + { + public int cxLeftWidth; + public int cxRightWidth; + public int cyTopHeight; + public int cyBottomHeight; + } public enum MONITOR { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index cea9f88799..6900d73c93 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -34,7 +34,7 @@ namespace Avalonia.Win32 private IInputRoot _owner; private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock(); private bool _trackingMouse; - private bool _decorated = true; + private SystemDecorations _decorated = SystemDecorations.Full; private bool _resizable = true; private bool _topmost = false; private bool _taskbarIcon = true; @@ -97,7 +97,7 @@ namespace Avalonia.Win32 { get { - if (_decorated) + if (_decorated == SystemDecorations.Full) { var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); @@ -281,7 +281,7 @@ namespace Avalonia.Win32 UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Hide); } - public void SetSystemDecorations(bool value) + public void SetSystemDecorations(SystemDecorations value) { if (value == _decorated) { @@ -464,7 +464,7 @@ namespace Avalonia.Win32 return IntPtr.Zero; case WindowsMessage.WM_NCCALCSIZE: - if (ToInt32(wParam) == 1 && !_decorated) + if (ToInt32(wParam) == 1 && _decorated != SystemDecorations.Full) { return IntPtr.Zero; } @@ -682,14 +682,14 @@ namespace Avalonia.Win32 break; case WindowsMessage.WM_NCPAINT: - if (!_decorated) + if (_decorated != SystemDecorations.Full) { return IntPtr.Zero; } break; case WindowsMessage.WM_NCACTIVATE: - if (!_decorated) + if (_decorated != SystemDecorations.Full) { return new IntPtr(1); } @@ -1001,7 +1001,7 @@ namespace Avalonia.Win32 style |= WindowStyles.WS_OVERLAPPEDWINDOW; - if (!_decorated) + if (_decorated != SystemDecorations.Full) { style ^= (WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU); } @@ -1011,6 +1011,10 @@ namespace Avalonia.Win32 style ^= (WindowStyles.WS_SIZEFRAME); } + MARGINS margins = new MARGINS(); + margins.cyBottomHeight = _decorated == SystemDecorations.BorderOnly ? 1 : 0; + UnmanagedMethods.DwmExtendFrameIntoClientArea(_hwnd, ref margins); + GetClientRect(_hwnd, out var oldClientRect); var oldClientRectOrigin = new UnmanagedMethods.POINT(); ClientToScreen(_hwnd, ref oldClientRectOrigin); @@ -1024,7 +1028,7 @@ namespace Avalonia.Win32 if (oldDecorated != _decorated) { var newRect = oldClientRect; - if (_decorated) + if (_decorated == SystemDecorations.Full) AdjustWindowRectEx(ref newRect, (uint)style, false, GetWindowLong(_hwnd, (int)WindowLongParam.GWL_EXSTYLE)); SetWindowPos(_hwnd, IntPtr.Zero, newRect.left, newRect.top, newRect.Width, newRect.Height, diff --git a/src/iOS/Avalonia.iOS/EmbeddableImpl.cs b/src/iOS/Avalonia.iOS/EmbeddableImpl.cs index 65a6c15971..838bf49846 100644 --- a/src/iOS/Avalonia.iOS/EmbeddableImpl.cs +++ b/src/iOS/Avalonia.iOS/EmbeddableImpl.cs @@ -20,7 +20,7 @@ namespace Avalonia.iOS return Disposable.Empty; } - public void SetSystemDecorations(bool enabled) + public void SetSystemDecorations(SystemDecorations enabled) { }