committed by
Nikita Tsukanov
28 changed files with 554 additions and 4 deletions
@ -0,0 +1,62 @@ |
|||
using System; |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ScreenPage : UserControl |
|||
{ |
|||
private double _leftMost; |
|||
|
|||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) |
|||
{ |
|||
base.OnAttachedToVisualTree(e); |
|||
Window w = (Window)VisualRoot; |
|||
w.PositionChanged += (sender, args) => InvalidateVisual(); |
|||
} |
|||
|
|||
public override void Render(DrawingContext context) |
|||
{ |
|||
base.Render(context); |
|||
Window w = (Window)VisualRoot; |
|||
Screen[] screens = w.Screens.All; |
|||
|
|||
Pen p = new Pen(Brushes.Black); |
|||
if (screens != null) |
|||
foreach (Screen screen in screens) |
|||
{ |
|||
if (screen.Bounds.X / 10f < _leftMost) |
|||
{ |
|||
_leftMost = screen.Bounds.X / 10f; |
|||
InvalidateVisual(); |
|||
return; |
|||
} |
|||
|
|||
Rect boundsRect = new Rect(screen.Bounds.X / 10f + Math.Abs(_leftMost), screen.Bounds.Y / 10f, screen.Bounds.Width / 10f, |
|||
screen.Bounds.Height / 10f); |
|||
Rect workingAreaRect = new Rect(screen.WorkingArea.X / 10f + Math.Abs(_leftMost), screen.WorkingArea.Y / 10f, screen.WorkingArea.Width / 10f, |
|||
screen.WorkingArea.Height / 10f); |
|||
context.DrawRectangle(p, boundsRect); |
|||
context.DrawRectangle(p, workingAreaRect); |
|||
|
|||
FormattedText text = new FormattedText(); |
|||
text.Text = $"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}"; |
|||
context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height), text); |
|||
|
|||
text.Text = $"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"; |
|||
context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text); |
|||
|
|||
text.Text = $"Primary: {screen.Primary}"; |
|||
context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text); |
|||
|
|||
text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new Rect(w.Position, w.Bounds.Size)))}"; |
|||
context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text); |
|||
} |
|||
|
|||
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10, w.Bounds.Width / 10, w.Bounds.Height / 10)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace Avalonia.Platform |
|||
{ |
|||
public interface IScreenImpl |
|||
{ |
|||
int ScreenCount { get; } |
|||
|
|||
Screen[] AllScreens { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
namespace Avalonia.Platform |
|||
{ |
|||
public class Screen |
|||
{ |
|||
public Rect Bounds { get; } |
|||
|
|||
public Rect WorkingArea { get; } |
|||
|
|||
public bool Primary { get; } |
|||
|
|||
public Screen(Rect bounds, Rect workingArea, bool primary) |
|||
{ |
|||
this.Bounds = bounds; |
|||
this.WorkingArea = workingArea; |
|||
this.Primary = primary; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
using System.Linq; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Utilities; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
public class Screens |
|||
{ |
|||
private readonly IScreenImpl _iScreenImpl; |
|||
|
|||
public int ScreenCount => _iScreenImpl.ScreenCount; |
|||
public Screen[] All => _iScreenImpl?.AllScreens; |
|||
public Screen Primary => All.FirstOrDefault(x => x.Primary); |
|||
|
|||
public Screens(IScreenImpl iScreenImpl) |
|||
{ |
|||
_iScreenImpl = iScreenImpl; |
|||
} |
|||
|
|||
public Screen ScreenFromBounds(Rect bounds){ |
|||
|
|||
Screen currMaxScreen = null; |
|||
double maxAreaSize = 0; |
|||
foreach (Screen screen in All) |
|||
{ |
|||
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 SceenFromPoint(Point point) |
|||
{ |
|||
return All.FirstOrDefault(x=>x.Bounds.Contains(point)); |
|||
} |
|||
|
|||
public Screen ScreenFromVisual(IVisual visual) |
|||
{ |
|||
Point tl = visual.PointToScreen(visual.Bounds.TopLeft); |
|||
Point br = visual.PointToScreen(visual.Bounds.BottomRight); |
|||
return ScreenFromBounds(new Rect(tl,br)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
using System; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Utilities; |
|||
using Gdk; |
|||
using Screen = Avalonia.Platform.Screen; |
|||
using Window = Gtk.Window; |
|||
|
|||
namespace Avalonia.Gtk |
|||
{ |
|||
internal class ScreenImpl : IScreenImpl |
|||
{ |
|||
private Window window; |
|||
|
|||
public int ScreenCount |
|||
{ |
|||
get => window.Display.DefaultScreen.NMonitors; |
|||
} |
|||
public Screen[] AllScreens { |
|||
get |
|||
{ |
|||
Screen[] screens = new Screen[ScreenCount]; |
|||
var screen = window.Display.DefaultScreen; |
|||
|
|||
for (short i = 0; i < screens.Length; i++) |
|||
{ |
|||
Rectangle geometry = screen.GetMonitorGeometry(i); |
|||
Rect geometryRect = new Rect(geometry.X, geometry.Y, geometry.Width, geometry.Height); |
|||
Screen s = new Screen(geometryRect, geometryRect, false); |
|||
screens[i] = s; |
|||
} |
|||
|
|||
return screens; |
|||
} |
|||
} |
|||
|
|||
public ScreenImpl(Window window) |
|||
{ |
|||
this.window = window; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Gtk3 |
|||
{ |
|||
public class GtkScreen : Screen |
|||
{ |
|||
private readonly int _screenId; |
|||
|
|||
public GtkScreen(Rect bounds, Rect workingArea, bool primary, int screenId) : base(bounds, workingArea, primary) |
|||
{ |
|||
this._screenId = screenId; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
return _screenId; |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is GtkScreen screen) ? this._screenId == screen._screenId : base.Equals(obj); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
using System; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Gtk3.Interop; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Utilities; |
|||
|
|||
namespace Avalonia.Gtk3 |
|||
{ |
|||
internal class ScreenImpl : IScreenImpl |
|||
{ |
|||
public int ScreenCount |
|||
{ |
|||
get => _allScreens.Length; |
|||
} |
|||
|
|||
private Screen[] _allScreens; |
|||
public Screen[] AllScreens |
|||
{ |
|||
get |
|||
{ |
|||
if (_allScreens == null) |
|||
{ |
|||
IntPtr display = Native.GdkGetDefaultDisplay(); |
|||
GdkScreen screen = Native.GdkDisplayGetDefaultScreen(display); |
|||
short primary = Native.GdkScreenGetPrimaryMonitor(screen); |
|||
Screen[] screens = new Screen[ScreenCount]; |
|||
for (short i = 0; i < screens.Length; i++) |
|||
{ |
|||
GdkRectangle workArea = new GdkRectangle(), geometry = new GdkRectangle(); |
|||
Native.GdkScreenGetMonitorGeometry(screen, i, ref geometry); |
|||
Native.GdkScreenGetMonitorWorkarea(screen, i, ref workArea); |
|||
Rect workAreaRect = new Rect(workArea.X, workArea.Y, workArea.Width, workArea.Height); |
|||
Rect geometryRect = new Rect(geometry.X, geometry.Y, geometry.Width, geometry.Height); |
|||
GtkScreen s = new GtkScreen(geometryRect, workAreaRect, i == primary, i); |
|||
screens[i] = s; |
|||
} |
|||
|
|||
_allScreens = screens; |
|||
} |
|||
|
|||
return _allScreens; |
|||
} |
|||
} |
|||
|
|||
public ScreenImpl() |
|||
{ |
|||
IntPtr display = Native.GdkGetDefaultDisplay(); |
|||
GdkScreen screen = Native.GdkDisplayGetDefaultScreen(display); |
|||
Signal.Connect<Native.D.monitors_changed>(screen, "monitors-changed", MonitorsChanged); |
|||
} |
|||
|
|||
private unsafe void MonitorsChanged(IntPtr screen, IntPtr userData) |
|||
{ |
|||
_allScreens = null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using System; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.MonoMac |
|||
{ |
|||
public class MacScreen : Screen |
|||
{ |
|||
private readonly IntPtr handle; |
|||
|
|||
public MacScreen(Rect bounds, Rect workingArea, bool primary, IntPtr handle) : base(bounds, workingArea, primary) |
|||
{ |
|||
this.handle = handle; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
return (int)handle; |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is MacScreen screen) ? this.handle == screen.handle : base.Equals(obj); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Utilities; |
|||
using MonoMac.AppKit; |
|||
using MonoMac.Foundation; |
|||
|
|||
namespace Avalonia.MonoMac |
|||
{ |
|||
public class ScreenImpl : IScreenImpl |
|||
{ |
|||
private const string NSApplicationDidChangeScreenParametersNotification = "NSApplicationDidChangeScreenParametersNotification"; |
|||
|
|||
public int ScreenCount |
|||
{ |
|||
get => NSScreen.Screens.Length; |
|||
} |
|||
|
|||
private Screen[] _allScreens; |
|||
public Screen[] AllScreens |
|||
{ |
|||
get |
|||
{ |
|||
if (_allScreens == null) |
|||
{ |
|||
NSScreen[] screens = NSScreen.Screens; |
|||
Screen[] s = new Screen[screens.Length]; |
|||
NSScreen primary = NSScreen.MainScreen; |
|||
for (int i = 0; i < screens.Length; i++) |
|||
{ |
|||
Rect bounds = screens[i].Frame.ToAvaloniaRect().ConvertRectY(); |
|||
Rect workArea = screens[i].VisibleFrame.ToAvaloniaRect().ConvertRectY(); |
|||
s[i] = new MacScreen(bounds, workArea, i == 0, screens[i].Handle); |
|||
} |
|||
|
|||
_allScreens = s; |
|||
} |
|||
return _allScreens; |
|||
} |
|||
} |
|||
|
|||
public ScreenImpl() |
|||
{ |
|||
NSNotificationCenter.DefaultCenter.AddObserver(NSApplicationDidChangeScreenParametersNotification, MonitorsChanged); |
|||
} |
|||
|
|||
private void MonitorsChanged(NSNotification notification) |
|||
{ |
|||
_allScreens = null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
using System.Linq; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Utilities; |
|||
using static Avalonia.Win32.Interop.UnmanagedMethods; |
|||
|
|||
#if NETSTANDARD
|
|||
using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception; |
|||
#endif
|
|||
|
|||
namespace Avalonia.Win32 |
|||
{ |
|||
public class ScreenImpl : IScreenImpl |
|||
{ |
|||
public int ScreenCount |
|||
{ |
|||
get => GetSystemMetrics(SystemMetric.SM_CMONITORS); |
|||
} |
|||
|
|||
private Screen[] _allScreens; |
|||
public Screen[] AllScreens |
|||
{ |
|||
get |
|||
{ |
|||
if (_allScreens == null) |
|||
{ |
|||
int index = 0; |
|||
Screen[] screens = new Screen[ScreenCount]; |
|||
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, |
|||
(IntPtr monitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr data) => |
|||
{ |
|||
MONITORINFO monitorInfo = new MONITORINFO(); |
|||
if (GetMonitorInfo(monitor, monitorInfo)) |
|||
{ |
|||
RECT bounds = monitorInfo.rcMonitor; |
|||
RECT workingArea = monitorInfo.rcWork; |
|||
Rect avaloniaBounds = new Rect(bounds.left, bounds.top, bounds.right - bounds.left, |
|||
bounds.bottom - bounds.top); |
|||
Rect avaloniaWorkArea = |
|||
new Rect(workingArea.left, workingArea.top, workingArea.right - bounds.left, |
|||
workingArea.bottom - bounds.top); |
|||
screens[index] = |
|||
new WinScreen(avaloniaBounds, avaloniaWorkArea, monitorInfo.dwFlags == 1, |
|||
monitor); |
|||
index++; |
|||
} |
|||
return true; |
|||
}, IntPtr.Zero); |
|||
_allScreens = screens; |
|||
} |
|||
return _allScreens; |
|||
} |
|||
} |
|||
|
|||
public void InvalidateScreensCache() |
|||
{ |
|||
_allScreens = null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using System; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Win32 |
|||
{ |
|||
public class WinScreen : Screen |
|||
{ |
|||
private readonly IntPtr _hMonitor; |
|||
|
|||
public WinScreen(Rect bounds, Rect workingArea, bool primary, IntPtr hMonitor) : base(bounds, workingArea, primary) |
|||
{ |
|||
this._hMonitor = hMonitor; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
return (int)_hMonitor; |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return (obj is WinScreen screen) ? this._hMonitor == screen._hMonitor : base.Equals(obj); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue