Browse Source

Make WindowState bindable.

Requested changes.
José Pedro 8 years ago
parent
commit
2af15cbee4

+ 5 - 0
src/Avalonia.Controls/Platform/IWindowImpl.cs

@@ -16,6 +16,11 @@ namespace Avalonia.Platform
         /// </summary>
         WindowState WindowState { get; set; }
 
+        /// <summary>
+        /// Gets or sets a method called when the minimized/maximized state of the window changes.
+        /// </summary>
+        Action<WindowState> WindowStateChanged { get; set; }
+
         /// <summary>
         /// Sets the title of the window.
         /// </summary>

+ 17 - 9
src/Avalonia.Controls/Window.cs

@@ -67,13 +67,19 @@ namespace Avalonia.Controls
         /// </summary>
         public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
             AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
-        
+
         /// <summary>
         /// Enables or disables the taskbar icon
         /// </summary>
         public static readonly StyledProperty<bool> ShowInTaskbarProperty =
             AvaloniaProperty.Register<Window, bool>(nameof(ShowInTaskbar), true);
-        
+
+        /// <summary>
+        /// Enables or disables the taskbar icon
+        /// </summary>
+        public static readonly StyledProperty<WindowState> WindowStateProperty =
+            AvaloniaProperty.Register<Window, WindowState>(nameof(WindowState));
+
         /// <summary>
         /// Defines the <see cref="Title"/> property.
         /// </summary>
@@ -118,6 +124,9 @@ namespace Avalonia.Controls
             IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
 
             CanResizeProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue));
+
+            WindowStateProperty.Changed.AddClassHandler<Window>(
+                (w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; });
         }
 
         /// <summary>
@@ -138,8 +147,11 @@ namespace Avalonia.Controls
             impl.Closing = HandleClosing;
             _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
             Screens = new Screens(PlatformImpl?.Screen);
-        }
 
+            if (PlatformImpl != null)
+                PlatformImpl.WindowStateChanged = s => WindowState = s;
+        }
+        
         /// <inheritdoc/>
         event EventHandler<NameScopeEventArgs> INameScope.Registered
         {
@@ -205,12 +217,8 @@ namespace Avalonia.Controls
         /// </summary>
         public WindowState WindowState
         {
-            get { return PlatformImpl?.WindowState ?? WindowState.Normal; }
-            set
-            {
-                if (PlatformImpl != null)
-                    PlatformImpl.WindowState = value;
-            }
+            get { return GetValue(WindowStateProperty); }
+            set { SetValue(WindowStateProperty, value); }
         }
 
         /// <summary>

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

@@ -42,6 +42,7 @@ namespace Avalonia.DesignerSupport.Remote
         public Func<bool> Closing { get; set; }
         public IPlatformHandle Handle { get; }
         public WindowState WindowState { get; set; }
+        public Action<WindowState> WindowStateChanged { get; set; }
         public Size MaxClientSize { get; } = new Size(4096, 4096);
         public event Action LostFocus;
 

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

@@ -32,6 +32,7 @@ namespace Avalonia.DesignerSupport.Remote
         public Point Position { get; set; }
         public Action<Point> PositionChanged { get; set; }
         public WindowState WindowState { get; set; }
+        public Action<WindowState> WindowStateChanged { get; set; }
         public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
         public void Dispose()
         {

+ 1 - 1
src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs

@@ -241,7 +241,7 @@ namespace Avalonia.Gtk3
             return true;
         }
 
-        void ConnectEvent(string name, Native.D.signal_onevent handler) 
+        protected void ConnectEvent(string name, Native.D.signal_onevent handler) 
             => Disposables.Add(Signal.Connect<Native.D.signal_onevent>(GtkWidget, name, handler));
         void Connect<T>(string name, T handler) => Disposables.Add(Signal.Connect(GtkWidget, name, handler));
 

+ 21 - 3
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@@ -1,18 +1,34 @@
 using System;
-using System.Linq.Expressions;
 using Avalonia.Controls;
 using Avalonia.Gtk3.Interop;
 using Avalonia.Platform;
-using System.Runtime.InteropServices;
 
 namespace Avalonia.Gtk3
 {
     class WindowImpl : WindowBaseImpl, IWindowImpl
     {
+        private WindowState _lastWindowState;
+
         public WindowImpl() : base(Native.GtkWindowNew(GtkWindowType.TopLevel))
         {
         }
 
+        protected unsafe override bool OnStateChanged(IntPtr w, IntPtr pev, IntPtr userData)
+        {
+            var windowStateEvent = (GdkEventWindowState*)pev;
+            var newWindowState = windowStateEvent->new_window_state;
+            var windowState = newWindowState.HasFlag(GdkWindowState.Iconified) ? WindowState.Minimized
+                : (newWindowState.HasFlag(GdkWindowState.Maximized) ? WindowState.Maximized : WindowState.Normal);
+
+            if (windowState != _lastWindowState)
+            {
+                _lastWindowState = windowState;
+                WindowStateChanged?.Invoke(windowState);
+            }
+
+            return base.OnStateChanged(w, pev, userData);
+        }
+
         public void SetTitle(string title)
         {
             using (var t = new Utf8Buffer(title))
@@ -43,7 +59,9 @@ namespace Avalonia.Gtk3
                 }
             }
         }
-        
+
+        public Action<WindowState> WindowStateChanged { get; set; }
+
         public IDisposable ShowDialog()
         {
             Native.GtkWindowSetModal(GtkWidget, true);

+ 16 - 0
src/OSX/Avalonia.MonoMac/WindowImpl.cs

@@ -12,10 +12,24 @@ namespace Avalonia.MonoMac
         public bool IsResizable = true;
         public CGRect? UndecoratedLastUnmaximizedFrame;
 
+        private WindowState _lastWindowState;
+
         public WindowImpl()
         {
             UpdateStyle();
             Window.SetCanBecomeKeyAndMain();
+            
+            Window.DidResize += delegate
+            {
+                var windowState = Window.IsMiniaturized ? WindowState.Minimized
+                    : (IsZoomed ? WindowState.Maximized : WindowState.Normal);
+
+                if (windowState != _lastWindowState)
+                {
+                    _lastWindowState = windowState;
+                    WindowStateChanged?.Invoke(windowState);
+                }
+            };
         }
 
         public WindowState WindowState
@@ -49,6 +63,8 @@ namespace Avalonia.MonoMac
             }
         }
 
+        public Action<WindowState> WindowStateChanged { get; set; }
+
         bool IsZoomed => IsDecorated ? Window.IsZoomed : UndecoratedIsMaximized;
 
         public bool UndecoratedIsMaximized => Window.Frame == Window.Screen.VisibleFrame;

+ 17 - 2
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -34,6 +34,7 @@ namespace Avalonia.Win32
         private bool _resizable = true;
         private double _scaling = 1;
         private WindowState _showWindowState;
+        private WindowState _lastWindowState;
         private FramebufferManager _framebuffer;
         private OleDropTarget _dropTarget;
         private Size _minSize;
@@ -77,6 +78,8 @@ namespace Avalonia.Win32
 
         public Action<Point> PositionChanged { get; set; }
 
+        public Action<WindowState> WindowStateChanged { get; set; }
+
         public Thickness BorderThickness
         {
             get
@@ -617,14 +620,25 @@ namespace Avalonia.Win32
                     return IntPtr.Zero;
 
                 case UnmanagedMethods.WindowsMessage.WM_SIZE:
+                    var size = (UnmanagedMethods.SizeCommand)wParam;
+
                     if (Resized != null &&
-                        (wParam == (IntPtr)UnmanagedMethods.SizeCommand.Restored ||
-                         wParam == (IntPtr)UnmanagedMethods.SizeCommand.Maximized))
+                        (size == UnmanagedMethods.SizeCommand.Restored ||
+                         size == UnmanagedMethods.SizeCommand.Maximized))
                     {
                         var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16);
                         Resized(clientSize / Scaling);
                     }
 
+                    var windowState = size == SizeCommand.Maximized ? WindowState.Maximized
+                        : (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal);
+
+                    if (windowState != _lastWindowState)
+                    {
+                        _lastWindowState = windowState;
+                        WindowStateChanged?.Invoke(windowState);
+                    }
+
                     return IntPtr.Zero;
 
                 case UnmanagedMethods.WindowsMessage.WM_MOVE:
@@ -654,6 +668,7 @@ namespace Avalonia.Win32
                     (Screen as ScreenImpl)?.InvalidateScreensCache();
                     return IntPtr.Zero;
             }
+
 #if USE_MANAGED_DRAG
 
             if (_managedDrag.PreprocessInputEvent(ref e))