Workaround for getting dark title bar in Windows

Uses undocumented APIs to change the use dark title bar in Windows
This commit is contained in:
Pratyush Nair 2021-05-17 16:48:17 +05:30
parent bd8b525faa
commit 03ae320417
1 changed files with 209 additions and 209 deletions

View File

@ -1,209 +1,209 @@
#include <stdio.h> #include <stdio.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include "api/api.h" #include "api/api.h"
#include "renderer.h" #include "renderer.h"
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <dwmapi.h> #include <dwmapi.h>
#include <SDL2/SDL_syswm.h> #include <SDL2/SDL_syswm.h>
enum WINDOWCOMPOSITIONATTRIB { enum WINDOWCOMPOSITIONATTRIB {
WCA_USEDARKMODECOLORS = 26 WCA_USEDARKMODECOLORS = 26
}; };
struct WINDOWCOMPOSITIONATTRIBDATA { struct WINDOWCOMPOSITIONATTRIBDATA {
enum WINDOWCOMPOSITIONATTRIB Attrib; enum WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData; PVOID pvData;
SIZE_T cbData; SIZE_T cbData;
}; };
enum PreferredAppMode { Default, AllowDark, ForceDark, ForceLight, Max }; enum PreferredAppMode { Default, AllowDark, ForceDark, ForceLight, Max };
typedef BOOL(WINAPI *fnSetWindowCompositionAttribute)( typedef BOOL(WINAPI *fnSetWindowCompositionAttribute)(
HWND hWnd, struct WINDOWCOMPOSITIONATTRIBDATA *); HWND hWnd, struct WINDOWCOMPOSITIONATTRIBDATA *);
typedef VOID(WINAPI *fnRefreshImmersiveColorPolicyState)(); // ordinal 104 typedef VOID(WINAPI *fnRefreshImmersiveColorPolicyState)(); // ordinal 104
typedef BOOL(WINAPI *fnShouldAppsUseDarkMode)(); // ordinal 132 typedef BOOL(WINAPI *fnShouldAppsUseDarkMode)(); // ordinal 132
typedef enum PreferredAppMode(WINAPI *fnSetPreferredAppMode)( typedef enum PreferredAppMode(WINAPI *fnSetPreferredAppMode)(
enum PreferredAppMode appMode); // ordinal 135 enum PreferredAppMode appMode); // ordinal 135
fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = NULL; fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = NULL;
fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = NULL; fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = NULL;
fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = NULL; fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = NULL;
fnSetPreferredAppMode _SetPreferredAppMode = NULL; fnSetPreferredAppMode _SetPreferredAppMode = NULL;
HWND getWinHandle(SDL_Window *win) { HWND getWinHandle(SDL_Window *win) {
SDL_SysWMinfo infoWindow; SDL_SysWMinfo infoWindow;
SDL_VERSION(&infoWindow.version); SDL_VERSION(&infoWindow.version);
SDL_GetWindowWMInfo(win, &infoWindow); SDL_GetWindowWMInfo(win, &infoWindow);
return (infoWindow.info.win.window); return (infoWindow.info.win.window);
} }
void get_dark_titlebar(SDL_Window *window, int dark) { void get_dark_titlebar(SDL_Window *window, int dark) {
HWND hwnd; HWND hwnd;
hwnd = getWinHandle(window); hwnd = getWinHandle(window);
HMODULE hUxtheme = HMODULE hUxtheme =
LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (hUxtheme) { if (hUxtheme) {
_SetWindowCompositionAttribute = _SetWindowCompositionAttribute =
(fnSetWindowCompositionAttribute)(GetProcAddress( (fnSetWindowCompositionAttribute)(GetProcAddress(
GetModuleHandleW(L"user32.dll"), "SetWindowCompositionAttribute")); GetModuleHandleW(L"user32.dll"), "SetWindowCompositionAttribute"));
_RefreshImmersiveColorPolicyState = (fnRefreshImmersiveColorPolicyState)( _RefreshImmersiveColorPolicyState = (fnRefreshImmersiveColorPolicyState)(
GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104))); GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104)));
_ShouldAppsUseDarkMode = (fnShouldAppsUseDarkMode)( _ShouldAppsUseDarkMode = (fnShouldAppsUseDarkMode)(
GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132))); GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132)));
_SetPreferredAppMode = (fnSetPreferredAppMode)( _SetPreferredAppMode = (fnSetPreferredAppMode)(
GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135))); GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135)));
if (_RefreshImmersiveColorPolicyState && _ShouldAppsUseDarkMode && if (_RefreshImmersiveColorPolicyState && _ShouldAppsUseDarkMode &&
_SetPreferredAppMode) { _SetPreferredAppMode) {
_SetPreferredAppMode(AllowDark); _SetPreferredAppMode(AllowDark);
_RefreshImmersiveColorPolicyState(); _RefreshImmersiveColorPolicyState();
LONG ldark = dark; LONG ldark = dark;
struct WINDOWCOMPOSITIONATTRIBDATA data = {WCA_USEDARKMODECOLORS, &ldark, struct WINDOWCOMPOSITIONATTRIBDATA data = {WCA_USEDARKMODECOLORS, &ldark,
sizeof ldark}; sizeof ldark};
_SetWindowCompositionAttribute(hwnd, &data); _SetWindowCompositionAttribute(hwnd, &data);
} }
} }
} }
#elif __linux__ #elif __linux__
#include <unistd.h> #include <unistd.h>
#elif __APPLE__ #elif __APPLE__
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#endif #endif
SDL_Window *window; SDL_Window *window;
static double get_scale(void) { static double get_scale(void) {
float dpi; float dpi;
SDL_GetDisplayDPI(0, NULL, &dpi, NULL); SDL_GetDisplayDPI(0, NULL, &dpi, NULL);
#if _WIN32 #if _WIN32
return dpi / 96.0; return dpi / 96.0;
#else #else
return 1.0; return 1.0;
#endif #endif
} }
static void get_exe_filename(char *buf, int sz) { static void get_exe_filename(char *buf, int sz) {
#if _WIN32 #if _WIN32
int len = GetModuleFileName(NULL, buf, sz - 1); int len = GetModuleFileName(NULL, buf, sz - 1);
buf[len] = '\0'; buf[len] = '\0';
#elif __linux__ #elif __linux__
char path[512]; char path[512];
sprintf(path, "/proc/%d/exe", getpid()); sprintf(path, "/proc/%d/exe", getpid());
int len = readlink(path, buf, sz - 1); int len = readlink(path, buf, sz - 1);
buf[len] = '\0'; buf[len] = '\0';
#elif __APPLE__ #elif __APPLE__
unsigned size = sz; unsigned size = sz;
_NSGetExecutablePath(buf, &size); _NSGetExecutablePath(buf, &size);
#else #else
strcpy(buf, "./lite"); strcpy(buf, "./lite");
#endif #endif
} }
static void init_window_icon(void) { static void init_window_icon(void) {
#ifndef _WIN32 #ifndef _WIN32
#include "../icon.inl" #include "../icon.inl"
(void) icon_rgba_len; /* unused */ (void) icon_rgba_len; /* unused */
SDL_Surface *surf = SDL_CreateRGBSurfaceFrom( SDL_Surface *surf = SDL_CreateRGBSurfaceFrom(
icon_rgba, 64, 64, icon_rgba, 64, 64,
32, 64 * 4, 32, 64 * 4,
0x000000ff, 0x000000ff,
0x0000ff00, 0x0000ff00,
0x00ff0000, 0x00ff0000,
0xff000000); 0xff000000);
SDL_SetWindowIcon(window, surf); SDL_SetWindowIcon(window, surf);
SDL_FreeSurface(surf); SDL_FreeSurface(surf);
#endif #endif
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
#ifdef _WIN32 #ifdef _WIN32
HINSTANCE lib = LoadLibrary("user32.dll"); HINSTANCE lib = LoadLibrary("user32.dll");
int (*SetProcessDPIAware)() = (void*) GetProcAddress(lib, "SetProcessDPIAware"); int (*SetProcessDPIAware)() = (void*) GetProcAddress(lib, "SetProcessDPIAware");
SetProcessDPIAware(); SetProcessDPIAware();
#endif #endif
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
SDL_EnableScreenSaver(); SDL_EnableScreenSaver();
SDL_EventState(SDL_DROPFILE, SDL_ENABLE); SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
atexit(SDL_Quit); atexit(SDL_Quit);
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* Available since 2.0.8 */ #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* Available since 2.0.8 */
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
#endif #endif
#if SDL_VERSION_ATLEAST(2, 0, 5) #if SDL_VERSION_ATLEAST(2, 0, 5)
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
#endif #endif
SDL_DisplayMode dm; SDL_DisplayMode dm;
SDL_GetCurrentDisplayMode(0, &dm); SDL_GetCurrentDisplayMode(0, &dm);
window = SDL_CreateWindow( window = SDL_CreateWindow(
"", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8, "", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8,
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
#if _WIN32 #if _WIN32
get_dark_titlebar(window, 1); get_dark_titlebar(window, 1);
#endif #endif
init_window_icon(); init_window_icon();
ren_init(window); ren_init(window);
lua_State *L = luaL_newstate(); lua_State *L = luaL_newstate();
luaL_openlibs(L); luaL_openlibs(L);
api_load_libs(L); api_load_libs(L);
lua_newtable(L); lua_newtable(L);
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
lua_pushstring(L, argv[i]); lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, i + 1); lua_rawseti(L, -2, i + 1);
} }
lua_setglobal(L, "ARGS"); lua_setglobal(L, "ARGS");
lua_pushstring(L, "1.11"); lua_pushstring(L, "1.11");
lua_setglobal(L, "VERSION"); lua_setglobal(L, "VERSION");
lua_pushstring(L, SDL_GetPlatform()); lua_pushstring(L, SDL_GetPlatform());
lua_setglobal(L, "PLATFORM"); lua_setglobal(L, "PLATFORM");
lua_pushnumber(L, get_scale()); lua_pushnumber(L, get_scale());
lua_setglobal(L, "SCALE"); lua_setglobal(L, "SCALE");
char exename[2048]; char exename[2048];
get_exe_filename(exename, sizeof(exename)); get_exe_filename(exename, sizeof(exename));
lua_pushstring(L, exename); lua_pushstring(L, exename);
lua_setglobal(L, "EXEFILE"); lua_setglobal(L, "EXEFILE");
(void) luaL_dostring(L, (void) luaL_dostring(L,
"local core\n" "local core\n"
"xpcall(function()\n" "xpcall(function()\n"
" SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n" " SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n"
" PATHSEP = package.config:sub(1, 1)\n" " PATHSEP = package.config:sub(1, 1)\n"
" EXEDIR = EXEFILE:match(\"^(.+)[/\\\\].*$\")\n" " EXEDIR = EXEFILE:match(\"^(.+)[/\\\\].*$\")\n"
" package.path = EXEDIR .. '/data/?.lua;' .. package.path\n" " package.path = EXEDIR .. '/data/?.lua;' .. package.path\n"
" package.path = EXEDIR .. '/data/?/init.lua;' .. package.path\n" " package.path = EXEDIR .. '/data/?/init.lua;' .. package.path\n"
" core = require('core')\n" " core = require('core')\n"
" core.init()\n" " core.init()\n"
" core.run()\n" " core.run()\n"
"end, function(err)\n" "end, function(err)\n"
" print('Error: ' .. tostring(err))\n" " print('Error: ' .. tostring(err))\n"
" print(debug.traceback(nil, 2))\n" " print(debug.traceback(nil, 2))\n"
" if core and core.on_error then\n" " if core and core.on_error then\n"
" pcall(core.on_error, err)\n" " pcall(core.on_error, err)\n"
" end\n" " end\n"
" os.exit(1)\n" " os.exit(1)\n"
"end)"); "end)");
lua_close(L); lua_close(L);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }