import * as electron from "electron"; import * as fs from "fs-extra"; import * as path from "path"; /* We read/write to this file every time again because this file could be used by multible processes */ const data_file: string = path.join(electron.app.getPath('userData'), "window-bounds.json"); import BrowserWindow = Electron.BrowserWindow; import Rectangle = Electron.Rectangle; let _changed_data: {[key: string]:Rectangle} = {}; let _changed_saver: NodeJS.Timer; export async function save_changes() { clearTimeout(_changed_saver); try { const data = (await fs.pathExists(data_file) ? await fs.readJson(data_file) : {}) || {}; Object.assign(data, _changed_data); await fs.ensureFile(data_file); await fs.writeJson(data_file, data); path_exists = true; _changed_data = {}; } catch(error) { console.warn("Failed to save window bounds: %o", error); } console.log("Window bounds have been successfully saved!"); } let path_exists = undefined; export async function get_last_bounds(key: string) : Promise { try { if(typeof(path_exists) === "undefined" ? !(path_exists = await fs.pathExists(data_file)) : !path_exists) throw "skip!"; const data = await fs.readJson(data_file) || {}; if(data[key]) return data[key]; } catch(error) { if(error !== "skip!") console.warn("Failed to load window bounds for %s: %o", key, error); } return { height: undefined, width: undefined, x: undefined, y: undefined } } export function track_bounds(key: string, window: BrowserWindow) { const events = ['move', 'moved', 'resize']; const update_bounds = () => { _changed_data[key] = window.getBounds(); clearTimeout(_changed_saver); _changed_saver = setTimeout(save_changes, 1000); }; for(const event of events) window.on(event as any, update_bounds); window.on('closed', () => { for(const event of events) window.removeListener(event as any, update_bounds); }) } export async function apply_bounds(key: string, window: BrowserWindow, bounds?: Rectangle, options?: { apply_size?: boolean; apply_position?: boolean }) { const screen = electron.screen; if(!bounds) bounds = await get_last_bounds(key); if(!options) options = {}; const original_bounds = window.getBounds(); if(typeof(options.apply_size) !== "boolean" || options.apply_size) { let height = bounds.height > 0 ? bounds.height : original_bounds.height; let width = bounds.width > 0 ? bounds.width : original_bounds.width; if(height != original_bounds.height || width != original_bounds.width) window.setSize(width, height, true); } if(typeof(options.apply_position) !== "boolean" || options.apply_position) { let x = typeof(bounds.x) === "number" ? bounds.x : original_bounds.x; let y = typeof(bounds.y) === "number" ? bounds.y : original_bounds.y; if(x != original_bounds.x || y != original_bounds.y) { const display = screen.getDisplayNearestPoint({ x: x, y: y }); if(display) { const bounds = display.workArea || display.bounds; let flag_invalid = false; flag_invalid = flag_invalid || bounds.x > x || (bounds.x + bounds.width) < x; flag_invalid = flag_invalid || bounds.y > x || (bounds.y + bounds.height) < y; if(!flag_invalid) { window.setPosition(x, y, true); console.log("Updating position for %s", key); } } } } }