diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index f9bfaf0b47..8c51e1cf50 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -276,6 +276,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase virtual HRESULT SetTitleBarColor (AvnColor color) = 0; virtual HRESULT SetWindowState(AvnWindowState state) = 0; virtual HRESULT GetWindowState(AvnWindowState*ret) = 0; + virtual HRESULT SetExtendClientArea (bool enable) = 0; }; AVNCOM(IAvnWindowBaseEvents, 05) : IUnknown diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index abfae3cf1e..19b0524a26 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -474,6 +474,7 @@ private: bool _inSetWindowState; NSRect _preZoomSize; bool _transitioningWindowState; + bool _isClientAreaExtended; FORWARD_IUNKNOWN() BEGIN_INTERFACE_MAP() @@ -487,6 +488,7 @@ private: ComPtr WindowEvents; WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl) { + _isClientAreaExtended = false; _fullScreenActive = false; _canResize = true; _decorations = SystemDecorationsFull; @@ -766,6 +768,28 @@ private: } } + virtual HRESULT SetExtendClientArea (bool enable) override + { + _isClientAreaExtended = enable; + [Window setTitleVisibility:NSWindowTitleHidden]; + [Window setTitlebarAppearsTransparent:enable]; + Window.movableByWindowBackground = true; + + NSRect x; + x.size.height = 50; + x.size.width = Window.frame.size.width; + [Window contentLayoutRect] = x; + + + auto customToolbar = [NSToolbar new]; + + customToolbar.showsBaselineSeparator = true; + Window.toolbar = customToolbar; + + UpdateStyle(); + return S_OK; + } + void EnterFullScreenMode () { _fullScreenActive = true; @@ -924,6 +948,11 @@ protected: { s |= NSWindowStyleMaskMiniaturizable; } + + if(_isClientAreaExtended) + { + s |= NSWindowStyleMaskFullSizeContentView | NSWindowStyleMaskTexturedBackground; + } return s; } }; diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 532869e751..0adc009911 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -1,6 +1,8 @@ using System; using Avalonia.Controls; using Avalonia.Controls.Platform; +using Avalonia.Input; +using Avalonia.Input.Raw; using Avalonia.Native.Interop; using Avalonia.OpenGL; using Avalonia.Platform; @@ -100,14 +102,43 @@ namespace Avalonia.Native public Action ExtendClientAreaToDecorationsChanged { get; set; } - public Thickness ExtendedMargins { get; } = new Thickness(); + public Thickness ExtendedMargins { get; } = new Thickness(0, 20, 0, 0); public Thickness OffScreenMargin { get; } = new Thickness(); - public bool IsClientAreaExtendedToDecorations { get; } + private bool _isExtended; + public bool IsClientAreaExtendedToDecorations => _isExtended; + + protected override bool ChromeHitTest (RawPointerEventArgs e) + { + if(_isExtended) + { + if(e.Type == RawPointerEventType.LeftButtonDown) + { + var visual = (_inputRoot as Window).Renderer.HitTestFirst(e.Position, _inputRoot as Window, x => + { + if (x is IInputElement ie && !ie.IsHitTestVisible) + { + return false; + } + return true; + }); + + if(visual == null) + { + _native.BeginMoveDrag(); + } + } + } + + return false; + } public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) { + _isExtended = extendIntoClientAreaHint; + _native.SetExtendClientArea(extendIntoClientAreaHint); + ExtendClientAreaToDecorationsChanged?.Invoke(true); } public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index a7ca528b2b..f6c2dd289b 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -45,7 +45,7 @@ namespace Avalonia.Native public abstract class WindowBaseImpl : IWindowBaseImpl, IFramebufferPlatformSurface { - IInputRoot _inputRoot; + protected IInputRoot _inputRoot; IAvnWindowBase _native; private object _syncRoot = new object(); private bool _deferredRendering = false; @@ -254,6 +254,11 @@ namespace Avalonia.Native return args.Handled; } + protected virtual bool ChromeHitTest (RawPointerEventArgs e) + { + return false; + } + public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta) { Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); @@ -265,7 +270,12 @@ namespace Avalonia.Native break; default: - Input?.Invoke(new RawPointerEventArgs(_mouse, timeStamp, _inputRoot, (RawPointerEventType)type, point.ToAvaloniaPoint(), (RawInputModifiers)modifiers)); + var e = new RawPointerEventArgs(_mouse, timeStamp, _inputRoot, (RawPointerEventType)type, point.ToAvaloniaPoint(), (RawInputModifiers)modifiers); + + if(!ChromeHitTest(e)) + { + Input?.Invoke(e); + } break; } }