diff --git a/source/Main.hx b/source/Main.hx index 8731d6fb075..0a5e4f9c98c 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -45,24 +45,10 @@ import backend.Highscore; @:cppInclude('./external/gamemode_client.h') @:cppFileCode('#define GAMEMODE_AUTO') #end -#if windows -@:buildXml(' - - - - -') -@:cppFileCode(' -#include -#include -#pragma comment(lib, "Shell32.lib") -extern "C" HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(PCWSTR AppID); -') -#end // // // // // // // // // class Main extends Sprite { - var game = { + private static final game = { width: 1280, // WINDOW width height: 720, // WINDOW height initialState: TitleState, // initial game state @@ -84,21 +70,9 @@ class Main extends Sprite { super(); - #if windows - // DPI Scaling fix for windows - // this shouldn't be needed for other systems - // Credit to YoshiCrafter29 for finding this function - untyped __cpp__("SetProcessDPIAware();"); - - var display = lime.system.System.getDisplay(0); - if (display != null) { - var dpiScale:Float = display.dpi / 96; - Application.current.window.width = Std.int(game.width * dpiScale); - Application.current.window.height = Std.int(game.height * dpiScale); - - Application.current.window.x = Std.int((Application.current.window.display.bounds.width - Application.current.window.width) / 2); - Application.current.window.y = Std.int((Application.current.window.display.bounds.height - Application.current.window.height) / 2); - } + #if (cpp && windows) + backend.Native.fixScaling(); + backend.Native.setWindowDarkMode(true, true); #end // Credits to MAJigsaw77 (he's the og author for this code) diff --git a/source/backend/Native.hx b/source/backend/Native.hx new file mode 100644 index 00000000000..96709075c62 --- /dev/null +++ b/source/backend/Native.hx @@ -0,0 +1,217 @@ +package backend; + +import lime.app.Application; +import lime.system.Display; +import lime.system.System; + +import flixel.util.FlxColor; + +#if (cpp && windows) +@:buildXml(' + + + + +') +@:cppFileCode(' +#include +#include +#include +#include + +#define attributeDarkMode 20 +#define attributeDarkModeFallback 19 + +#define attributeCaptionColor 34 +#define attributeTextColor 35 +#define attributeBorderColor 36 + +struct HandleData { + DWORD pid = 0; + HWND handle = 0; +}; + +BOOL CALLBACK findByPID(HWND handle, LPARAM lParam) { + DWORD targetPID = ((HandleData*)lParam)->pid; + DWORD curPID = 0; + + GetWindowThreadProcessId(handle, &curPID); + if (targetPID != curPID || GetWindow(handle, GW_OWNER) != (HWND)0 || !IsWindowVisible(handle)) { + return TRUE; + } + + ((HandleData*)lParam)->handle = handle; + return FALSE; +} + +HWND curHandle = 0; +void getHandle() { + if (curHandle == (HWND)0) { + HandleData data; + data.pid = GetCurrentProcessId(); + EnumWindows(findByPID, (LPARAM)&data); + curHandle = data.handle; + } +} +') +#end +class Native +{ + public static function __init__():Void + { + registerDPIAware(); + } + + public static function registerDPIAware():Void + { + #if (cpp && windows) + // DPI Scaling fix for windows + // this shouldn't be needed for other systems + // Credit to YoshiCrafter29 for finding this function + untyped __cpp__(' + SetProcessDPIAware(); + #ifdef DPI_AWARENESS_CONTEXT + SetProcessDpiAwarenessContext( + #ifdef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 + DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 + #else + DPI_AWARENESS_CONTEXT_SYSTEM_AWARE + #endif + ); + #endif + '); + #end + } + + private static var fixedScaling:Bool = false; + public static function fixScaling():Void + { + if (fixedScaling) return; + fixedScaling = true; + + #if (cpp && windows) + final display:Null = System.getDisplay(0); + if (display != null) + { + final dpiScale:Float = display.dpi / 96; + @:privateAccess Application.current.window.width = Std.int(Main.game.width * dpiScale); + @:privateAccess Application.current.window.height = Std.int(Main.game.height * dpiScale); + + Application.current.window.x = Std.int((Application.current.window.display.bounds.width - Application.current.window.width) / 2); + Application.current.window.y = Std.int((Application.current.window.display.bounds.height - Application.current.window.height) / 2); + } + + untyped __cpp__(' + getHandle(); + if (curHandle != (HWND)0) { + HDC curHDC = GetDC(curHandle); + RECT curRect; + GetClientRect(curHandle, &curRect); + FillRect(curHDC, &curRect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + ReleaseDC(curHandle, curHDC); + } + '); + #end + } + + /** + * Enables or disables dark mode support for the title bar. + * Only works on Windows. + * + * @param enable Whether to enable or disable dark mode support. + * @param instant Whether to skip the transition tween. + */ + public static function setWindowDarkMode(enable:Bool = true, instant:Bool = false):Void + { + #if (cpp && windows) + var success:Bool = false; + untyped __cpp__(' + getHandle(); + if (curHandle != (HWND)0) { + const BOOL darkMode = enable ? TRUE : FALSE; + if ( + S_OK == DwmSetWindowAttribute(curHandle, attributeDarkMode, (LPCVOID)&darkMode, (DWORD)sizeof(darkMode)) || + S_OK == DwmSetWindowAttribute(curHandle, attributeDarkModeFallback, (LPCVOID)&darkMode, (DWORD)sizeof(darkMode)) + ) { + success = true; + } + + UpdateWindow(curHandle); + } + '); + + if (instant && success) + { + final curBarColor:Null = windowBarColor; + windowBarColor = FlxColor.BLACK; + windowBarColor = curBarColor; + } + #end + } + + /** + * The color of the window title bar. If `null`, the default is used. + * Only works on Windows. + */ + public static var windowBarColor(default, set):Null = null; + public static function set_windowBarColor(value:Null):Null + { + #if (cpp && windows) + final intColor:Int = Std.isOfType(value, Int) ? cast FlxColor.fromRGB(value.blue, value.green, value.red, value.alpha) : 0xffffffff; + untyped __cpp__(' + getHandle(); + if (curHandle != (HWND)0) { + const COLORREF targetColor = (COLORREF)intColor; + DwmSetWindowAttribute(curHandle, attributeCaptionColor, (LPCVOID)&targetColor, (DWORD)sizeof(targetColor)); + UpdateWindow(curHandle); + } + '); + #end + + return windowBarColor = value; + } + + /** + * The color of the window title bar text. If `null`, the default is used. + * Only works on Windows. + */ + public static var windowTextColor(default, set):Null = null; + public static function set_windowTextColor(value:Null):Null + { + #if (cpp && windows) + final intColor:Int = Std.isOfType(value, Int) ? cast FlxColor.fromRGB(value.blue, value.green, value.red, value.alpha) : 0xffffffff; + untyped __cpp__(' + getHandle(); + if (curHandle != (HWND)0) { + const COLORREF targetColor = (COLORREF)intColor; + DwmSetWindowAttribute(curHandle, attributeTextColor, (LPCVOID)&targetColor, (DWORD)sizeof(targetColor)); + UpdateWindow(curHandle); + } + '); + #end + + return windowTextColor = value; + } + + /** + * The color of the window border. If `null`, the default is used. + * Only works on Windows. + */ + public static var windowBorderColor(default, set):Null = null; + public static function set_windowBorderColor(value:Null):Null + { + #if (cpp && windows) + final intColor:Int = Std.isOfType(value, Int) ? cast FlxColor.fromRGB(value.blue, value.green, value.red, value.alpha) : 0xffffffff; + untyped __cpp__(' + getHandle(); + if (curHandle != (HWND)0) { + const COLORREF targetColor = (COLORREF)intColor; + DwmSetWindowAttribute(curHandle, attributeBorderColor, (LPCVOID)&targetColor, (DWORD)sizeof(targetColor)); + UpdateWindow(curHandle); + } + '); + #end + + return windowBorderColor = value; + } +} \ No newline at end of file