monitor.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import {Tile, TileState} from './tile.js';
  2. import {Direction} from './tileWindowManager.js';
  3. import {Position} from './position.js';
  4. export class Monitor {
  5. _root;
  6. _index;
  7. _fullscreenState = false;
  8. constructor(index) {
  9. this._index = index;
  10. this._root = null;
  11. }
  12. set root(root) {
  13. this._root = root;
  14. }
  15. get root() {
  16. return this._root;
  17. }
  18. get index() {
  19. return this._index;
  20. }
  21. get fullscreen() {
  22. return this._fullscreenState;
  23. }
  24. set fullscreen(b) {
  25. this._fullscreenState = b;
  26. }
  27. size() {
  28. return this._root ? this._root._nr_tiles : 0;
  29. }
  30. updateSize() {
  31. if (this._root) {
  32. const area = global.workspace_manager.get_active_workspace().get_work_area_for_monitor(this.index);
  33. if (area) {
  34. let pos = new Position(1.0, 0, 0, area.width, area.height);
  35. pos.splitProportion = this._root.position.splitProportion;
  36. this._root.resize(pos);
  37. }
  38. }
  39. }
  40. static bestFitMonitor(monitors) {
  41. return monitors.reduce((acc, val) => val.size() < acc.size() ? val : acc, monitors[0]);
  42. }
  43. static tileDistance(t1, t2) {
  44. let vector = [t1.position.x - t2.position.x, t1.position.y - t2.position.y];
  45. return Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]);
  46. }
  47. closestTile(source, dir) {
  48. // Class to store the result
  49. class BestTile {
  50. tile = null;
  51. distance = null;
  52. constructor(tile = null, distance = null) {
  53. this.tile = tile;
  54. this.distance = distance;
  55. }
  56. }
  57. ;
  58. // We search for the closest tile in a Direction. We recursively iterate the tree
  59. let findClosest = tile => {
  60. switch (dir) {
  61. case Direction.East:
  62. if (tile.leaf && tile.position.x > source.position.x) {
  63. return new BestTile(tile, Monitor.tileDistance(tile, source));
  64. } else if (tile.leaf) {
  65. return new BestTile();
  66. } else if (tile.child1 && tile.child2) {
  67. let res1 = findClosest(tile.child1);
  68. let res2 = findClosest(tile.child2);
  69. if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
  70. (res2.distance && !res1.distance))
  71. return res2;
  72. else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
  73. (res1.distance && !res2.distance))
  74. return res1;
  75. else
  76. return new BestTile();
  77. }
  78. return new BestTile();
  79. case Direction.West:
  80. if (tile.leaf && tile.position.x < source.position.x) {
  81. return new BestTile(tile, Monitor.tileDistance(tile, source));
  82. } else if (tile.leaf) {
  83. return new BestTile();
  84. } else if (tile.child1 && tile.child2) {
  85. let res1 = findClosest(tile.child1);
  86. let res2 = findClosest(tile.child2);
  87. if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
  88. (res2.distance && !res1.distance))
  89. return res2;
  90. else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
  91. (res1.distance && !res2.distance))
  92. return res1;
  93. else
  94. return new BestTile();
  95. }
  96. return new BestTile();
  97. case Direction.North:
  98. if (tile.leaf && tile.position.y < source.position.y) {
  99. return new BestTile(tile, Monitor.tileDistance(tile, source));
  100. } else if (tile.leaf) {
  101. return new BestTile();
  102. } else if (tile.child1 && tile.child2) {
  103. let res1 = findClosest(tile.child1);
  104. let res2 = findClosest(tile.child2);
  105. if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
  106. (res2.distance && !res1.distance))
  107. return res2;
  108. else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
  109. (res1.distance && !res2.distance))
  110. return res1;
  111. else
  112. return new BestTile();
  113. }
  114. return new BestTile();
  115. case Direction.South:
  116. if (tile.leaf && tile.position.y > source.position.y) {
  117. return new BestTile(tile, Monitor.tileDistance(tile, source));
  118. } else if (tile.leaf) {
  119. return new BestTile();
  120. } else if (tile.child1 && tile.child2) {
  121. let res1 = findClosest(tile.child1);
  122. let res2 = findClosest(tile.child2);
  123. if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
  124. (res2.distance && !res1.distance))
  125. return res2;
  126. else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
  127. (res1.distance && !res2.distance))
  128. return res1;
  129. else
  130. return new BestTile();
  131. }
  132. return new BestTile();
  133. default:
  134. return new BestTile();
  135. }
  136. };
  137. if (this.root) {
  138. let res = findClosest(this.root);
  139. return res.tile;
  140. }
  141. return null;
  142. }
  143. destroy() {
  144. this._index = -1;
  145. this._root = null;
  146. }
  147. static fromObject(obj) {
  148. let monitor = new Monitor(obj._index);
  149. monitor.fullscreen = obj._fullscreenState;
  150. if (!obj._root)
  151. monitor.root = null;
  152. else
  153. monitor.root = Tile.fromObject(obj._root);
  154. return monitor;
  155. }
  156. closestMonitor(dir) {
  157. let nMonitors = global.display.get_n_monitors();
  158. let _currGeo = global.display.get_monitor_geometry(this.index);
  159. let min;
  160. let best = null;
  161. switch (dir) {
  162. case Direction.North:
  163. for (let i = 0; i < nMonitors; i++) {
  164. if (this.index !== i) {
  165. let _geometry = global.display.get_monitor_geometry(i);
  166. if (_geometry.y < _currGeo.y && (min === undefined || _geometry.y > min)) {
  167. min = _geometry.y;
  168. best = i;
  169. }
  170. }
  171. }
  172. return best;
  173. case Direction.South:
  174. for (let i = 0; i < nMonitors; i++) {
  175. if (this.index !== i) {
  176. let _geometry = global.display.get_monitor_geometry(i);
  177. if (_geometry.y > _currGeo.y && (min === undefined || _geometry.y < min)) {
  178. min = _geometry.y;
  179. best = i;
  180. }
  181. }
  182. }
  183. return best;
  184. case Direction.East:
  185. for (let i = 0; i < nMonitors; i++) {
  186. if (this.index !== i) {
  187. let _geometry = global.display.get_monitor_geometry(i);
  188. if (_geometry.x > _currGeo.x && (min === undefined || _geometry.x < min)) {
  189. min = _geometry.x;
  190. best = i;
  191. }
  192. }
  193. }
  194. return best;
  195. case Direction.West:
  196. for (let i = 0; i < nMonitors; i++) {
  197. if (this.index !== i) {
  198. let _geometry = global.display.get_monitor_geometry(i);
  199. if (_geometry.x < _currGeo.x && (!min || _geometry.x > min)) {
  200. min = _geometry.x;
  201. best = i;
  202. }
  203. }
  204. }
  205. return best;
  206. default:
  207. return null;
  208. }
  209. }
  210. /** Returns tile closest to the edge on a monitor
  211. * - If the monitor is in fullscreen it returns the maximized window
  212. *
  213. * @param {Direction} dir
  214. * @returns {Tile | null}
  215. */
  216. getTile(dir) {
  217. if (this.root === null)
  218. return null;
  219. if (this.fullscreen)
  220. return this.root.find(t => t.state === TileState.MAXIMIZED);
  221. let getTileBis = t => {
  222. switch (dir) {
  223. case Direction.East:
  224. if (t.child2 !== null && t.child1 !== null)
  225. return t.child1.position.x > t.child2.position.x ? getTileBis(t.child1) : getTileBis(t.child2);
  226. else if (t.child1 !== null)
  227. return getTileBis(t.child1);
  228. else if (t.child2 !== null)
  229. return getTileBis(t.child2);
  230. else
  231. return t;
  232. case Direction.West:
  233. if (t.child2 !== null && t.child1 !== null)
  234. return t.child1.position.x < t.child2.position.x ? getTileBis(t.child1) : getTileBis(t.child2);
  235. else if (t.child1 !== null)
  236. return getTileBis(t.child1);
  237. else if (t.child2 !== null)
  238. return getTileBis(t.child2);
  239. else
  240. return t;
  241. case Direction.North:
  242. if (t.child2 !== null && t.child1 !== null)
  243. return t.child1.position.y < t.child2.position.y ? getTileBis(t.child1) : getTileBis(t.child2);
  244. else if (t.child1 !== null)
  245. return getTileBis(t.child1);
  246. else if (t.child2 !== null)
  247. return getTileBis(t.child2);
  248. else
  249. return t;
  250. case Direction.South:
  251. if (t.child2 !== null && t.child1 !== null)
  252. return t.child1.position.y > t.child2.position.y ? getTileBis(t.child1) : getTileBis(t.child2);
  253. else if (t.child1 !== null)
  254. return getTileBis(t.child1);
  255. else if (t.child2 !== null)
  256. return getTileBis(t.child2);
  257. else
  258. return t;
  259. default:
  260. return t;
  261. }
  262. };
  263. return getTileBis(this.root);
  264. }
  265. }