Browse Source

Merge branch 'master' into feature/textbox-fix-right-click

Jumar Macato 5 years ago
parent
commit
2ef3cdaee7

+ 4 - 4
azure-pipelines.yml

@@ -35,16 +35,16 @@ jobs:
     vmImage: 'macOS-10.14'
   steps:
   - task: UseDotNet@2
-    displayName: 'Use .NET Core SDK 3.1.x'
+    displayName: 'Use .NET Core SDK 3.1.101'
     inputs:
       packageType: sdk
-      version: 3.1.x
+      version: 3.1.101
 
   - task: UseDotNet@2
-    displayName: 'Use .NET Core Runtime 3.1.x'
+    displayName: 'Use .NET Core Runtime 3.1.1'
     inputs:
       packageType: runtime
-      version: 3.1.x
+      version: 3.1.1
 
   - task: CmdLine@2
     displayName: 'Install Mono 5.18'

+ 7 - 1
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;

+ 60 - 21
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;
     }
 };

+ 9 - 2
samples/ControlCatalog/MainView.xaml

@@ -59,10 +59,17 @@
       <TabItem Header="TreeView"><pages:TreeViewPage/></TabItem>
       <TabItem Header="Viewbox"><pages:ViewboxPage/></TabItem>
       <TabControl.Tag>
-        <ComboBox x:Name="Themes" SelectedIndex="0" Width="100" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Bottom">
+        <StackPanel Width="115" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Bottom">
+          <ComboBox x:Name="Decorations" SelectedIndex="0" Margin="0,0,0,8">
+            <ComboBoxItem>No Decorations</ComboBoxItem>
+            <ComboBoxItem>Border Only</ComboBoxItem>
+            <ComboBoxItem>Full Decorations</ComboBoxItem>
+          </ComboBox>
+          <ComboBox x:Name="Themes" SelectedIndex="0">
             <ComboBoxItem>Light</ComboBoxItem>
             <ComboBoxItem>Dark</ComboBoxItem>
-        </ComboBox>
+          </ComboBox>
+        </StackPanel>
       </TabControl.Tag>
     </TabControl>
   </Grid>

+ 14 - 0
samples/ControlCatalog/MainView.xaml.cs

@@ -56,6 +56,20 @@ namespace ControlCatalog
                 }
             };
             Styles.Add(light);
+
+            var decorations = this.Find<ComboBox>("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<ComboBox>("Decorations");
+            decorations.SelectedIndex = (int)((Window)VisualRoot).SystemDecorations;
         }
     }
 }

+ 1 - 1
src/Avalonia.Controls/Platform/IWindowImpl.cs

@@ -36,7 +36,7 @@ namespace Avalonia.Platform
         /// <summary>
         /// Enables or disables system window decorations (title bar, buttons, etc)
         /// </summary>
-        void SetSystemDecorations(bool enabled);
+        void SetSystemDecorations(SystemDecorations enabled);
 
         /// <summary>
         /// Sets the icon of this window.

+ 82 - 14
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,
     }
 
+    /// <summary>
+    /// Determines system decorations (title bar, border, etc) for a <see cref="Window"/>
+    /// </summary>
+    public enum SystemDecorations
+    {
+        /// <summary>
+        /// No decorations
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// Window border without titlebar
+        /// </summary>
+        BorderOnly = 1,
+
+        /// <summary>
+        /// Fully decorated (default)
+        /// </summary>
+        Full = 2
+    }
+
     /// <summary>
     /// A top-level window.
     /// </summary>
@@ -59,8 +80,18 @@ namespace Avalonia.Controls
         /// <summary>
         /// Enables or disables system window decorations (title bar, buttons, etc)
         /// </summary>
-        public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
-            AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
+        [Obsolete("Use SystemDecorationsProperty instead")]
+        public static readonly DirectProperty<Window, bool> HasSystemDecorationsProperty =
+            AvaloniaProperty.RegisterDirect<Window, bool>(
+                nameof(HasSystemDecorations),
+                o => o.HasSystemDecorations,
+                (o, v) => o.HasSystemDecorations = v);
+
+        /// <summary>
+        /// Defines the <see cref="SystemDecorations"/> property.
+        /// </summary>
+        public static readonly StyledProperty<SystemDecorations> SystemDecorationsProperty =
+            AvaloniaProperty.Register<Window, SystemDecorations>(nameof(SystemDecorations), SystemDecorations.Full);
 
         /// <summary>
         /// Enables or disables the taskbar icon
@@ -124,9 +155,6 @@ namespace Avalonia.Controls
         {
             BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
             TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue));
-            HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
-                (s, e) => s.PlatformImpl?.SetSystemDecorations((bool)e.NewValue));
-
             ShowInTaskbarProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue));
 
             IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue)?.PlatformImpl));
@@ -135,12 +163,11 @@ namespace Avalonia.Controls
 
             WindowStateProperty.Changed.AddClassHandler<Window>(
                 (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; });
-            
+
             MinWidthProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight)));
             MinHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight)));
             MaxWidthProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight)));
             MaxHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue)));
-
         }
 
         /// <summary>
@@ -191,11 +218,30 @@ namespace Avalonia.Controls
         /// <summary>
         /// Enables or disables system window decorations (title bar, buttons, etc)
         /// </summary>
-        /// 
+        [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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sets the system decorations (title bar, border, etc)
+        /// </summary>
+        /// 
+        public SystemDecorations SystemDecorations
+        {
+            get { return GetValue(SystemDecorationsProperty); }
+            set { SetValue(SystemDecorationsProperty, value); }
         }
 
         /// <summary>
@@ -584,5 +630,27 @@ namespace Avalonia.Controls
         /// <see cref="Closing"/> event needs to be raised.
         /// </remarks>
         protected virtual void OnClosing(CancelEventArgs e) => Closing?.Invoke(this, e);
+
+        protected override void OnPropertyChanged<T>(
+            AvaloniaProperty<T> property,
+            Optional<T> oldValue,
+            BindingValue<T> newValue,
+            BindingPriority priority)
+        {
+            if (property == SystemDecorationsProperty)
+            {
+                var typedNewValue = newValue.GetValueOrDefault<SystemDecorations>();
+
+                PlatformImpl?.SetSystemDecorations(typedNewValue);
+
+                var o = oldValue.GetValueOrDefault<SystemDecorations>() == SystemDecorations.Full;
+                var n = typedNewValue == SystemDecorations.Full;
+
+                if (o != n)
+                {
+                    RaisePropertyChanged(HasSystemDecorationsProperty, o, n);
+                }
+            }
+        }
     }
 }

+ 1 - 1
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@@ -96,7 +96,7 @@ namespace Avalonia.DesignerSupport.Remote
         {
         }
 
-        public void SetSystemDecorations(bool enabled)
+        public void SetSystemDecorations(SystemDecorations enabled)
         {
         }
 

+ 1 - 1
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@@ -110,7 +110,7 @@ namespace Avalonia.DesignerSupport.Remote
         {
         }
 
-        public void SetSystemDecorations(bool enabled)
+        public void SetSystemDecorations(SystemDecorations enabled)
         {
         }
 

+ 2 - 2
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)

+ 11 - 5
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);
         }
 
 

+ 10 - 0
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
         {

+ 12 - 8
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,

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