import {BrowserWindow, Menu, MenuItem, MessageBoxOptions, app, dialog} from "electron"; import * as electron from "electron"; import * as winmgr from "./window"; export let prevent_instant_close: boolean = true; export function set_prevent_instant_close(flag: boolean) { prevent_instant_close = flag; } export let is_debug: boolean; export let allow_dev_tools: boolean; import {Arguments, parse_arguments, process_args} from "../shared/process-arguments"; import * as updater from "./app-updater"; import * as loader from "./ui-loader"; import {open as open_changelog} from "./app-updater/changelog"; import * as crash_handler from "../crash_handler"; // 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 main_window: BrowserWindow = null; function create_menu() : Menu { const menu = new Menu(); if(allow_dev_tools) { menu.append(new MenuItem({ id: "developer-tools", enabled: true, label: "Developer", submenu: [ { id: "tool-dev-tools", label: "Open developer tools", enabled: true, click: event => { main_window.webContents.openDevTools(); } }, { id: "tool-page-reload", label: "Reload current page", enabled: true, click: event => { main_window.reload(); } } ] })); menu.items[0].visible = false; } menu.append(new MenuItem({ id: "help", enabled: true, label: "Help", submenu: [ { id: "update-check", label: "Check for updates", click: () => updater.selected_channel().then(channel => updater.execute_graphical(channel, true)) }, { id: "changelog", label: "View ChangeLog file", click: open_changelog }, { id: "hr-01", type: "separator" }, { id: "visit-home", label: "Visit TeaSpeak.de", click: () => electron.shell.openExternal("https://teaspeak.de") }, { id: "visit-support", label: "Get support", click: () => electron.shell.openExternal("https://forum.teaspeak.de") }, { id: "about-teaclient", label: "About TeaClient", click: () => { updater.current_version().then(version => { dialog.showMessageBox({ title: "TeaClient info", message: "TeaClient by TeaSpeak (WolverinDEV)\nVersion: " + version.toString(true), buttons: ["close"] } as MessageBoxOptions, result => {}); }); } }, ] })); return menu; } function spawn_main_window(entry_point: string) { // Create the browser window. console.log("Spawning main window"); main_window = new BrowserWindow({ width: 800, height: 600, show: false, webPreferences: { webSecurity: false, nodeIntegrationInWorker: true, nodeIntegration: true }, }); const menu = create_menu(); if(menu.items.length > 0) main_window.setMenu(menu); main_window.webContents.on('devtools-closed', event => { console.log("Dev tools destroyed!"); }); main_window.on('closed', () => { main_window = null; prevent_instant_close = false; }); main_window.loadFile(loader.ui.preloading_page(entry_point)); main_window.once('ready-to-show', () => { main_window.show(); winmgr.apply_bounds('main-window', main_window).then(() => { winmgr.track_bounds('main-window', main_window); main_window.focus(); loader.ui.cleanup(); if(allow_dev_tools && !main_window.webContents.isDevToolsOpened()) main_window.webContents.openDevTools(); prevent_instant_close = false; /* just to ensure that the client could be unloaded */ }); }); main_window.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => { console.log("Got new window " + frameName); if (frameName === 'teaforo-login') { // open window as modal Object.assign(options, { modal: true, parent: main_window, width: 100, height: 100 }); let a = new BrowserWindow(options); a.show(); } else { const url_preview = require("./url-preview"); url_preview.open_preview(url); } event.preventDefault(); }); main_window.webContents.on('crashed', event => { console.error("UI thread crashed! Closing app!"); if(!process_args.has_flag(Arguments.DEBUG)) { main_window.close(); prevent_instant_close = false; } }); } function handle_error(message: string) { console.log("Caught loading error: %s", message); //"A critical error happened while loading TeaClient!", "A critical error happened while loading TeaClient!
" + message dialog.showMessageBox({ type: "error", buttons: ["exit"], title: "A critical error happened while loading TeaClient!", message: message }); loader.ui.cancel(); } function init_listener() { app.on('quit', () => { console.debug("Finalizing crash handler"); crash_handler.finalize_handler(); console.log("RUNNING quit!"); loader.cleanup(); console.log("RUNNING quit 2!"); loader.ui.cleanup(); console.log("RUNNING quit done!"); }); app.on('window-all-closed', () => { console.log("RUNNING all win closed!"); // On macOS it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { if(!prevent_instant_close) { console.log("All windows have been closed, closing app."); app.quit(); } else { console.log("All windows have been closed, but we dont want to quit instantly. Waiting 10 seconds if something happens"); setTimeout(() => { if(BrowserWindow.getAllWindows().length == 0) { console.log("All windows have been closed for over an minute. Exiting app!"); app.quit(); } }, 10 * 1000); } } }); app.on('activate', () => { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (main_window === null) { //spawn_loading_screen(); //createWindow() } }); app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { console.log("Allowing untrusted certificate for %o", url); event.preventDefault(); callback(true); }); } export function execute() { console.log("Main app executed!"); parse_arguments(); is_debug = process_args.has_flag(...Arguments.DEBUG); allow_dev_tools = process_args.has_flag(...Arguments.DEV_TOOLS); if(is_debug) { console.log("Enabled debug!"); console.log("Arguments: %o", process_args); } Menu.setApplicationMenu(null); init_listener(); 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) => { loader.ui.cleanup(); /* close the window */ if(entry_point) //has not been canceled spawn_main_window(entry_point); else { console.warn("Missing entry point!"); } }).catch(handle_error); }