From 43dd156be72c3c74680ee1cf27888c107f59d8eb Mon Sep 17 00:00:00 2001 From: astrovm <~@4st.li> Date: Thu, 13 Aug 2026 02:08:33 -0300 Subject: [PATCH] Unify BoxedWine card game resizing --- .../resize-host.c | 78 ++++++++++------ native/solitaire/resize-host.c | 84 ------------------ site/apps/core/boxedwine-card-game.js | 39 ++++++++ site/apps/core/boxedwine-resize.js | 17 ++-- site/apps/core/boxedwine.js | 7 +- site/apps/solitaire/index.js | 36 ++------ site/apps/xp-card-games/index.js | 45 +--------- site/iframe/freecell/SOURCES.json | 10 +-- site/iframe/freecell/xp-freecell.zip | Bin 178462 -> 178720 bytes site/iframe/solitaire/SOURCES.json | 10 +-- site/iframe/solitaire/xp-solitaire.zip | Bin 177971 -> 178239 bytes site/iframe/spider-solitaire/SOURCES.json | 10 +-- .../spider-solitaire/xp-spider-solitaire.zip | Bin 271617 -> 271876 bytes tests/solitaire.test.ts | 14 ++- tests/xp-card-games.test.ts | 13 +++ 15 files changed, 162 insertions(+), 201 deletions(-) rename native/{xp-card-games => boxedwine}/resize-host.c (53%) delete mode 100644 native/solitaire/resize-host.c create mode 100644 site/apps/core/boxedwine-card-game.js diff --git a/native/xp-card-games/resize-host.c b/native/boxedwine/resize-host.c similarity index 53% rename from native/xp-card-games/resize-host.c rename to native/boxedwine/resize-host.c index fc5db9ff..bc9d321f 100644 --- a/native/xp-card-games/resize-host.c +++ b/native/boxedwine/resize-host.c @@ -1,21 +1,13 @@ #define WIN32_LEAN_AND_MEAN #include -#define SIZE_FILE L"D:\\solitaire-size.txt" +#define SIZE_FILE L"D:\\boxedwine-size.txt" -#if defined(RESIZE_FREECELL) -#define TARGET_EXECUTABLE L"freecell.exe" -#define TARGET_TITLE L"FreeCell" -#define NATIVE_SCREEN_WIDTH 640 -#define NATIVE_SCREEN_HEIGHT 480 -#elif defined(RESIZE_SPIDER_SOLITAIRE) -#define TARGET_EXECUTABLE L"spider.exe" -#define TARGET_TITLE L"Spider Solitaire" -#define NATIVE_SCREEN_WIDTH 794 -#define NATIVE_SCREEN_HEIGHT 601 -#else -#error A supported card game must be selected. -#endif +typedef struct { + DWORD process_id; + HWND window; + LONG area; +} WindowSearch; static BOOL parse_dimension(char **cursor, char *end, unsigned int *value) { unsigned int result = 0; @@ -31,7 +23,9 @@ static BOOL parse_dimension(char **cursor, char *end, unsigned int *value) { return TRUE; } -static BOOL read_window_size(unsigned int *width, unsigned int *height) { +static BOOL read_window_size(unsigned int *width, unsigned int *height, + unsigned int *native_width, + unsigned int *native_height) { char buffer[64]; DWORD bytes_read = 0; HANDLE file = CreateFileW(SIZE_FILE, GENERIC_READ, @@ -43,8 +37,37 @@ static BOOL read_window_size(unsigned int *width, unsigned int *height) { char *cursor = buffer; char *end = buffer + bytes_read; return read && parse_dimension(&cursor, end, width) && - parse_dimension(&cursor, end, height) && *width >= 100 && - *height >= 100; + parse_dimension(&cursor, end, height) && + parse_dimension(&cursor, end, native_width) && + parse_dimension(&cursor, end, native_height) && *width >= 100 && + *height >= 100 && *native_width >= 100 && *native_height >= 100; +} + +static BOOL CALLBACK find_process_window(HWND window, LPARAM parameter) { + WindowSearch *search = (WindowSearch *)parameter; + DWORD process_id = 0; + RECT bounds; + GetWindowThreadProcessId(window, &process_id); + if (process_id != search->process_id || !IsWindowVisible(window) || + GetWindow(window, GW_OWNER) || !GetWindowRect(window, &bounds)) + return TRUE; + LONG area = (bounds.right - bounds.left) * (bounds.bottom - bounds.top); + if (area > search->area) { + search->window = window; + search->area = area; + } + return TRUE; +} + +static BOOL find_target(WCHAR *application_path, WCHAR *filename) { + static const WCHAR *targets[] = {L"sol.exe", L"freecell.exe", L"spider.exe"}; + for (unsigned int index = 0; index < sizeof(targets) / sizeof(targets[0]); + ++index) { + lstrcpyW(filename, targets[index]); + if (GetFileAttributesW(application_path) != INVALID_FILE_ATTRIBUTES) + return TRUE; + } + return FALSE; } static DWORD run(void) { @@ -62,8 +85,8 @@ static DWORD run(void) { if (!path_length || path_length == MAX_PATH) return 1; WCHAR *filename = application_path + path_length; while (filename > application_path && filename[-1] != L'\\') --filename; - if (filename == application_path) return 1; - lstrcpyW(filename, TARGET_EXECUTABLE); + if (filename == application_path || !find_target(application_path, filename)) + return 1; if (!CreateProcessW(application_path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &process)) return 1; @@ -72,17 +95,22 @@ static DWORD run(void) { while (WaitForSingleObject(process.hProcess, 50) == WAIT_TIMEOUT) { unsigned int width; unsigned int height; - HWND application = FindWindowW(NULL, TARGET_TITLE); - if (!application || !read_window_size(&width, &height)) continue; + unsigned int native_width; + unsigned int native_height; + WindowSearch search = {process.dwProcessId, NULL, 0}; + EnumWindows(find_process_window, (LPARAM)&search); + if (!search.window || + !read_window_size(&width, &height, &native_width, &native_height)) + continue; if (width == applied_width && height == applied_height) continue; if (!calibrated) { RECT bounds; - if (!GetWindowRect(application, &bounds)) continue; - width_adjustment = bounds.right - bounds.left - NATIVE_SCREEN_WIDTH; - height_adjustment = bounds.bottom - bounds.top - NATIVE_SCREEN_HEIGHT; + if (!GetWindowRect(search.window, &bounds)) continue; + width_adjustment = bounds.right - bounds.left - (int)native_width; + height_adjustment = bounds.bottom - bounds.top - (int)native_height; calibrated = TRUE; } - if (SetWindowPos(application, NULL, 0, 0, (int)width + width_adjustment, + if (SetWindowPos(search.window, NULL, 0, 0, (int)width + width_adjustment, (int)height + height_adjustment, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE)) { applied_width = width; diff --git a/native/solitaire/resize-host.c b/native/solitaire/resize-host.c deleted file mode 100644 index c126390f..00000000 --- a/native/solitaire/resize-host.c +++ /dev/null @@ -1,84 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#include - -#define SIZE_FILE L"D:\\solitaire-size.txt" -#define NATIVE_SCREEN_WIDTH 586 -#define NATIVE_SCREEN_HEIGHT 438 - -static BOOL parse_dimension(char **cursor, char *end, unsigned int *value) { - unsigned int result = 0; - while (*cursor < end && (**cursor == ' ' || **cursor == '\r' || - **cursor == '\n' || **cursor == '\t')) - ++*cursor; - if (*cursor == end || **cursor < '0' || **cursor > '9') return FALSE; - while (*cursor < end && **cursor >= '0' && **cursor <= '9') { - result = result * 10 + (unsigned int)(**cursor - '0'); - ++*cursor; - } - *value = result; - return TRUE; -} - -static BOOL read_window_size(unsigned int *width, unsigned int *height) { - char buffer[64]; - DWORD bytes_read = 0; - HANDLE file = CreateFileW(SIZE_FILE, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == INVALID_HANDLE_VALUE) return FALSE; - BOOL read = ReadFile(file, buffer, sizeof(buffer), &bytes_read, NULL); - CloseHandle(file); - char *cursor = buffer; - char *end = buffer + bytes_read; - return read && parse_dimension(&cursor, end, width) && - parse_dimension(&cursor, end, height) && *width >= 100 && - *height >= 100; -} - -static DWORD run(void) { - STARTUPINFOW startup = {0}; - PROCESS_INFORMATION process = {0}; - WCHAR solitaire_path[MAX_PATH]; - unsigned int applied_width = 0; - unsigned int applied_height = 0; - int width_adjustment = 0; - int height_adjustment = 0; - BOOL calibrated = FALSE; - - startup.cb = sizeof(startup); - DWORD path_length = GetModuleFileNameW(NULL, solitaire_path, MAX_PATH); - if (!path_length || path_length == MAX_PATH) return 1; - WCHAR *filename = solitaire_path + path_length; - while (filename > solitaire_path && filename[-1] != L'\\') --filename; - if (filename == solitaire_path) return 1; - lstrcpyW(filename, L"sol.exe"); - if (!CreateProcessW(solitaire_path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, - &startup, &process)) - return 1; - - CloseHandle(process.hThread); - while (WaitForSingleObject(process.hProcess, 50) == WAIT_TIMEOUT) { - unsigned int width; - unsigned int height; - HWND solitaire = FindWindowW(NULL, L"Solitaire"); - if (!solitaire || !read_window_size(&width, &height)) continue; - if (width == applied_width && height == applied_height) continue; - if (!calibrated) { - RECT bounds; - if (!GetWindowRect(solitaire, &bounds)) continue; - width_adjustment = bounds.right - bounds.left - NATIVE_SCREEN_WIDTH; - height_adjustment = bounds.bottom - bounds.top - NATIVE_SCREEN_HEIGHT; - calibrated = TRUE; - } - if (SetWindowPos(solitaire, NULL, 0, 0, (int)width + width_adjustment, - (int)height + height_adjustment, - SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE)) { - applied_width = width; - applied_height = height; - } - } - CloseHandle(process.hProcess); - return 0; -} - -void WinMainCRTStartup(void) { ExitProcess(run()); } diff --git a/site/apps/core/boxedwine-card-game.js b/site/apps/core/boxedwine-card-game.js new file mode 100644 index 00000000..79a12529 --- /dev/null +++ b/site/apps/core/boxedwine-card-game.js @@ -0,0 +1,39 @@ +import { defineApplication } from "./application.js"; +import { mountBoxedWineApplication } from "./boxedwine.js"; + +export const defineBoxedWineCardGame = ({ + id, + title, + icon, + archive, + width, + height, + nativeWidth = width - 6, + nativeHeight = height - 32, +}) => + defineApplication({ + id: `__${id}`, + title, + icon, + kind: "native-game", + deepLinkId: id, + offlineGameId: id, + window: { + width, + height, + fitToWorkArea: true, + resizable: true, + maximizable: true, + }, + mount: () => + mountBoxedWineApplication({ + title: `Windows XP ${title}`, + packageId: id, + archive, + executable: "resize-host.exe", + nativeWidth, + nativeHeight, + frameTop: 32, + background: "#27811f", + }), + }); diff --git a/site/apps/core/boxedwine-resize.js b/site/apps/core/boxedwine-resize.js index f0c214f4..9802aafc 100644 --- a/site/apps/core/boxedwine-resize.js +++ b/site/apps/core/boxedwine-resize.js @@ -1,12 +1,16 @@ const isResizeMessage = (event, origin) => { - const { type, width, height } = event.data || {}; + const { type, width, height, baseWidth, baseHeight } = event.data || {}; return ( event.origin === origin && type === "boxedwine-framebuffer-resize" && Number.isInteger(width) && Number.isInteger(height) && + Number.isInteger(baseWidth) && + Number.isInteger(baseHeight) && width > 0 && - height > 0 + height > 0 && + baseWidth > 0 && + baseHeight > 0 ); }; @@ -22,12 +26,15 @@ export const installBoxedWineResizeBridge = (hostWindow, module) => { typeof module.FS?.writeFile !== "function" ) return; - const { width, height } = pendingResize; - const sizePath = "/d_drive/solitaire-size.txt"; + const { width, height, baseWidth, baseHeight } = pendingResize; + const sizePath = "/d_drive/boxedwine-size.txt"; const temporaryPath = `${sizePath}.tmp`; module._boxedwine_resize_screen(width, height); - module.FS.writeFile(temporaryPath, `${width} ${height}`); + module.FS.writeFile( + temporaryPath, + `${width} ${height} ${baseWidth} ${baseHeight}`, + ); try { module.FS.unlink(sizePath); } catch { diff --git a/site/apps/core/boxedwine.js b/site/apps/core/boxedwine.js index 4b9837bc..5ceec910 100644 --- a/site/apps/core/boxedwine.js +++ b/site/apps/core/boxedwine.js @@ -110,7 +110,12 @@ export const mountBoxedWineApplication = ({ frame.style.transformOrigin = ""; } frame.contentWindow?.postMessage( - { type: "boxedwine-framebuffer-resize", ...framebuffer }, + { + type: "boxedwine-framebuffer-resize", + ...framebuffer, + baseWidth: nativeWidth, + baseHeight: nativeHeight + frameTop, + }, new URL(frame.src).origin, ); }; diff --git a/site/apps/solitaire/index.js b/site/apps/solitaire/index.js index 57e7b507..1d6b303d 100644 --- a/site/apps/solitaire/index.js +++ b/site/apps/solitaire/index.js @@ -1,32 +1,12 @@ -import { mountBoxedWineApplication } from "../core/boxedwine.js"; -import { defineApplication } from "../core/application.js"; +import { defineBoxedWineCardGame } from "../core/boxedwine-card-game.js"; -const mountSolitaire = () => - mountBoxedWineApplication({ - title: "Windows XP Solitaire", - packageId: "solitaire", - archive: "xp-solitaire", - executable: "resize-host.exe", - nativeWidth: 586, - nativeHeight: 406, - frameTop: 32, - background: "#27811f", - }); - -export const solitaireApplication = defineApplication({ - id: "__solitaire", +export const solitaireApplication = defineBoxedWineCardGame({ + id: "solitaire", title: "Solitaire", icon: "Solitaire.png", - kind: "native-game", - deepLinkId: "solitaire", - offlineGameId: "solitaire", - window: { - width: 592, - height: 438, - className: "xp-native-solitaire-window", - fitToWorkArea: true, - resizable: true, - maximizable: true, - }, - mount: mountSolitaire, + archive: "xp-solitaire", + width: 592, + height: 438, + nativeWidth: 586, + nativeHeight: 406, }); diff --git a/site/apps/xp-card-games/index.js b/site/apps/xp-card-games/index.js index 6f812f78..c778f2b2 100644 --- a/site/apps/xp-card-games/index.js +++ b/site/apps/xp-card-games/index.js @@ -1,45 +1,7 @@ -import { defineApplication } from "../core/application.js"; -import { mountBoxedWineApplication } from "../core/boxedwine.js"; - -const defineXpCardGame = ({ - id, - title, - icon, - archive, - width, - height, - nativeWidth = width - 6, - nativeHeight = height - 31, -}) => - defineApplication({ - id: `__${id}`, - title, - icon, - kind: "native-game", - deepLinkId: id, - offlineGameId: id, - window: { - width, - height, - fitToWorkArea: true, - resizable: true, - maximizable: true, - }, - mount: () => - mountBoxedWineApplication({ - title: `Windows XP ${title}`, - packageId: id, - archive, - executable: "resize-host.exe", - nativeWidth, - nativeHeight, - frameTop: 32, - background: "#27811f", - }), - }); +import { defineBoxedWineCardGame } from "../core/boxedwine-card-game.js"; export const xpCardGameApplications = [ - defineXpCardGame({ + defineBoxedWineCardGame({ id: "freecell", title: "FreeCell", icon: "FreeCell.png", @@ -49,12 +11,13 @@ export const xpCardGameApplications = [ nativeWidth: 640, nativeHeight: 448, }), - defineXpCardGame({ + defineBoxedWineCardGame({ id: "spider-solitaire", title: "Spider Solitaire", icon: "SpiderSolitaire.png", archive: "xp-spider-solitaire", width: 800, height: 600, + nativeHeight: 569, }), ]; diff --git a/site/iframe/freecell/SOURCES.json b/site/iframe/freecell/SOURCES.json index 677e55bf..9c3f055c 100644 --- a/site/iframe/freecell/SOURCES.json +++ b/site/iframe/freecell/SOURCES.json @@ -5,8 +5,8 @@ "sourceSha256": "fd8c8d42c1581e8767217fe800bfc0d5649c0ad20d754c927d6c763e446d1927", "package": { "file": "xp-freecell.zip", - "bytes": 178462, - "sha256": "048b03721fd9205387274e24c095a21344b1cf97cb3b03d08dd496372a9ee6a7" + "bytes": 178720, + "sha256": "11262b2bd42a0da786a0ef8facf61c9395bea97768285da2529a27bef14c3252" }, "files": { "freecell.exe": { @@ -18,9 +18,9 @@ "sha256": "0fb81e48d8b45e9995ae1e05fd28c1631dbbcdc71180904c1356bfa2c1ead506" }, "resize-host.exe": { - "source": "native/xp-card-games/resize-host.c", - "build": "i686-w64-mingw32-gcc -Os -s -nostdlib -mwindows -DRESIZE_FREECELL native/xp-card-games/resize-host.c -lkernel32 -luser32 -o resize-host.exe", - "sha256": "ad94b439cc8bc9e18e00ee9332f558c347773f66e97dcefb2548346b9d6f4426" + "source": "native/boxedwine/resize-host.c", + "build": "i686-w64-mingw32-gcc -Os -s -nostdlib -mwindows native/boxedwine/resize-host.c -lkernel32 -luser32 -o resize-host.exe", + "sha256": "adf6e0075ed512a40eaa06ec9f0389f1777e0b885153a4fc1b9eedf070426f5c" } } } diff --git a/site/iframe/freecell/xp-freecell.zip b/site/iframe/freecell/xp-freecell.zip index 541ea1601fbedcaf5f77a83d456fa6fb4fe7515a..6bddd38653941e50d186a72b0e46e8adb9ffbf01 100644 GIT binary patch delta 1600 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 diff --git a/site/iframe/solitaire/SOURCES.json b/site/iframe/solitaire/SOURCES.json index 424dbc4c..ce0b2564 100644 --- a/site/iframe/solitaire/SOURCES.json +++ b/site/iframe/solitaire/SOURCES.json @@ -5,8 +5,8 @@ "sourceSha256": "fd8c8d42c1581e8767217fe800bfc0d5649c0ad20d754c927d6c763e446d1927", "package": { "file": "xp-solitaire.zip", - "bytes": 177971, - "sha256": "074945b324b42c105146f309f2fe55744ea719acfdb42cdddc32b0857b28b802" + "bytes": 178239, + "sha256": "d4ba31c630b08b478a60bee49630e6b4fc449ed0a168ca3d4a2bda1c89c4216c" }, "files": { "sol.exe": { @@ -18,9 +18,9 @@ "sha256": "0fb81e48d8b45e9995ae1e05fd28c1631dbbcdc71180904c1356bfa2c1ead506" }, "resize-host.exe": { - "source": "native/solitaire/resize-host.c", - "build": "i686-w64-mingw32-gcc -Os -s -nostdlib -mwindows native/solitaire/resize-host.c -lkernel32 -luser32 -o resize-host.exe", - "sha256": "1d2bee7b669f10d2af97e2670fcdabedb3c060f45a68e2eed4285adea23f3727" + "source": "native/boxedwine/resize-host.c", + "build": "i686-w64-mingw32-gcc -Os -s -nostdlib -mwindows native/boxedwine/resize-host.c -lkernel32 -luser32 -o resize-host.exe", + "sha256": "adf6e0075ed512a40eaa06ec9f0389f1777e0b885153a4fc1b9eedf070426f5c" } } } diff --git a/site/iframe/solitaire/xp-solitaire.zip b/site/iframe/solitaire/xp-solitaire.zip index e23918ff012ecf8973ec5a5d9590cf31cc113c20..2ba1aaa2693eb32324af662b409e952edb2c21bf 100644 GIT binary patch delta 1637 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 D`Rw`V delta 1349 zcmV-L1-kl#%n*Uf5P*aMgaU*Ev;=b>4s;C-U6W#Sh~NYO000h`fgc1Ge^y^iTU8kU z+Foa=-P(k*p~37f=>yZO_LgY|VM!eYmW)581*#KuU3(p!rES_<=yWD558Hz?Fi70QEE}lxJLeW?hQY-cj0s=zoqNvr=lA`- zbI<+Ld~_Ie0KlQ<^8llue~J_SUiwjY?7p-EJ}N&nKWKBMV_tBHr5L^uDF zWEj#bZCCo2N_sgVe>eYxFolti59tS+7t?e0{(B{T=2xc-rmvb8FF*%yAM)_RIbTsrmM#j##hp*e?PjU()6r${#NyL(!lD^ zeL?YERt|V42zdtaCPFAOEz{XaTvn^X%HxbDr>zyJ<){`^GpZ3)kIIn>Oii)sm011# zjNFA;!Vkh71{y<88yRs?q>)-S9$5f9T6h$PwAC(ky4;mVRKJndy53twy?4Iw*9D@8}86dH@mgWfCJ@LB3Ak z&6@@m(I?~;70hU*Z7SJr6`5f;DIRTDv7Z>PB16L6{ouwNL$!4~&SltUvE6$IdC57CN99apnvpCax5>4+v+O>^(C{S7 z-}e}97?J6X%E%HkhpG8_Ej81-h#OMAlV#Pe*3*0=e2XzLg%_Twoe{VTfWE)1?dHec2Dj%Z#Gt?aF6zX-< zJE&UBDHqfjD_$L_hlGEga}Mgl(S&%|9|?vfNe~Rhz_SOEy{l z1W-!>0v-bt00ICA08=fFI1NX;06`xFmyjg{Ee>=I4PBFBbBN#s0000Em&+vtGX{1f H1ONa4$Q*HC diff --git a/tests/solitaire.test.ts b/tests/solitaire.test.ts index 2324de6e..bc4d0aed 100644 --- a/tests/solitaire.test.ts +++ b/tests/solitaire.test.ts @@ -192,6 +192,8 @@ describe("Windows XP Solitaire through BoxedWine", () => { type: "boxedwine-framebuffer-resize", width: 1372, height: 844, + baseWidth: 586, + baseHeight: 438, }, origin: new URL(frame.src).origin, }); @@ -206,6 +208,8 @@ describe("Windows XP Solitaire through BoxedWine", () => { type: "boxedwine-framebuffer-resize", width: 586, height: 438, + baseWidth: 586, + baseHeight: 438, }, origin: new URL(frame.src).origin, }); @@ -225,6 +229,8 @@ describe("Windows XP Solitaire through BoxedWine", () => { type: "boxedwine-framebuffer-resize", width: 586, height: 438, + baseWidth: 586, + baseHeight: 438, }, origin: new URL(frame.src).origin, }); @@ -256,6 +262,8 @@ describe("Windows XP Solitaire through BoxedWine", () => { type: "boxedwine-framebuffer-resize", width: 1372, height: 844, + baseWidth: 586, + baseHeight: 438, }, }); module._boxedwine_resize_screen = (width, height) => @@ -274,7 +282,7 @@ describe("Windows XP Solitaire through BoxedWine", () => { }; module.onRuntimeInitialized(); expect(resizeCalls).toEqual([{ width: 1372, height: 844 }]); - expect(files.get("/d_drive/solitaire-size.txt")).toBe("1372 844"); + expect(files.get("/d_drive/boxedwine-size.txt")).toBe("1372 844 586 438"); messageListener({ origin: "https://flash.test", @@ -282,10 +290,12 @@ describe("Windows XP Solitaire through BoxedWine", () => { type: "boxedwine-framebuffer-resize", width: 586, height: 438, + baseWidth: 586, + baseHeight: 438, }, }); expect(resizeCalls.at(-1)).toEqual({ width: 586, height: 438 }); - expect(files.get("/d_drive/solitaire-size.txt")).toBe("586 438"); + expect(files.get("/d_drive/boxedwine-size.txt")).toBe("586 438 586 438"); messageListener({ origin: "https://other.test", diff --git a/tests/xp-card-games.test.ts b/tests/xp-card-games.test.ts index 6893d87d..f991db8f 100644 --- a/tests/xp-card-games.test.ts +++ b/tests/xp-card-games.test.ts @@ -122,6 +122,8 @@ describe("Windows XP card games through BoxedWine", () => { type: "boxedwine-framebuffer-resize", width: nativeWidth, height: nativeHeight + 32, + baseWidth: nativeWidth, + baseHeight: nativeHeight + 32, }); Object.defineProperties(desktop, { @@ -146,6 +148,8 @@ describe("Windows XP card games through BoxedWine", () => { type: "boxedwine-framebuffer-resize", width: 1018, height: 739, + baseWidth: nativeWidth, + baseHeight: nativeHeight + 32, }); }); @@ -165,6 +169,15 @@ describe("Windows XP card games through BoxedWine", () => { for (const [name, source] of Object.entries(manifest.windowsXp.files)) { expect(sha256(files[name])).toBe(source.sha256); } + const solitaireManifest = JSON.parse( + await readFile( + join(projectDirectory, "site", "iframe", "solitaire", "SOURCES.json"), + "utf8", + ), + ); + expect(manifest.windowsXp.files["resize-host.exe"].sha256).toBe( + solitaireManifest.windowsXp.files["resize-host.exe"].sha256, + ); }); } });