From a7ace8f57bad9dfdb153348d85311d65a0a9af17 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Wed, 15 Dec 2021 14:27:42 +0100 Subject: [PATCH] Add more platform specific screen from X methods. --- src/Avalonia.Controls/Platform/IScreenImpl.cs | 8 +++ src/Avalonia.Controls/Screens.cs | 51 ++++++++++++++----- src/Avalonia.Controls/Window.cs | 2 +- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 15 ++++++ .../HeadlessPlatformStubs.cs | 15 ++++++ src/Avalonia.Native/ScreenImpl.cs | 15 ++++++ src/Avalonia.X11/X11Screens.cs | 15 ++++++ src/Web/Avalonia.Web.Blazor/WinStubs.cs | 15 ++++++ src/Windows/Avalonia.Win32/ScreenImpl.cs | 39 ++++++++++++++ src/Windows/Avalonia.Win32/WinScreen.cs | 6 ++- 10 files changed, 164 insertions(+), 17 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IScreenImpl.cs b/src/Avalonia.Controls/Platform/IScreenImpl.cs index 5bd45057d9..b68391aa52 100644 --- a/src/Avalonia.Controls/Platform/IScreenImpl.cs +++ b/src/Avalonia.Controls/Platform/IScreenImpl.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable enable + namespace Avalonia.Platform { public interface IScreenImpl @@ -7,5 +9,11 @@ namespace Avalonia.Platform int ScreenCount { get; } IReadOnlyList AllScreens { get; } + + Screen? ScreenFromWindow(IWindowBaseImpl window); + + Screen? ScreenFromPoint(PixelPoint point); + + Screen? ScreenFromRect(PixelRect rect); } } diff --git a/src/Avalonia.Controls/Screens.cs b/src/Avalonia.Controls/Screens.cs index 8a0a0fa728..786502361c 100644 --- a/src/Avalonia.Controls/Screens.cs +++ b/src/Avalonia.Controls/Screens.cs @@ -20,30 +20,53 @@ namespace Avalonia.Controls _iScreenImpl = iScreenImpl; } - public Screen ScreenFromBounds(PixelRect bounds){ - - Screen currMaxScreen = null; - double maxAreaSize = 0; - foreach (Screen screen in All) + public Screen ScreenFromBounds(PixelRect bounds) + { + Screen currMaxScreen = _iScreenImpl.ScreenFromRect(bounds); + + if (currMaxScreen == null) { - double left = MathUtilities.Clamp(bounds.X, screen.Bounds.X, screen.Bounds.X + screen.Bounds.Width); - double top = MathUtilities.Clamp(bounds.Y, screen.Bounds.Y, screen.Bounds.Y + screen.Bounds.Height); - double right = MathUtilities.Clamp(bounds.X + bounds.Width, screen.Bounds.X, screen.Bounds.X + screen.Bounds.Width); - double bottom = MathUtilities.Clamp(bounds.Y + bounds.Height, screen.Bounds.Y, screen.Bounds.Y + screen.Bounds.Height); - double area = (right - left) * (bottom - top); - if (area > maxAreaSize) + double maxAreaSize = 0; + foreach (Screen screen in All) { - maxAreaSize = area; - currMaxScreen = screen; + double left = MathUtilities.Clamp(bounds.X, screen.Bounds.X, screen.Bounds.X + screen.Bounds.Width); + double top = MathUtilities.Clamp(bounds.Y, screen.Bounds.Y, screen.Bounds.Y + screen.Bounds.Height); + double right = MathUtilities.Clamp(bounds.X + bounds.Width, screen.Bounds.X, screen.Bounds.X + screen.Bounds.Width); + double bottom = MathUtilities.Clamp(bounds.Y + bounds.Height, screen.Bounds.Y, screen.Bounds.Y + screen.Bounds.Height); + double area = (right - left) * (bottom - top); + if (area > maxAreaSize) + { + maxAreaSize = area; + currMaxScreen = screen; + } } } return currMaxScreen; } + public Screen ScreenFromWindow(IWindowBaseImpl window) + { + var screen = _iScreenImpl.ScreenFromWindow(window); + + if (screen == null && window.Position is { } position) + { + screen = ScreenFromPoint(position); + } + + return screen; + } + public Screen ScreenFromPoint(PixelPoint point) { - return All.FirstOrDefault(x => x.Bounds.Contains(point)); + var screen = _iScreenImpl.ScreenFromPoint(point); + + if (screen == null) + { + screen = All.FirstOrDefault(x => x.Bounds.Contains(point)); + } + + return screen; } public Screen ScreenFromVisual(IVisual visual) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 4c94b725ea..ca325229cc 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -863,7 +863,7 @@ namespace Avalonia.Controls if (WindowStartupLocation == WindowStartupLocation.CenterScreen) { - var screen = Screens.ScreenFromPoint(owner?.Position ?? Position); + var screen = Screens.ScreenFromWindow(owner); if (screen != null) { diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 9dcd4d8e87..b6988a27a6 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -236,5 +236,20 @@ namespace Avalonia.DesignerSupport.Remote public IReadOnlyList AllScreens { get; } = new Screen[] { new Screen(1, new PixelRect(0, 0, 4000, 4000), new PixelRect(0, 0, 4000, 4000), true) }; + + public Screen ScreenFromPoint(PixelPoint point) + { + return null; + } + + public Screen ScreenFromRect(PixelRect rect) + { + return null; + } + + public Screen ScreenFromWindow(IWindowBaseImpl window) + { + return null; + } } } diff --git a/src/Avalonia.Headless/HeadlessPlatformStubs.cs b/src/Avalonia.Headless/HeadlessPlatformStubs.cs index 605659d464..9318ae3d59 100644 --- a/src/Avalonia.Headless/HeadlessPlatformStubs.cs +++ b/src/Avalonia.Headless/HeadlessPlatformStubs.cs @@ -203,5 +203,20 @@ namespace Avalonia.Headless new Screen(1, new PixelRect(0, 0, 1920, 1280), new PixelRect(0, 0, 1920, 1280), true), }; + + public Screen ScreenFromPoint(PixelPoint point) + { + return null; + } + + public Screen ScreenFromRect(PixelRect rect) + { + return null; + } + + public Screen ScreenFromWindow(IWindowBaseImpl window) + { + return null; + } } } diff --git a/src/Avalonia.Native/ScreenImpl.cs b/src/Avalonia.Native/ScreenImpl.cs index 7b4a001486..03f9b438b4 100644 --- a/src/Avalonia.Native/ScreenImpl.cs +++ b/src/Avalonia.Native/ScreenImpl.cs @@ -48,5 +48,20 @@ namespace Avalonia.Native _native?.Dispose(); _native = null; } + + public Screen ScreenFromPoint(PixelPoint point) + { + return null; + } + + public Screen ScreenFromRect(PixelRect rect) + { + return null; + } + + public Screen ScreenFromWindow(IWindowBaseImpl window) + { + return null; + } } } diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index bf5c74e0e5..906f4af64e 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -200,6 +200,21 @@ namespace Avalonia.X11 } + public Screen ScreenFromWindow(IWindowBaseImpl window) + { + return null; + } + + public Screen ScreenFromPoint(PixelPoint point) + { + return null; + } + + public Screen ScreenFromRect(PixelRect rect) + { + return null; + } + public int ScreenCount => _impl.Screens.Length; public IReadOnlyList AllScreens => diff --git a/src/Web/Avalonia.Web.Blazor/WinStubs.cs b/src/Web/Avalonia.Web.Blazor/WinStubs.cs index 7b2bff6bfd..17c1bca138 100644 --- a/src/Web/Avalonia.Web.Blazor/WinStubs.cs +++ b/src/Web/Avalonia.Web.Blazor/WinStubs.cs @@ -55,5 +55,20 @@ namespace Avalonia.Web.Blazor public IReadOnlyList AllScreens { get; } = new[] { new Screen(96, new PixelRect(0, 0, 4000, 4000), new PixelRect(0, 0, 4000, 4000), true) }; + + public Screen? ScreenFromPoint(PixelPoint point) + { + return null; + } + + public Screen? ScreenFromRect(PixelRect rect) + { + return null; + } + + public Screen? ScreenFromWindow(IWindowBaseImpl window) + { + return null; + } } } diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs index 442794f0f0..5942208594 100644 --- a/src/Windows/Avalonia.Win32/ScreenImpl.cs +++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Avalonia.Platform; using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; @@ -70,5 +71,43 @@ namespace Avalonia.Win32 { _allScreens = null; } + + public Screen ScreenFromWindow(IWindowBaseImpl window) + { + var handle = window.Handle.Handle; + + var monitor = MonitorFromWindow(handle, MONITOR.MONITOR_DEFAULTTONEAREST); + + return FindScreenByHandle(monitor); + } + + public Screen ScreenFromPoint(PixelPoint point) + { + var monitor = MonitorFromPoint(new POINT + { + X = point.X, + Y = point.Y + }, MONITOR.MONITOR_DEFAULTTONEAREST); + + return FindScreenByHandle(monitor); + } + + public Screen ScreenFromRect(PixelRect rect) + { + var monitor = MonitorFromRect(new RECT + { + left = rect.TopLeft.X, + top = rect.TopLeft.Y, + right = rect.TopRight.X, + bottom = rect.BottomRight.Y + }, MONITOR.MONITOR_DEFAULTTONEAREST); + + return FindScreenByHandle(monitor); + } + + private Screen FindScreenByHandle(IntPtr handle) + { + return AllScreens.Cast().FirstOrDefault(m => m.Handle == handle); + } } } diff --git a/src/Windows/Avalonia.Win32/WinScreen.cs b/src/Windows/Avalonia.Win32/WinScreen.cs index 0cf9fe31db..f103cc3b66 100644 --- a/src/Windows/Avalonia.Win32/WinScreen.cs +++ b/src/Windows/Avalonia.Win32/WinScreen.cs @@ -9,9 +9,11 @@ namespace Avalonia.Win32 public WinScreen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool primary, IntPtr hMonitor) : base(pixelDensity, bounds, workingArea, primary) { - this._hMonitor = hMonitor; + _hMonitor = hMonitor; } + public IntPtr Handle => _hMonitor; + public override int GetHashCode() { return (int)_hMonitor; @@ -19,7 +21,7 @@ namespace Avalonia.Win32 public override bool Equals(object obj) { - return (obj is WinScreen screen) ? this._hMonitor == screen._hMonitor : base.Equals(obj); + return (obj is WinScreen screen) ? _hMonitor == screen._hMonitor : base.Equals(obj); } } }