| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931 |
- import Meta from 'gi://Meta';
- import GLib from 'gi://GLib';
- import {Orientation, Tile, TileState} from './tile.js';
- import {Position} from './position.js';
- import * as Resize from './resize.js';
- import Gio from 'gi://Gio';
- import * as Main from 'resource:///org/gnome/shell/ui/main.js';
- import {Monitor} from './monitor.js';
- import Shell from 'gi://Shell';
- import Mtk from 'gi://Mtk';
- import {TopBarSearchEntry} from './topBarSearchEntry.js';
- export var Direction;
- (function (Direction) {
- Direction[Direction['North'] = 1] = 'North';
- Direction[Direction['South'] = 2] = 'South';
- Direction[Direction['West'] = 3] = 'West';
- Direction[Direction['East'] = 4] = 'East';
- })(Direction || (Direction = {}));
- export class TileWindowManager {
- /** ************************************************/
- // Store all signals to be restored when extension is disabled
- _wrappedWindows;
- _nMonitors;
- _windowCreatedSignal;
- _windowGrabSignal;
- _workspaceAddedSignal;
- _workspaceRemovedSignal;
- _activeWorkspaceSignal;
- _grabBeginSignal;
- _monitorChangedSignal;
- _workareasChangedSignal;
- /** ************************************************/
- _settings;
- _userResize;
- static locked = false;
- // Alternate windows rotation
- static rotateEven = [0, 0];
- // Search bar widgets
- _topBarSearchEntry;
- _modalSearchEntry;
- _sourceId;
- // Tiles structures
- static _workspaces = new Map();
- static _main_monitor;
- constructor(extension) {
- if (!TileWindowManager._workspaces)
- TileWindowManager._workspaces = new Map();
- TileWindowManager._main_monitor = global.display.get_primary_monitor();
- this._settings = extension._settings;
- this._nMonitors = global.display.get_n_monitors();
- for (let i = 0; i < global.workspace_manager.n_workspaces; i++) {
- let _monitors = new Array(this._nMonitors);
- for (let j = 0; j < _monitors.length; j++)
- _monitors[j] = new Monitor(j);
- TileWindowManager._workspaces.set(i, _monitors);
- }
- this._wrappedWindows = new Map();
- this._userResize = new Set();
- this._sourceId = null;
- if (TileWindowManager.locked)
- this._loadAfterSessionLock();
- global.get_window_actors().forEach(actor => {
- if (actor.meta_window &&
- actor.meta_window.get_window_type() === Meta.WindowType.NORMAL)
- this._addNewWindow(actor.meta_window);
- });
- this.updateMonitors();
- this._windowCreatedSignal = global.display.connect('window-created', (display, obj) => this._onWindowCreated(display, obj));
- this._workareasChangedSignal = global.display.connect('workareas-changed', () => {
- TileWindowManager._workspaces.forEach(val => {
- val.forEach(m => m.updateSize());
- });
- this.updateMonitors();
- });
- this._grabBeginSignal = global.display.connect('grab-op-begin', (_, w) => this._userResize.add(w));
- this._windowGrabSignal = global.display.connect('grab-op-end', (_, window, op) => {
- this._onGrab(window, op);
- this._userResize.delete(window);
- });
- this._workspaceAddedSignal = global.workspace_manager.connect('workspace-added', (_, index) => {
- this._onWorkspaceCreated(index);
- });
- this._workspaceRemovedSignal = global.workspace_manager.connect('workspace-removed', (_, index) => {
- this._onWorkspaceRemoved(index);
- });
- this._activeWorkspaceSignal = global.workspace_manager.connect('active-workspace-changed', () => {
- this.updateMonitors();
- this.updateAdjacents();
- });
- this._monitorChangedSignal = global.backend.get_monitor_manager().connect('monitors-changed', () => {
- const n = global.display.get_n_monitors();
- if (n !== this._nMonitors) {
- let diff = n - this._nMonitors;
- this._nMonitors = n;
- if (diff > 0)
- this._addMonitors();
- else
- this._removeMonitors();
- }
- });
- }
- static getMonitors(workspaceIndex = undefined) {
- let wk;
- if (!workspaceIndex)
- wk = TileWindowManager._workspaces.get(global.workspace_manager.get_active_workspace_index());
- else
- wk = TileWindowManager._workspaces.get(workspaceIndex);
- if (wk)
- return wk;
- else
- return [];
- }
- _addMonitors() {
- let newPrimMonitor = global.display.get_primary_monitor();
- TileWindowManager._workspaces.forEach((val, _, __) => {
- let currPrim = null;
- if (newPrimMonitor !== TileWindowManager._main_monitor)
- currPrim = val.filter(e => e.index === TileWindowManager._main_monitor)[0];
- while (val.length !== this._nMonitors) {
- const index = val.length;
- val.push(new Monitor(index));
- // Move content on the new primary screen
- if (index === newPrimMonitor) {
- val[index].fullscreen = currPrim?.fullscreen ?? false;
- val[index].root = currPrim?.root ?? null;
- val[index].root?.forEach(el => {
- el.monitor = index;
- });
- if (currPrim?.fullscreen)
- currPrim.fullscreen = false;
- if (currPrim?.root)
- currPrim.root = null;
- }
- }
- });
- TileWindowManager._main_monitor = newPrimMonitor;
- }
- _removeMonitors() {
- TileWindowManager._workspaces.forEach((val, _, __) => {
- let windows = [];
- while (val.length !== this._nMonitors)
- windows.push(val.pop());
- for (let i = 0; i < windows.length; i++) {
- windows[i]?.root?.forEach(t => {
- if (t.window)
- this._insertWindow(t.window, null, 0);
- });
- }
- });
- TileWindowManager._main_monitor = global.display.get_primary_monitor();
- this.updateMonitors();
- this.updateAdjacents();
- }
- /**
- * Refresh **ALL** existing tiles.
- */
- updateMonitors() {
- TileWindowManager._workspaces.forEach((value, _) => {
- value.forEach(el => el.root?.update());
- });
- }
- updateAdjacents() {
- TileWindowManager._workspaces.forEach((value, _) => {
- value.forEach(el => el.root?.forEach(t => t.findAdjacents()));
- });
- }
- destroy() {
- global.display.disconnect(this._windowCreatedSignal);
- global.display.disconnect(this._windowGrabSignal);
- global.display.disconnect(this._grabBeginSignal);
- global.display.disconnect(this._workareasChangedSignal);
- global.workspace_manager.disconnect(this._workspaceAddedSignal);
- global.workspace_manager.disconnect(this._workspaceRemovedSignal);
- global.workspace_manager.disconnect(this._activeWorkspaceSignal);
- global.backend.disconnect(this._monitorChangedSignal);
- if (Resize.resizeSourceId !== null)
- GLib.Source.remove(Resize.resizeSourceId);
- // Disconnect each window
- this._wrappedWindows.forEach((value, key) => {
- key.minimize = value[0];
- key.maximize = value[1];
- key.disconnect(value[2]);
- key.disconnect(value[3]);
- key.disconnect(value[4]);
- key.disconnect(value[5]);
- key.disconnect(value[6]);
- key.disconnect(value[7]);
- this._wrappedWindows.delete(key);
- });
- this._wrappedWindows.clear();
- this._topBarSearchEntry?.destroy();
- TileWindowManager._main_monitor = null;
- TileWindowManager._workspaces = null;
- }
- /** Check if the window is a `valid` window.
- * A `valid` window is a window created by user and
- * running an app.
- * It is tricky to filter windows correctly. Here we exclude
- * windows that don't have app id (the id is just the app number).
- * This method must be called when we're sure the window is **fully**
- * created (basically when wait for first-frame signal). Otherwise
- * we may badly filter some windows.
- *
- * @param {Meta.Window} window
- * @returns boolean
- */
- _isValidWindow(window) {
- if (!window)
- return false;
- if (window.get_window_type() !== Meta.WindowType.NORMAL)
- return false;
- let app = Shell.WindowTracker.get_default().get_window_app(window);
- if (!app)
- return false;
- if (app.get_id().startsWith('window:'))
- return false;
- for (var [_, value] of TileWindowManager._workspaces) {
- let containsWindow = value.reduce((acc, val) => val.root ? acc || val.root.contains(window) : acc, false);
- if (containsWindow)
- return false;
- }
- return true;
- }
- _onWorkspaceCreated(index) {
- let _monitors = new Array(global.display.get_n_monitors());
- for (let i = 0; i < _monitors.length; i++)
- _monitors[i] = new Monitor(i);
- if (!TileWindowManager._workspaces.has(index))
- TileWindowManager._workspaces.set(index, _monitors);
- }
- _onWorkspaceRemoved(index) {
- TileWindowManager._workspaces.delete(index);
- let newMap = new Map();
- TileWindowManager._workspaces.forEach((value, key) => {
- if (key > index) {
- value.forEach(el => el.root?.forEach(t => {
- t.workspace = key - 1;
- }));
- newMap.set(key - 1, value);
- } else {
- newMap.set(key, value);
- }
- });
- TileWindowManager._workspaces = newMap;
- this.updateMonitors();
- this.updateAdjacents();
- }
- _onWindowCreated(_, window) {
- // Wait for first frame to be sure window is fully created
- window.get_compositor_private().connect('first-frame', () => {
- this._addNewWindow(window);
- });
- }
- _windowWorkspaceChanged(window) {
- let tile = window.tile;
- if (tile) {
- let w = window.get_workspace()?.index();
- if (w !== null) {
- window.change_workspace_by_index(w, false);
- if (w !== window.tile.workspace) {
- this._removeWindow(window);
- this._insertWindow(window, w);
- tile.workspace = w;
- }
- this.updateMonitors();
- this.updateAdjacents();
- }
- }
- }
- /** Connect to signals and remove some functions
- *
- * @param {Meta.Window} window
- */
- configureWindowSignals(window) {
- let minimizeSignal = window.connect('notify::minimized', () => {
- if (!window.minimized) {
- let tile = window.tile;
- if (tile.state === TileState.MINIMIZED) {
- if (TileWindowManager.getMonitors()[tile.monitor].fullscreen) {
- if (this._settings?.get_int('fullscreen-switch') === 0)
- this.maximizeTile(window, true);
- else
- this.maximizeTile(window);
- }
- }
- } else {
- if (window.tile.state === TileState.MINIMIZED)
- return;
- window.unminimize();
- }
- });
- let maximizeSignal1 = window.connect('notify::maximized-horizontally', () => {
- if (window.tile.state === TileState.MAXIMIZED)
- return;
- if (window.maximized_horizontally || window.maximized_vertically)
- window.unmaximize(Meta.MaximizeFlags.BOTH);
- });
- let maximizeSignal2 = window.connect('notify::maximized-vertically', () => {
- if (window.tile.state === TileState.MAXIMIZED)
- return;
- if (window.maximized_horizontally || window.maximized_vertically)
- window.unmaximize(Meta.MaximizeFlags.BOTH);
- });
- let unmanagedSignal = window.connect('unmanaged', () => {
- this._removeWindow(window);
- this._removeWindowSignals(window);
- });
- let workspaceChangedSignal = window.connect('workspace-changed', w => this._windowWorkspaceChanged(w));
- let sizeChangedSignal = window.connect('size-changed', w => {
- let tile = w.tile;
- if (!this._userResize.has(w) &&
- (tile.position.width !== w.get_frame_rect().width ||
- tile.position.height !== w.get_frame_rect().height))
- tile.update();
- });
- window._originalMaximize = window.maximize;
- window._originalMinimize = window.minimize;
- this._wrappedWindows.set(window, [window.minimize, window.maximize, minimizeSignal,
- maximizeSignal1, maximizeSignal2,
- unmanagedSignal, workspaceChangedSignal, sizeChangedSignal]);
- window.minimize = () => { };
- window.maximize = () => { };
- }
- _addNewWindow(window) {
- if (!this._isValidWindow(window))
- return;
- this.configureWindowSignals(window);
- this._insertWindow(window);
- }
- _insertWindow(window, workspace = null, monitor = null) {
- let _monitors = TileWindowManager._workspaces.get(workspace != null ? workspace : window.get_workspace()?.index());
- if (!_monitors)
- return;
- let selectedMonitor;
- // Select monitor
- if (monitor !== null) {
- selectedMonitor = _monitors[monitor];
- } else if (this._settings?.get_int('monitor-tile-insertion-behavior') === 0) {
- selectedMonitor = Monitor.bestFitMonitor(_monitors);
- } else {
- let m = global.display.get_current_monitor();
- selectedMonitor = _monitors[m];
- }
- // Selected monitor index
- let index = selectedMonitor.index;
- // Now insert tile on selected monitor
- if (selectedMonitor.size() === 0) {
- let tile = Tile.createTileLeaf(window, new Position(1.0, 0, 0, 0, 0), index);
- tile.workspace = window.get_workspace().index();
- window.tile = tile;
- _monitors[index].root = tile;
- _monitors[index].root?.update();
- } else {
- _monitors[index].root?.addWindowOnBlock(window);
- window.tile.workspace = window.get_workspace().index();
- if (_monitors[index].fullscreen)
- window.tile.state = TileState.MINIMIZED;
- _monitors[index].root?.update();
- }
- }
- _removeWindowSignals(window) {
- window.tile?.destroy();
- // Disconnect signals
- let s = this._wrappedWindows.get(window);
- if (s) {
- window.minimize = s[0];
- window.maximize = s[1];
- window.disconnect(s[2]);
- window.disconnect(s[3]);
- window.disconnect(s[4]);
- window.disconnect(s[5]);
- window.disconnect(s[6]);
- window.disconnect(s[7]);
- }
- this._wrappedWindows.delete(window);
- }
- _removeWindow(window) {
- // get Tile from window
- let tile = window.tile;
- // Not found
- if (!tile)
- return;
- let m = tile.monitor;
- if (TileWindowManager.getMonitors()[m].fullscreen) {
- TileWindowManager.getMonitors()[m].fullscreen = false;
- let focus = null;
- TileWindowManager.getMonitors()[m].root?.forEach(el => {
- el.state = TileState.DEFAULT;
- el.window?.unminimize();
- if (!focus && el.window && el.window !== window) {
- el.window?.focus(0);
- focus = el;
- }
- });
- }
- if (tile.removeTile() === null)
- TileWindowManager.getMonitors(tile.workspace)[m].root = null;
- else
- TileWindowManager.getMonitors()[m].root?.update();
- }
- _onGrab(window, op) {
- if (!window)
- return;
- let tile = window.tile;
- if (!tile)
- return;
- let m = tile.monitor;
- let rect;
- switch (op) {
- case Meta.GrabOp.MOVING:
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- TileWindowManager.getMonitors()[m].root?.update();
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_E:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeE(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_W:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeW(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_N:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeN(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_S:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeS(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_NE:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeN(tile, rect);
- Resize.resizeE(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_NW:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeN(tile, rect);
- Resize.resizeW(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_SE:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeS(tile, rect);
- Resize.resizeE(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- case Meta.GrabOp.RESIZING_SW:
- rect = window.get_frame_rect();
- if (this._sourceId !== null)
- GLib.Source.remove(this._sourceId);
- this._sourceId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
- Resize.resizeS(tile, rect);
- Resize.resizeW(tile, rect);
- this._sourceId = null;
- return GLib.SOURCE_REMOVE;
- });
- break;
- default:
- break;
- }
- }
- /** Resize operation with keyboard. This operation is
- * different from the one operated with the mouse (grab operation)
- * because we handle left/right resize differently.
- *
- * @param {Meta.GrabOp} op
- * @param {number} resizeGap
- * @returns void
- */
- resizeFocusedWindow(op, resizeGap = 10) {
- let window = global.display.focusWindow;
- if (!window)
- return;
- let tile = window.tile;
- if (op === Meta.GrabOp.RESIZING_E) {
- if (tile.adjacents[1]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x,
- y: tile.position.y,
- width: tile.position.width + resizeGap,
- height: tile.position.height,
- });
- Resize.resizeE(tile, r);
- } else if (tile.adjacents[0]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x + resizeGap,
- y: tile.position.y,
- width: tile.position.width - resizeGap,
- height: tile.position.height,
- });
- Resize.resizeW(tile, r);
- }
- } else if (op === Meta.GrabOp.RESIZING_W) {
- if (tile.adjacents[0]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x - resizeGap,
- y: tile.position.y,
- width: tile.position.width + resizeGap,
- height: tile.position.height,
- });
- Resize.resizeW(tile, r);
- } else if (tile.adjacents[1]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x,
- y: tile.position.y,
- width: tile.position.width - resizeGap,
- height: tile.position.height,
- });
- Resize.resizeE(tile, r);
- }
- } else if (op === Meta.GrabOp.RESIZING_N) {
- if (tile.adjacents[2]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x,
- y: tile.position.y - resizeGap,
- width: tile.position.width,
- height: tile.position.height + resizeGap,
- });
- Resize.resizeN(tile, r);
- } else if (tile.adjacents[3]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x,
- y: tile.position.y,
- width: tile.position.width,
- height: tile.position.height - resizeGap,
- });
- Resize.resizeS(tile, r);
- }
- } else if (op === Meta.GrabOp.RESIZING_S) {
- if (tile.adjacents[3]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x,
- y: tile.position.y,
- width: tile.position.width,
- height: tile.position.height + resizeGap,
- });
- Resize.resizeS(tile, r);
- } else if (tile.adjacents[2]) {
- let r = new Mtk.Rectangle({
- x: tile.position.x,
- y: tile.position.y + resizeGap,
- width: tile.position.width,
- height: tile.position.height - resizeGap,
- });
- Resize.resizeN(tile, r);
- }
- }
- }
- /** Clock wise windows rotation.
- * Rotates the parent tile (if existing).
- *
- * @param {Meta.Window} window
- * @returns
- */
- rotateWindow(window) {
- let tile = window.tile;
- if (!tile)
- return;
- let parent = tile.parent;
- if (!parent)
- return;
- let newPositions;
- if (parent.orientation === Orientation.Horizontal) {
- newPositions = parent.position.split(Orientation.Vertical);
- if (parent.child1 && parent.child2) {
- newPositions[TileWindowManager.rotateEven[0] === 0 ? 0 : 1].splitProportion = parent.child1.position.splitProportion;
- newPositions[TileWindowManager.rotateEven[0] === 0 ? 1 : 0].splitProportion = parent.child2.position.splitProportion;
- parent.child1.resize(newPositions[TileWindowManager.rotateEven[0] === 0 ? 0 : 1]);
- parent.child2.resize(newPositions[TileWindowManager.rotateEven[0] === 0 ? 1 : 0]);
- parent.forEach(el => el.findAdjacents());
- TileWindowManager.rotateEven[0] = (TileWindowManager.rotateEven[0] + 1) % 2;
- parent.update();
- } else {
- return;
- }
- parent.orientation = Orientation.Vertical;
- } else if (parent.orientation === Orientation.Vertical) {
- newPositions = parent.position.split(Orientation.Horizontal);
- if (parent.child1 && parent.child2) {
- newPositions[TileWindowManager.rotateEven[1] === 0 ? 1 : 0].splitProportion = parent.child1.position.splitProportion;
- newPositions[TileWindowManager.rotateEven[1] === 0 ? 0 : 1].splitProportion = parent.child2.position.splitProportion;
- parent.child1.resize(newPositions[TileWindowManager.rotateEven[1] === 0 ? 1 : 0]);
- parent.child2.resize(newPositions[TileWindowManager.rotateEven[1] === 0 ? 0 : 1]);
- parent.forEach(el => el.findAdjacents());
- TileWindowManager.rotateEven[1] = (TileWindowManager.rotateEven[1] + 1) % 2;
- parent.update();
- } else {
- return;
- }
- parent.orientation = Orientation.Horizontal;
- }
- }
- /** Maximize the currently focused window.
- * Others windows are reduced using tile specific state.
- *
- * @param {Meta.Window} window
- * @param {boolean} replace true to stay in fullscreen and just replace the window otherwise false
- * @returns
- */
- maximizeTile(window, replace = false) {
- let tile = window.tile;
- if (!tile)
- return;
- let m = tile.monitor;
- if (TileWindowManager.getMonitors()[tile.monitor].fullscreen) {
- TileWindowManager.getMonitors()[tile.monitor].fullscreen = false;
- TileWindowManager.getMonitors()[m].root?.forEach(el => {
- el.state = TileState.DEFAULT;
- if (el.window?.minimized)
- el.window?.unminimize();
- });
- if (replace) {
- TileWindowManager.getMonitors()[m].fullscreen = true;
- TileWindowManager.getMonitors()[m].root?.forEach(el => {
- if (el.id === tile.id)
- el.state = TileState.MAXIMIZED;
- else
- el.state = TileState.MINIMIZED;
- });
- }
- } else {
- TileWindowManager.getMonitors()[tile.monitor].fullscreen = true;
- TileWindowManager.getMonitors()[m].root?.forEach(el => {
- if (el.id === tile.id)
- el.state = TileState.MAXIMIZED;
- else
- el.state = TileState.MINIMIZED;
- });
- }
- TileWindowManager.getMonitors()[m].root?.update();
- }
- moveTile(dir) {
- let window = global.display.get_focus_window();
- if (!window)
- return;
- let tile = window.tile;
- if (!tile.window)
- return;
- let exchangeTile = TileWindowManager.getMonitors()[tile.monitor].closestTile(tile, dir);
- if (!exchangeTile || !exchangeTile.window)
- return;
- let tmpWindow = exchangeTile.window;
- exchangeTile.window = tile.window;
- tile.window = tmpWindow;
- tile.window.tile = tile;
- exchangeTile.window.tile = exchangeTile;
- TileWindowManager.getMonitors()[tile.monitor].root?.update();
- }
- changeFocus(dir) {
- let window = global.display.get_focus_window();
- if (!window)
- return;
- let tile = window.tile;
- if (!tile.window)
- return;
- if (TileWindowManager.getMonitors()[tile.monitor].fullscreen === true) {
- let mon = TileWindowManager.getMonitors()[tile.monitor].closestMonitor(dir);
- if (mon === null)
- return;
- let newFocus;
- switch (dir) {
- case Direction.North:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.South);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- case Direction.South:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.North);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- case Direction.East:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.West);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- case Direction.West:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.East);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- }
- } else {
- let newFocus = TileWindowManager.getMonitors()[tile.monitor].closestTile(tile, dir);
- if (newFocus === null) {
- let mon = TileWindowManager.getMonitors()[tile.monitor].closestMonitor(dir);
- if (mon === null)
- return;
- switch (dir) {
- case Direction.North:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.South);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- case Direction.South:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.North);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- case Direction.East:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.West);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- case Direction.West:
- newFocus = TileWindowManager.getMonitors()[mon].getTile(Direction.East);
- if (newFocus)
- newFocus?.window?.focus(0);
- break;
- default:
- }
- } else {
- newFocus?.window?.focus(0);
- }
- }
- }
- createSearchBar() {
- if (this._topBarSearchEntry && this._topBarSearchEntry.isAlive()) {
- this._topBarSearchEntry.destroy();
- this._topBarSearchEntry = undefined;
- return;
- }
- if (this._settings)
- this._topBarSearchEntry = new TopBarSearchEntry(this._settings);
- }
- refresh() {
- TileWindowManager.getMonitors().forEach(el => el.root ? el.root.update() : null);
- }
- moveToWorkspace(next) {
- let window = global.display.get_focus_window();
- let tile = window.tile;
- let current = tile.workspace;
- if (next) {
- if (current < global.workspaceManager.get_n_workspaces() - 1) {
- tile.workspace = current + 1;
- window.change_workspace_by_index(tile.workspace, false);
- this._removeWindow(window);
- this._insertWindow(window, current + 1);
- }
- } else if (current > 0) {
- tile.workspace = current - 1;
- window.change_workspace_by_index(tile.workspace, false);
- this._removeWindow(window);
- this._insertWindow(window, current - 1);
- }
- this.updateMonitors();
- this.updateAdjacents();
- }
- moveToNextMonitor() {
- let window = global.display.get_focus_window();
- this._removeWindow(window);
- let tile = window.tile;
- let monitors = TileWindowManager.getMonitors();
- let newMonitorIndex = (tile.monitor + 1) % monitors.length;
- let newMonitor = monitors[newMonitorIndex];
- if (newMonitor.size() === 0) {
- let newTile = Tile.createTileLeaf(window, new Position(1.0, 0, 0, 0, 0), newMonitorIndex);
- newTile.workspace = window.get_workspace().index();
- window.tile = newTile;
- newMonitor.root = newTile;
- newMonitor.root?.update();
- } else {
- // Easier to create a new tile for insertion
- newMonitor.root?.addWindowOnBlock(window);
- window.tile.workspace = window.get_workspace().index();
- if (newMonitor.fullscreen)
- window.tile.state = TileState.MINIMIZED;
- newMonitor.root?.update();
- }
- }
- /** Extension is disabled on screen lock.
- * We save the state of the Monitors before we quit.
- *
- * @returns
- */
- _saveBeforeSessionLock() {
- if (!Main.sessionMode.isLocked)
- return;
- TileWindowManager.locked = true;
- const userPath = GLib.get_user_config_dir();
- const parentPath = GLib.build_filenamev([userPath, '/grimble']);
- const parent = Gio.File.new_for_path(parentPath);
- try {
- parent.make_directory_with_parents(null);
- } catch (e) {
- if (e.code !== Gio.IOErrorEnum.EXISTS)
- throw e;
- }
- const path = GLib.build_filenamev([parentPath, '/tilingWmSession2.json']);
- const file = Gio.File.new_for_path(path);
- try {
- file.create(Gio.FileCreateFlags.NONE, null);
- } catch (e) {
- if (e.code !== Gio.IOErrorEnum.EXISTS)
- throw e;
- }
- file.replace_contents(JSON.stringify({
- windows: Array.from(TileWindowManager._workspaces.entries()),
- }, (key, value) => {
- if (value instanceof Meta.Window)
- return value.get_id();
- else if (key === '_parent') // remove cyclic references
- return undefined;
- else
- return value;
- }), null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null);
- }
- _loadAfterSessionLock() {
- if (!TileWindowManager.locked)
- return;
- TileWindowManager.locked = false;
- const userPath = GLib.get_user_config_dir();
- const path = GLib.build_filenamev([userPath, '/grimble/tilingWmSession2.json']);
- const file = Gio.File.new_for_path(path);
- if (!file.query_exists(null))
- return;
- try {
- file.create(Gio.FileCreateFlags.NONE, null);
- } catch (e) {
- if (e.code !== Gio.IOErrorEnum.EXISTS)
- throw e;
- }
- const [success, contents] = file.load_contents(null);
- if (!success || !contents.length)
- return;
- const openWindows = global.display.list_all_windows();
- const states = JSON.parse(new TextDecoder().decode(contents), (key, value) => key === '_window' && typeof value === 'number'
- ? openWindows.find(val => val.get_id() === value)
- : value);
- let map = new Map(states.windows);
- map.forEach((mapValue, mapKey, _) => {
- mapValue.forEach((value, index, array) => {
- // We have to rebuild correct types of each object
- array[index] = Monitor.fromObject(value);
- array[index].root?.forEach(el => {
- if (el.window) {
- this.configureWindowSignals(el.window);
- el.window.change_workspace_by_index(mapKey, false);
- }
- });
- });
- TileWindowManager._workspaces.set(mapKey, mapValue);
- });
- this.updateMonitors();
- }
- }
|