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 4d0451135..e2c9c043e 100644 --- a/gcs/electron/modules/webcam.ts +++ b/gcs/electron/modules/webcam.ts @@ -1,8 +1,10 @@ -import path from "path"; -import { BrowserWindow, ipcMain } from "electron"; +import { BrowserWindow, ipcMain } from "electron" +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 @@ -13,79 +15,94 @@ 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 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"), { + search: id && name ? `?deviceId=${id}&deviceName=${name}` : "", + }) } -export function openWebcamPopout(videoStreamId: string, name: string, aspect: number){ - - 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") - } +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("2nd webcam window requested, ignoring") + } - 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..d5b43d1f7 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-dev2", "license": "GPL-3.0-only", "homepage": "https://fgcs.projectfalcon.uk", "githubLink": "https://github.com/Avis-Drone-Labs/FGCS", 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.ts b/gcs/vite.config.mts similarity index 50% rename from gcs/vite.config.ts rename to gcs/vite.config.mts index 77b1bff59..1a76d22e4 100644 --- a/gcs/vite.config.ts +++ b/gcs/vite.config.mts @@ -1,7 +1,7 @@ -import react from '@vitejs/plugin-react' -import path from 'node:path' -import { defineConfig } from 'vite' -import electron from 'vite-plugin-electron/simple' +import react from "@vitejs/plugin-react" +import path, { resolve } from "node:path" +import { defineConfig } from "vite" +import electron from "vite-plugin-electron/simple" // https://vitejs.dev/config/ export default defineConfig({ @@ -10,16 +10,26 @@ export default defineConfig({ electron({ main: { // Shortcut of `build.lib.entry`. - entry: 'electron/main.ts', + 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'), + 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"), + }, + }, + }, })