143 lines
3.2 KiB
TypeScript
143 lines
3.2 KiB
TypeScript
"use strict";
|
|
// License: MIT
|
|
|
|
import { Prefs } from "./prefs";
|
|
import { windows } from "./browser";
|
|
// eslint-disable-next-line no-unused-vars
|
|
import { Port } from "./bus";
|
|
|
|
|
|
const VALID_WINDOW_STATES = Object.freeze(new Set(["normal", "maximized"]));
|
|
|
|
interface Constraints {
|
|
minWidth: number;
|
|
minHeight: number;
|
|
left?: number;
|
|
top?: number;
|
|
}
|
|
|
|
export class WindowStateTracker {
|
|
private width: number;
|
|
|
|
private height: number;
|
|
|
|
private readonly minWidth: number;
|
|
|
|
private readonly minHeight: number;
|
|
|
|
private left: number;
|
|
|
|
private top: number;
|
|
|
|
private state: string;
|
|
|
|
private readonly key: string;
|
|
|
|
private windowId: number;
|
|
|
|
constructor(windowType: string, constraints: Constraints) {
|
|
// eslint-disable-next-line no-magic-numbers
|
|
const {minWidth = 500, minHeight = 400, left = -1, top = -1} = constraints;
|
|
this.width = this.minWidth = minWidth;
|
|
this.height = this.minHeight = minHeight;
|
|
this.left = left;
|
|
this.top = top;
|
|
this.state = "normal";
|
|
this.key = `window-state-${windowType}`;
|
|
this.update = this.update.bind(this);
|
|
}
|
|
|
|
async init() {
|
|
const initialState = await Prefs.get(this.key);
|
|
if (initialState) {
|
|
Object.assign(this, initialState);
|
|
}
|
|
this.validate();
|
|
}
|
|
|
|
getOptions(options: any) {
|
|
const result = Object.assign(options, {
|
|
state: this.state,
|
|
});
|
|
if (result.state !== "maximized") {
|
|
result.width = this.width;
|
|
result.height = this.height;
|
|
if (this.top >= 0) {
|
|
result.top = this.top;
|
|
result.left = this.left;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
validate() {
|
|
this.width = Math.max(this.minWidth, this.width) || this.minWidth;
|
|
this.height = Math.max(this.minHeight, this.height) || this.minHeight;
|
|
this.top = Math.max(-1, this.top) || -1;
|
|
this.left = Math.max(-1, this.left) || -1;
|
|
this.state = VALID_WINDOW_STATES.has(this.state) ? this.state : "normal";
|
|
}
|
|
|
|
async update() {
|
|
if (!this.windowId) {
|
|
return;
|
|
}
|
|
try {
|
|
const window = await windows.get(this.windowId);
|
|
if (!VALID_WINDOW_STATES.has(window.state)) {
|
|
return;
|
|
}
|
|
const previous = JSON.stringify(this);
|
|
this.width = window.width;
|
|
this.height = window.height;
|
|
this.left = window.left;
|
|
this.top = window.top;
|
|
this.state = window.state;
|
|
this.validate();
|
|
if (previous === JSON.stringify(this)) {
|
|
// Nothing changed
|
|
return;
|
|
}
|
|
await this.save();
|
|
}
|
|
catch {
|
|
// ignored
|
|
}
|
|
}
|
|
|
|
track(windowId: number, port?: Port) {
|
|
if (port) {
|
|
port.on("resized", this.update);
|
|
port.on("unload", e => this.finalize(e));
|
|
port.on("disconnect", this.finalize.bind(this));
|
|
}
|
|
this.windowId = windowId;
|
|
}
|
|
|
|
async finalize(state?: any) {
|
|
if (state) {
|
|
this.left = state.left;
|
|
this.top = state.top;
|
|
}
|
|
await this.update();
|
|
this.windowId = 0;
|
|
if (state) {
|
|
await this.save();
|
|
}
|
|
}
|
|
|
|
async save() {
|
|
await Prefs.set(this.key, this.toJSON());
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
width: this.width,
|
|
height: this.height,
|
|
top: this.top,
|
|
left: this.left,
|
|
state: this.state,
|
|
};
|
|
}
|
|
}
|