Browse Source

Merge pull request #9221 from AvaloniaUI/fixes/8869-show-windowstate

Fix setting WindowState before showing Window.
pull/9460/head
Max Katz 4 years ago
committed by GitHub
parent
commit
fc6645e229
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      samples/IntegrationTestApp/MainWindow.axaml
  2. 2
      samples/IntegrationTestApp/MainWindow.axaml.cs
  3. 2
      samples/IntegrationTestApp/ShowWindowTest.axaml
  4. 10
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  5. 11
      src/Windows/Avalonia.Win32/WindowImpl.cs
  6. 17
      tests/Avalonia.IntegrationTests.Appium/ElementExtensions.cs
  7. 99
      tests/Avalonia.IntegrationTests.Appium/WindowTests.cs

6
samples/IntegrationTestApp/MainWindow.axaml

@ -128,6 +128,12 @@
<ComboBoxItem>CenterScreen</ComboBoxItem> <ComboBoxItem>CenterScreen</ComboBoxItem>
<ComboBoxItem>CenterOwner</ComboBoxItem> <ComboBoxItem>CenterOwner</ComboBoxItem>
</ComboBox> </ComboBox>
<ComboBox Name="ShowWindowState" SelectedIndex="0">
<ComboBoxItem>Normal</ComboBoxItem>
<ComboBoxItem>Minimized</ComboBoxItem>
<ComboBoxItem>Maximized</ComboBoxItem>
<ComboBoxItem>FullScreen</ComboBoxItem>
</ComboBox>
<Button Name="ShowWindow">Show Window</Button> <Button Name="ShowWindow">Show Window</Button>
<Button Name="SendToBack">Send to Back</Button> <Button Name="SendToBack">Send to Back</Button>
<Button Name="ExitFullscreen">Exit Fullscreen</Button> <Button Name="ExitFullscreen">Exit Fullscreen</Button>

2
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -59,6 +59,7 @@ namespace IntegrationTestApp
var sizeTextBox = this.GetControl<TextBox>("ShowWindowSize"); var sizeTextBox = this.GetControl<TextBox>("ShowWindowSize");
var modeComboBox = this.GetControl<ComboBox>("ShowWindowMode"); var modeComboBox = this.GetControl<ComboBox>("ShowWindowMode");
var locationComboBox = this.GetControl<ComboBox>("ShowWindowLocation"); var locationComboBox = this.GetControl<ComboBox>("ShowWindowLocation");
var stateComboBox = this.GetControl<ComboBox>("ShowWindowState");
var size = !string.IsNullOrWhiteSpace(sizeTextBox.Text) ? Size.Parse(sizeTextBox.Text) : (Size?)null; var size = !string.IsNullOrWhiteSpace(sizeTextBox.Text) ? Size.Parse(sizeTextBox.Text) : (Size?)null;
var owner = (Window)this.GetVisualRoot()!; var owner = (Window)this.GetVisualRoot()!;
@ -85,6 +86,7 @@ namespace IntegrationTestApp
} }
sizeTextBox.Text = string.Empty; sizeTextBox.Text = string.Empty;
window.WindowState = (WindowState)stateComboBox.SelectedIndex;
switch (modeComboBox.SelectedIndex) switch (modeComboBox.SelectedIndex)
{ {

2
samples/IntegrationTestApp/ShowWindowTest.axaml

@ -30,7 +30,7 @@
<ComboBoxItem>Normal</ComboBoxItem> <ComboBoxItem>Normal</ComboBoxItem>
<ComboBoxItem>Minimized</ComboBoxItem> <ComboBoxItem>Minimized</ComboBoxItem>
<ComboBoxItem>Maximized</ComboBoxItem> <ComboBoxItem>Maximized</ComboBoxItem>
<ComboBoxItem>Fullscreen</ComboBoxItem> <ComboBoxItem>FullScreen</ComboBoxItem>
</ComboBox> </ComboBox>
<Label Grid.Column="0" Grid.Row="8">Order (mac)</Label> <Label Grid.Column="0" Grid.Row="8">Order (mac)</Label>

10
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -588,9 +588,13 @@ namespace Avalonia.Win32
Resized(clientSize / RenderScaling, _resizeReason); Resized(clientSize / RenderScaling, _resizeReason);
} }
var windowState = size == SizeCommand.Maximized ? var windowState = size switch
WindowState.Maximized : {
(size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal); SizeCommand.Maximized => WindowState.Maximized,
SizeCommand.Minimized => WindowState.Minimized,
_ when _isFullScreenActive => WindowState.FullScreen,
_ => WindowState.Normal,
};
if (windowState != _lastWindowState) if (windowState != _lastWindowState)
{ {

11
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -269,6 +269,11 @@ namespace Avalonia.Win32
{ {
get get
{ {
if (!IsWindowVisible(_hwnd))
{
return _showWindowState;
}
if (_isFullScreenActive) if (_isFullScreenActive)
{ {
return WindowState.FullScreen; return WindowState.FullScreen;
@ -562,6 +567,9 @@ namespace Avalonia.Win32
public void Resize(Size value, PlatformResizeReason reason) public void Resize(Size value, PlatformResizeReason reason)
{ {
if (WindowState != WindowState.Normal)
return;
int requestedClientWidth = (int)(value.Width * RenderScaling); int requestedClientWidth = (int)(value.Width * RenderScaling);
int requestedClientHeight = (int)(value.Height * RenderScaling); int requestedClientHeight = (int)(value.Height * RenderScaling);
@ -902,11 +910,10 @@ namespace Avalonia.Win32
var window_rect = monitor_info.rcMonitor.ToPixelRect(); var window_rect = monitor_info.rcMonitor.ToPixelRect();
_isFullScreenActive = true;
SetWindowPos(_hwnd, IntPtr.Zero, window_rect.X, window_rect.Y, SetWindowPos(_hwnd, IntPtr.Zero, window_rect.X, window_rect.Y,
window_rect.Width, window_rect.Height, window_rect.Width, window_rect.Height,
SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED); SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED);
_isFullScreenActive = true;
} }
else else
{ {

17
tests/Avalonia.IntegrationTests.Appium/ElementExtensions.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using OpenQA.Selenium; using OpenQA.Selenium;
using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Interactions; using OpenQA.Selenium.Interactions;
@ -110,24 +111,30 @@ namespace Avalonia.IntegrationTests.Appium
{ {
var oldWindows = session.FindElements(By.XPath("/XCUIElementTypeApplication/XCUIElementTypeWindow")); var oldWindows = session.FindElements(By.XPath("/XCUIElementTypeApplication/XCUIElementTypeWindow"));
var oldWindowTitles = oldWindows.ToDictionary(x => x.Text); var oldWindowTitles = oldWindows.ToDictionary(x => x.Text);
element.Click(); element.Click();
// Wait for animations to run.
Thread.Sleep(1000);
var newWindows = session.FindElements(By.XPath("/XCUIElementTypeApplication/XCUIElementTypeWindow")); var newWindows = session.FindElements(By.XPath("/XCUIElementTypeApplication/XCUIElementTypeWindow"));
var newWindowTitles = newWindows.ToDictionary(x => x.Text); var newWindowTitles = newWindows.ToDictionary(x => x.Text);
var newWindowTitle = Assert.Single(newWindowTitles.Keys.Except(oldWindowTitles.Keys)); var newWindowTitle = Assert.Single(newWindowTitles.Keys.Except(oldWindowTitles.Keys));
var newWindow = (AppiumWebElement)newWindowTitles[newWindowTitle];
return Disposable.Create(() => return Disposable.Create(() =>
{ {
// TODO: We should be able to use Cmd+W here but Avalonia apps don't seem to have this shortcut // TODO: We should be able to use Cmd+W here but Avalonia apps don't seem to have this shortcut
// set up by default. // set up by default.
var (close, _, _) = newWindow.GetChromeButtons(); var windows = session.FindElements(By.XPath("/XCUIElementTypeApplication/XCUIElementTypeWindow"));
var text = windows.Select(x => x.Text).ToList();
var newWindow = session.FindElements(By.XPath("/XCUIElementTypeApplication/XCUIElementTypeWindow"))
.First(x => x.Text == newWindowTitle);
var (close, _, _) = ((AppiumWebElement)newWindow).GetChromeButtons();
close!.Click(); close!.Click();
}); });
} }
} }
public static void SendClick(this AppiumWebElement element) public static void SendClick(this AppiumWebElement element)
{ {
// The Click() method seems to correspond to accessibilityPerformPress on macOS but certain controls // The Click() method seems to correspond to accessibilityPerformPress on macOS but certain controls

99
tests/Avalonia.IntegrationTests.Appium/WindowTests.cs

@ -57,7 +57,53 @@ namespace Avalonia.IntegrationTests.Appium
} }
} }
} }
[Theory]
[MemberData(nameof(WindowStateData))]
public void WindowState(Size? size, ShowWindowMode mode, WindowState state)
{
using var window = OpenWindow(size, mode, state: state);
try
{
var info = GetWindowInfo();
Assert.Equal(state, info.WindowState);
switch (state)
{
case Controls.WindowState.Normal:
Assert.True(info.FrameSize.Width * info.Scaling < info.ScreenRect.Size.Width);
Assert.True(info.FrameSize.Height * info.Scaling < info.ScreenRect.Size.Height);
break;
case Controls.WindowState.Maximized:
case Controls.WindowState.FullScreen:
Assert.True(info.FrameSize.Width * info.Scaling >= info.ScreenRect.Size.Width);
Assert.True(info.FrameSize.Height * info.Scaling >= info.ScreenRect.Size.Height);
break;
}
}
finally
{
if (state == Controls.WindowState.FullScreen)
{
try
{
_session.FindElementByAccessibilityId("WindowState").SendClick();
_session.FindElementByName("Normal").SendClick();
// Wait for animations to run.
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
Thread.Sleep(1000);
}
catch
{
/* Ignore errors in cleanup */
}
}
}
}
[PlatformFact(TestPlatforms.Windows)] [PlatformFact(TestPlatforms.Windows)]
public void OnWindows_Docked_Windows_Retain_Size_Position_When_Restored() public void OnWindows_Docked_Windows_Retain_Size_Position_When_Restored()
{ {
@ -100,7 +146,7 @@ namespace Avalonia.IntegrationTests.Appium
[InlineData(ShowWindowMode.NonOwned)] [InlineData(ShowWindowMode.NonOwned)]
[InlineData(ShowWindowMode.Owned)] [InlineData(ShowWindowMode.Owned)]
[InlineData(ShowWindowMode.Modal)] [InlineData(ShowWindowMode.Modal)]
public void WindowState(ShowWindowMode mode) public void ShowMode(ShowWindowMode mode)
{ {
using var window = OpenWindow(null, mode, WindowStartupLocation.Manual); using var window = OpenWindow(null, mode, WindowStartupLocation.Manual);
var windowState = _session.FindElementByAccessibilityId("WindowState"); var windowState = _session.FindElementByAccessibilityId("WindowState");
@ -123,8 +169,8 @@ namespace Avalonia.IntegrationTests.Appium
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || mode == ShowWindowMode.NonOwned) if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || mode == ShowWindowMode.NonOwned)
{ {
windowState.Click(); windowState.Click();
_session.FindElementByName("Fullscreen").SendClick(); _session.FindElementByName("FullScreen").SendClick();
Assert.Equal("Fullscreen", windowState.GetComboBoxValue()); Assert.Equal("FullScreen", windowState.GetComboBoxValue());
current = GetWindowInfo(); current = GetWindowInfo();
var clientSize = PixelSize.FromSize(current.ClientSize, current.Scaling); var clientSize = PixelSize.FromSize(current.ClientSize, current.Scaling);
@ -163,6 +209,35 @@ namespace Avalonia.IntegrationTests.Appium
return data; return data;
} }
public static TheoryData<Size?, ShowWindowMode, WindowState> WindowStateData()
{
var sizes = new Size?[] { null, new Size(400, 300) };
var data = new TheoryData<Size?, ShowWindowMode, WindowState>();
foreach (var size in sizes)
{
foreach (var mode in Enum.GetValues<ShowWindowMode>())
{
foreach (var state in Enum.GetValues<WindowState>())
{
// Not sure how to handle testing minimized windows currently.
if (state == Controls.WindowState.Minimized)
continue;
// Child/Modal windows cannot be fullscreen on macOS.
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) &&
state == Controls.WindowState.FullScreen &&
mode != ShowWindowMode.NonOwned)
continue;
data.Add(size, mode, state);
}
}
}
return data;
}
private static void AssertCloseEnough(PixelPoint expected, PixelPoint actual) private static void AssertCloseEnough(PixelPoint expected, PixelPoint actual)
{ {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@ -189,11 +264,16 @@ namespace Avalonia.IntegrationTests.Appium
} }
} }
private IDisposable OpenWindow(Size? size, ShowWindowMode mode, WindowStartupLocation location) private IDisposable OpenWindow(
Size? size,
ShowWindowMode mode,
WindowStartupLocation location = WindowStartupLocation.Manual,
WindowState state = Controls.WindowState.Normal)
{ {
var sizeTextBox = _session.FindElementByAccessibilityId("ShowWindowSize"); var sizeTextBox = _session.FindElementByAccessibilityId("ShowWindowSize");
var modeComboBox = _session.FindElementByAccessibilityId("ShowWindowMode"); var modeComboBox = _session.FindElementByAccessibilityId("ShowWindowMode");
var locationComboBox = _session.FindElementByAccessibilityId("ShowWindowLocation"); var locationComboBox = _session.FindElementByAccessibilityId("ShowWindowLocation");
var stateComboBox = _session.FindElementByAccessibilityId("ShowWindowState");
var showButton = _session.FindElementByAccessibilityId("ShowWindow"); var showButton = _session.FindElementByAccessibilityId("ShowWindow");
if (size.HasValue) if (size.HasValue)
@ -205,6 +285,9 @@ namespace Avalonia.IntegrationTests.Appium
locationComboBox.Click(); locationComboBox.Click();
_session.FindElementByName(location.ToString()).SendClick(); _session.FindElementByName(location.ToString()).SendClick();
stateComboBox.Click();
_session.FindElementByName(state.ToString()).SendClick();
return showButton.OpenWindowWithClick(); return showButton.OpenWindowWithClick();
} }
@ -228,7 +311,8 @@ namespace Avalonia.IntegrationTests.Appium
PixelPoint.Parse(_session.FindElementByAccessibilityId("Position").Text), PixelPoint.Parse(_session.FindElementByAccessibilityId("Position").Text),
ReadOwnerRect(), ReadOwnerRect(),
PixelRect.Parse(_session.FindElementByAccessibilityId("ScreenRect").Text), PixelRect.Parse(_session.FindElementByAccessibilityId("ScreenRect").Text),
double.Parse(_session.FindElementByAccessibilityId("Scaling").Text)); double.Parse(_session.FindElementByAccessibilityId("Scaling").Text),
Enum.Parse<WindowState>(_session.FindElementByAccessibilityId("WindowState").Text));
} }
catch (OpenQA.Selenium.NoSuchElementException) when (retry++ < 3) catch (OpenQA.Selenium.NoSuchElementException) when (retry++ < 3)
{ {
@ -252,6 +336,7 @@ namespace Avalonia.IntegrationTests.Appium
PixelPoint Position, PixelPoint Position,
PixelRect? OwnerRect, PixelRect? OwnerRect,
PixelRect ScreenRect, PixelRect ScreenRect,
double Scaling); double Scaling,
WindowState WindowState);
} }
} }

Loading…
Cancel
Save