Skip to content

Commit 22cb306

Browse files
committed
Add support for getting DPI from the window (SDL)
1 parent 4c1c740 commit 22cb306

3 files changed

Lines changed: 76 additions & 14 deletions

File tree

sources/engine/Stride.Games/SDL/GameFormSDL.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ namespace Stride.Games
1515
/// </summary>
1616
public class GameFormSDL : Window
1717
{
18-
#region Initialization
18+
#region Initialization
19+
1920
/// <summary>
2021
/// Initializes a new instance of the 'GameForm' class.
2122
/// </summary>
@@ -39,9 +40,11 @@ public GameFormSDL(string text) : base(text)
3940
RestoredActions += GameForm_RestoredActions;
4041
KeyDownActions += GameFormSDL_KeyDownActions;
4142
}
43+
4244
#endregion
4345

4446
#region Events
47+
4548
/// <summary>
4649
/// Occurs when [app activated].
4750
/// </summary>
@@ -75,6 +78,7 @@ public GameFormSDL(string text) : base(text)
7578
#endregion
7679

7780
#region Implementation
81+
7882
// TODO: The code below is taken from GameForm.cs of the Windows Desktop implementation. This needs reviewing
7983
private FormWindowState previousWindowState;
8084

sources/engine/Stride.Games/SDL/GameWindowSDL.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ protected override void Initialize(GameContext<Window> gameContext)
109109

110110
window.ClientSize = new Size2(width, height);
111111

112-
window.MouseEnterActions += WindowOnMouseEnterActions;
112+
window.MouseEnterActions += WindowOnMouseEnterActions;
113113
window.MouseLeaveActions += WindowOnMouseLeaveActions;
114114

115115
var gameForm = window as GameFormSDL;
@@ -120,7 +120,7 @@ protected override void Initialize(GameContext<Window> gameContext)
120120
gameForm.SizeChanged += OnClientSizeChanged;
121121
gameForm.CloseActions += GameForm_CloseActions;
122122
gameForm.FullscreenToggle += OnFullscreenToggle;
123-
123+
gameForm.DisplayChangedActions += WindowOnDisplayChangedActions;
124124
}
125125
else
126126
{
@@ -380,6 +380,12 @@ public override bool Focused
380380
}
381381
}
382382

383+
private void WindowOnDisplayChangedActions(WindowEvent sdlWindowEvent)
384+
{
385+
Dpi = new Int2((int) window.Dpi);
386+
DpiScale = window.DpiScale;
387+
}
388+
383389
protected override void Destroy()
384390
{
385391
if (window != null)

sources/engine/Stride.Graphics/SDL/Window.cs

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@ public unsafe class Window : IDisposable
1515

1616
private Silk.NET.SDL.Window* sdlHandle;
1717

18-
#region Initialization
18+
#region Initialization
1919

2020
/// <summary>
2121
/// Initializes static members of the <see cref="Window"/> class.
2222
/// </summary>
2323
static Window()
2424
{
25-
SDL = Silk.NET.SDL.Sdl.GetApi();
25+
SDL = Sdl.GetApi();
2626

27-
// jklawreszuk: Workaround for wayland (see #2487 for more details)
27+
// jklawreszuk: Workaround for wayland (see #2487 for more details)
2828
// TODO: Wayland SDL_EGL_MakeCurrent does not cover multi-context scenario (https://github.com/libsdl-org/SDL/issues/9072)
2929
if (OperatingSystem.IsLinux())
3030
SDL.SetHint("SDL_VIDEODRIVER", "x11");
3131

3232
SDL.Init(Sdl.InitEverything);
3333

34-
// Pass first mouse event when user clicked on window
34+
// Pass first mouse event when user clicked on window
3535
SDL.SetHint(Sdl.HintMouseFocusClickthrough, "1");
3636

3737
// Don't leave fullscreen on focus loss
@@ -73,11 +73,10 @@ public Window(string title, IntPtr parent)
7373
// Create the SDL window and then extract the native handle.
7474
sdlHandle = SDL.CreateWindow(title, Sdl.WindowposUndefined, Sdl.WindowposUndefined, 640, 480, (uint)flags);
7575
}
76-
7776

7877
if (sdlHandle == null)
7978
{
80-
throw new Exception("Cannot allocate SDL Window: " + SDL.GetErrorS());
79+
throw new Exception("Cannot allocate SDL Window: " + SDL.GetErrorS());
8180
}
8281

8382
SysWMInfo info = default;
@@ -105,6 +104,13 @@ public Window(string title, IntPtr parent)
105104
{
106105
Handle = (IntPtr)info.Info.Cocoa.Window;
107106
}
107+
108+
var displayIndex = SDL.GetWindowDisplayIndex(sdlHandle);
109+
if (displayIndex == -1)
110+
displayIndex = 0;
111+
112+
DisplayIndex = displayIndex;
113+
108114
Application.RegisterWindow(this);
109115
Application.ProcessEvents();
110116
}
@@ -321,7 +327,7 @@ public Size2 Size
321327
}
322328
set { SDL.SetWindowSize(sdlHandle, value.Width, value.Height); }
323329
}
324-
330+
325331
/// <summary>
326332
/// The opacity of the window.
327333
/// </summary>
@@ -446,6 +452,30 @@ public FormBorderStyle FormBorderStyle
446452
}
447453
}
448454

455+
/// <summary>
456+
/// DPI (dots per inch) of the Window.
457+
/// </summary>
458+
public float Dpi
459+
{
460+
get
461+
{
462+
float ddpi, hdpi, vdpi;
463+
464+
if (SDL.GetDisplayDPI(DisplayIndex, &ddpi, &hdpi, &vdpi) != 0)
465+
{
466+
// Failed to get DPI, return a default value of 96 which is the standard DPI for many platforms.
467+
return 96.0f;
468+
}
469+
470+
return ddpi;
471+
}
472+
}
473+
474+
/// <summary>
475+
/// DPI scaling factor of the Window. 100 % corresponds to a DPI of 96.
476+
/// </summary>
477+
public float DpiScale => Dpi / 96.0f;
478+
449479
public void SetRelativeMouseMode(bool enabled)
450480
{
451481
SDL.SetRelativeMouseMode(enabled ? SdlBool.True : SdlBool.False);
@@ -489,6 +519,7 @@ public void SetRelativeMouseMode(bool enabled)
489519
public event WindowEventDelegate MouseLeaveActions;
490520
public event WindowEventDelegate FocusGainedActions;
491521
public event WindowEventDelegate FocusLostActions;
522+
public event WindowEventDelegate DisplayChangedActions;
492523
public event DropEventDelegate DropFileActions;
493524

494525
/// <summary>
@@ -554,7 +585,7 @@ public virtual void ProcessEvent(Event e)
554585
case EventType.Fingerup:
555586
FingerReleaseActions?.Invoke(e.Tfinger);
556587
break;
557-
588+
558589
case EventType.Dropfile:
559590
DropFileActions?.Invoke(Silk.NET.Core.Native.SilkMarshal.PtrToString((IntPtr)e.Drop.File, Silk.NET.Core.Native.NativeStringEncoding.UTF8));
560591
break;
@@ -610,12 +641,27 @@ public virtual void ProcessEvent(Event e)
610641
case WindowEventID.FocusLost:
611642
FocusLostActions?.Invoke(e.Window);
612643
break;
613-
}
644+
645+
case WindowEventID.DisplayChanged:
646+
OnDisplayChanged(e.Window);
647+
break;
648+
}
614649
break;
615650
}
616651
}
617652
}
618653

654+
private void OnDisplayChanged(WindowEvent e)
655+
{
656+
var displayIndex = SDL.GetWindowDisplayIndex(sdlHandle);
657+
if (displayIndex == -1)
658+
displayIndex = 0;
659+
660+
DisplayIndex = displayIndex;
661+
662+
DisplayChangedActions?.Invoke(e);
663+
}
664+
619665
/// <summary>
620666
/// Platform specific handle for Window.
621667
/// </summary>
@@ -632,6 +678,11 @@ public virtual void ProcessEvent(Event e)
632678
/// </summary>
633679
public IntPtr Display { get; private set; }
634680

681+
/// <summary>
682+
/// Index of the display where the current Window is being shown.
683+
/// </summary>
684+
public int DisplayIndex { get; private set; }
685+
635686
/// <summary>
636687
/// Surface of current Window (valid only for Android).
637688
/// </summary>
@@ -650,7 +701,8 @@ public bool Exists
650701
get { return SdlHandle != IntPtr.Zero; }
651702
}
652703

653-
#region Disposal
704+
#region Disposal
705+
654706
~Window()
655707
{
656708
Dispose(false);
@@ -690,7 +742,7 @@ protected virtual void Dispose(bool disposing)
690742
Handle = IntPtr.Zero;
691743
}
692744
}
693-
745+
694746
// This code added to correctly implement the disposable pattern.
695747
public void Dispose()
696748
{

0 commit comments

Comments
 (0)