diff --git a/src/Avalonia.Native.OSX/window.h b/src/Avalonia.Native.OSX/window.h index 58dca5bc9a7..82c7b9e7319 100644 --- a/src/Avalonia.Native.OSX/window.h +++ b/src/Avalonia.Native.OSX/window.h @@ -28,4 +28,9 @@ struct INSWindowHolder virtual AvnWindow* GetNSWindow () = 0; }; +struct IWindowStateChanged +{ + virtual void WindowStateChanged () = 0; +}; + #endif /* window_h */ diff --git a/src/Avalonia.Native.OSX/window.mm b/src/Avalonia.Native.OSX/window.mm index 4fba1aee91e..54259386151 100644 --- a/src/Avalonia.Native.OSX/window.mm +++ b/src/Avalonia.Native.OSX/window.mm @@ -44,6 +44,16 @@ virtual HRESULT Hide () return S_OK; } + virtual HRESULT Activate () + { + if(Window != nullptr) + { + [Window makeKeyWindow]; + } + + return S_OK; + } + virtual HRESULT SetTopMost (bool value) { [Window setLevel: value ? NSFloatingWindowLevel : NSNormalWindowLevel]; @@ -187,6 +197,11 @@ void UpdateStyle() { [Window setStyleMask:GetStyle()]; } + + virtual void OnResized () + { + + } }; NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, NSRunLoopCommonModes, NSConnectionReplyMode, nil]; @@ -455,7 +470,6 @@ - (void)scrollWheel:(NSEvent *)event [super scrollWheel:event]; } - - (void)mouseEntered:(NSEvent *)event { _isMouseOver = true; @@ -541,6 +555,18 @@ - (void)windowDidMove:(NSNotification *)notification _parent->GetPosition(&position); _parent->BaseEvents->PositionChanged(position); } + +// TODO this breaks resizing. +/*- (void)windowDidResize:(NSNotification *)notification +{ + + auto parent = dynamic_cast(_parent.operator->()); + + if(parent != nullptr) + { + parent->WindowStateChanged(); + } +}*/ @end class PopupImpl : public WindowBaseImpl, public IAvnPopup @@ -570,11 +596,13 @@ virtual NSWindowStyleMask GetStyle() return ptr; } -class WindowImpl : public WindowBaseImpl, public IAvnWindow +class WindowImpl : public WindowBaseImpl, public IAvnWindow, public IWindowStateChanged { private: bool _canResize = true; bool _hasDecorations = true; + CGRect _lastUndecoratedFrame; + AvnWindowState _lastWindowState; BEGIN_INTERFACE_MAP() INHERIT_INTERFACE_MAP(WindowBaseImpl) @@ -587,6 +615,39 @@ virtual NSWindowStyleMask GetStyle() [Window setCanBecomeKeyAndMain]; } + void WindowStateChanged () + { + AvnWindowState state; + GetWindowState(&state); + WindowEvents->WindowStateChanged(state); + } + + bool UndecoratedIsMaximized () + { + return CGRectEqualToRect([Window frame], [Window screen].visibleFrame); + } + + bool IsZoomed () + { + return _hasDecorations ? [Window isZoomed] : UndecoratedIsMaximized(); + } + + void DoZoom() + { + if (_hasDecorations) + { + [Window performZoom:Window]; + } + else + { + if (!UndecoratedIsMaximized()) + { + _lastUndecoratedFrame = [Window frame]; + } + + [Window zoom:Window]; + } + } virtual HRESULT SetCanResize(bool value) { @@ -602,7 +663,79 @@ virtual HRESULT SetHasDecorations(bool value) return S_OK; } + virtual HRESULT GetWindowState (AvnWindowState*ret) + { + if(ret == nullptr) + { + return E_POINTER; + } + + if([Window isMiniaturized]) + { + *ret = Minimized; + return S_OK; + } + + if([Window isZoomed]) + { + *ret = Maximized; + return S_OK; + } + + *ret = Normal; + + return S_OK; + } + + virtual HRESULT SetWindowState (AvnWindowState state) + { + switch (state) { + case Maximized: + if([Window isMiniaturized]) + { + [Window deminiaturize:Window]; + } + + if(!IsZoomed()) + { + DoZoom(); + } + break; + + case Minimized: + [Window miniaturize:Window]; + break; + + default: + if([Window isMiniaturized]) + { + [Window deminiaturize:Window]; + } + + if(IsZoomed()) + { + DoZoom(); + } + break; + } + + return S_OK; + } + protected: + virtual void OnResized () + { + auto windowState = [Window isMiniaturized] ? Minimized + : (IsZoomed() ? Maximized : Normal); + + if (windowState != _lastWindowState) + { + _lastWindowState = windowState; + + WindowEvents->WindowStateChanged(windowState); + } + } + virtual NSWindowStyleMask GetStyle() { unsigned long s = NSWindowStyleMaskBorderless; diff --git a/src/Avalonia.Native/PopupImpl.cs b/src/Avalonia.Native/PopupImpl.cs index fa11d5469b9..8f662aa519e 100644 --- a/src/Avalonia.Native/PopupImpl.cs +++ b/src/Avalonia.Native/PopupImpl.cs @@ -28,6 +28,10 @@ public PopupEvents(PopupImpl parent) : base(parent) { _parent = parent; } + + void IAvnWindowEvents.WindowStateChanged(AvnWindowState state) + { + } } } } diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index aefc950b94d..7d1b1e2f506 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -22,6 +22,11 @@ public WindowEvents(WindowImpl parent) : base(parent) { _parent = parent; } + + void IAvnWindowEvents.WindowStateChanged(AvnWindowState state) + { + _parent.WindowStateChanged?.Invoke((WindowState)state); + } } public IAvnWindow Native => _native; @@ -46,7 +51,18 @@ public void SetTitle(string title) { } - public WindowState WindowState { get; set; } = WindowState.Normal; + public WindowState WindowState + { + get + { + return (WindowState)_native.GetWindowState(); + } + set + { + _native.SetWindowState((AvnWindowState)value); + } + } + public Action WindowStateChanged { get; set; } public void ShowTaskbarIcon(bool value) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 3b5b46c6987..8c92d5de1a4 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -162,7 +162,7 @@ void IAvnWindowBaseEvents.RunRenderPriorityJobs() public void Activate() { - + _native.Activate(); } public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta) diff --git a/src/headers/avalonia-native.h b/src/headers/avalonia-native.h index 3780d8c422d..a3f191daabe 100644 --- a/src/headers/avalonia-native.h +++ b/src/headers/avalonia-native.h @@ -82,6 +82,13 @@ enum AvnInputModifiers MiddleMouseButton = 64 }; +enum AvnWindowState +{ + Normal, + Minimized, + Maximized, +}; + AVNCOM(IAvaloniaNativeFactory, 01) : virtual IUnknown { public: @@ -100,6 +107,7 @@ AVNCOM(IAvnWindowBase, 02) : virtual IUnknown virtual HRESULT Show() = 0; virtual HRESULT Hide () = 0; virtual HRESULT Close() = 0; + virtual HRESULT Activate () = 0; virtual HRESULT GetClientSize(AvnSize*ret) = 0; virtual HRESULT GetMaxClientSize(AvnSize* ret) = 0; virtual HRESULT GetScaling(double*ret)=0; @@ -123,6 +131,8 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase { virtual HRESULT SetCanResize(bool value) = 0; virtual HRESULT SetHasDecorations(bool value) = 0; + virtual HRESULT SetWindowState(AvnWindowState state) = 0; + virtual HRESULT GetWindowState(AvnWindowState*ret) = 0; }; AVNCOM(IAvnWindowBaseEvents, 05) : IUnknown @@ -145,7 +155,7 @@ AVNCOM(IAvnWindowBaseEvents, 05) : IUnknown AVNCOM(IAvnWindowEvents, 06) : IAvnWindowBaseEvents { - + virtual void WindowStateChanged (AvnWindowState state) = 0; }; AVNCOM(IAvnMacOptions, 07) : virtual IUnknown