refactor arrange
This commit is contained in:
216
src/Actions.ts
216
src/Actions.ts
@@ -2,7 +2,7 @@ module Actions {
|
|||||||
export function init(world: World, config: Config) {
|
export function init(world: World, config: Config) {
|
||||||
return {
|
return {
|
||||||
focusLeft: () => {
|
focusLeft: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
if (prevColumn === null) {
|
if (prevColumn === null) {
|
||||||
return;
|
return;
|
||||||
@@ -12,7 +12,7 @@ module Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusRight: () => {
|
focusRight: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const nextColumn = grid.getNextColumn(column);
|
const nextColumn = grid.getNextColumn(column);
|
||||||
if (nextColumn === null) {
|
if (nextColumn === null) {
|
||||||
return;
|
return;
|
||||||
@@ -22,7 +22,7 @@ module Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusUp: () => {
|
focusUp: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const prevWindow = column.getPrevWindow(window);
|
const prevWindow = column.getPrevWindow(window);
|
||||||
if (prevWindow === null) {
|
if (prevWindow === null) {
|
||||||
return;
|
return;
|
||||||
@@ -32,7 +32,7 @@ module Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusDown: () => {
|
focusDown: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const nextWindow = column.getNextWindow(window);
|
const nextWindow = column.getNextWindow(window);
|
||||||
if (nextWindow === null) {
|
if (nextWindow === null) {
|
||||||
return;
|
return;
|
||||||
@@ -42,27 +42,29 @@ module Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusStart: () => {
|
focusStart: () => {
|
||||||
const grid = world.getCurrentGrid();
|
world.do((clientManager, svm) => {
|
||||||
const firstColumn = grid.getFirstColumn();
|
const grid = svm.getCurrent().grid;
|
||||||
if (firstColumn === null) {
|
const firstColumn = grid.getFirstColumn();
|
||||||
return;
|
if (firstColumn === null) {
|
||||||
}
|
return;
|
||||||
firstColumn.focus();
|
}
|
||||||
grid.container.arrange();
|
firstColumn.focus();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
focusEnd: () => {
|
focusEnd: () => {
|
||||||
const grid = world.getCurrentGrid();
|
world.do((clientManager, svm) => {
|
||||||
const lastColumn = grid.getLastColumn();
|
const grid = svm.getCurrent().grid;
|
||||||
if (lastColumn === null) {
|
const lastColumn = grid.getLastColumn();
|
||||||
return;
|
if (lastColumn === null) {
|
||||||
}
|
return;
|
||||||
lastColumn.focus();
|
}
|
||||||
grid.container.arrange();
|
lastColumn.focus();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveLeft: () => {
|
windowMoveLeft: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
if (column.getWindowCount() === 1) {
|
if (column.getWindowCount() === 1) {
|
||||||
// move from own column into existing column
|
// move from own column into existing column
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
@@ -70,18 +72,17 @@ module Actions {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.moveToColumn(prevColumn);
|
window.moveToColumn(prevColumn);
|
||||||
grid.container.onGridReordered();
|
grid.container.autoAdjustScroll();
|
||||||
} else {
|
} else {
|
||||||
// move from shared column into own column
|
// move from shared column into own column
|
||||||
const newColumn = new Column(grid, grid.getPrevColumn(column));
|
const newColumn = new Column(grid, grid.getPrevColumn(column));
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
}
|
}
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveRight: () => {
|
windowMoveRight: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
if (column.getWindowCount() === 1) {
|
if (column.getWindowCount() === 1) {
|
||||||
// move from own column into existing column
|
// move from own column into existing column
|
||||||
const nextColumn = grid.getNextColumn(column);
|
const nextColumn = grid.getNextColumn(column);
|
||||||
@@ -89,97 +90,89 @@ module Actions {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.moveToColumn(nextColumn);
|
window.moveToColumn(nextColumn);
|
||||||
grid.container.onGridReordered();
|
grid.container.autoAdjustScroll();
|
||||||
} else {
|
} else {
|
||||||
// move from shared column into own column
|
// move from shared column into own column
|
||||||
const newColumn = new Column(grid, column);
|
const newColumn = new Column(grid, column);
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
}
|
}
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveUp: () => {
|
windowMoveUp: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
// TODO (optimization): only arrange moved windows
|
||||||
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
column.moveWindowUp(window);
|
column.moveWindowUp(window);
|
||||||
grid.container.arrange(); // TODO (optimization): only arrange moved windows
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveDown: () => {
|
windowMoveDown: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
// TODO (optimization): only arrange moved windows
|
||||||
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
column.moveWindowDown(window);
|
column.moveWindowDown(window);
|
||||||
grid.container.arrange(); // TODO (optimization): only arrange moved windows
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveStart: () => {
|
windowMoveStart: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const newColumn = new Column(grid, null);
|
const newColumn = new Column(grid, null);
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveEnd: () => {
|
windowMoveEnd: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const newColumn = new Column(grid, grid.getLastColumn());
|
const newColumn = new Column(grid, grid.getLastColumn());
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowToggleFloating: () => {
|
windowToggleFloating: () => {
|
||||||
const kwinClient = workspace.activeClient;
|
const kwinClient = workspace.activeClient;
|
||||||
world.toggleFloatingClient(kwinClient);
|
world.do((clientManager, svm) => {
|
||||||
|
clientManager.toggleFloatingClient(kwinClient);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveLeft: () => {
|
columnMoveLeft: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
grid.moveColumnLeft(column);
|
grid.moveColumnLeft(column);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveRight: () => {
|
columnMoveRight: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
grid.moveColumnRight(column);
|
grid.moveColumnRight(column);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveStart: () => {
|
columnMoveStart: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
column.moveAfter(null);
|
column.moveAfter(null);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveEnd: () => {
|
columnMoveEnd: () => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
column.moveAfter(grid.getLastColumn());
|
column.moveAfter(grid.getLastColumn());
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnToggleStacked: () => {
|
columnToggleStacked: () => {
|
||||||
world.doIfTiledFocused(false, (window, column, grid) => {
|
world.doIfTiledFocused(false, (world, svm, window, column, grid) => {
|
||||||
column.toggleStacked();
|
column.toggleStacked();
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnWidthIncrease: () => {
|
columnWidthIncrease: () => {
|
||||||
world.doIfTiledFocused(false, (window, column, grid) => {
|
world.doIfTiledFocused(false, (world, svm, window, column, grid) => {
|
||||||
grid.increaseColumnWidth(column);
|
grid.increaseColumnWidth(column);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnWidthDecrease: () => {
|
columnWidthDecrease: () => {
|
||||||
world.doIfTiledFocused(false, (window, column, grid) => {
|
world.doIfTiledFocused(false, (world, svm, window, column, grid) => {
|
||||||
grid.decreaseColumnWidth(column);
|
grid.decreaseColumnWidth(column);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -192,66 +185,65 @@ module Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
gridScrollStart: () => {
|
gridScrollStart: () => {
|
||||||
const grid = world.getCurrentGrid();
|
world.do((clientManager, svm) => {
|
||||||
const firstColumn = grid.getFirstColumn();
|
const grid = svm.getCurrent().grid;
|
||||||
if (firstColumn === null) {
|
const firstColumn = grid.getFirstColumn();
|
||||||
return;
|
if (firstColumn === null) {
|
||||||
}
|
return;
|
||||||
grid.container.scrollToColumn(firstColumn);
|
}
|
||||||
grid.container.arrange();
|
grid.container.scrollToColumn(firstColumn);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
gridScrollEnd: () => {
|
gridScrollEnd: () => {
|
||||||
const grid = world.getCurrentGrid();
|
world.do((clientManager, svm) => {
|
||||||
const lastColumn = grid.getLastColumn();
|
const grid = svm.getCurrent().grid;
|
||||||
if (lastColumn === null) {
|
const lastColumn = grid.getLastColumn();
|
||||||
return;
|
if (lastColumn === null) {
|
||||||
}
|
return;
|
||||||
grid.container.scrollToColumn(lastColumn);
|
}
|
||||||
grid.container.arrange();
|
grid.container.scrollToColumn(lastColumn);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
gridScrollFocused: () => {
|
gridScrollFocused: () => {
|
||||||
const focusedWindow = world.getFocusedWindow(true);
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
if (focusedWindow === null) {
|
grid.container.scrollCenterColumn(column);
|
||||||
return;
|
})
|
||||||
}
|
|
||||||
const column = focusedWindow.column;
|
|
||||||
const grid = column.grid;
|
|
||||||
grid.container.scrollCenterColumn(column);
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
gridScrollLeftColumn: () => {
|
gridScrollLeftColumn: () => {
|
||||||
const grid = world.getCurrentGrid();
|
world.do((clientManager, svm) => {
|
||||||
const column = grid.getLeftmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
const grid = svm.getCurrent().grid;
|
||||||
if (column === null) {
|
const column = grid.getLeftmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
||||||
return;
|
if (column === null) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
if (prevColumn === null) {
|
if (prevColumn === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
grid.container.scrollToColumn(prevColumn);
|
grid.container.scrollToColumn(prevColumn);
|
||||||
grid.container.arrange();
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
gridScrollRightColumn: () => {
|
gridScrollRightColumn: () => {
|
||||||
const grid = world.getCurrentGrid();
|
world.do((clientManager, svm) => {
|
||||||
const column = grid.getRightmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
const grid = svm.getCurrent().grid;
|
||||||
if (column === null) {
|
const column = grid.getRightmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
||||||
return;
|
if (column === null) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const nextColumn = grid.getNextColumn(column);
|
const nextColumn = grid.getNextColumn(column);
|
||||||
if (nextColumn === null) {
|
if (nextColumn === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
grid.container.scrollToColumn(nextColumn);
|
grid.container.scrollToColumn(nextColumn);
|
||||||
grid.container.arrange();
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -259,28 +251,29 @@ module Actions {
|
|||||||
export function initNum(world: World) {
|
export function initNum(world: World) {
|
||||||
return {
|
return {
|
||||||
focusColumn: (columnIndex: number) => {
|
focusColumn: (columnIndex: number) => {
|
||||||
const grid = world.getCurrentGrid();
|
world.do((clientManager, svm) => {
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
const grid = svm.getCurrent().grid;
|
||||||
if (targetColumn === null) {
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
return null;
|
if (targetColumn === null) {
|
||||||
}
|
return null;
|
||||||
targetColumn.focus();
|
}
|
||||||
|
targetColumn.focus();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveToColumn: (columnIndex: number) => {
|
windowMoveToColumn: (columnIndex: number) => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
if (targetColumn === null) {
|
if (targetColumn === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
window.moveToColumn(targetColumn);
|
window.moveToColumn(targetColumn);
|
||||||
grid.container.onGridReordered();
|
grid.container.autoAdjustScroll();
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveToColumn: (columnIndex: number) => {
|
columnMoveToColumn: (columnIndex: number) => {
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
world.doIfTiledFocused(true, (world, svm, window, column, grid) => {
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
if (targetColumn === null || targetColumn === column) {
|
if (targetColumn === null || targetColumn === column) {
|
||||||
return null;
|
return null;
|
||||||
@@ -290,43 +283,38 @@ module Actions {
|
|||||||
} else {
|
} else {
|
||||||
column.moveAfter(grid.getPrevColumn(targetColumn));
|
column.moveAfter(grid.getPrevColumn(targetColumn));
|
||||||
}
|
}
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveToDesktop: (desktopIndex: number) => {
|
columnMoveToDesktop: (desktopIndex: number) => {
|
||||||
world.doIfTiledFocused(true, (window, column, oldGrid) => {
|
world.doIfTiledFocused(true, (clientManager, svm, window, column, oldGrid) => {
|
||||||
const desktopNumber = desktopIndex + 1;
|
const desktopNumber = desktopIndex + 1;
|
||||||
const newGrid = world.getGridInCurrentActivity(desktopNumber);
|
const newGrid = svm.getInCurrentActivity(desktopNumber).grid;
|
||||||
if (newGrid === null || newGrid === oldGrid) {
|
if (newGrid === null || newGrid === oldGrid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
column.moveToGrid(newGrid, newGrid.getLastColumn());
|
column.moveToGrid(newGrid, newGrid.getLastColumn());
|
||||||
oldGrid.container.arrange();
|
|
||||||
newGrid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
tailMoveToDesktop: (desktopIndex: number) => {
|
tailMoveToDesktop: (desktopIndex: number) => {
|
||||||
world.doIfTiledFocused(true, (window, column, oldGrid) => {
|
world.doIfTiledFocused(true, (clientManager, svm, window, column, oldGrid) => {
|
||||||
const desktopNumber = desktopIndex + 1;
|
const desktopNumber = desktopIndex + 1;
|
||||||
const newGrid = world.getGridInCurrentActivity(desktopNumber);
|
const newGrid = svm.getInCurrentActivity(desktopNumber).grid;
|
||||||
if (newGrid === null || newGrid === oldGrid) {
|
if (newGrid === null || newGrid === oldGrid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
oldGrid.evacuateTail(newGrid, column);
|
oldGrid.evacuateTail(newGrid, column);
|
||||||
oldGrid.container.arrange();
|
|
||||||
newGrid.container.arrange();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridScroll(world: World, amount: number) {
|
function gridScroll(world: World, amount: number) {
|
||||||
const scrollAmount = amount;
|
world.do((clientManager, svm) => {
|
||||||
const grid = world.getCurrentGrid();
|
const grid = svm.getCurrent().grid;
|
||||||
grid.container.adjustScroll(scrollAmount, false);
|
grid.container.adjustScroll(amount, false);
|
||||||
grid.container.arrange();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Config = {
|
export type Config = {
|
||||||
|
|||||||
@@ -47,10 +47,12 @@ class Column {
|
|||||||
|
|
||||||
public moveWindowUp(window: Window) {
|
public moveWindowUp(window: Window) {
|
||||||
this.windows.moveBack(window);
|
this.windows.moveBack(window);
|
||||||
|
this.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public moveWindowDown(window: Window) {
|
public moveWindowDown(window: Window) {
|
||||||
this.windows.moveForward(window);
|
this.windows.moveForward(window);
|
||||||
|
this.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getWindowCount() {
|
public getWindowCount() {
|
||||||
@@ -124,6 +126,8 @@ class Column {
|
|||||||
|
|
||||||
window.height += heightDelta;
|
window.height += heightDelta;
|
||||||
otherWindow.height -= heightDelta;
|
otherWindow.height -= heightDelta;
|
||||||
|
|
||||||
|
this.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public resizeWindows() {
|
public resizeWindows() {
|
||||||
@@ -144,9 +148,11 @@ class Column {
|
|||||||
remainingWindows--;
|
remainingWindows--;
|
||||||
}
|
}
|
||||||
// TODO: respect min height
|
// TODO: respect min height
|
||||||
|
|
||||||
|
this.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFocusTaker() {
|
public getFocusTaker() {
|
||||||
if (this.focusTaker === null || !this.windows.contains(this.focusTaker)) {
|
if (this.focusTaker === null || !this.windows.contains(this.focusTaker)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -206,6 +212,7 @@ class Column {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.stacked = !this.stacked;
|
this.stacked = !this.stacked;
|
||||||
|
this.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public isVisible(scrollPos: ScrollView.Pos, fullyVisible: boolean) {
|
public isVisible(scrollPos: ScrollView.Pos, fullyVisible: boolean) {
|
||||||
@@ -230,6 +237,8 @@ class Column {
|
|||||||
if (window.isFocused()) {
|
if (window.isFocused()) {
|
||||||
this.onWindowFocused(window);
|
this.onWindowFocused(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onWindowRemoved(window: Window, passFocus: boolean) {
|
public onWindowRemoved(window: Window, passFocus: boolean) {
|
||||||
@@ -251,6 +260,8 @@ class Column {
|
|||||||
windowToFocus.focus();
|
windowToFocus.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onWindowFocused(window: Window) {
|
public onWindowFocused(window: Window) {
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ class Grid {
|
|||||||
this.userResize = false;
|
this.userResize = false;
|
||||||
this.userResizeFinishedDelayer = new Delayer(50, () => {
|
this.userResizeFinishedDelayer = new Delayer(50, () => {
|
||||||
// this delay prevents windows' contents from freezing after resizing
|
// this delay prevents windows' contents from freezing after resizing
|
||||||
this.container.onGridWidthChanged();
|
this.container.onLayoutChanged();
|
||||||
|
this.container.autoAdjustScroll();
|
||||||
this.container.arrange();
|
this.container.arrange();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -24,7 +25,8 @@ class Grid {
|
|||||||
public moveColumnLeft(column: Column) {
|
public moveColumnLeft(column: Column) {
|
||||||
this.columns.moveBack(column);
|
this.columns.moveBack(column);
|
||||||
this.columnsSetX(column);
|
this.columnsSetX(column);
|
||||||
this.container.onGridReordered();
|
this.container.onLayoutChanged();
|
||||||
|
this.container.autoAdjustScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public moveColumnRight(column: Column) {
|
public moveColumnRight(column: Column) {
|
||||||
@@ -66,6 +68,14 @@ class Grid {
|
|||||||
return this.lastFocusedColumn;
|
return this.lastFocusedColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getLastFocusedWindow() {
|
||||||
|
const lastFocusedColumn = this.getLastFocusedColumn();
|
||||||
|
if (lastFocusedColumn === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return lastFocusedColumn.getFocusTaker();
|
||||||
|
}
|
||||||
|
|
||||||
private columnsSetX(firstMovedColumn: Column|null) {
|
private columnsSetX(firstMovedColumn: Column|null) {
|
||||||
const lastUnmovedColumn = firstMovedColumn === null ? this.columns.getLast() : this.columns.getPrev(firstMovedColumn);
|
const lastUnmovedColumn = firstMovedColumn === null ? this.columns.getLast() : this.columns.getPrev(firstMovedColumn);
|
||||||
let x = lastUnmovedColumn === null ? 0 : lastUnmovedColumn.getRight() + this.config.gapsInnerHorizontal;
|
let x = lastUnmovedColumn === null ? 0 : lastUnmovedColumn.getRight() + this.config.gapsInnerHorizontal;
|
||||||
@@ -200,6 +210,11 @@ class Grid {
|
|||||||
column.arrange(x);
|
column.arrange(x);
|
||||||
x += column.getWidth() + this.config.gapsInnerHorizontal;
|
x += column.getWidth() + this.config.gapsInnerHorizontal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const focusedWindow = this.getLastFocusedWindow();
|
||||||
|
if (focusedWindow !== null) {
|
||||||
|
focusedWindow.client.ensureTransientsVisible(this.container.clientArea);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onColumnAdded(column: Column, prevColumn: Column|null) {
|
public onColumnAdded(column: Column, prevColumn: Column|null) {
|
||||||
@@ -209,7 +224,8 @@ class Grid {
|
|||||||
this.columns.insertAfter(column, prevColumn);
|
this.columns.insertAfter(column, prevColumn);
|
||||||
}
|
}
|
||||||
this.columnsSetX(column);
|
this.columnsSetX(column);
|
||||||
this.container.onGridWidthChanged();
|
this.container.onLayoutChanged();
|
||||||
|
this.container.autoAdjustScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onColumnRemoved(column: Column, passFocus: boolean) {
|
public onColumnRemoved(column: Column, passFocus: boolean) {
|
||||||
@@ -226,8 +242,9 @@ class Grid {
|
|||||||
if (passFocus && columnToFocus !== null) {
|
if (passFocus && columnToFocus !== null) {
|
||||||
columnToFocus.focus();
|
columnToFocus.focus();
|
||||||
} else {
|
} else {
|
||||||
this.container.onGridWidthChanged();
|
this.container.autoAdjustScroll();
|
||||||
}
|
}
|
||||||
|
this.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onColumnMoved(column: Column, prevColumn: Column|null) {
|
public onColumnMoved(column: Column, prevColumn: Column|null) {
|
||||||
@@ -235,15 +252,17 @@ class Grid {
|
|||||||
const firstMovedColumn = movedLeft ? column : this.getNextColumn(column);
|
const firstMovedColumn = movedLeft ? column : this.getNextColumn(column);
|
||||||
this.columns.move(column, prevColumn);
|
this.columns.move(column, prevColumn);
|
||||||
this.columnsSetX(firstMovedColumn);
|
this.columnsSetX(firstMovedColumn);
|
||||||
this.container.onGridReordered();
|
this.container.onLayoutChanged();
|
||||||
|
this.container.autoAdjustScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onColumnWidthChanged(column: Column, oldWidth: number, width: number) {
|
public onColumnWidthChanged(column: Column, oldWidth: number, width: number) {
|
||||||
const nextColumn = this.columns.getNext(column);
|
const nextColumn = this.columns.getNext(column);
|
||||||
this.columnsSetX(nextColumn);
|
this.columnsSetX(nextColumn);
|
||||||
if (!this.userResize) {
|
if (!this.userResize) {
|
||||||
this.container.onGridWidthChanged();
|
this.container.autoAdjustScroll();
|
||||||
}
|
}
|
||||||
|
this.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onColumnFocused(column: Column) {
|
public onColumnFocused(column: Column) {
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
class ScrollView {
|
class ScrollView {
|
||||||
public readonly world: World;
|
|
||||||
public readonly grid: Grid;
|
public readonly grid: Grid;
|
||||||
public readonly desktop: number;
|
public readonly desktop: number;
|
||||||
private readonly config: ScrollView.Config;
|
private readonly config: ScrollView.Config;
|
||||||
private scrollX: number;
|
private scrollX: number;
|
||||||
|
private dirty: boolean;
|
||||||
public clientArea: QRect;
|
public clientArea: QRect;
|
||||||
public tilingArea: QRect;
|
public tilingArea: QRect;
|
||||||
|
|
||||||
constructor(world: World, desktop: number, config: ScrollView.Config, layoutConfig: LayoutConfig) {
|
constructor(desktop: number, config: ScrollView.Config, layoutConfig: LayoutConfig) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.world = world;
|
|
||||||
this.scrollX = 0;
|
this.scrollX = 0;
|
||||||
|
this.dirty = false;
|
||||||
this.desktop = desktop;
|
this.desktop = desktop;
|
||||||
this.grid = new Grid(this, layoutConfig);
|
this.grid = new Grid(this, layoutConfig);
|
||||||
this.updateArea();
|
this.updateArea();
|
||||||
@@ -65,7 +65,7 @@ class ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public scrollToColumn(column: Column) {
|
public scrollToColumn(column: Column) {
|
||||||
this.scrollX = this.getScrollPosForColumn(column).x;
|
this.setScroll(this.getScrollPosForColumn(column).x, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public scrollCenterColumn(column: Column) {
|
public scrollCenterColumn(column: Column) {
|
||||||
@@ -74,18 +74,18 @@ class ScrollView {
|
|||||||
this.adjustScroll(Math.round(windowCenter - screenCenter), false);
|
this.adjustScroll(Math.round(windowCenter - screenCenter), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private autoAdjustScroll() {
|
public autoAdjustScroll() {
|
||||||
const focusedWindow = this.world.getFocusedWindow(true);
|
const focusedColumn = this.grid.getLastFocusedColumn();
|
||||||
if (focusedWindow === null) {
|
if (focusedColumn === null) {
|
||||||
this.removeOverscroll();
|
this.removeOverscroll();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const column = focusedWindow.column;
|
if (focusedColumn.grid !== this.grid) {
|
||||||
if (column.grid !== this.grid) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.scrollToColumn(column);
|
|
||||||
|
this.scrollToColumn(focusedColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getScrollPos(scrollX: number) {
|
private getScrollPos(scrollX: number) {
|
||||||
@@ -108,11 +108,15 @@ class ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setScroll(x: number, force: boolean) {
|
private setScroll(x: number, force: boolean) {
|
||||||
|
const oldScrollX = this.scrollX;
|
||||||
this.scrollX = force ? x : this.clampScrollX(x);
|
this.scrollX = force ? x : this.clampScrollX(x);
|
||||||
|
if (this.scrollX !== oldScrollX) {
|
||||||
|
this.onLayoutChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private applyScrollPos(scrollPos: ScrollView.Pos) {
|
private applyScrollPos(scrollPos: ScrollView.Pos) {
|
||||||
this.scrollX = scrollPos.x;
|
this.setScroll(scrollPos.x, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public adjustScroll(dx: number, force: boolean) {
|
public adjustScroll(dx: number, force: boolean) {
|
||||||
@@ -126,16 +130,15 @@ class ScrollView {
|
|||||||
public arrange() {
|
public arrange() {
|
||||||
// TODO (optimization): only arrange visible windows
|
// TODO (optimization): only arrange visible windows
|
||||||
this.updateArea();
|
this.updateArea();
|
||||||
|
if (!this.dirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.grid.arrange(this.tilingArea.x - this.scrollX);
|
this.grid.arrange(this.tilingArea.x - this.scrollX);
|
||||||
this.world.ensureFocusedTransientsVisible(); // TODO: refactor - call from elsewhere
|
this.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public onGridWidthChanged() {
|
public onLayoutChanged() {
|
||||||
this.autoAdjustScroll();
|
this.dirty = true;
|
||||||
}
|
|
||||||
|
|
||||||
public onGridReordered() {
|
|
||||||
this.autoAdjustScroll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class Window {
|
|||||||
}
|
}
|
||||||
this.client.setMaximize(false, false);
|
this.client.setMaximize(false, false);
|
||||||
this.client.setFullScreen(false);
|
this.client.setFullScreen(false);
|
||||||
|
this.column.grid.container.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMaximizedChanged(horizontally: boolean, vertically: boolean) {
|
public onMaximizedChanged(horizontally: boolean, vertically: boolean) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ class WindowRuleEnforcer {
|
|||||||
private readonly preferTiling: ClientMatcher;
|
private readonly preferTiling: ClientMatcher;
|
||||||
private readonly followCaption: Set<string>;
|
private readonly followCaption: Set<string>;
|
||||||
|
|
||||||
constructor(world: World, windowRules: WindowRule[]) {
|
constructor(windowRules: WindowRule[]) {
|
||||||
const [mapFloat, mapTile] = createWindowRuleMaps(windowRules);
|
const [mapFloat, mapTile] = createWindowRuleMaps(windowRules);
|
||||||
this.preferFloating = new ClientMatcher(mapFloat);
|
this.preferFloating = new ClientMatcher(mapFloat);
|
||||||
this.preferTiling = new ClientMatcher(mapTile);
|
this.preferTiling = new ClientMatcher(mapTile);
|
||||||
@@ -26,11 +26,13 @@ class WindowRuleEnforcer {
|
|||||||
const manager = new SignalManager();
|
const manager = new SignalManager();
|
||||||
manager.connect(kwinClient.captionChanged, () => {
|
manager.connect(kwinClient.captionChanged, () => {
|
||||||
const shouldTile = enforcer.shouldTile(kwinClient);
|
const shouldTile = enforcer.shouldTile(kwinClient);
|
||||||
if (shouldTile) {
|
world.do((clientManager, svm) => {
|
||||||
world.tileClient(kwinClient);
|
if (shouldTile) {
|
||||||
} else {
|
clientManager.tileClient(kwinClient);
|
||||||
world.untileClient(kwinClient);
|
} else {
|
||||||
}
|
clientManager.untileClient(kwinClient);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ function initWorkspaceSignalHandlers(world: World) {
|
|||||||
const manager = new SignalManager();
|
const manager = new SignalManager();
|
||||||
|
|
||||||
manager.connect(workspace.clientAdded, (kwinClient: AbstractClient) => {
|
manager.connect(workspace.clientAdded, (kwinClient: AbstractClient) => {
|
||||||
console.assert(!world.hasClient(kwinClient));
|
|
||||||
if (Clients.canTileEver(kwinClient)) {
|
if (Clients.canTileEver(kwinClient)) {
|
||||||
// never open new tileable clients on all desktops or activities
|
// never open new tileable clients on all desktops or activities
|
||||||
if (kwinClient.desktop <= 0) {
|
if (kwinClient.desktop <= 0) {
|
||||||
@@ -12,26 +11,32 @@ function initWorkspaceSignalHandlers(world: World) {
|
|||||||
kwinClient.activities = [workspace.currentActivity];
|
kwinClient.activities = [workspace.currentActivity];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
world.addClient(kwinClient);
|
world.do((clientManager, svm) => {
|
||||||
|
clientManager.addClient(kwinClient)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(workspace.clientRemoved, (kwinClient: AbstractClient) => {
|
manager.connect(workspace.clientRemoved, (kwinClient: AbstractClient) => {
|
||||||
console.assert(world.hasClient(kwinClient));
|
world.do((clientManager, svm) => {
|
||||||
world.removeClient(kwinClient, true);
|
clientManager.removeClient(kwinClient, true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(workspace.clientMinimized, (kwinClient: AbstractClient) => {
|
manager.connect(workspace.clientMinimized, (kwinClient: AbstractClient) => {
|
||||||
world.minimizeClient(kwinClient);
|
world.do((clientManager, svm) => {
|
||||||
|
clientManager.minimizeClient(kwinClient);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(workspace.clientUnminimized, (kwinClient: AbstractClient) => {
|
manager.connect(workspace.clientUnminimized, (kwinClient: AbstractClient) => {
|
||||||
world.unminimizeClient(kwinClient);
|
world.do((clientManager, svm) => {
|
||||||
|
clientManager.unminimizeClient(kwinClient);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(workspace.clientMaximizeSet, (kwinClient: AbstractClient, horizontally: boolean, vertically: boolean) => {
|
manager.connect(workspace.clientMaximizeSet, (kwinClient: AbstractClient, horizontally: boolean, vertically: boolean) => {
|
||||||
world.doIfTiled(kwinClient, false, (window, column, grid) => {
|
world.doIfTiled(kwinClient, false, (world, svm, window, column, grid) => {
|
||||||
window.onMaximizedChanged(horizontally, vertically);
|
window.onMaximizedChanged(horizontally, vertically);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -39,17 +44,14 @@ function initWorkspaceSignalHandlers(world: World) {
|
|||||||
if (kwinClient === null) {
|
if (kwinClient === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
world.onClientFocused(kwinClient);
|
world.do((clientManager, svm) => {
|
||||||
world.doIfTiled(kwinClient, true, (window, column, grid) => {
|
clientManager.onClientFocused(kwinClient);
|
||||||
window.onFocused();
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(workspace.clientFullScreenSet, (kwinClient: X11Client, fullScreen: boolean, user: boolean) => {
|
manager.connect(workspace.clientFullScreenSet, (kwinClient: X11Client, fullScreen: boolean, user: boolean) => {
|
||||||
world.doIfTiled(kwinClient, false, (window, column, grid) => {
|
world.doIfTiled(kwinClient, false, (clientManager, svm, window, column, grid) => {
|
||||||
window.onFullScreenChanged(fullScreen);
|
window.onFullScreenChanged(fullScreen);
|
||||||
grid.container.arrange();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
164
src/world/ClientManager.ts
Normal file
164
src/world/ClientManager.ts
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
class ClientManager {
|
||||||
|
private readonly world: World;
|
||||||
|
private readonly scrollViewManager: ScrollViewManager;
|
||||||
|
private readonly clientMap: Map<AbstractClient, ClientWrapper>;
|
||||||
|
private lastFocusedClient: AbstractClient|null;
|
||||||
|
private readonly windowRuleEnforcer: WindowRuleEnforcer;
|
||||||
|
|
||||||
|
constructor(config: Config, world: World, svm: ScrollViewManager) {
|
||||||
|
this.world = world;
|
||||||
|
this.scrollViewManager = svm;
|
||||||
|
this.clientMap = new Map();
|
||||||
|
this.lastFocusedClient = null;
|
||||||
|
|
||||||
|
let parsedWindowRules: WindowRule[] = [];
|
||||||
|
try {
|
||||||
|
parsedWindowRules = JSON.parse(config.windowRules);
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log("failed to parse windowRules:", error);
|
||||||
|
}
|
||||||
|
this.windowRuleEnforcer = new WindowRuleEnforcer(parsedWindowRules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addClient(kwinClient: AbstractClient) {
|
||||||
|
console.assert(!this.hasClient(kwinClient));
|
||||||
|
const client = new ClientWrapper(
|
||||||
|
kwinClient,
|
||||||
|
new ClientStateFloating(),
|
||||||
|
this.findTransientFor(kwinClient),
|
||||||
|
this.windowRuleEnforcer.initClientSignalManager(this.world, kwinClient),
|
||||||
|
);
|
||||||
|
this.clientMap.set(kwinClient, client);
|
||||||
|
|
||||||
|
if (kwinClient.dock) {
|
||||||
|
client.stateManager.setState(new ClientStateDocked(this.world, kwinClient), false);
|
||||||
|
} else if (this.windowRuleEnforcer.shouldTile(kwinClient)) {
|
||||||
|
const grid = this.scrollViewManager.getForClient(client.kwinClient).grid;
|
||||||
|
client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeClient(kwinClient: AbstractClient, passFocus: boolean) {
|
||||||
|
console.assert(this.hasClient(kwinClient));
|
||||||
|
const client = this.clientMap.get(kwinClient);
|
||||||
|
if (client === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.destroy(passFocus && kwinClient === this.lastFocusedClient);
|
||||||
|
this.clientMap.delete(kwinClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private findTransientFor(kwinClient: AbstractClient) {
|
||||||
|
if (!kwinClient.transient) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transientFor = this.clientMap.get(kwinClient.transientFor);
|
||||||
|
if (transientFor === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return transientFor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public minimizeClient(kwinClient: AbstractClient) {
|
||||||
|
const client = this.clientMap.get(kwinClient);
|
||||||
|
if (client === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (client.stateManager.getState() instanceof ClientStateTiled) {
|
||||||
|
client.stateManager.setState(new ClientStateTiledMinimized(), kwinClient === this.lastFocusedClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unminimizeClient(kwinClient: AbstractClient) {
|
||||||
|
const client = this.clientMap.get(kwinClient);
|
||||||
|
if (client === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (client.stateManager.getState() instanceof ClientStateTiledMinimized) {
|
||||||
|
const grid = this.scrollViewManager.getForClient(client.kwinClient).grid;
|
||||||
|
client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public tileClient(kwinClient: AbstractClient) {
|
||||||
|
const client = this.clientMap.get(kwinClient);
|
||||||
|
if (client === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (client.stateManager.getState() instanceof ClientStateTiled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const grid = this.scrollViewManager.getForClient(client.kwinClient).grid;
|
||||||
|
client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public untileClient(kwinClient: AbstractClient) {
|
||||||
|
const client = this.clientMap.get(kwinClient);
|
||||||
|
if (client === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (client.stateManager.getState() instanceof ClientStateTiled) {
|
||||||
|
client.stateManager.setState(new ClientStateFloating(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggleFloatingClient(kwinClient: AbstractClient) {
|
||||||
|
const client = this.clientMap.get(kwinClient);
|
||||||
|
if (client === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientState = client.stateManager.getState();
|
||||||
|
if (clientState instanceof ClientStateFloating && Clients.canTileEver(kwinClient)) {
|
||||||
|
Clients.makeTileable(kwinClient);
|
||||||
|
const grid = this.scrollViewManager.getForClient(client.kwinClient).grid;
|
||||||
|
client.stateManager.setState(new ClientStateTiled(this.world, client, grid), false);
|
||||||
|
} else if (clientState instanceof ClientStateTiled) {
|
||||||
|
client.stateManager.setState(new ClientStateFloating(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasClient(kwinClient: AbstractClient) {
|
||||||
|
return this.clientMap.has(kwinClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClientFocused(kwinClient: AbstractClient) {
|
||||||
|
this.lastFocusedClient = kwinClient;
|
||||||
|
const window = this.findTiledWindow(kwinClient, true);
|
||||||
|
if (window !== null) {
|
||||||
|
window.onFocused();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public findTiledWindow(kwinClient: AbstractClient, followTransient: boolean) {
|
||||||
|
const client = this.clientMap.get(kwinClient);
|
||||||
|
if (client === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.findTiledWindowOfClient(client, followTransient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private findTiledWindowOfClient(client: ClientWrapper, followTransient: boolean): Window|null {
|
||||||
|
const clientState = client.stateManager.getState();
|
||||||
|
if (clientState instanceof ClientStateTiled) {
|
||||||
|
return clientState.window;
|
||||||
|
} else if (followTransient && client.transientFor !== null) {
|
||||||
|
return this.findTiledWindowOfClient(client.transientFor, true);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeAllClients() {
|
||||||
|
for (const kwinClient of Array.from(this.clientMap.keys())) {
|
||||||
|
this.removeClient(kwinClient, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.removeAllClients();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,13 +2,11 @@ class ClientStateTiled {
|
|||||||
readonly window: Window;
|
readonly window: Window;
|
||||||
private readonly signalManager: SignalManager;
|
private readonly signalManager: SignalManager;
|
||||||
|
|
||||||
constructor(world: World, client: ClientWrapper) {
|
constructor(world: World, client: ClientWrapper, grid: Grid) {
|
||||||
client.prepareForTiling();
|
client.prepareForTiling();
|
||||||
|
|
||||||
const grid = world.getClientGrid(client.kwinClient);
|
|
||||||
const column = new Column(grid, grid.getLastFocusedColumn() ?? grid.getLastColumn());
|
const column = new Column(grid, grid.getLastFocusedColumn() ?? grid.getLastColumn());
|
||||||
const window = new Window(client, column);
|
const window = new Window(client, column);
|
||||||
grid.container.arrange();
|
|
||||||
|
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.signalManager = ClientStateTiled.initSignalManager(world, window);
|
this.signalManager = ClientStateTiled.initSignalManager(world, window);
|
||||||
@@ -21,7 +19,6 @@ class ClientStateTiled {
|
|||||||
const grid = window.column.grid;
|
const grid = window.column.grid;
|
||||||
const clientWrapper = window.client;
|
const clientWrapper = window.client;
|
||||||
window.destroy(passFocus);
|
window.destroy(passFocus);
|
||||||
grid.container.arrange();
|
|
||||||
|
|
||||||
clientWrapper.prepareForFloating(grid.container.clientArea);
|
clientWrapper.prepareForFloating(grid.container.clientArea);
|
||||||
}
|
}
|
||||||
@@ -32,39 +29,45 @@ class ClientStateTiled {
|
|||||||
const manager = new SignalManager();
|
const manager = new SignalManager();
|
||||||
|
|
||||||
manager.connect(kwinClient.desktopChanged, () => {
|
manager.connect(kwinClient.desktopChanged, () => {
|
||||||
if (kwinClient.desktop === -1) {
|
world.do((clientManager, svm) => {
|
||||||
// windows on all desktops are not supported
|
if (kwinClient.desktop === -1) {
|
||||||
world.untileClient(kwinClient);
|
// windows on all desktops are not supported
|
||||||
return;
|
clientManager.untileClient(kwinClient);
|
||||||
}
|
return;
|
||||||
ClientStateTiled.moveWindowToCorrectGrid(world, window);
|
}
|
||||||
|
ClientStateTiled.moveWindowToCorrectGrid(svm, window);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(kwinClient.activitiesChanged, (kwinClient: AbstractClient) => {
|
manager.connect(kwinClient.activitiesChanged, (kwinClient: AbstractClient) => {
|
||||||
if (kwinClient.activities.length !== 1) {
|
world.do((clientManager, svm) => {
|
||||||
// windows on multiple activities are not supported
|
if (kwinClient.activities.length !== 1) {
|
||||||
world.untileClient(kwinClient);
|
// windows on multiple activities are not supported
|
||||||
return;
|
clientManager.untileClient(kwinClient);
|
||||||
}
|
return;
|
||||||
ClientStateTiled.moveWindowToCorrectGrid(world, window);
|
}
|
||||||
|
ClientStateTiled.moveWindowToCorrectGrid(svm, window);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
let lastResize = false;
|
let lastResize = false;
|
||||||
manager.connect(kwinClient.moveResizedChanged, () => {
|
manager.connect(kwinClient.moveResizedChanged, () => {
|
||||||
if (world.untileOnDrag && kwinClient.move) {
|
world.do((clientManager, svm) => {
|
||||||
world.untileClient(kwinClient);
|
if (world.untileOnDrag && kwinClient.move) {
|
||||||
return;
|
clientManager.untileClient(kwinClient);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const grid = window.column.grid;
|
const grid = window.column.grid;
|
||||||
const resize = kwinClient.resize;
|
const resize = kwinClient.resize;
|
||||||
if (!lastResize && resize) {
|
if (!lastResize && resize) {
|
||||||
grid.onUserResizeStarted();
|
grid.onUserResizeStarted();
|
||||||
}
|
}
|
||||||
if (lastResize && !resize) {
|
if (lastResize && !resize) {
|
||||||
grid.onUserResizeFinished();
|
grid.onUserResizeFinished();
|
||||||
}
|
}
|
||||||
lastResize = resize;
|
lastResize = resize;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let cursorChangedAfterResizeStart = false;
|
let cursorChangedAfterResizeStart = false;
|
||||||
@@ -76,27 +79,27 @@ class ClientStateTiled {
|
|||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(kwinClient.frameGeometryChanged, (kwinClient: TopLevel, oldGeometry: QRect) => {
|
manager.connect(kwinClient.frameGeometryChanged, (kwinClient: TopLevel, oldGeometry: QRect) => {
|
||||||
const scrollView = window.column.grid.container;
|
world.do((clientManager, svm) => {
|
||||||
if (kwinClient.resize) {
|
const scrollView = window.column.grid.container;
|
||||||
window.onUserResize(oldGeometry, !cursorChangedAfterResizeStart);
|
if (kwinClient.resize) {
|
||||||
scrollView.arrange();
|
window.onUserResize(oldGeometry, !cursorChangedAfterResizeStart);
|
||||||
} else {
|
} else {
|
||||||
const maximized = rectEqual(kwinClient.frameGeometry, scrollView.clientArea);
|
const maximized = rectEqual(kwinClient.frameGeometry, scrollView.clientArea);
|
||||||
if (!client.isManipulatingGeometry() && !kwinClient.fullScreen && !maximized) {
|
if (!client.isManipulatingGeometry() && !kwinClient.fullScreen && !maximized) {
|
||||||
window.onProgrammaticResize(oldGeometry);
|
window.onProgrammaticResize(oldGeometry);
|
||||||
scrollView.arrange();
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static moveWindowToCorrectGrid(world: World, window: Window) {
|
private static moveWindowToCorrectGrid(svm: ScrollViewManager, window: Window) {
|
||||||
const kwinClient = window.client.kwinClient;
|
const kwinClient = window.client.kwinClient;
|
||||||
|
|
||||||
const oldGrid = window.column.grid;
|
const oldGrid = window.column.grid;
|
||||||
const newGrid = world.getClientGrid(kwinClient);
|
const newGrid = svm.getForClient(kwinClient).grid;
|
||||||
if (oldGrid === newGrid) {
|
if (oldGrid === newGrid) {
|
||||||
// window already on the correct grid
|
// window already on the correct grid
|
||||||
return;
|
return;
|
||||||
@@ -104,7 +107,5 @@ class ClientStateTiled {
|
|||||||
|
|
||||||
const newColumn = new Column(newGrid, newGrid.getLastFocusedColumn() ?? newGrid.getLastColumn());
|
const newColumn = new Column(newGrid, newGrid.getLastFocusedColumn() ?? newGrid.getLastColumn());
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
oldGrid.container.arrange();
|
|
||||||
newGrid.container.arrange();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
class ScrollViewManager {
|
class ScrollViewManager {
|
||||||
private readonly world: World;
|
|
||||||
private readonly config: ScrollView.Config;
|
private readonly config: ScrollView.Config;
|
||||||
public readonly layoutConfig: LayoutConfig;
|
public readonly layoutConfig: LayoutConfig;
|
||||||
private readonly scrollViewsPerActivity: Map<string, ScrollView[]>;
|
private readonly scrollViewsPerActivity: Map<string, ScrollView[]>;
|
||||||
private nDesktops: number;
|
private nDesktops: number;
|
||||||
|
|
||||||
constructor(world: World, config: ScrollView.Config, layoutConfig: LayoutConfig, currentActivity: string, nDesktops: number) {
|
constructor(config: ScrollView.Config, layoutConfig: LayoutConfig, currentActivity: string) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.layoutConfig = layoutConfig;
|
this.layoutConfig = layoutConfig;
|
||||||
this.world = world;
|
|
||||||
this.scrollViewsPerActivity = new Map();
|
this.scrollViewsPerActivity = new Map();
|
||||||
this.nDesktops = 0;
|
this.nDesktops = 0;
|
||||||
this.setNDesktops(nDesktops);
|
this.update()
|
||||||
this.addActivity(currentActivity);
|
this.addActivity(currentActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(activity: string, desktopNumber: number) {
|
public update() {
|
||||||
|
this.setNDesktops(workspace.desktops);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(activity: string, desktopNumber: number) {
|
||||||
const desktopIndex = desktopNumber - 1;
|
const desktopIndex = desktopNumber - 1;
|
||||||
if (desktopIndex >= this.nDesktops || this.nDesktops < 0) {
|
if (desktopIndex >= this.nDesktops || this.nDesktops < 0) {
|
||||||
throw new Error("invalid desktop number: " + String(desktopNumber));
|
throw new Error("invalid desktop number: " + String(desktopNumber));
|
||||||
@@ -26,7 +28,20 @@ class ScrollViewManager {
|
|||||||
return this.scrollViewsPerActivity.get(activity)![desktopIndex];
|
return this.scrollViewsPerActivity.get(activity)![desktopIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
setNDesktops(nDesktops: number) {
|
public getCurrent() {
|
||||||
|
return this.get(workspace.currentActivity, workspace.currentDesktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getInCurrentActivity(desktopNumber: number) {
|
||||||
|
return this.get(workspace.currentActivity, desktopNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getForClient(kwinClient: AbstractClient) {
|
||||||
|
console.assert(kwinClient.activities.length === 1);
|
||||||
|
return this.get(kwinClient.activities[0], kwinClient.desktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setNDesktops(nDesktops: number) {
|
||||||
if (nDesktops > this.nDesktops) {
|
if (nDesktops > this.nDesktops) {
|
||||||
this.addDesktopsToActivities(nDesktops - this.nDesktops);
|
this.addDesktopsToActivities(nDesktops - this.nDesktops);
|
||||||
} else if (nDesktops < this.nDesktops) {
|
} else if (nDesktops < this.nDesktops) {
|
||||||
@@ -45,7 +60,7 @@ class ScrollViewManager {
|
|||||||
const nStart = scrollViews.length;
|
const nStart = scrollViews.length;
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
const desktopNumber = nStart + i + 1;
|
const desktopNumber = nStart + i + 1;
|
||||||
scrollViews.push(new ScrollView(this.world, desktopNumber, this.config, this.layoutConfig));
|
scrollViews.push(new ScrollView(desktopNumber, this.config, this.layoutConfig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,13 +75,13 @@ class ScrollViewManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addActivity(activity: string) {
|
private addActivity(activity: string) {
|
||||||
const scrollViews: ScrollView[] = [];
|
const scrollViews: ScrollView[] = [];
|
||||||
this.addDesktops(scrollViews, this.nDesktops);
|
this.addDesktops(scrollViews, this.nDesktops);
|
||||||
this.scrollViewsPerActivity.set(activity, scrollViews);
|
this.scrollViewsPerActivity.set(activity, scrollViews);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeActivity(activity: string) {
|
private removeActivity(activity: string) {
|
||||||
const removedScrollViews = this.scrollViewsPerActivity.get(activity)!;
|
const removedScrollViews = this.scrollViewsPerActivity.get(activity)!;
|
||||||
this.scrollViewsPerActivity.delete(activity);
|
this.scrollViewsPerActivity.delete(activity);
|
||||||
const targetActivityScrollViews = this.scrollViewsPerActivity.values().next().value;
|
const targetActivityScrollViews = this.scrollViewsPerActivity.values().next().value;
|
||||||
@@ -75,7 +90,13 @@ class ScrollViewManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*scrollViews() {
|
public destroy() {
|
||||||
|
for (const scrollView of this.scrollViews()) {
|
||||||
|
scrollView.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public *scrollViews() {
|
||||||
for (const scrollViews of this.scrollViewsPerActivity.values()) {
|
for (const scrollViews of this.scrollViewsPerActivity.values()) {
|
||||||
for (const scrollView of scrollViews) {
|
for (const scrollView of scrollViews) {
|
||||||
yield scrollView;
|
yield scrollView;
|
||||||
|
|||||||
@@ -1,36 +1,24 @@
|
|||||||
class World {
|
class World {
|
||||||
public readonly untileOnDrag: boolean;
|
public readonly untileOnDrag: boolean;
|
||||||
private readonly scrollViewManager: ScrollViewManager;
|
private readonly scrollViewManager: ScrollViewManager;
|
||||||
private readonly clientMap: Map<AbstractClient, ClientWrapper>;
|
public readonly clientManager: ClientManager;
|
||||||
private lastFocusedClient: AbstractClient|null;
|
|
||||||
private readonly workspaceSignalManager: SignalManager;
|
private readonly workspaceSignalManager: SignalManager;
|
||||||
private readonly windowRuleEnforcer: WindowRuleEnforcer;
|
|
||||||
private readonly screenResizedDelayer: Delayer;
|
private readonly screenResizedDelayer: Delayer;
|
||||||
|
|
||||||
constructor(config: Config) {
|
constructor(config: Config) {
|
||||||
this.untileOnDrag = config.untileOnDrag;
|
this.untileOnDrag = config.untileOnDrag;
|
||||||
this.clientMap = new Map();
|
|
||||||
this.lastFocusedClient = null;
|
|
||||||
this.workspaceSignalManager = initWorkspaceSignalHandlers(this);
|
this.workspaceSignalManager = initWorkspaceSignalHandlers(this);
|
||||||
|
|
||||||
let parsedWindowRules: WindowRule[] = [];
|
|
||||||
try {
|
|
||||||
parsedWindowRules = JSON.parse(config.windowRules);
|
|
||||||
} catch (error: any) {
|
|
||||||
console.log("failed to parse windowRules:", error);
|
|
||||||
}
|
|
||||||
this.windowRuleEnforcer = new WindowRuleEnforcer(this, parsedWindowRules);
|
|
||||||
|
|
||||||
this.screenResizedDelayer = new Delayer(1000, () => {
|
this.screenResizedDelayer = new Delayer(1000, () => {
|
||||||
// this delay ensures that docks get taken into account by `workspace.clientArea`
|
// this delay ensures that docks get taken into account by `workspace.clientArea`
|
||||||
const gridManager = this.scrollViewManager; // workaround for bug in Qt5's JS engine
|
const gridManager = this.scrollViewManager; // workaround for bug in Qt5's JS engine
|
||||||
for (const scrollView of gridManager.scrollViews()) {
|
for (const scrollView of gridManager.scrollViews()) {
|
||||||
scrollView.arrange();
|
scrollView.onLayoutChanged();
|
||||||
}
|
}
|
||||||
|
this.update();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.scrollViewManager = new ScrollViewManager(
|
this.scrollViewManager = new ScrollViewManager(
|
||||||
this,
|
|
||||||
{
|
{
|
||||||
marginTop: config.gapsOuterTop,
|
marginTop: config.gapsOuterTop,
|
||||||
marginBottom: config.gapsOuterBottom,
|
marginBottom: config.gapsOuterBottom,
|
||||||
@@ -40,206 +28,59 @@ class World {
|
|||||||
},
|
},
|
||||||
config,
|
config,
|
||||||
workspace.currentActivity,
|
workspace.currentActivity,
|
||||||
workspace.desktops,
|
|
||||||
);
|
);
|
||||||
|
this.clientManager = new ClientManager(config, this, this.scrollViewManager);
|
||||||
this.addExistingClients();
|
this.addExistingClients();
|
||||||
}
|
this.update();
|
||||||
|
|
||||||
public updateDesktops() {
|
|
||||||
this.scrollViewManager.setNDesktops(workspace.desktops);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private addExistingClients() {
|
private addExistingClients() {
|
||||||
const kwinClients = workspace.clientList();
|
const kwinClients = workspace.clientList();
|
||||||
for (let i = 0; i < kwinClients.length; i++) {
|
for (let i = 0; i < kwinClients.length; i++) {
|
||||||
const kwinClient = kwinClients[i];
|
const kwinClient = kwinClients[i];
|
||||||
this.addClient(kwinClient);
|
this.clientManager.addClient(kwinClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getGrid(activity: string, desktopNumber: number) {
|
public updateDesktops() {
|
||||||
console.assert(desktopNumber > 0 && desktopNumber <= workspace.desktops);
|
this.scrollViewManager.update();
|
||||||
return this.scrollViewManager.get(activity, desktopNumber).grid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getGridInCurrentActivity(desktopNumber: number) {
|
public update() {
|
||||||
return this.getGrid(workspace.currentActivity, desktopNumber);
|
this.scrollViewManager.getCurrent().arrange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCurrentGrid() {
|
public do(f: (clientManager: ClientManager, svm: ScrollViewManager) => void) {
|
||||||
return this.getGrid(workspace.currentActivity, workspace.currentDesktop);
|
f(this.clientManager, this.scrollViewManager);
|
||||||
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getClientGrid(kwinClient: AbstractClient) {
|
public doIfTiled(
|
||||||
console.assert(kwinClient.activities.length === 1);
|
kwinClient: AbstractClient,
|
||||||
return this.getGrid(kwinClient.activities[0], kwinClient.desktop);
|
followTransient: boolean,
|
||||||
}
|
f: (clientManager: ClientManager, svm: ScrollViewManager, window: Window, column: Column, grid: Grid) => void,
|
||||||
|
) {
|
||||||
public addClient(kwinClient: AbstractClient) {
|
const window = this.clientManager.findTiledWindow(kwinClient, followTransient);
|
||||||
const client = new ClientWrapper(
|
|
||||||
kwinClient,
|
|
||||||
new ClientStateFloating(),
|
|
||||||
this.findTransientFor(kwinClient),
|
|
||||||
this.windowRuleEnforcer.initClientSignalManager(this, kwinClient),
|
|
||||||
);
|
|
||||||
this.clientMap.set(kwinClient, client);
|
|
||||||
|
|
||||||
if (kwinClient.dock) {
|
|
||||||
client.stateManager.setState(new ClientStateDocked(this, kwinClient), false);
|
|
||||||
} else if (this.windowRuleEnforcer.shouldTile(kwinClient)) {
|
|
||||||
client.stateManager.setState(new ClientStateTiled(this, client), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeClient(kwinClient: AbstractClient, passFocus: boolean) {
|
|
||||||
const client = this.clientMap.get(kwinClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client.destroy(passFocus && kwinClient === this.lastFocusedClient);
|
|
||||||
this.clientMap.delete(kwinClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
private findTransientFor(kwinClient: AbstractClient) {
|
|
||||||
if (!kwinClient.transient) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const transientFor = this.clientMap.get(kwinClient.transientFor);
|
|
||||||
if (transientFor === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return transientFor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ensureFocusedTransientsVisible() {
|
|
||||||
this.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
window.client.ensureTransientsVisible(grid.container.clientArea);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public minimizeClient(kwinClient: AbstractClient) {
|
|
||||||
const client = this.clientMap.get(kwinClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (client.stateManager.getState() instanceof ClientStateTiled) {
|
|
||||||
client.stateManager.setState(new ClientStateTiledMinimized(), kwinClient === this.lastFocusedClient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unminimizeClient(kwinClient: AbstractClient) {
|
|
||||||
const client = this.clientMap.get(kwinClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (client.stateManager.getState() instanceof ClientStateTiledMinimized) {
|
|
||||||
client.stateManager.setState(new ClientStateTiled(this, client), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public tileClient(kwinClient: AbstractClient) {
|
|
||||||
const client = this.clientMap.get(kwinClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (client.stateManager.getState() instanceof ClientStateTiled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client.stateManager.setState(new ClientStateTiled(this, client), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public untileClient(kwinClient: AbstractClient) {
|
|
||||||
const client = this.clientMap.get(kwinClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (client.stateManager.getState() instanceof ClientStateTiled) {
|
|
||||||
client.stateManager.setState(new ClientStateFloating(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleFloatingClient(kwinClient: AbstractClient) {
|
|
||||||
const client = this.clientMap.get(kwinClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const clientState = client.stateManager.getState();
|
|
||||||
if (clientState instanceof ClientStateFloating && Clients.canTileEver(kwinClient)) {
|
|
||||||
Clients.makeTileable(kwinClient);
|
|
||||||
client.stateManager.setState(new ClientStateTiled(this, client), false);
|
|
||||||
} else if (clientState instanceof ClientStateTiled) {
|
|
||||||
client.stateManager.setState(new ClientStateFloating(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasClient(kwinClient: AbstractClient) {
|
|
||||||
return this.clientMap.has(kwinClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onClientFocused(kwinClient: AbstractClient) {
|
|
||||||
this.lastFocusedClient = kwinClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
private findTiledWindow(client: ClientWrapper, followTransient: boolean): Window|null {
|
|
||||||
const clientState = client.stateManager.getState();
|
|
||||||
if (clientState instanceof ClientStateTiled) {
|
|
||||||
return clientState.window;
|
|
||||||
} else if (followTransient && client.transientFor !== null) {
|
|
||||||
return this.findTiledWindow(client.transientFor, true);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public doIfTiled(kwinClient: AbstractClient, followTransient: boolean, f: (window: Window, column: Column, grid: Grid) => void) {
|
|
||||||
const client = this.clientMap.get(kwinClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const window = this.findTiledWindow(client, followTransient);
|
|
||||||
if (window === null) {
|
if (window === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const column = window.column;
|
const column = window.column;
|
||||||
const grid = column.grid;
|
const grid = column.grid;
|
||||||
f(window, column, grid);
|
f(this.clientManager, this.scrollViewManager, window, column, grid);
|
||||||
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public doIfTiledFocused(followTransient: boolean, f: (window: Window, column: Column, grid: Grid) => void) {
|
public doIfTiledFocused(
|
||||||
|
followTransient: boolean,
|
||||||
|
f: (clientManager: ClientManager, svm: ScrollViewManager, window: Window, column: Column, grid: Grid) => void,
|
||||||
|
) {
|
||||||
this.doIfTiled(workspace.activeClient, followTransient, f);
|
this.doIfTiled(workspace.activeClient, followTransient, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFocusedWindow(followTransient: boolean) {
|
|
||||||
const activeClient = workspace.activeClient;
|
|
||||||
if (activeClient === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = this.clientMap.get(activeClient);
|
|
||||||
if (client === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.findTiledWindow(client, followTransient);
|
|
||||||
}
|
|
||||||
|
|
||||||
private removeAllClients() {
|
|
||||||
for (const kwinClient of Array.from(this.clientMap.keys())) {
|
|
||||||
this.removeClient(kwinClient, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this.workspaceSignalManager.destroy();
|
this.workspaceSignalManager.destroy();
|
||||||
this.removeAllClients();
|
this.clientManager.destroy();
|
||||||
for (const scrollView of this.scrollViewManager.scrollViews()) {
|
this.scrollViewManager.destroy();
|
||||||
scrollView.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onScreenResized() {
|
public onScreenResized() {
|
||||||
|
|||||||
Reference in New Issue
Block a user