From 4ffee1d04b53b85a6bfbcfe3ccb2303b0c4b0747 Mon Sep 17 00:00:00 2001 From: Kush Makkapati Date: Thu, 18 Sep 2025 07:21:06 +0100 Subject: [PATCH 1/4] Start resolving build issues with multiple html files --- gcs/electron/modules/webcam.ts | 136 ++++++++++++++++++--------------- gcs/package.json | 5 +- gcs/tsconfig.node.json | 2 +- gcs/vite.config.mts | 43 +++++++++++ gcs/vite.config.ts | 25 ------ 5 files changed, 123 insertions(+), 88 deletions(-) create mode 100644 gcs/vite.config.mts delete mode 100644 gcs/vite.config.ts diff --git a/gcs/electron/modules/webcam.ts b/gcs/electron/modules/webcam.ts index 4d0451135..f00f97628 100644 --- a/gcs/electron/modules/webcam.ts +++ b/gcs/electron/modules/webcam.ts @@ -1,5 +1,5 @@ -import path from "path"; -import { BrowserWindow, ipcMain } from "electron"; +import { BrowserWindow, ipcMain } from "electron" +import path from "path" let webcamPopoutWin: BrowserWindow | null = null @@ -13,79 +13,95 @@ const WEBCAM_TITLEBAR_HEIGHT: number = 28 * @param id The device stream ID * @param name The name of the device */ -function loadWebcam(id: string = "", name: string = ""){ - const VITE_DEV_SERVER_URL = process.env['VITE_DEV_SERVER_URL'] - const params: string = id && name ? "webcam.html?deviceId=" + id + "&deviceName=" + name : "webcam.html"; +function loadWebcam(id: string = "", name: string = "") { + const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"] + const params: string = + id && name + ? "webcam.html?deviceId=" + id + "&deviceName=" + name + : "webcam.html" if (VITE_DEV_SERVER_URL) webcamPopoutWin?.loadURL(VITE_DEV_SERVER_URL + params) else - webcamPopoutWin?.loadFile(path.join(process.env.DIST, 'webcam.html'), {hash: params}) + webcamPopoutWin?.loadFile(path.join(process.env.DIST, "webcam.html"), { + hash: params, + }) } -export function openWebcamPopout(videoStreamId: string, name: string, aspect: number){ +export function openWebcamPopout( + videoStreamId: string, + name: string, + aspect: number, +) { + if (webcamPopoutWin === null) { + webcamPopoutWin = new BrowserWindow({ + width: 400, + height: 300, + frame: false, + icon: path.join(process.env.VITE_PUBLIC, "app_icon.ico"), + show: false, + title: "Webcam", + webPreferences: { + nodeIntegration: true, + preload: path.join(__dirname, "preload.js"), + contextIsolation: true, + }, + fullscreen: false, + fullscreenable: false, + }) + } else { + console.warn("HOW ARE YOU CREATEING 2 WEBCAM WINDOWS TELL ME") + } - if (webcamPopoutWin === null) { - webcamPopoutWin = new BrowserWindow({ - width: 400, - height: 300, - frame: false, - alwaysOnTop: true, - icon: path.join(process.env.VITE_PUBLIC, 'app_icon.ico'), - show: false, - title: "Webcam", - webPreferences: { - nodeIntegration: true, - preload: path.join(__dirname, 'preload.js'), - contextIsolation: true - }, - fullscreen: false, - fullscreenable: false, - }); - } else{ - console.warn("HOW ARE YOU CREATEING 2 WEBCAM WINDOWS TELL ME") - } + loadWebcam(videoStreamId, name) + webcamPopoutWin.setTitle(name) - loadWebcam(videoStreamId, name); - webcamPopoutWin.setTitle(name); + webcamPopoutWin.on("will-resize", (event, newBounds) => { + event.preventDefault() - webcamPopoutWin.on('will-resize', (event, newBounds) => { - event.preventDefault(); + const newWidth = newBounds.width + const newHeight = Math.round(newWidth / aspect + WEBCAM_TITLEBAR_HEIGHT) - const newWidth = newBounds.width; - const newHeight = Math.round((newWidth / aspect) + WEBCAM_TITLEBAR_HEIGHT); + webcamPopoutWin?.setBounds({ + x: newBounds.x, + y: newBounds.y, + width: newWidth, + height: newHeight, + }) + }) - webcamPopoutWin?.setBounds({ - x: newBounds.x, - y: newBounds.y, - width: newWidth, - height: newHeight - }); - }); + // Windows doesn't consider maximising to be fullscreening so we must prevent default + webcamPopoutWin.on("maximize", (e: Event) => { + e.preventDefault() + }) - // Windows doesn't consider maximising to be fullscreening so we must prevent default - webcamPopoutWin.on("maximize", (e: Event) => { - e.preventDefault(); - }); - - // Ensure initial size fits the aspect ratio () - webcamPopoutWin.setSize(webcamPopoutWin.getBounds().width, Math.round(webcamPopoutWin.getBounds().width / aspect) + WEBCAM_TITLEBAR_HEIGHT); - webcamPopoutWin.setMinimumSize(Math.round(aspect * (MIN_WEBCAM_HEIGHT-28)), MIN_WEBCAM_HEIGHT); - webcamPopoutWin.show(); + // Ensure initial size fits the aspect ratio () + webcamPopoutWin.setSize( + webcamPopoutWin.getBounds().width, + Math.round(webcamPopoutWin.getBounds().width / aspect) + + WEBCAM_TITLEBAR_HEIGHT, + ) + webcamPopoutWin.setMinimumSize( + Math.round(aspect * (MIN_WEBCAM_HEIGHT - 28)), + MIN_WEBCAM_HEIGHT, + ) + webcamPopoutWin.show() } -export function closeWebcamPopout(mainWindow: BrowserWindow | null){ - console.log("Destroying webcam window") - destroyWebcamWindow(); - mainWindow?.webContents.send("webcam-closed"); +export function closeWebcamPopout(mainWindow: BrowserWindow | null) { + console.log("Destroying webcam window") + destroyWebcamWindow() + mainWindow?.webContents.send("webcam-closed") } -export function destroyWebcamWindow(){ - webcamPopoutWin?.close() - webcamPopoutWin = null +export function destroyWebcamWindow() { + webcamPopoutWin?.close() + webcamPopoutWin = null } -export default function registerWebcamIPC(mainWindow: BrowserWindow){ - ipcMain.handle("openWebcamWindow", (_, videoStreamId, name, aspect) => {openWebcamPopout(videoStreamId, name, aspect)}) - ipcMain.handle("closeWebcamWindow", () => closeWebcamPopout(mainWindow)) -} \ No newline at end of file +export default function registerWebcamIPC(mainWindow: BrowserWindow) { + ipcMain.handle("openWebcamWindow", (_, videoStreamId, name, aspect) => { + openWebcamPopout(videoStreamId, name, aspect) + }) + ipcMain.handle("closeWebcamWindow", () => closeWebcamPopout(mainWindow)) +} diff --git a/gcs/package.json b/gcs/package.json index a847cbd38..b167a12ee 100644 --- a/gcs/package.json +++ b/gcs/package.json @@ -6,7 +6,7 @@ "name": "Avis-Drone-Labs" }, "private": true, - "version": "0.1.9-alpha", + "version": "0.1.10-alpha-dev1", "license": "GPL-3.0-only", "homepage": "https://fgcs.projectfalcon.uk", "githubLink": "https://github.com/Avis-Drone-Labs/FGCS", @@ -98,7 +98,8 @@ "typescript": "^5.2.2", "vite": "^4.5.3", "vite-plugin-electron": "^0.14.0", - "vite-plugin-electron-renderer": "^0.14.5" + "vite-plugin-electron-renderer": "^0.14.5", + "vite-plugin-static-copy": "^3.1.2" }, "resolutions": { "strip-ansi": "6.0.1", diff --git a/gcs/tsconfig.node.json b/gcs/tsconfig.node.json index 42872c59f..a8583534f 100644 --- a/gcs/tsconfig.node.json +++ b/gcs/tsconfig.node.json @@ -6,5 +6,5 @@ "moduleResolution": "bundler", "allowSyntheticDefaultImports": true }, - "include": ["vite.config.ts"] + "include": ["vite.config.mts"] } diff --git a/gcs/vite.config.mts b/gcs/vite.config.mts new file mode 100644 index 000000000..d90646685 --- /dev/null +++ b/gcs/vite.config.mts @@ -0,0 +1,43 @@ +import react from "@vitejs/plugin-react" +import path, { resolve } from "node:path" +import { defineConfig } from "vite" +import electron from "vite-plugin-electron/simple" +import { viteStaticCopy } from "vite-plugin-static-copy" + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + react(), + viteStaticCopy({ + targets: [ + { src: "linkStats.html", dest: "." }, + { src: "aboutWindow.html", dest: "." }, + { src: "webcam.html", dest: "." }, + ], + }), + electron({ + main: { + // Shortcut of `build.lib.entry`. + entry: "electron/main.ts", + }, + preload: { + // Shortcut of `build.rollupOptions.input`. + // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`. + input: path.join(__dirname, "electron/preload.js"), + }, + // Ployfill the Electron and Node.js built-in modules for Renderer process. + // See 👉 https://github.com/electron-vite/vite-plugin-electron-renderer + renderer: {}, + }), + ], + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + linkStats: resolve(__dirname, "linkStats.html"), + aboutWindow: resolve(__dirname, "aboutWindow.html"), + webcam: resolve(__dirname, "webcam.html"), + }, + }, + }, +}) diff --git a/gcs/vite.config.ts b/gcs/vite.config.ts deleted file mode 100644 index 77b1bff59..000000000 --- a/gcs/vite.config.ts +++ /dev/null @@ -1,25 +0,0 @@ -import react from '@vitejs/plugin-react' -import path from 'node:path' -import { defineConfig } from 'vite' -import electron from 'vite-plugin-electron/simple' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [ - react(), - electron({ - main: { - // Shortcut of `build.lib.entry`. - entry: 'electron/main.ts', - }, - preload: { - // Shortcut of `build.rollupOptions.input`. - // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`. - input: path.join(__dirname, 'electron/preload.js'), - }, - // Ployfill the Electron and Node.js built-in modules for Renderer process. - // See 👉 https://github.com/electron-vite/vite-plugin-electron-renderer - renderer: {}, - }), - ], -}) From 0c1ce61ee199574630ff0fdb9b4299d6c8bc33d2 Mon Sep 17 00:00:00 2001 From: Kush Makkapati Date: Thu, 18 Sep 2025 19:50:21 +0100 Subject: [PATCH 2/4] Fix popout windows in build, fix popout windows not closing in build --- gcs/electron/main.ts | 14 ++++++++++---- gcs/electron/modules/webcam.ts | 5 +++-- gcs/package.json | 5 ++--- gcs/vite.config.mts | 8 -------- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/gcs/electron/main.ts b/gcs/electron/main.ts index 5afda953b..839e5685f 100644 --- a/gcs/electron/main.ts +++ b/gcs/electron/main.ts @@ -226,6 +226,10 @@ function createWindow() { win?.setAlwaysOnTop(false) }) + win.on("close", () => { + closeWithBackend() + }) + // Set Main Menu on Mac Only if (process.platform === "darwin") { setMainMenu() @@ -341,10 +345,7 @@ function startBackend() { // for applications and their menu bar to stay active until the user quits // explicitly with Cmd + Q. function closeWithBackend() { - if (process.platform !== "darwin") { - app.quit() - win = null - } + // Always close all popout windows first destroyWebcamWindow() destroyAboutWindow() destroyLinkStatsWindow() @@ -352,7 +353,12 @@ function closeWithBackend() { // kill any processes with the name "fgcs_backend.exe" // Windows spawn("taskkill /f /im fgcs_backend.exe", { shell: true }) + if (process.platform !== "darwin") { + app.quit() + win = null + } } + app.on("window-all-closed", () => { closeWithBackend() }) diff --git a/gcs/electron/modules/webcam.ts b/gcs/electron/modules/webcam.ts index f00f97628..2ece38ffd 100644 --- a/gcs/electron/modules/webcam.ts +++ b/gcs/electron/modules/webcam.ts @@ -3,6 +3,8 @@ import path from "path" let webcamPopoutWin: BrowserWindow | null = null +const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"] + const MIN_WEBCAM_HEIGHT: number = 100 const WEBCAM_TITLEBAR_HEIGHT: number = 28 @@ -14,7 +16,6 @@ const WEBCAM_TITLEBAR_HEIGHT: number = 28 * @param name The name of the device */ function loadWebcam(id: string = "", name: string = "") { - const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"] const params: string = id && name ? "webcam.html?deviceId=" + id + "&deviceName=" + name @@ -24,7 +25,7 @@ function loadWebcam(id: string = "", name: string = "") { webcamPopoutWin?.loadURL(VITE_DEV_SERVER_URL + params) else webcamPopoutWin?.loadFile(path.join(process.env.DIST, "webcam.html"), { - hash: params, + search: `?deviceId=${id}&deviceName=${name}`, }) } diff --git a/gcs/package.json b/gcs/package.json index b167a12ee..d5b43d1f7 100644 --- a/gcs/package.json +++ b/gcs/package.json @@ -6,7 +6,7 @@ "name": "Avis-Drone-Labs" }, "private": true, - "version": "0.1.10-alpha-dev1", + "version": "0.1.10-alpha-dev2", "license": "GPL-3.0-only", "homepage": "https://fgcs.projectfalcon.uk", "githubLink": "https://github.com/Avis-Drone-Labs/FGCS", @@ -98,8 +98,7 @@ "typescript": "^5.2.2", "vite": "^4.5.3", "vite-plugin-electron": "^0.14.0", - "vite-plugin-electron-renderer": "^0.14.5", - "vite-plugin-static-copy": "^3.1.2" + "vite-plugin-electron-renderer": "^0.14.5" }, "resolutions": { "strip-ansi": "6.0.1", diff --git a/gcs/vite.config.mts b/gcs/vite.config.mts index d90646685..1a76d22e4 100644 --- a/gcs/vite.config.mts +++ b/gcs/vite.config.mts @@ -2,19 +2,11 @@ import react from "@vitejs/plugin-react" import path, { resolve } from "node:path" import { defineConfig } from "vite" import electron from "vite-plugin-electron/simple" -import { viteStaticCopy } from "vite-plugin-static-copy" // https://vitejs.dev/config/ export default defineConfig({ plugins: [ react(), - viteStaticCopy({ - targets: [ - { src: "linkStats.html", dest: "." }, - { src: "aboutWindow.html", dest: "." }, - { src: "webcam.html", dest: "." }, - ], - }), electron({ main: { // Shortcut of `build.lib.entry`. From d4bd4153450e167fdb4704ccc4190915d456da8e Mon Sep 17 00:00:00 2001 From: Kush Makkapati Date: Thu, 18 Sep 2025 19:54:10 +0100 Subject: [PATCH 3/4] Update gcs/electron/modules/webcam.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- gcs/electron/modules/webcam.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcs/electron/modules/webcam.ts b/gcs/electron/modules/webcam.ts index 2ece38ffd..47ea25134 100644 --- a/gcs/electron/modules/webcam.ts +++ b/gcs/electron/modules/webcam.ts @@ -25,7 +25,7 @@ function loadWebcam(id: string = "", name: string = "") { webcamPopoutWin?.loadURL(VITE_DEV_SERVER_URL + params) else webcamPopoutWin?.loadFile(path.join(process.env.DIST, "webcam.html"), { - search: `?deviceId=${id}&deviceName=${name}`, + search: id && name ? `?deviceId=${id}&deviceName=${name}` : "", }) } From 1181901ec9d39fd4af97e313dea70ce3c342a9bb Mon Sep 17 00:00:00 2001 From: Kush Makkapati Date: Fri, 19 Sep 2025 16:00:05 +0100 Subject: [PATCH 4/4] Change console warn message --- gcs/electron/modules/webcam.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcs/electron/modules/webcam.ts b/gcs/electron/modules/webcam.ts index 47ea25134..e2c9c043e 100644 --- a/gcs/electron/modules/webcam.ts +++ b/gcs/electron/modules/webcam.ts @@ -51,7 +51,7 @@ export function openWebcamPopout( fullscreenable: false, }) } else { - console.warn("HOW ARE YOU CREATEING 2 WEBCAM WINDOWS TELL ME") + console.warn("2nd webcam window requested, ignoring") } loadWebcam(videoStreamId, name)