浏览代码

Merge pull request #16 from AvaloniaUI/features/window-management

implement window state change events and manipulation.
danwalmsley 7 年之前
父节点
当前提交
d1b0e06bb5

+ 5 - 0
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 */

+ 135 - 2
src/Avalonia.Native.OSX/window.mm

@@ -44,6 +44,16 @@ public:
         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 @@ protected:
     {
         [Window setStyleMask:GetStyle()];
     }
+    
+    virtual void OnResized ()
+    {
+        
+    }
 };
 
 NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, NSRunLoopCommonModes, NSConnectionReplyMode, nil];
@@ -455,7 +470,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     [super scrollWheel:event];
 }
 
-
 - (void)mouseEntered:(NSEvent *)event
 {
     _isMouseOver = true;
@@ -541,6 +555,18 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     _parent->GetPosition(&position);
     _parent->BaseEvents->PositionChanged(position);
 }
+
+// TODO this breaks resizing.
+/*- (void)windowDidResize:(NSNotification *)notification
+{
+    
+    auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
+    
+    if(parent != nullptr)
+    {
+        parent->WindowStateChanged();
+    }
+}*/
 @end
 
 class PopupImpl : public WindowBaseImpl, public IAvnPopup
@@ -570,11 +596,13 @@ extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events)
     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 @@ private:
         [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 @@ private:
         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;

+ 4 - 0
src/Avalonia.Native/PopupImpl.cs

@@ -28,6 +28,10 @@ namespace Avalonia.Native
             {
                 _parent = parent;
             }
+
+            void IAvnWindowEvents.WindowStateChanged(AvnWindowState state)
+            {
+            }
         }
     }
 }

+ 17 - 1
src/Avalonia.Native/WindowImpl.cs

@@ -22,6 +22,11 @@ namespace Avalonia.Native
             {
                 _parent = parent;
             }
+
+            void IAvnWindowEvents.WindowStateChanged(AvnWindowState state)
+            {
+                _parent.WindowStateChanged?.Invoke((WindowState)state);
+            }
         }
 
         public IAvnWindow Native => _native;
@@ -46,7 +51,18 @@ namespace Avalonia.Native
         {
         }
 
-        public WindowState WindowState { get; set; } = WindowState.Normal;
+        public WindowState WindowState
+        {
+            get
+            {
+                return (WindowState)_native.GetWindowState();
+            }
+            set
+            {
+                _native.SetWindowState((AvnWindowState)value);
+            }
+        }
+
         public Action<WindowState> WindowStateChanged { get; set; }
 
         public void ShowTaskbarIcon(bool value)

+ 1 - 1
src/Avalonia.Native/WindowImplBase.cs

@@ -162,7 +162,7 @@ namespace Avalonia.Native
 
         public void Activate()
         {
-        
+            _native.Activate();
         }
 
         public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)

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