Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions native/xp-card-games/resize-host.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#define SIZE_FILE L"D:\\solitaire-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

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 application_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, application_path, MAX_PATH);
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 (!CreateProcessW(application_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 application = FindWindowW(NULL, TARGET_TITLE);
if (!application || !read_window_size(&width, &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;
calibrated = TRUE;
}
if (SetWindowPos(application, 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()); }
6 changes: 3 additions & 3 deletions site/apps/catalog/accessories.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const accessoryApplications = [
program("__calculator", "Calculator", "Calculator.png", "calculator", {
window: {
width: 260,
height: 259,
height: 260,
resizable: false,
maximizable: false,
className: "xp-calculator-window",
Expand All @@ -24,8 +24,8 @@ export const accessoryApplications = [
height: 338,
left: 24,
top: 30,
resizable: false,
maximizable: false,
resizable: true,
maximizable: true,
className: "xp-command-prompt-window",
},
},
Expand Down
4 changes: 4 additions & 0 deletions site/apps/programs/renderers/terminal.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export const renderTerminal = (context, program, programId) => {
screen.scrollTop = screen.scrollHeight;
});
screen.addEventListener("pointerdown", () => input.focus());
context.windowElement.addEventListener("pointerdown", (event) => {
if (event.target.closest(".title-buttons, .resize-handle")) return;
setTimeout(() => input.focus(), 0);
});
setTimeout(() => input.focus(), 0);
return content;
};
10 changes: 3 additions & 7 deletions site/apps/xp-card-games/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const defineXpCardGame = ({
title,
icon,
archive,
executable,
width,
height,
nativeWidth = width - 6,
Expand All @@ -23,20 +22,19 @@ const defineXpCardGame = ({
width,
height,
fitToWorkArea: true,
resizable: false,
maximizable: false,
resizable: true,
maximizable: true,
},
mount: () =>
mountBoxedWineApplication({
title: `Windows XP ${title}`,
packageId: id,
archive,
executable,
executable: "resize-host.exe",
nativeWidth,
nativeHeight,
frameTop: 32,
background: "#27811f",
scaleOnly: true,
}),
});

Expand All @@ -46,7 +44,6 @@ export const xpCardGameApplications = [
title: "FreeCell",
icon: "FreeCell.png",
archive: "xp-freecell",
executable: "freecell.exe",
width: 646,
height: 479,
nativeWidth: 640,
Expand All @@ -57,7 +54,6 @@ export const xpCardGameApplications = [
title: "Spider Solitaire",
icon: "SpiderSolitaire.png",
archive: "xp-spider-solitaire",
executable: "spider.exe",
width: 800,
height: 600,
}),
Expand Down
88 changes: 64 additions & 24 deletions site/css/shell/themes.css
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ html[data-xp-appearance="classic"] .start-program-flyout button:focus-visible {

.xp-calculator-window {
min-width: min(260px, calc(100% - 8px));
min-height: min(259px, calc(100% - 8px));
min-height: min(260px, calc(100% - 8px));
}

.xp-native-calculator {
Expand All @@ -714,7 +714,7 @@ html[data-xp-appearance="classic"] .start-program-flyout button:focus-visible {
z-index: 3;
display: flex;
height: 21px;
padding-left: 1px;
padding-left: 0;
background: #ece9d8;
}

Expand All @@ -723,13 +723,23 @@ html[data-xp-appearance="classic"] .start-program-flyout button:focus-visible {
}

.xp-calculator-menu-trigger {
box-sizing: border-box;
height: 21px;
padding: 1px 6px 2px;
padding: 1px 3px 2px;
border: 1px solid transparent;
background: transparent;
color: #000;
}

.xp-calculator-menu-group:nth-child(1) .xp-calculator-menu-trigger {
width: 30px;
}

.xp-calculator-menu-group:nth-child(2) .xp-calculator-menu-trigger,
.xp-calculator-menu-group:nth-child(3) .xp-calculator-menu-trigger {
width: 34px;
}

.xp-calculator-menu-trigger:hover,
.xp-calculator-menu-trigger[aria-expanded="true"] {
border-color: #316ac5;
Expand Down Expand Up @@ -786,14 +796,19 @@ html[data-xp-appearance="classic"] .start-program-flyout button:focus-visible {
}

.xp-calculator-body {
padding: 3px 6px 6px;
position: relative;
height: 209px;
padding: 0;
}

.xp-calculator-display {
box-sizing: border-box;
width: 100%;
position: absolute;
top: 0;
left: 7px;
width: 239px;
height: 23px;
margin: 0 0 13px;
margin: 0;
padding: 2px 4px;
border: 1px solid #7f9db9;
border-radius: 0;
Expand All @@ -806,37 +821,55 @@ html[data-xp-appearance="classic"] .start-program-flyout button:focus-visible {
}

.xp-calculator-clear-row {
display: grid;
grid-template-columns: 34px 61px 60px 60px;
gap: 5px;
margin-bottom: 6px;
position: absolute;
top: 36px;
left: 11px;
width: 234px;
height: 28px;
}

.xp-calculator-clear-row .xp-calculator-memory-indicator {
box-sizing: border-box;
width: 26px;
height: 26px;
margin-left: 4px;
height: 27px;
margin: 1px 0 0;
border: 1px solid;
border-color: #7f7f7f #fff #fff #7f7f7f;
color: #d00000;
color: #f00;
text-align: center;
font:
11px/24px Tahoma,
sans-serif;
}

.xp-calculator-clear-row button {
position: absolute;
top: 0;
width: 61px;
height: 28px;
}

.xp-calculator-clear-row button:nth-of-type(1) {
left: 43px;
}

.xp-calculator-clear-row button:nth-of-type(2) {
left: 108px;
}

.xp-calculator-clear-row button:nth-of-type(3) {
left: 173px;
}

.xp-calculator-clear-row button,
.xp-calculator-keys button {
box-sizing: border-box;
height: 27px;
padding: 1px 2px;
border: 1px solid #003c74;
border-radius: 3px;
background: #ece9d8;
box-shadow:
inset 1px 1px #fff,
inset -1px -1px #aca899;
background: linear-gradient(180deg, #fff, #f7f6f1 8%, #ece9d8 88%, #d6d0c4);
box-shadow: inset 1px 1px #fff;
}

.xp-calculator-clear-row button:active,
Expand All @@ -847,27 +880,34 @@ html[data-xp-appearance="classic"] .start-program-flyout button:focus-visible {
}

.xp-calculator-clear-row button {
color: #d00000;
color: #f00;
}

.xp-calculator-keys {
position: absolute;
top: 72px;
left: 9px;
display: grid;
grid-template-columns: repeat(6, 34px);
gap: 6px 5px;
grid-template-columns: 39px repeat(5, 34px);
gap: 6px;
}

.xp-calculator-keys button {
width: 34px;
}

.xp-calculator-keys button[data-key-type="number"] {
color: #0000d0;
color: #00f;
}

.xp-calculator-keys button[data-key-type="operator"],
.xp-calculator-keys button[data-key-type="memory"] {
color: #d00000;
color: #f00;
}

.xp-command-prompt-window {
min-width: min(668px, calc(100% - 8px));
min-height: min(338px, calc(100% - 8px));
min-width: min(320px, calc(100% - 8px));
min-height: min(180px, calc(100% - 8px));
}

.xp-command-prompt-window .window-content,
Expand Down
9 changes: 7 additions & 2 deletions site/iframe/freecell/SOURCES.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"sourceSha256": "fd8c8d42c1581e8767217fe800bfc0d5649c0ad20d754c927d6c763e446d1927",
"package": {
"file": "xp-freecell.zip",
"bytes": 177107,
"sha256": "a450542c141eab60dec0ff0611ef2c4ab6a1e2a03c090a81d3769d5ad92f1348"
"bytes": 178462,
"sha256": "048b03721fd9205387274e24c095a21344b1cf97cb3b03d08dd496372a9ee6a7"
},
"files": {
"freecell.exe": {
Expand All @@ -16,6 +16,11 @@
"cards.dll": {
"member": "I386/CARDS.DL_",
"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"
}
}
}
Expand Down
Binary file modified site/iframe/freecell/xp-freecell.zip
Binary file not shown.
9 changes: 7 additions & 2 deletions site/iframe/spider-solitaire/SOURCES.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
"sourceSha256": "fd8c8d42c1581e8767217fe800bfc0d5649c0ad20d754c927d6c763e446d1927",
"package": {
"file": "xp-spider-solitaire.zip",
"bytes": 270263,
"sha256": "ba3b5323193d91fcf5d32a2985e5e162881452228f9664b69f597b18de7dd70a"
"bytes": 271617,
"sha256": "950bc7a733a96cbc4cdc222e394f4aea8fe710c343a2857bf8b5460422ce5112"
},
"files": {
"spider.exe": {
"member": "I386/SPIDER.EX_",
"sha256": "d309a839843ccd8b9edef7a271a611eb7794f83a825b69a87cc259c9ede87288"
},
"resize-host.exe": {
"source": "native/xp-card-games/resize-host.c",
"build": "i686-w64-mingw32-gcc -Os -s -nostdlib -mwindows -DRESIZE_SPIDER_SOLITAIRE native/xp-card-games/resize-host.c -lkernel32 -luser32 -o resize-host.exe",
"sha256": "a54053947fc3cfda0ded2832b307d3ae075921b19efd4afefefd54006d84f3a5"
}
}
}
Expand Down
Binary file modified site/iframe/spider-solitaire/xp-spider-solitaire.zip
Binary file not shown.
Loading