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)
{
}