From c98b57a5253aaa655cd3367fc6ede0c6281f172a Mon Sep 17 00:00:00 2001 From: MrDaedra Date: Fri, 3 Feb 2017 15:24:08 +0300 Subject: [PATCH 1/5] Moved ShowDialog implementation from platform-specific interface to portable Window class. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 1 + src/Avalonia.Controls/Window.cs | 48 +++++++++++++++---- src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs | 1 + src/Gtk/Avalonia.Gtk/WindowImpl.cs | 1 + src/Gtk/Avalonia.Gtk/WindowImplBase.cs | 1 + src/Windows/Avalonia.Win32/WindowImpl.cs | 5 +- 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 609e9834cb..08899d5c14 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -28,6 +28,7 @@ namespace Avalonia.Platform /// /// An that should be used to close the window. /// + [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] IDisposable ShowDialog(); /// diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 40c52a748d..0a1fb55ced 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -11,6 +11,8 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Styling; using System.Collections.Generic; +using System.Linq; +using System.Reactive.Disposables; namespace Avalonia.Controls { @@ -45,7 +47,7 @@ namespace Avalonia.Controls /// public class Window : TopLevel, IStyleable, IFocusScope, ILayoutRoot, INameScope { - private static IList s_windows = new List(); + private static IList s_windows = new List(); /// /// Retrieves an enumeration of all Windows in the currently running application. @@ -89,7 +91,7 @@ namespace Avalonia.Controls TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue)); HasSystemDecorationsProperty.Changed.AddClassHandler( (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); - + IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); } @@ -180,7 +182,7 @@ namespace Avalonia.Controls Size ILayoutRoot.MaxClientSize => _maxPlatformClientSize; /// - Type IStyleable.StyleKey => typeof(Window); + Type IStyleable.StyleKey => typeof(Window); /// /// Closes the window. @@ -238,7 +240,7 @@ namespace Avalonia.Controls PlatformImpl.Show(); } } - + /// /// Shows the window as a dialog. /// @@ -263,14 +265,14 @@ namespace Avalonia.Controls { s_windows.Add(this); - EnsureInitialized(); - LayoutManager.Instance.ExecuteInitialLayoutPass(this); + EnsureInitialized(); + LayoutManager.Instance.ExecuteInitialLayoutPass(this); using (BeginAutoSizing()) { - var modal = PlatformImpl.ShowDialog(); + var modal = GetModal(); var result = new TaskCompletionSource(); - + Observable.FromEventPattern(this, nameof(Closed)) .Take(1) .Subscribe(_ => @@ -282,6 +284,32 @@ namespace Avalonia.Controls return result.Task; } } + + private IDisposable GetModal() + { + var disabled = s_windows.Where(w => w.IsEnabled && w != this); + Window activated = null; + foreach (var window in disabled) + { + if (window.IsActive) + { + activated = window; + } + + window.IsEnabled = false; + } + + PlatformImpl.Show(); + + return Disposable.Create(() => + { + foreach (var window in disabled) + { + window.IsEnabled = true; + } + activated?.Activate(); + }); + } /// void INameScope.Register(string name, object element) @@ -307,7 +335,7 @@ namespace Avalonia.Controls var sizeToContent = SizeToContent; var size = ClientSize; var desired = base.MeasureOverride(availableSize.Constrain(_maxPlatformClientSize)); - + switch (sizeToContent) { case SizeToContent.Width: @@ -348,7 +376,7 @@ namespace Avalonia.Controls init.BeginInit(); init.EndInit(); } - } + } } } diff --git a/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs b/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs index a5a34cd47b..5ef1788073 100644 --- a/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs +++ b/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs @@ -45,6 +45,7 @@ namespace Avalonia.Gtk { } + [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public override IDisposable ShowDialog() => Disposable.Create(() => { }); public override void SetSystemDecorations(bool enabled) diff --git a/src/Gtk/Avalonia.Gtk/WindowImpl.cs b/src/Gtk/Avalonia.Gtk/WindowImpl.cs index eca7c24136..c82ded1263 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImpl.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImpl.cs @@ -108,6 +108,7 @@ namespace Avalonia.Gtk } } + [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public override IDisposable ShowDialog() { Window.Modal = true; diff --git a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs index db4b5e9dde..97641ed22c 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs @@ -167,6 +167,7 @@ namespace Avalonia.Gtk } public abstract void SetTitle(string title); + [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public abstract IDisposable ShowDialog(); public abstract void SetSystemDecorations(bool enabled); public abstract void SetIcon(IWindowIconImpl icon); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 9680f31973..c3cbb0e449 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -136,7 +136,7 @@ namespace Avalonia.Win32 public WindowState WindowState { get - { + { var placement = default(UnmanagedMethods.WINDOWPLACEMENT); UnmanagedMethods.GetWindowPlacement(_hwnd, ref placement); @@ -175,7 +175,7 @@ namespace Avalonia.Win32 } public IPopupImpl CreatePopup() - { + { return new PopupImpl(); } @@ -332,6 +332,7 @@ namespace Avalonia.Win32 } } + [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public virtual IDisposable ShowDialog() { var disabled = s_instances.Where(x => x != this && x.IsEnabled).ToList(); From adda76bcc08dc78780eecdb4b7f3029eec75004a Mon Sep 17 00:00:00 2001 From: Andrey Alonzov Date: Wed, 8 Feb 2017 20:23:56 +0300 Subject: [PATCH 2/5] Changes according to PR comments. --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 1 - src/Avalonia.Controls/Window.cs | 26 ++++++++--------- src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs | 1 - src/Gtk/Avalonia.Gtk/WindowImpl.cs | 1 - src/Gtk/Avalonia.Gtk/WindowImplBase.cs | 1 - src/Windows/Avalonia.Win32/WindowImpl.cs | 28 ++----------------- 6 files changed, 16 insertions(+), 42 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 08899d5c14..609e9834cb 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -28,7 +28,6 @@ namespace Avalonia.Platform /// /// An that should be used to close the window. /// - [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] IDisposable ShowDialog(); /// diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 0a1fb55ced..94ee3e9415 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -47,7 +47,7 @@ namespace Avalonia.Controls /// public class Window : TopLevel, IStyleable, IFocusScope, ILayoutRoot, INameScope { - private static IList s_windows = new List(); + private static IList s_windows = new List(); /// /// Retrieves an enumeration of all Windows in the currently running application. @@ -91,7 +91,7 @@ namespace Avalonia.Controls TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue)); HasSystemDecorationsProperty.Changed.AddClassHandler( (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); - + IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); } @@ -182,7 +182,7 @@ namespace Avalonia.Controls Size ILayoutRoot.MaxClientSize => _maxPlatformClientSize; /// - Type IStyleable.StyleKey => typeof(Window); + Type IStyleable.StyleKey => typeof(Window); /// /// Closes the window. @@ -240,7 +240,7 @@ namespace Avalonia.Controls PlatformImpl.Show(); } } - + /// /// Shows the window as a dialog. /// @@ -265,14 +265,14 @@ namespace Avalonia.Controls { s_windows.Add(this); - EnsureInitialized(); - LayoutManager.Instance.ExecuteInitialLayoutPass(this); + EnsureInitialized(); + LayoutManager.Instance.ExecuteInitialLayoutPass(this); using (BeginAutoSizing()) { - var modal = GetModal(); + var modal = ShowModal(); var result = new TaskCompletionSource(); - + Observable.FromEventPattern(this, nameof(Closed)) .Take(1) .Subscribe(_ => @@ -284,8 +284,8 @@ namespace Avalonia.Controls return result.Task; } } - - private IDisposable GetModal() + + private IDisposable ShowModal() { var disabled = s_windows.Where(w => w.IsEnabled && w != this); Window activated = null; @@ -299,7 +299,7 @@ namespace Avalonia.Controls window.IsEnabled = false; } - PlatformImpl.Show(); + PlatformImpl.ShowDialog(); return Disposable.Create(() => { @@ -335,7 +335,7 @@ namespace Avalonia.Controls var sizeToContent = SizeToContent; var size = ClientSize; var desired = base.MeasureOverride(availableSize.Constrain(_maxPlatformClientSize)); - + switch (sizeToContent) { case SizeToContent.Width: @@ -376,7 +376,7 @@ namespace Avalonia.Controls init.BeginInit(); init.EndInit(); } - } + } } } diff --git a/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs b/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs index 5ef1788073..a5a34cd47b 100644 --- a/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs +++ b/src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs @@ -45,7 +45,6 @@ namespace Avalonia.Gtk { } - [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public override IDisposable ShowDialog() => Disposable.Create(() => { }); public override void SetSystemDecorations(bool enabled) diff --git a/src/Gtk/Avalonia.Gtk/WindowImpl.cs b/src/Gtk/Avalonia.Gtk/WindowImpl.cs index c82ded1263..eca7c24136 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImpl.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImpl.cs @@ -108,7 +108,6 @@ namespace Avalonia.Gtk } } - [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public override IDisposable ShowDialog() { Window.Modal = true; diff --git a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs index 7310a12289..4d7552aa72 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs @@ -167,7 +167,6 @@ namespace Avalonia.Gtk } public abstract void SetTitle(string title); - [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public abstract IDisposable ShowDialog(); public abstract void SetSystemDecorations(bool enabled); public abstract void SetIcon(IWindowIconImpl icon); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index cb2bc84094..189f27593f 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -137,7 +137,7 @@ namespace Avalonia.Win32 public WindowState WindowState { get - { + { var placement = default(UnmanagedMethods.WINDOWPLACEMENT); UnmanagedMethods.GetWindowPlacement(_hwnd, ref placement); @@ -176,7 +176,7 @@ namespace Avalonia.Win32 } public IPopupImpl CreatePopup() - { + { return new PopupImpl(); } @@ -342,33 +342,11 @@ namespace Avalonia.Win32 } } - [Obsolete("Use Avalonia.Controls.Window.ShowDialog() instead.")] public virtual IDisposable ShowDialog() { - var disabled = s_instances.Where(x => x != this && x.IsEnabled).ToList(); - WindowImpl activated = null; - - foreach (var window in disabled) - { - if (window._isActive) - { - activated = window; - } - - window.IsEnabled = false; - } - Show(); - return Disposable.Create(() => - { - foreach (var window in disabled) - { - window.IsEnabled = true; - } - - activated?.Activate(); - }); + return Disposable.Empty; } public void SetCursor(IPlatformHandle cursor) From 10b6f9ed121d4112a1dde1ebfd913e8b2d948f20 Mon Sep 17 00:00:00 2001 From: MrDaedra Date: Thu, 16 Feb 2017 10:27:17 +0300 Subject: [PATCH 3/5] Reimplemented ShowDialog to use returned disposable --- src/Avalonia.Controls/Window.cs | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 94ee3e9415..4a1f6d2c5e 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -12,7 +12,6 @@ using Avalonia.Platform; using Avalonia.Styling; using System.Collections.Generic; using System.Linq; -using System.Reactive.Disposables; namespace Avalonia.Controls { @@ -270,7 +269,11 @@ namespace Avalonia.Controls using (BeginAutoSizing()) { - var modal = ShowModal(); + var affectedWindows = s_windows.Where(w => w.IsEnabled && w != this); + Window activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault(); + SetIsEnabled(affectedWindows, false); + + var modal = PlatformImpl.ShowDialog(); var result = new TaskCompletionSource(); Observable.FromEventPattern(this, nameof(Closed)) @@ -278,6 +281,8 @@ namespace Avalonia.Controls .Subscribe(_ => { modal.Dispose(); + SetIsEnabled(affectedWindows, true); + activated?.Activate(); result.SetResult((TResult)_dialogResult); }); @@ -285,30 +290,12 @@ namespace Avalonia.Controls } } - private IDisposable ShowModal() + void SetIsEnabled(IEnumerable windows, bool isEnabled) { - var disabled = s_windows.Where(w => w.IsEnabled && w != this); - Window activated = null; - foreach (var window in disabled) + foreach (var window in windows) { - if (window.IsActive) - { - activated = window; - } - - window.IsEnabled = false; + window.IsEnabled = isEnabled; } - - PlatformImpl.ShowDialog(); - - return Disposable.Create(() => - { - foreach (var window in disabled) - { - window.IsEnabled = true; - } - activated?.Activate(); - }); } /// From 8e6b6258ed249f75aa6c67c2a70662569523e91a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 18 Mar 2017 13:48:26 +0100 Subject: [PATCH 4/5] Fix re-enabling windows when dialog is closed. --- src/Avalonia.Controls/Window.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 57470aa60e..e66b1beb1e 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -269,8 +269,8 @@ namespace Avalonia.Controls using (BeginAutoSizing()) { - var affectedWindows = s_windows.Where(w => w.IsEnabled && w != this); - Window activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault(); + var affectedWindows = s_windows.Where(w => w.IsEnabled && w != this).ToList(); + var activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault(); SetIsEnabled(affectedWindows, false); var modal = PlatformImpl.ShowDialog(); From 04b35fef629e8d376bbe167fc1b605866ebbb631 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 18 Mar 2017 14:28:27 +0100 Subject: [PATCH 5/5] Removed unused field. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 72e1cea9df..f2d7e0e043 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -33,7 +33,6 @@ namespace Avalonia.Win32 private IntPtr _hwnd; private IInputRoot _owner; private bool _trackingMouse; - private bool _isActive; private bool _decorated = true; private double _scaling = 1; private WindowState _showWindowState; @@ -393,12 +392,10 @@ namespace Avalonia.Win32 { case UnmanagedMethods.WindowActivate.WA_ACTIVE: case UnmanagedMethods.WindowActivate.WA_CLICKACTIVE: - _isActive = true; Activated?.Invoke(); break; case UnmanagedMethods.WindowActivate.WA_INACTIVE: - _isActive = false; Deactivated?.Invoke(); break; }