From 3c8814269466b0665d629128511d14d3d396f8b9 Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Sat, 24 Jan 2026 09:41:04 +0000 Subject: [PATCH] Make Screen abstract (#20529) --- api/Avalonia.nupkg.xml | 108 ++++++++++++++++++ src/Avalonia.Controls/Platform/Screen.cs | 29 +---- .../Input/PointerTestsBase.cs | 4 +- .../ContextMenuTests.cs | 2 +- .../DesktopStyleApplicationLifetimeTests.cs | 4 +- .../MenuItemTests.cs | 2 +- .../WindowTests.cs | 28 ++--- tests/Avalonia.LeakTests/ControlTests.cs | 4 +- tests/Avalonia.UnitTests/MockScreen.cs | 21 ++++ .../MockWindowingPlatform.cs | 2 +- 10 files changed, 155 insertions(+), 49 deletions(-) create mode 100644 tests/Avalonia.UnitTests/MockScreen.cs diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml index 5b4d58be5b..ea0bf4b88c 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -175,6 +175,48 @@ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Platform.Screen.#ctor(System.Double,Avalonia.PixelRect,Avalonia.PixelRect,System.Boolean) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_Bounds(Avalonia.PixelRect) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_CurrentOrientation(Avalonia.Platform.ScreenOrientation) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_DisplayName(System.String) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_IsPrimary(System.Boolean) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_Scaling(System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_WorkingArea(Avalonia.PixelRect) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0002 F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache @@ -331,6 +373,48 @@ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Platform.Screen.#ctor(System.Double,Avalonia.PixelRect,Avalonia.PixelRect,System.Boolean) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_Bounds(Avalonia.PixelRect) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_CurrentOrientation(Avalonia.Platform.ScreenOrientation) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_DisplayName(System.String) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_IsPrimary(System.Boolean) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_Scaling(System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Platform.Screen.set_WorkingArea(Avalonia.PixelRect) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0002 M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType) @@ -601,6 +685,18 @@ baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + + CP0009 + T:Avalonia.Platform.Screen + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0009 + T:Avalonia.Platform.Screen + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0012 M:Avalonia.Media.Fonts.FontCollectionBase.get_Count @@ -631,6 +727,12 @@ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0012 + M:Avalonia.Platform.Screen.Equals(Avalonia.Platform.Screen) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0012 M:Avalonia.Media.Fonts.FontCollectionBase.get_Count @@ -691,6 +793,12 @@ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0012 + M:Avalonia.Platform.Screen.Equals(Avalonia.Platform.Screen) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0012 M:Avalonia.Media.Fonts.FontCollectionBase.get_Count diff --git a/src/Avalonia.Controls/Platform/Screen.cs b/src/Avalonia.Controls/Platform/Screen.cs index 4622fee005..c3b62860c7 100644 --- a/src/Avalonia.Controls/Platform/Screen.cs +++ b/src/Avalonia.Controls/Platform/Screen.cs @@ -1,8 +1,5 @@ using System; using System.ComponentModel; -using System.Runtime.CompilerServices; -using Avalonia.Diagnostics; -using Avalonia.Metadata; using Avalonia.Utilities; namespace Avalonia.Platform @@ -45,7 +42,7 @@ namespace Avalonia.Platform /// /// Represents a single display screen. /// - public class Screen : IEquatable + public abstract class Screen : IEquatable { /// /// Gets the device name associated with a display. @@ -96,22 +93,6 @@ namespace Avalonia.Platform [Obsolete("Use the IsPrimary property instead.", true), EditorBrowsable(EditorBrowsableState.Never)] public bool Primary => IsPrimary; - /// - /// Initializes a new instance of the class. - /// - /// The scaling factor applied to the screen by the operating system. - /// The overall pixel-size of the screen. - /// The actual working-area pixel-size of the screen. - /// Whether the screen is the primary one. - [Unstable(ObsoletionMessages.MayBeRemovedInAvalonia12)] - public Screen(double scaling, PixelRect bounds, PixelRect workingArea, bool isPrimary) - { - Scaling = scaling; - Bounds = bounds; - WorkingArea = workingArea; - IsPrimary = isPrimary; - } - private protected Screen() { } /// @@ -123,19 +104,15 @@ namespace Avalonia.Platform /// public virtual IPlatformHandle? TryGetPlatformHandle() => null; - // TODO12: make abstract /// - public override int GetHashCode() - => RuntimeHelpers.GetHashCode(this); + public abstract override int GetHashCode(); /// public override bool Equals(object? obj) => obj is Screen other && Equals(other); - // TODO12: make abstract /// - public virtual bool Equals(Screen? other) - => ReferenceEquals(this, other); + public abstract bool Equals(Screen? other); public static bool operator ==(Screen? left, Screen? right) { diff --git a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs index 02c67c5896..a12e5015fd 100644 --- a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs +++ b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs @@ -54,9 +54,9 @@ public abstract class PointerTestsBase : ScopedTestBase impl.Setup(r => r.PointToScreen(It.IsAny())).Returns(p => new PixelPoint((int)p.X, (int)p.Y)); impl.Setup(r => r.PointToClient(It.IsAny())).Returns(p => new Point(p.X, p.Y)); - var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); + var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); var screens = new Mock(); - screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object); + screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1); impl.Setup(x => x.TryGetFeature(It.Is(t => t == typeof(IScreenImpl)))).Returns(screens.Object); return impl; diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs index dcfd7d8ab2..51ed2296a3 100644 --- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs @@ -666,7 +666,7 @@ namespace Avalonia.Controls.UnitTests var screen = new PixelRect(new PixelPoint(), new PixelSize(100, 100)); var screenImpl = new Mock(); screenImpl.Setup(x => x.ScreenCount).Returns(1); - screenImpl.Setup(X => X.AllScreens).Returns( new[] { new Screen(1, screen, screen, true) }); + screenImpl.Setup(X => X.AllScreens).Returns( new[] { new MockScreen(1, screen, screen, true) }); var windowImpl = MockWindowingPlatform.CreateWindowMock(); _popupImpl = MockWindowingPlatform.CreatePopupMock(windowImpl.Object); diff --git a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs index bae1f91319..aa213d996c 100644 --- a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs @@ -300,9 +300,9 @@ namespace Avalonia.Controls.UnitTests windowImpl.Setup(x => x.DesktopScaling).Returns(1); windowImpl.Setup(x => x.RenderScaling).Returns(1); - var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); + var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); var screens = new Mock(); - screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object); + screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1); windowImpl.Setup(x => x.TryGetFeature(It.Is(t => t == typeof(IScreenImpl)))).Returns(screens.Object); var services = TestServices.StyledWindow.With( diff --git a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs index 35bf427bc1..c143f8db12 100644 --- a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs +++ b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs @@ -848,7 +848,7 @@ namespace Avalonia.Controls.UnitTests var screen = new PixelRect(new PixelPoint(), new PixelSize(100, 100)); var screenImpl = new Mock(); screenImpl.Setup(x => x.ScreenCount).Returns(1); - screenImpl.Setup(X => X.AllScreens).Returns(new[] { new Screen(1, screen, screen, true) }); + screenImpl.Setup(X => X.AllScreens).Returns(new[] { new MockScreen(1, screen, screen, true) }); var windowImpl = MockWindowingPlatform.CreateWindowMock(); _popupImpl = MockWindowingPlatform.CreatePopupMock(windowImpl.Object); diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 2ec0b7f80d..24b17c46f7 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -518,11 +518,11 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Window_Should_Not_Be_Centered_When_WindowStartupLocation_Is_CenterScreen_And_Window_Is_Hidden_And_Shown() { - var screen1 = new Mock(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true); + var screen1 = new MockScreen(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true); var screens = new Mock(); - screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object }); - screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1.Object); + screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1 }); + screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1); var windowImpl = MockWindowingPlatform.CreateWindowMock(); @@ -553,12 +553,12 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Window_Should_Be_Centered_When_WindowStartupLocation_Is_CenterScreen() { - var screen1 = new Mock(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true); - var screen2 = new Mock(1.0, new PixelRect(new PixelSize(1366, 768)), new PixelRect(new PixelSize(1366, 728)), false); + var screen1 = new MockScreen(1.0, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 1040)), true); + var screen2 = new MockScreen(1.0, new PixelRect(new PixelSize(1366, 768)), new PixelRect(new PixelSize(1366, 728)), false); var screens = new Mock(); - screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object, screen2.Object }); - screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1.Object); + screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1, screen2 }); + screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1); var windowImpl = MockWindowingPlatform.CreateWindowMock(); @@ -576,8 +576,8 @@ namespace Avalonia.Controls.UnitTests window.Show(); var expectedPosition = new PixelPoint( - (int)(screen1.Object.WorkingArea.Size.Width / 2 - window.ClientSize.Width / 2), - (int)(screen1.Object.WorkingArea.Size.Height / 2 - window.ClientSize.Height / 2)); + (int)(screen1.WorkingArea.Size.Width / 2 - window.ClientSize.Width / 2), + (int)(screen1.WorkingArea.Size.Height / 2 - window.ClientSize.Height / 2)); Assert.Equal(window.Position, expectedPosition); } @@ -586,10 +586,10 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Window_Should_Be_Sized_To_MinSize_If_InitialSize_Less_Than_MinSize() { - var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); + var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); var screens = new Mock(); - screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1.Object }); - screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1.Object); + screens.Setup(x => x.AllScreens).Returns(new Screen[] { screen1 }); + screens.Setup(x => x.ScreenFromPoint(It.IsAny())).Returns(screen1); var windowImpl = MockWindowingPlatform.CreateWindowMock(400, 300); windowImpl.Setup(x => x.DesktopScaling).Returns(1.75); @@ -1146,9 +1146,9 @@ namespace Avalonia.Controls.UnitTests private static Mock CreateImpl() { - var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); + var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); var screens = new Mock(); - screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object); + screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1); var windowImpl = new Mock(); windowImpl.Setup(r => r.Compositor).Returns(RendererMocks.CreateDummyCompositor()); diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 0ff811ff22..11197888a5 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -402,9 +402,9 @@ namespace Avalonia.LeakTests { using (Start()) { - var screen1 = new Mock(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); + var screen1 = new MockScreen(1.75, new PixelRect(new PixelSize(1920, 1080)), new PixelRect(new PixelSize(1920, 966)), true); var screens = new Mock(); - screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1.Object); + screens.Setup(x => x.ScreenFromWindow(It.IsAny())).Returns(screen1); var impl = new Mock(); impl.Setup(r => r.TryGetFeature(It.IsAny())).Returns((object?)null); diff --git a/tests/Avalonia.UnitTests/MockScreen.cs b/tests/Avalonia.UnitTests/MockScreen.cs new file mode 100644 index 0000000000..adf6ebf24b --- /dev/null +++ b/tests/Avalonia.UnitTests/MockScreen.cs @@ -0,0 +1,21 @@ +using System.Runtime.CompilerServices; +using Avalonia.Platform; + +namespace Avalonia.UnitTests; + +internal class MockScreen : Screen +{ + public MockScreen(double scaling, PixelRect bounds, PixelRect workingArea, bool isPrimary) + { + Scaling = scaling; + Bounds = bounds; + WorkingArea = workingArea; + IsPrimary = isPrimary; + } + + public override int GetHashCode() + => RuntimeHelpers.GetHashCode(this); + + public override bool Equals(Screen? other) + => ReferenceEquals(this, other); +} diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs index 23b96538fe..9ddcb217ec 100644 --- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs +++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs @@ -126,7 +126,7 @@ namespace Avalonia.UnitTests { var screenImpl = new Mock(); var bounds = new PixelRect(0, 0, (int)s_screenSize.Width, (int)s_screenSize.Height); - var screen = new Screen(96, bounds, bounds, true); + var screen = new MockScreen(96, bounds, bounds, true); screenImpl.Setup(x => x.AllScreens).Returns(new[] { screen }); screenImpl.Setup(x => x.ScreenCount).Returns(1); return screenImpl;