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