diff --git a/Makefile b/Makefile index 1005c41..d15c6d4 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ package: .PHONY: runx runx: - ./src/main/shell/run-electron-app-in-xorg + IMGFLOAT_CHANNELS_URL=http://localhost:8080/channels ./src/main/shell/run-electron-app-in-xorg .PHONY: ssl ssl: diff --git a/src/main/node/app.js b/src/main/node/app.js index adfb490..5aca1c4 100644 --- a/src/main/node/app.js +++ b/src/main/node/app.js @@ -1,8 +1,9 @@ const { app, BrowserWindow } = require("electron"); const path = require("path"); +let broadcastRect = { width: 0, height: 0 }; function createWindow() { - const url = "https://imgfloat.kruhlmann.dev/channels"; + const url = process.env["IMGFLOAT_CHANNELS_URL"] || "https://imgfloat.kruhlmann.dev/channels"; const initialWindowWidthPx = 960; const initialWindowHeightPx = 640; const applicationWindow = new BrowserWindow({ @@ -27,31 +28,30 @@ function createWindow() { const lockWindowToCanvas = async () => { if (applicationWindow.isDestroyed()) { - return false; + return; } - try { - const size = await applicationWindow.webContents.executeJavaScript(`(() => { - const canvas = document.getElementById('broadcast-canvas'); - if (!canvas || !canvas.width || !canvas.height) { - return null; - } - return { width: Math.round(canvas.width), height: Math.round(canvas.height) }; - })();`); - - if (size?.width && size?.height) { - const [currentWidth, currentHeight] = applicationWindow.getSize(); - if (currentWidth !== size.width || currentHeight !== size.height) { - applicationWindow.setSize(size.width, size.height, false); - } - applicationWindow.setMinimumSize(size.width, size.height); - applicationWindow.setMaximumSize(size.width, size.height); - applicationWindow.setResizable(false); - return true; + const size = await applicationWindow.webContents.executeJavaScript(`(() => { + const canvas = document.getElementById('broadcast-canvas'); + if (!canvas) { + return null; + } + const rect = canvas.getBoundingClientRect(); + return { + width: Math.round(rect.width), + height: Math.round(rect.height), + }; + })();`); + + if (size?.width && size?.height) { + if (broadcastRect.width !== size.width || broadcastRect.height !== size.height) { + console.log( + `Window size did not match canvas old: ${broadcastRect.width}x${broadcastRect.height} new: ${size.width}x${size.height}. Resizing.`, + ); + applicationWindow.setContentSize(size.width, size.height, false); + applicationWindow.setResizable(false); + broadcastRect = { ...size }; } - } catch (error) { - // Best-effort sizing; ignore errors from early navigation states. } - return false; }; const handleNavigation = (navigationUrl) => { @@ -65,9 +65,6 @@ function createWindow() { lockWindowToCanvas(); } else { clearCanvasSizeInterval(); - applicationWindow.setResizable(true); - applicationWindow.setMinimumSize(320, 240); - applicationWindow.setMaximumSize(10000, 10000); applicationWindow.setSize(initialWindowWidthPx, initialWindowHeightPx, false); } } catch { diff --git a/src/main/resources/static/css/styles.css b/src/main/resources/static/css/styles.css index 57ed61e..a65c876 100644 --- a/src/main/resources/static/css/styles.css +++ b/src/main/resources/static/css/styles.css @@ -1103,11 +1103,6 @@ button:disabled:hover { } .broadcast-body canvas { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; pointer-events: none; } diff --git a/src/main/resources/static/js/broadcast.js b/src/main/resources/static/js/broadcast.js index 0340c13..17bc30f 100644 --- a/src/main/resources/static/js/broadcast.js +++ b/src/main/resources/static/js/broadcast.js @@ -154,15 +154,6 @@ function fetchCanvasSettings() { } function resizeCanvas() { - const scale = Math.min(window.innerWidth / canvasSettings.width, window.innerHeight / canvasSettings.height); - const displayWidth = canvasSettings.width * scale; - const displayHeight = canvasSettings.height * scale; - canvas.width = canvasSettings.width; - canvas.height = canvasSettings.height; - canvas.style.width = `${displayWidth}px`; - canvas.style.height = `${displayHeight}px`; - canvas.style.left = `${(window.innerWidth - displayWidth) / 2}px`; - canvas.style.top = `${(window.innerHeight - displayHeight) / 2}px`; draw(); } @@ -279,8 +270,8 @@ function applyPatch(assetId, patch) { const targetLayer = Number.isFinite(patch.layer) ? patch.layer : Number.isFinite(patch.zIndex) - ? patch.zIndex - : null; + ? patch.zIndex + : null; if (!isAudio && Number.isFinite(targetLayer)) { const currentOrder = getLayerOrder().filter((id) => id !== assetId); const insertIndex = Math.max(0, currentOrder.length - Math.round(targetLayer)); @@ -773,7 +764,7 @@ function setVideoSource(element, asset) { } applyVideoSource(element, next.objectUrl, asset); }) - .catch(() => {}); + .catch(() => { }); } function applyVideoSource(element, objectUrl, asset) { diff --git a/src/main/shell/run-electron-app-in-xorg b/src/main/shell/run-electron-app-in-xorg index 5fa24e8..8795c40 100755 --- a/src/main/shell/run-electron-app-in-xorg +++ b/src/main/shell/run-electron-app-in-xorg @@ -18,14 +18,14 @@ done echo "Using DISPLAY=:$DISP" -Xephyr ":$DISP" -screen "$SCREEN" -resizeable -ac & -XEPHYR_PID=$! - cleanup() { kill "$ELECTRON_PID" "$OPENBOX_PID" "$XEPHYR_PID" 2>/dev/null || true } trap cleanup EXIT INT TERM +Xephyr ":$DISP" -screen "$SCREEN" -resizeable -ac & +XEPHYR_PID=$! + sleep 1 DISPLAY=":$DISP" openbox & @@ -35,12 +35,23 @@ sleep 0.5 DISPLAY=":$DISP" electron "$APP_ENTRY" & ELECTRON_PID=$! +DISPLAY=":$DISP" xsetroot -solid "#009999" + +while :; do + if ! kill -0 "$ELECTRON_PID" 2>/dev/null; then + echo "Electron exited — killing Xephyr" + kill "$XEPHYR_PID" 2>/dev/null || true + break + fi + + if ! kill -0 "$XEPHYR_PID" 2>/dev/null; then + echo "Xephyr exited — killing Electron" + kill "$ELECTRON_PID" 2>/dev/null || true + break + fi -# monitor X server — when it dies, kill Electron -while kill -0 "$XEPHYR_PID" 2>/dev/null; do sleep 0.5 done -echo "Xephyr exited — killing Electron" -kill "$ELECTRON_PID" 2>/dev/null || true wait "$ELECTRON_PID" 2>/dev/null || true +wait "$XEPHYR_PID" 2>/dev/null || true