import {Tile, TileState} from './tile.js'; import {Direction} from './tileWindowManager.js'; import {Position} from './position.js'; export class Monitor { _root; _index; _fullscreenState = false; constructor(index) { this._index = index; this._root = null; } set root(root) { this._root = root; } get root() { return this._root; } get index() { return this._index; } get fullscreen() { return this._fullscreenState; } set fullscreen(b) { this._fullscreenState = b; } size() { return this._root ? this._root._nr_tiles : 0; } updateSize() { if (this._root) { const area = global.workspace_manager.get_active_workspace().get_work_area_for_monitor(this.index); if (area) { let pos = new Position(1.0, 0, 0, area.width, area.height); pos.splitProportion = this._root.position.splitProportion; this._root.resize(pos); } } } static bestFitMonitor(monitors) { return monitors.reduce((acc, val) => val.size() < acc.size() ? val : acc, monitors[0]); } static tileDistance(t1, t2) { let vector = [t1.position.x - t2.position.x, t1.position.y - t2.position.y]; return Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]); } closestTile(source, dir) { // Class to store the result class BestTile { tile = null; distance = null; constructor(tile = null, distance = null) { this.tile = tile; this.distance = distance; } } ; // We search for the closest tile in a Direction. We recursively iterate the tree let findClosest = tile => { switch (dir) { case Direction.East: if (tile.leaf && tile.position.x > source.position.x) { return new BestTile(tile, Monitor.tileDistance(tile, source)); } else if (tile.leaf) { return new BestTile(); } else if (tile.child1 && tile.child2) { let res1 = findClosest(tile.child1); let res2 = findClosest(tile.child2); if ((res1.distance && res2.distance && res1.distance > res2.distance) || (res2.distance && !res1.distance)) return res2; else if ((res1.distance && res2.distance && res1.distance < res2.distance) || (res1.distance && !res2.distance)) return res1; else return new BestTile(); } return new BestTile(); case Direction.West: if (tile.leaf && tile.position.x < source.position.x) { return new BestTile(tile, Monitor.tileDistance(tile, source)); } else if (tile.leaf) { return new BestTile(); } else if (tile.child1 && tile.child2) { let res1 = findClosest(tile.child1); let res2 = findClosest(tile.child2); if ((res1.distance && res2.distance && res1.distance > res2.distance) || (res2.distance && !res1.distance)) return res2; else if ((res1.distance && res2.distance && res1.distance < res2.distance) || (res1.distance && !res2.distance)) return res1; else return new BestTile(); } return new BestTile(); case Direction.North: if (tile.leaf && tile.position.y < source.position.y) { return new BestTile(tile, Monitor.tileDistance(tile, source)); } else if (tile.leaf) { return new BestTile(); } else if (tile.child1 && tile.child2) { let res1 = findClosest(tile.child1); let res2 = findClosest(tile.child2); if ((res1.distance && res2.distance && res1.distance > res2.distance) || (res2.distance && !res1.distance)) return res2; else if ((res1.distance && res2.distance && res1.distance < res2.distance) || (res1.distance && !res2.distance)) return res1; else return new BestTile(); } return new BestTile(); case Direction.South: if (tile.leaf && tile.position.y > source.position.y) { return new BestTile(tile, Monitor.tileDistance(tile, source)); } else if (tile.leaf) { return new BestTile(); } else if (tile.child1 && tile.child2) { let res1 = findClosest(tile.child1); let res2 = findClosest(tile.child2); if ((res1.distance && res2.distance && res1.distance > res2.distance) || (res2.distance && !res1.distance)) return res2; else if ((res1.distance && res2.distance && res1.distance < res2.distance) || (res1.distance && !res2.distance)) return res1; else return new BestTile(); } return new BestTile(); default: return new BestTile(); } }; if (this.root) { let res = findClosest(this.root); return res.tile; } return null; } destroy() { this._index = -1; this._root = null; } static fromObject(obj) { let monitor = new Monitor(obj._index); monitor.fullscreen = obj._fullscreenState; if (!obj._root) monitor.root = null; else monitor.root = Tile.fromObject(obj._root); return monitor; } closestMonitor(dir) { let nMonitors = global.display.get_n_monitors(); let _currGeo = global.display.get_monitor_geometry(this.index); let min; let best = null; switch (dir) { case Direction.North: for (let i = 0; i < nMonitors; i++) { if (this.index !== i) { let _geometry = global.display.get_monitor_geometry(i); if (_geometry.y < _currGeo.y && (min === undefined || _geometry.y > min)) { min = _geometry.y; best = i; } } } return best; case Direction.South: for (let i = 0; i < nMonitors; i++) { if (this.index !== i) { let _geometry = global.display.get_monitor_geometry(i); if (_geometry.y > _currGeo.y && (min === undefined || _geometry.y < min)) { min = _geometry.y; best = i; } } } return best; case Direction.East: for (let i = 0; i < nMonitors; i++) { if (this.index !== i) { let _geometry = global.display.get_monitor_geometry(i); if (_geometry.x > _currGeo.x && (min === undefined || _geometry.x < min)) { min = _geometry.x; best = i; } } } return best; case Direction.West: for (let i = 0; i < nMonitors; i++) { if (this.index !== i) { let _geometry = global.display.get_monitor_geometry(i); if (_geometry.x < _currGeo.x && (!min || _geometry.x > min)) { min = _geometry.x; best = i; } } } return best; default: return null; } } /** Returns tile closest to the edge on a monitor * - If the monitor is in fullscreen it returns the maximized window * * @param {Direction} dir * @returns {Tile | null} */ getTile(dir) { if (this.root === null) return null; if (this.fullscreen) return this.root.find(t => t.state === TileState.MAXIMIZED); let getTileBis = t => { switch (dir) { case Direction.East: if (t.child2 !== null && t.child1 !== null) return t.child1.position.x > t.child2.position.x ? getTileBis(t.child1) : getTileBis(t.child2); else if (t.child1 !== null) return getTileBis(t.child1); else if (t.child2 !== null) return getTileBis(t.child2); else return t; case Direction.West: if (t.child2 !== null && t.child1 !== null) return t.child1.position.x < t.child2.position.x ? getTileBis(t.child1) : getTileBis(t.child2); else if (t.child1 !== null) return getTileBis(t.child1); else if (t.child2 !== null) return getTileBis(t.child2); else return t; case Direction.North: if (t.child2 !== null && t.child1 !== null) return t.child1.position.y < t.child2.position.y ? getTileBis(t.child1) : getTileBis(t.child2); else if (t.child1 !== null) return getTileBis(t.child1); else if (t.child2 !== null) return getTileBis(t.child2); else return t; case Direction.South: if (t.child2 !== null && t.child1 !== null) return t.child1.position.y > t.child2.position.y ? getTileBis(t.child1) : getTileBis(t.child2); else if (t.child1 !== null) return getTileBis(t.child1); else if (t.child2 !== null) return getTileBis(t.child2); else return t; default: return t; } }; return getTileBis(this.root); } }