A game framework written with osu! in mind.
at master 106 lines 4.0 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Drawing; 6using System.Runtime.InteropServices; 7using osu.Framework.Platform.Windows.Native; 8using SDL2; 9 10namespace osu.Framework.Platform.Windows 11{ 12 public class WindowsWindow : SDL2DesktopWindow 13 { 14 private const int seticon_message = 0x0080; 15 private const int icon_big = 1; 16 private const int icon_small = 0; 17 18 private const int large_icon_size = 256; 19 private const int small_icon_size = 16; 20 21 private Icon smallIcon; 22 private Icon largeIcon; 23 24 public WindowsWindow() 25 { 26 try 27 { 28 // SDL doesn't handle DPI correctly on windows, but this brings things mostly in-line with expectations. (https://bugzilla.libsdl.org/show_bug.cgi?id=3281) 29 SetProcessDpiAwareness(ProcessDpiAwareness.Process_System_DPI_Aware); 30 } 31 catch 32 { 33 // API doesn't exist on Windows 7 so it needs to be allowed to fail silently. 34 } 35 } 36 37 protected override Size SetBorderless() 38 { 39 SDL.SDL_SetWindowBordered(SDLWindowHandle, SDL.SDL_bool.SDL_FALSE); 40 41 Size positionOffsetHack = new Size(1, 1); 42 43 var newSize = CurrentDisplay.Bounds.Size + positionOffsetHack; 44 var newPosition = CurrentDisplay.Bounds.Location - positionOffsetHack; 45 46 // for now let's use the same 1px hack that we've always used to force borderless. 47 SDL.SDL_SetWindowSize(SDLWindowHandle, newSize.Width, newSize.Height); 48 Position = newPosition; 49 50 return newSize; 51 } 52 53 /// <summary> 54 /// On Windows, SDL will use the same image for both large and small icons (scaled as necessary). 55 /// This can look bad if scaling down a large image, so we use the Windows API directly so as 56 /// to get a cleaner icon set than SDL can provide. 57 /// If called before the window has been created, or we do not find two separate icon sizes, we fall back to the base method. 58 /// </summary> 59 internal override void SetIconFromGroup(IconGroup iconGroup) 60 { 61 smallIcon = iconGroup.CreateIcon(small_icon_size, small_icon_size); 62 largeIcon = iconGroup.CreateIcon(large_icon_size, large_icon_size); 63 64 var windowHandle = WindowHandle; 65 66 if (windowHandle == IntPtr.Zero || largeIcon == null || smallIcon == null) 67 base.SetIconFromGroup(iconGroup); 68 else 69 { 70 SendMessage(windowHandle, seticon_message, (IntPtr)icon_small, smallIcon.Handle); 71 SendMessage(windowHandle, seticon_message, (IntPtr)icon_big, largeIcon.Handle); 72 } 73 } 74 75 public override Point PointToClient(Point point) 76 { 77 ScreenToClient(WindowHandle, ref point); 78 return point; 79 } 80 81 public override Point PointToScreen(Point point) 82 { 83 ClientToScreen(WindowHandle, ref point); 84 return point; 85 } 86 87 [DllImport("SHCore.dll", SetLastError = true)] 88 internal static extern bool SetProcessDpiAwareness(ProcessDpiAwareness awareness); 89 90 internal enum ProcessDpiAwareness 91 { 92 Process_DPI_Unaware = 0, 93 Process_System_DPI_Aware = 1, 94 Process_Per_Monitor_DPI_Aware = 2 95 } 96 97 [DllImport("user32.dll", SetLastError = true)] 98 internal static extern bool ScreenToClient(IntPtr hWnd, ref Point point); 99 100 [DllImport("user32.dll", SetLastError = true)] 101 internal static extern bool ClientToScreen(IntPtr hWnd, ref Point point); 102 103 [DllImport("user32.dll", CharSet = CharSet.Auto)] 104 private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 105 } 106}