import {BrowserWindow, app, dialog} from "electron"; import * as path from "path"; export let is_debug: boolean; export let allow_dev_tools: boolean; import {Arguments, processArguments} from "../../shared/process-arguments"; import * as updater from "./../app-updater"; import * as loader from "./../ui-loader"; import * as url from "url"; import {loadWindowBounds, startTrackWindowBounds} from "../../shared/window"; import {referenceApp, dereferenceApp} from "../AppInstance"; import {closeURLPreview, openURLPreview} from "../url-preview"; // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. export let mainWindow: BrowserWindow = null; function spawnMainWindow(rendererEntryPoint: string) { app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { console.log("Allowing untrusted certificate for %o", url); event.preventDefault(); callback(true); }); // Create the browser window. console.log("Spawning main window"); referenceApp(); /* main browser window references the app */ mainWindow = new BrowserWindow({ width: 800, height: 600, minHeight: 600, minWidth: 600, show: false, webPreferences: { webSecurity: false, nodeIntegrationInWorker: true, nodeIntegration: true, preload: path.join(__dirname, "preload.js") }, icon: path.join(__dirname, "..", "..", "resources", "logo.ico"), }); mainWindow.webContents.on('devtools-closed', () => { console.log("Dev tools destroyed!"); }); mainWindow.on('closed', () => { app.releaseSingleInstanceLock(); closeURLPreview(); mainWindow = null; dereferenceApp(); }); mainWindow.loadURL(url.pathToFileURL(loader.ui.preloading_page(rendererEntryPoint)).toString()).catch(error => { console.error("Failed to load UI entry point: %o", error); handleUILoadingError("UI entry point failed to load"); }); mainWindow.once('ready-to-show', () => { mainWindow.show(); loadWindowBounds('main-window', mainWindow).then(() => { startTrackWindowBounds('main-window', mainWindow); mainWindow.focus(); loader.ui.cleanup(); if(allow_dev_tools && !mainWindow.webContents.isDevToolsOpened()) mainWindow.webContents.openDevTools(); }); }); mainWindow.webContents.on('new-window', (event, url_str, frameName, disposition, options, additionalFeatures) => { if(frameName.startsWith("__modal_external__")) { return; } event.preventDefault(); try { let url: URL; try { url = new URL(url_str); } catch(error) { throw "failed to parse URL"; } { let protocol = url.protocol.endsWith(":") ? url.protocol.substring(0, url.protocol.length - 1) : url.protocol; if(protocol !== "https" && protocol !== "http") { throw "invalid protocol (" + protocol + "). HTTP(S) are only supported!"; } } console.log("Got new window " + frameName); openURLPreview(url_str).then(() => {}); } catch(error) { console.error("Failed to open preview window for URL %s: %o", url_str, error); dialog.showErrorBox("Failed to open preview", "Failed to open preview URL: " + url_str + "\nError: " + error); } }); mainWindow.webContents.on('crashed', () => { console.error("UI thread crashed! Closing app!"); if(!processArguments.has_flag(Arguments.DEBUG)) { mainWindow.close(); } }); } function handleUILoadingError(message: string) { referenceApp(); console.log("Caught loading error: %s", message); if(mainWindow) { mainWindow.close(); mainWindow = undefined; } dialog.showMessageBox({ type: "error", buttons: ["exit"], title: "A critical error happened while loading TeaClient!", message: (message || "no error").toString() }).then(dereferenceApp); loader.ui.cancel(); } export function execute() { console.log("Main app executed!"); is_debug = processArguments.has_flag(...Arguments.DEBUG); allow_dev_tools = processArguments.has_flag(...Arguments.DEV_TOOLS); if(is_debug) { console.log("Enabled debug!"); console.log("Arguments: %o", processArguments); } console.log("Setting up render backend"); require("../render-backend"); console.log("Spawn loading screen"); loader.ui.execute_loader().then(async (entry_point: string) => { /* test if the updater may have an update found */ let awaiting_update_set = false; while(updater.update_question_open) { if(!awaiting_update_set) { awaiting_update_set = true; loader.ui.show_await_update(); console.log("Awaiting update stuff to be finished"); } await new Promise(resolve => setTimeout(resolve, 100)); } if(updater.update_restart_pending) return undefined; return entry_point; }).then((entry_point: string) => { referenceApp(); /* because we've no windows when we close the loader UI */ loader.ui.cleanup(); /* close the window */ if(entry_point) //has not been canceled spawnMainWindow(entry_point); else { handleUILoadingError("Missing UI entry point"); } dereferenceApp(); }).catch(handleUILoadingError); }