From ea90f05f83bea42dd47892f76d5de5012ff6afba Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 17 Nov 2020 14:34:44 +0100 Subject: [PATCH] Added Window.ShowActive for win32. --- .../Platform/IWindowBaseImpl.cs | 4 ++-- src/Avalonia.Controls/Window.cs | 20 ++++++++++++++++--- src/Avalonia.Controls/WindowBase.cs | 2 +- .../Remote/PreviewerWindowImpl.cs | 2 +- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 2 +- src/Avalonia.Headless/HeadlessWindowImpl.cs | 7 ++++--- src/Avalonia.X11/X11Window.cs | 2 +- src/Windows/Avalonia.Win32/PopupImpl.cs | 3 ++- src/Windows/Avalonia.Win32/Win32Platform.cs | 2 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 14 +++++++------ .../ContextMenuTests.cs | 16 +++++++-------- .../WindowBaseTests.cs | 2 +- .../MockWindowingPlatform.cs | 2 +- 13 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs index ecaf87d1ed..0d303a6666 100644 --- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs @@ -5,9 +5,9 @@ namespace Avalonia.Platform public interface IWindowBaseImpl : ITopLevelImpl { /// - /// Shows the top level. + /// Shows the window. /// - void Show(); + void Show(bool activate); /// /// Hides the window. diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 54574a7e1c..ab99cfad17 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -129,6 +129,12 @@ namespace Avalonia.Controls public static readonly StyledProperty SystemDecorationsProperty = AvaloniaProperty.Register(nameof(SystemDecorations), SystemDecorations.Full); + /// + /// Defines the property. + /// + public static readonly StyledProperty ShowActivatedProperty = + AvaloniaProperty.Register(nameof(ShowActivated), true); + /// /// Enables or disables the taskbar icon /// @@ -352,13 +358,21 @@ namespace Avalonia.Controls /// /// Sets the system decorations (title bar, border, etc) /// - /// public SystemDecorations SystemDecorations { get { return GetValue(SystemDecorationsProperty); } set { SetValue(SystemDecorationsProperty, value); } } + /// + /// Gets or sets a value that indicates whether a window is activated when first shown. + /// + public bool ShowActivated + { + get { return GetValue(ShowActivatedProperty); } + set { SetValue(ShowActivatedProperty, value); } + } + /// /// Enables or disables the taskbar icon /// @@ -650,7 +664,7 @@ namespace Avalonia.Controls Owner = parent; parent?.AddChild(this, false); - PlatformImpl?.Show(); + PlatformImpl?.Show(ShowActivated); Renderer?.Start(); SetWindowStartupLocation(Owner?.PlatformImpl); } @@ -720,7 +734,7 @@ namespace Avalonia.Controls PlatformImpl?.SetParent(owner.PlatformImpl); Owner = owner; owner.AddChild(this, true); - PlatformImpl?.Show(); + PlatformImpl?.Show(ShowActivated); Renderer?.Start(); diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 1efd6c8c1d..cdcb499e98 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -162,7 +162,7 @@ namespace Avalonia.Controls LayoutManager.ExecuteInitialLayoutPass(); _hasExecutedInitialLayoutPass = true; } - PlatformImpl?.Show(); + PlatformImpl?.Show(true); Renderer?.Start(); OnOpened(EventArgs.Empty); } diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 25c26be91e..787f44887f 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -20,7 +20,7 @@ namespace Avalonia.DesignerSupport.Remote ClientSize = new Size(1, 1); } - public void Show() + public void Show(bool activate) { } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index f377b1bcd1..f6783dc0b7 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -77,7 +77,7 @@ namespace Avalonia.DesignerSupport.Remote { } - public void Show() + public void Show(bool activate) { } diff --git a/src/Avalonia.Headless/HeadlessWindowImpl.cs b/src/Avalonia.Headless/HeadlessWindowImpl.cs index 8f4fa5e304..3a1f3bdaf7 100644 --- a/src/Avalonia.Headless/HeadlessWindowImpl.cs +++ b/src/Avalonia.Headless/HeadlessWindowImpl.cs @@ -75,9 +75,10 @@ namespace Avalonia.Headless public Action Closed { get; set; } public IMouseDevice MouseDevice { get; } - public void Show() + public void Show(bool activate) { - Dispatcher.UIThread.Post(() => Activated?.Invoke(), DispatcherPriority.Input); + if (activate) + Dispatcher.UIThread.Post(() => Activated?.Invoke(), DispatcherPriority.Input); } public void Hide() @@ -148,7 +149,7 @@ namespace Avalonia.Headless public void ShowDialog(IWindowImpl parent) { - Show(); + Show(true); } public void SetSystemDecorations(bool enabled) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 2cd3b973d8..d62e3bed23 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -815,7 +815,7 @@ namespace Avalonia.X11 XSetTransientForHint(_x11.Display, _handle, parent.Handle.Handle); } - public void Show() + public void Show(bool activate) { _wasMappedAtLeastOnce = true; XMapWindow(_x11.Display, _handle); diff --git a/src/Windows/Avalonia.Win32/PopupImpl.cs b/src/Windows/Avalonia.Win32/PopupImpl.cs index 7fb146899b..dd3fd1342c 100644 --- a/src/Windows/Avalonia.Win32/PopupImpl.cs +++ b/src/Windows/Avalonia.Win32/PopupImpl.cs @@ -17,8 +17,9 @@ namespace Avalonia.Win32 [ThreadStatic] private static IntPtr s_parentHandle; - public override void Show() + public override void Show(bool activate) { + // Popups are always shown non-activated. UnmanagedMethods.ShowWindow(Handle.Handle, UnmanagedMethods.ShowWindowCommand.ShowNoActivate); // We need to steal focus if it's held by a child window of our toplevel window diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index 5b16cae26e..af9531400e 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -229,7 +229,7 @@ namespace Avalonia.Win32 public IWindowImpl CreateEmbeddableWindow() { var embedded = new EmbeddedWindowImpl(); - embedded.Show(); + embedded.Show(true); return embedded; } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 715c8fc01d..f594763413 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -240,7 +240,7 @@ namespace Avalonia.Win32 { if (IsWindowVisible(_hwnd)) { - ShowWindow(value); + ShowWindow(value, true); } else { @@ -550,10 +550,11 @@ namespace Avalonia.Win32 UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide); } - public virtual void Show() + public virtual void Show(bool activate) { SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent != null ? _parent._hwnd : IntPtr.Zero); - ShowWindow(_showWindowState); + + ShowWindow(_showWindowState, activate); } public Action GotInputWhenDisabled { get; set; } @@ -891,7 +892,7 @@ namespace Avalonia.Win32 ExtendClientAreaToDecorationsChanged?.Invoke(_isClientAreaExtended); } - private void ShowWindow(WindowState state) + private void ShowWindow(WindowState state, bool activate) { ShowWindowCommand? command; @@ -901,7 +902,7 @@ namespace Avalonia.Win32 { case WindowState.Minimized: newWindowProperties.IsFullScreen = false; - command = ShowWindowCommand.Minimize; + command = activate ? ShowWindowCommand.Minimize : ShowWindowCommand.ShowMinNoActive; break; case WindowState.Maximized: newWindowProperties.IsFullScreen = false; @@ -910,7 +911,8 @@ namespace Avalonia.Win32 case WindowState.Normal: newWindowProperties.IsFullScreen = false; - command = ShowWindowCommand.Restore; + command = IsWindowVisible(_hwnd) ? ShowWindowCommand.Restore : + activate ? ShowWindowCommand.Normal : ShowWindowCommand.ShowNoActivate; break; case WindowState.FullScreen: diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs index c179aef9ac..39a3250686 100644 --- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs @@ -79,7 +79,7 @@ namespace Avalonia.Controls.UnitTests { using (Application()) { - popupImpl.Setup(x => x.Show()).Verifiable(); + popupImpl.Setup(x => x.Show(true)).Verifiable(); popupImpl.Setup(x => x.Hide()).Verifiable(); var sut = new ContextMenu(); @@ -99,7 +99,7 @@ namespace Avalonia.Controls.UnitTests _mouse.Click(target); Assert.False(sut.IsOpen); - popupImpl.Verify(x => x.Show(), Times.Once); + popupImpl.Verify(x => x.Show(true), Times.Once); popupImpl.Verify(x => x.Hide(), Times.Once); } } @@ -109,7 +109,7 @@ namespace Avalonia.Controls.UnitTests { using (Application()) { - popupImpl.Setup(x => x.Show()).Verifiable(); + popupImpl.Setup(x => x.Show(true)).Verifiable(); popupImpl.Setup(x => x.Hide()).Verifiable(); var sut = new ContextMenu(); @@ -130,7 +130,7 @@ namespace Avalonia.Controls.UnitTests Assert.True(sut.IsOpen); popupImpl.Verify(x => x.Hide(), Times.Once); - popupImpl.Verify(x => x.Show(), Times.Exactly(2)); + popupImpl.Verify(x => x.Show(true), Times.Exactly(2)); } } @@ -177,7 +177,7 @@ namespace Avalonia.Controls.UnitTests { using (Application()) { - popupImpl.Setup(x => x.Show()).Verifiable(); + popupImpl.Setup(x => x.Show(true)).Verifiable(); bool eventCalled = false; var sut = new ContextMenu(); @@ -193,7 +193,7 @@ namespace Avalonia.Controls.UnitTests Assert.True(eventCalled); Assert.False(sut.IsOpen); - popupImpl.Verify(x => x.Show(), Times.Never); + popupImpl.Verify(x => x.Show(true), Times.Never); } } @@ -297,7 +297,7 @@ namespace Avalonia.Controls.UnitTests { using (Application()) { - popupImpl.Setup(x => x.Show()).Verifiable(); + popupImpl.Setup(x => x.Show(true)).Verifiable(); popupImpl.Setup(x => x.Hide()).Verifiable(); bool eventCalled = false; @@ -321,7 +321,7 @@ namespace Avalonia.Controls.UnitTests Assert.True(eventCalled); Assert.True(sut.IsOpen); - popupImpl.Verify(x => x.Show(), Times.Once()); + popupImpl.Verify(x => x.Show(true), Times.Once()); popupImpl.Verify(x => x.Hide(), Times.Never); } } diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs index 84f212d1b3..8109b037c5 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs @@ -137,7 +137,7 @@ namespace Avalonia.Controls.UnitTests var target = new TestWindowBase(windowImpl.Object); target.IsVisible = true; - windowImpl.Verify(x => x.Show()); + windowImpl.Verify(x => x.Show(true)); } } diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs index 9ec8ca2d36..8a24a8366f 100644 --- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs +++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs @@ -58,7 +58,7 @@ namespace Avalonia.UnitTests windowImpl.Object.Resized?.Invoke(clientSize); }); - windowImpl.Setup(x => x.Show()).Callback(() => + windowImpl.Setup(x => x.Show(true)).Callback(() => { windowImpl.Object.Activated?.Invoke(); });