Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e531228fa9 | ||
|
|
d1cebec142 | ||
|
|
3c4d3e7216 | ||
|
|
e697638827 | ||
|
|
1306a88b0e |
@@ -46,8 +46,9 @@ export class DockerDriver implements Driver {
|
||||
`PUID=${uid}`,
|
||||
`PGID=${gid}`,
|
||||
`SUBFOLDER=${streamPath(id)}`,
|
||||
`SELKIES_MANUAL_WIDTH=${size.width}`,
|
||||
`SELKIES_MANUAL_HEIGHT=${size.height}`,
|
||||
// The game's size, rounded up to even for H.264
|
||||
`SELKIES_MANUAL_WIDTH=${size.width + (size.width % 2)}`,
|
||||
`SELKIES_MANUAL_HEIGHT=${size.height + (size.height % 2)}`,
|
||||
'SELKIES_UI_SHOW_SIDEBAR=false',
|
||||
'HARDEN_DESKTOP=true',
|
||||
'RESTART_APP=true',
|
||||
|
||||
@@ -59,7 +59,7 @@ export class GameCatalog {
|
||||
return null;
|
||||
}
|
||||
const page = await this.readContent(gameId, row, row.cmd).catch(() => null);
|
||||
return even((page && appletSize(page.toString('latin1'))) ?? DEFAULT_SIZE);
|
||||
return ((page && appletSize(page.toString('latin1'))) ?? DEFAULT_SIZE);
|
||||
}
|
||||
const program = await this.launchProgram(row);
|
||||
if (!program) {
|
||||
@@ -68,19 +68,19 @@ export class GameCatalog {
|
||||
const url = row.cmd.match(/https?:\/\/[^\s"']+/)?.[0];
|
||||
if (!url) {
|
||||
const exe = await readFile(program).catch(() => null);
|
||||
return even((exe && projectorStageSize(exe)) ?? DEFAULT_SIZE);
|
||||
return ((exe && projectorStageSize(exe)) ?? DEFAULT_SIZE);
|
||||
}
|
||||
const content = await this.readContent(gameId, row, url).catch(() => null);
|
||||
const extension = path.extname(new URL(url).pathname).toLowerCase();
|
||||
if (['.dcr', '.dir', '.dxr', '.cct', '.cst'].includes(extension)) {
|
||||
return even((content && directorStageSize(content)) ?? DEFAULT_SIZE);
|
||||
return ((content && directorStageSize(content)) ?? DEFAULT_SIZE);
|
||||
}
|
||||
if (extension === '.swf') {
|
||||
// The exact stage: in full screen, games that set noScale keep their native size
|
||||
return even((content && swfStageSize(content)) ?? DEFAULT_SIZE);
|
||||
// The exact stage, so the movie fills the display without scaling
|
||||
return ((content && swfStageSize(content)) ?? DEFAULT_SIZE);
|
||||
}
|
||||
const embed = content && embedSize(content.toString('latin1'));
|
||||
return even(embed ? { width: embed.width + 2 * PAGE_MARGIN, height: embed.height + 2 * PAGE_MARGIN } : BROWSER_SIZE);
|
||||
return (embed ? { width: embed.width + 2 * PAGE_MARGIN, height: embed.height + 2 * PAGE_MARGIN } : BROWSER_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,11 +151,6 @@ async function resolveCaseInsensitive(root: string, relative: string): Promise<s
|
||||
return (await stat(current).catch(() => null))?.isFile() ? current : null;
|
||||
}
|
||||
|
||||
/** H.264 needs even dimensions. */
|
||||
function even({ width, height }: Size): Size {
|
||||
return { width: width + (width % 2), height: height + (height % 2) };
|
||||
}
|
||||
|
||||
/** Reads the stage size from a SWF header: a rect of twips after the 8-byte header. */
|
||||
export function swfStageSize(swf: Buffer): Size | null {
|
||||
const signature = swf.toString('latin1', 0, 3);
|
||||
|
||||
@@ -177,11 +177,11 @@ test('GameCatalog streams allowed platforms whose launcher resolves, sized from
|
||||
legacy: { width: 300, height: 200 },
|
||||
missing: { width: 800, height: 600 },
|
||||
webstart: null,
|
||||
spr: { width: 500, height: 426 },
|
||||
oldcpu: { width: 500, height: 426 },
|
||||
spr: { width: 500, height: 425 },
|
||||
oldcpu: { width: 500, height: 425 },
|
||||
secure: { width: 640, height: 480 },
|
||||
navigator: { width: 528, height: 400 },
|
||||
flash: { width: 500, height: 376 },
|
||||
flash: { width: 500, height: 375 },
|
||||
unity: null,
|
||||
'no-program': null,
|
||||
exe: { width: 800, height: 600 },
|
||||
|
||||
@@ -30,6 +30,7 @@ RUN apt-get update && \
|
||||
libxtst6 \
|
||||
libxxf86vm1 \
|
||||
sqlite3 \
|
||||
x11-utils \
|
||||
xdotool && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@ writable mirror of the install, since they write beside themselves; a
|
||||
Director projector's `Prefs`, where it saves, is linked into `/config/saves`, as
|
||||
is Flash Player's save directory, so the session manager syncs both to the
|
||||
player's browser. OldCPUSimulator hangs under Wine, so its target runs under
|
||||
`cpulimit` at the same share of the CPU. Flash projectors switch to full screen,
|
||||
which hides their menu bar and scales the movie to the display, and Flashpoint
|
||||
Navigator's toolbars are hidden.
|
||||
`cpulimit` at the same share of the CPU. A Flash projector's window is
|
||||
stretched to the display and moved up by its menu bar's height, which hides the
|
||||
menu bar. GTK draws the menu bar in the window itself and the movie in a child
|
||||
window below it, so the movie's offset, read with `xwininfo`, is the menu bar's
|
||||
height. The window is made override-redirect first, since the window manager
|
||||
keeps windows on screen, and is kept in place while it's open, since Flash
|
||||
Player moves it back once the movie has loaded. Its full-screen mode isn't used, since some games, such
|
||||
as Bloons, don't play right in it. Flashpoint Navigator's toolbars are hidden.
|
||||
|
||||
@@ -47,8 +47,42 @@ case ${app,,} in
|
||||
mkdir -p "$HOME/saves/Flash_Player" "$HOME/.macromedia"
|
||||
[[ -e $HOME/.macromedia/Flash_Player ]] || ln -s "$HOME/saves/Flash_Player" "$HOME/.macromedia/Flash_Player"
|
||||
if [[ ${app,,} == 'fpsoftware\flash\'* ]]; then
|
||||
# Full screen hides the projector's menu bar and scales the movie to the display
|
||||
(xdotool search --sync --onlyvisible --name 'Flash Player' windowactivate --sync key ctrl+f) &
|
||||
# Hide the projector's menu bar by moving it above the display, and fill
|
||||
# the display with the movie. Not full screen, which some games, such as
|
||||
# Bloons, don't play right in. The window manager keeps windows on
|
||||
# screen, so the window is taken out of its hands first.
|
||||
(
|
||||
set +eo pipefail
|
||||
wid=$(xdotool search --sync --onlyvisible --name 'Flash Player' | head -1)
|
||||
read -r width height < <(xdotool getdisplaygeometry)
|
||||
# GTK draws the menu bar in the window itself, and the movie in the
|
||||
# largest child window, below it: the movie's offset is the menu bar's height
|
||||
menu=$(xwininfo -children -id "$wid" | awk '
|
||||
match($0, /[0-9]+x[0-9]+\+-?[0-9]+\+-?[0-9]+/) {
|
||||
split(substr($0, RSTART, RLENGTH), g, /[x+]/)
|
||||
if (g[1] * g[2] > area) { area = g[1] * g[2]; top = g[4] }
|
||||
}
|
||||
END { print top + 0 }')
|
||||
((menu >= 0 && menu < height)) || menu=0
|
||||
echo "Flash Player window $wid: menu bar ${menu}px, display ${width}x${height}"
|
||||
xdotool windowunmap --sync "$wid"
|
||||
xdotool set_window --overrideredirect 1 "$wid"
|
||||
xdotool windowmap --sync "$wid"
|
||||
place() { xdotool windowsize "$wid" "$width" $((height + menu)) windowmove "$wid" 0 $((-menu)); }
|
||||
place
|
||||
xdotool windowfocus "$wid"
|
||||
# Flash Player moves its window back once the movie has loaded, so it's
|
||||
# kept in place for as long as it's open
|
||||
moves=0
|
||||
while geometry=$(xdotool getwindowgeometry --shell "$wid" 2>/dev/null); do
|
||||
eval "$geometry"
|
||||
if ((X != 0 || Y != -menu || WIDTH != width || HEIGHT != height + menu)); then
|
||||
((++moves <= 3)) && echo "Flash Player window moved to $X,$Y (${WIDTH}x${HEIGHT}); putting it back"
|
||||
place
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
) &
|
||||
fi
|
||||
cd "${argv[0]}"
|
||||
exec "${argv[@]:1}" ;;
|
||||
|
||||
Reference in New Issue
Block a user