Skip to content

Commit 782f384

Browse files
committed
Wire up all relevant events
1 parent bd202f6 commit 782f384

16 files changed

+790
-272
lines changed

sources/Windowing/Windowing/IDisplay.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,4 @@ public interface IDisplay : IEquatable<IDisplay>
6363
/// An event raised when <see cref="KnownVideoModes" /> changes.
6464
/// </summary>
6565
event Action<DisplayVideoModeAvailabilityChangeEvent>? KnownVideoModesChanged;
66-
67-
/// <summary>
68-
/// An event raised when <see cref="VideoMode" /> changes.
69-
/// </summary>
70-
public event Action<VideoModeChangeEvent>? VideoModeChanged;
7166
}

sources/Windowing/Windowing/ISurfaceDisplay.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,9 @@ public interface ISurfaceDisplay
4444
/// An event raised when <see cref="AvailableVideoModes" /> changes.
4545
/// </summary>
4646
event Action<DisplayVideoModeAvailabilityChangeEvent>? AvailableVideoModesChanged;
47+
48+
/// <summary>
49+
/// An event raised when <see cref="VideoMode" /> changes.
50+
/// </summary>
51+
public event Action<VideoModeChangeEvent>? VideoModeChanged;
4752
}

sources/Windowing/Windowing/ISurfaceScale.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ namespace Silk.NET.Windowing;
44
/// Provides information pertaining to the surface's graphical scaling.
55
/// </summary>
66
/// <remarks>
7-
/// <see cref="ContentScale" /> is typically used to scale UI elements to the correct size for the end user.
7+
/// <see cref="Content" /> is typically used to scale UI elements to the correct size for the end user.
88
/// <see cref="PixelDensity" /> on the other hand is used to scale the entire application to cover the entire client
99
/// area in cases where the window client size is smaller than the actual drawable size (i.e. it is high density).
1010
/// If scaling content for legibility and scaling the application's rendering as a whole are not needed to be separated,
11-
/// it is recommended to use <see cref="DrawScale" />. Implementations shall always request a high density surface if
11+
/// it is recommended to use <see cref="Draw" />. Implementations shall always request a high density surface if
1212
/// given the choice, to account for the platforms where applications may not be able to opt-out of high density.
1313
/// </remarks>
1414
public interface ISurfaceScale
@@ -17,33 +17,38 @@ public interface ISurfaceScale
1717
/// Gets the factor with which the application should scale its content to make the content more legible for the
1818
/// user. This has no influence on <see cref="Surface.DrawableSize" />.
1919
/// </summary>
20-
/// <seealso cref="DrawScale" />
21-
float ContentScale { get; }
20+
/// <seealso cref="Draw" />
21+
float Content { get; }
2222

2323
/// <summary>
2424
/// Gets the suggested amplification factor when drawing in terms of <see cref="Surface.DrawableSize" />. This
2525
/// represents the scale from the pixel resolution to the desired content size, and is typically the multiplication
26-
/// of <see cref="PixelDensity" /> and <see cref="ContentScale" />.
26+
/// of <see cref="PixelDensity" /> and <see cref="Content" />.
2727
/// </summary>
2828
/// <remarks>
2929
/// For example, if <see cref="PixelDensity" /> is <c>2.0</c> (i.e. there are 2 pixels per screen coordinate)
3030
/// <i>and</i> the window manager requests that applications scale their content up by <c>2.0</c> to meet the user's
31-
/// settings as per <see cref="ContentScale" />, this would be <c>4.0</c>. This is because we're scaling once to
31+
/// settings as per <see cref="Content" />, this would be <c>4.0</c>. This is because we're scaling once to
3232
/// account for the fact that the application has twice the amount of pixels available to it for the given window
3333
/// size, and then scaling again so that what we are drawing appears zoomed in as per the user's request. Note that
3434
/// it is rarely the case that an operating system employs both dense pixels <i>and</i> content scale. macOS for
35-
/// instance, instead of setting <see cref="ContentScale" />, opts to scale the resolution in the cases where the
35+
/// instance, instead of setting <see cref="Content" />, opts to scale the resolution in the cases where the
3636
/// user wants magnified visuals instead of having the applications scale their content; whereas Windows sets
37-
/// <see cref="ContentScale" /> and instead always keeps <see cref="PixelDensity" /> as <c>1.0</c>. This is down
37+
/// <see cref="Content" /> and instead always keeps <see cref="PixelDensity" /> as <c>1.0</c>. This is down
3838
/// to philosophical differences between the window coordinate systems on platforms as to whether they prefer to
3939
/// deal in physical device pixels or physical content sizes.
4040
/// </remarks>
41-
float DrawScale { get; }
41+
float Draw { get; }
4242

4343
/// <summary>
4444
/// Gets the ratio of pixels rendered to window size. This shall be equivalent to
4545
/// <see cref="Surface.DrawableSize" /> divided by <see cref="ISurfaceWindow.ClientSize" />.
4646
/// </summary>
47-
/// <seealso cref="DrawScale" />
47+
/// <seealso cref="Draw" />
4848
float PixelDensity { get; }
49+
50+
/// <summary>
51+
/// An event raised when any scale factor changes.
52+
/// </summary>
53+
public event Action<ScaleChangedEvent>? Changed;
4954
}

sources/Windowing/Windowing/ISurfaceWindow.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,26 @@ Vector2 ClientSize
6565

6666
/// <summary>
6767
/// Gets or sets a value indicating whether, unless set to <c>false</c> before the next <see cref="Surface.Tick" />,
68-
/// the window will close resulting in the irrevocable termination of the surface.
68+
/// the window will close resulting in the irrevocable termination of the surface. Any children active at this point
69+
/// will also be irrevocably terminated, and parent windows should bear this in mind when responding to their
70+
/// <see cref="CloseRequested"/> events - not rejecting the closure request shall terminate all child surfaces too.
6971
/// </summary>
7072
bool IsCloseRequested { get; set; }
7173

74+
/// <summary>
75+
/// Raised when <see cref="IsCloseRequested" /> is set to <c>true</c>.
76+
/// </summary>
77+
event Action<WindowToggleEvent>? CloseRequested;
78+
7279
/// <summary>
7380
/// Gets or sets a value indicating whether the window is visible.
7481
/// </summary>
7582
bool IsVisible { get; set; }
7683

7784
/// <summary>
78-
/// Raised when <see cref="IsCloseRequested" /> is set to <c>true</c>.
85+
/// Raised when <see cref="IsVisible" /> changes.
7986
/// </summary>
80-
event Action<WindowToggleEvent>? CloseRequested;
87+
event Action<WindowToggleEvent>? VisibilityChanged;
8188

8289
/// <summary>
8390
/// Gets or sets a value indicating whether the window currently has input focus. If setting to <c>true</c>, the

sources/Windowing/Windowing/Implementations/SDL3/SdlDisplay.cs

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,22 @@
88

99
namespace Silk.NET.Windowing.SDL3;
1010

11-
internal class SdlDisplay(uint id) : IDisplay
11+
internal class SdlDisplay : IDisplay
1212
{
13-
public uint Id { get; } = id;
13+
private Rectangle<float> _bounds;
14+
private Rectangle<float> _workArea;
15+
16+
public SdlDisplay(SdlSurface surface, uint id)
17+
{
18+
Surface = surface;
19+
Id = id;
20+
_bounds = Bounds;
21+
_workArea = WorkArea;
22+
}
23+
24+
public uint Id { get; }
25+
public SdlSurface Surface { get; }
26+
1427
public Rectangle<float> Bounds
1528
{
1629
get
@@ -50,14 +63,14 @@ public IReadOnlyList<VideoMode>? KnownVideoModes
5063
return _silkModes;
5164
}
5265

53-
var videoModes = DisplayModes;
54-
var ret = new VideoMode[videoModes.Length + 1];
66+
UpdateDisplayModes();
67+
var ret = new VideoMode[_displayModes.Length + 1];
5568
ret[0] = default; // This is to change back to non-fullscreen.
56-
for (nuint i = 0; (int)i < videoModes.Length; i++)
69+
for (nuint i = 0; (int)i < _displayModes.Length; i++)
5770
{
58-
ref var videoMode = ref videoModes[i].Handle;
71+
ref var videoMode = ref _displayModes[i].Handle;
5972
ret[i + 1] = new VideoMode(
60-
(int)i,
73+
(int)(i + 1),
6174
new Vector2(videoMode.W, videoMode.H),
6275
videoMode.RefreshRate
6376
);
@@ -67,37 +80,78 @@ public IReadOnlyList<VideoMode>? KnownVideoModes
6780
}
6881
}
6982

70-
[field: AllowNull, MaybeNull]
83+
private Ptr<DisplayMode>[]? _displayModes;
84+
7185
internal Ptr<DisplayMode>[] DisplayModes
7286
{
7387
get
7488
{
75-
if (field is not null)
89+
if (_displayModes is not null)
7690
{
77-
return field;
91+
return _displayModes;
7892
}
7993

80-
var count = 0;
81-
var videoModes = Sdl.GetFullscreenDisplayModes(Id, count.AsRef());
82-
if (videoModes == nullptr)
83-
{
84-
Sdl.ThrowError();
85-
}
94+
UpdateDisplayModes();
95+
return _displayModes;
96+
}
97+
}
8698

87-
field = new Ptr<DisplayMode>[count];
88-
videoModes.AsSpan(count).CopyTo(field);
89-
Sdl.Free((Ref)videoModes);
90-
return field;
99+
[MemberNotNull(nameof(_displayModes))]
100+
private bool UpdateDisplayModes()
101+
{
102+
DebugPrint();
103+
var count = 0;
104+
var videoModes = Sdl.GetFullscreenDisplayModes(Id, count.AsRef());
105+
if (videoModes == nullptr)
106+
{
107+
Sdl.ThrowError();
91108
}
109+
110+
var span = videoModes.AsSpan(count);
111+
if (_displayModes?.Length == count && span.SequenceEqual(_displayModes))
112+
{
113+
return false;
114+
}
115+
116+
var wasNull = _displayModes is null;
117+
_displayModes = new Ptr<DisplayMode>[count];
118+
videoModes.AsSpan(count).CopyTo(_displayModes);
119+
Sdl.Free((Ref)videoModes);
120+
_silkModes = null;
121+
if (!wasNull)
122+
{
123+
DebugPrint("Raising KnownVideoModesChanged");
124+
_knownVideoModesChanged?.Invoke(new DisplayVideoModeAvailabilityChangeEvent());
125+
}
126+
127+
return !wasNull;
92128
}
93129

94130
public bool IsPrimary => Sdl.GetPrimaryDisplay() == Id;
95131

96132
public string Name => Sdl.GetDisplayName(Id).ReadToString();
97133

98134
public event Action<DisplayCoordinatesEvent>? CoordinatesChanged;
99-
public event Action<DisplayVideoModeAvailabilityChangeEvent>? KnownVideoModesChanged;
100-
public event Action<VideoModeChangeEvent>? VideoModeChanged;
135+
private Action<DisplayVideoModeAvailabilityChangeEvent>? _knownVideoModesChanged;
136+
137+
public event Action<DisplayVideoModeAvailabilityChangeEvent>? KnownVideoModesChanged
138+
{
139+
add
140+
{
141+
if (value is null)
142+
{
143+
return;
144+
}
145+
146+
if (_displayModes is null)
147+
{
148+
UpdateDisplayModes();
149+
}
150+
151+
_knownVideoModesChanged += value;
152+
}
153+
remove => _knownVideoModesChanged -= value;
154+
}
101155

102156
private bool Equals(SdlDisplay other) => Id == other.Id;
103157

@@ -108,4 +162,15 @@ obj is not null
108162
&& (ReferenceEquals(this, obj) || (obj.GetType() == GetType() && Equals((SdlDisplay)obj)));
109163

110164
public override int GetHashCode() => (int)Id;
165+
166+
public void OnCoordinatesChanged()
167+
{
168+
DebugPrint("Raising CoordinatesChanged...");
169+
CoordinatesChanged?.Invoke(
170+
new DisplayCoordinatesEvent(Surface, this, _bounds, Bounds, _workArea, WorkArea)
171+
);
172+
}
173+
174+
// If _displayModes is null, user doesn't care.
175+
public bool OnModeChanged() => _displayModes is not null && UpdateDisplayModes();
111176
}

0 commit comments

Comments
 (0)