Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57c4643098 | ||
|
|
e92563b424 | ||
|
|
671326bdd7 | ||
|
|
5e9db7d2cd | ||
|
|
b447eacdfd | ||
|
|
94f6e6f33b | ||
|
|
85b0221220 | ||
|
|
1894b055f7 | ||
|
|
05f7550a3b | ||
|
|
a04f629de0 | ||
|
|
4bda4d0d7c | ||
|
|
8bf076948a | ||
|
|
04bd85a287 |
11
README.md
11
README.md
@@ -22,6 +22,8 @@ Similar window managers include [PaperWM](https://github.com/paperwm/PaperWM) an
|
|||||||
- Doesn't support windows on multiple activities
|
- Doesn't support windows on multiple activities
|
||||||
|
|
||||||
## Key bindings
|
## Key bindings
|
||||||
|
The key bindings can be configured in KDE System Settings among KWin's own keyboard shortcuts.
|
||||||
|
Here's the default ones:
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Meta+Space | Toggle floating |
|
| Meta+Space | Toggle floating |
|
||||||
@@ -37,19 +39,16 @@ Similar window managers include [PaperWM](https://github.com/paperwm/PaperWM) an
|
|||||||
| Meta+Shift+S | Move window down |
|
| Meta+Shift+S | Move window down |
|
||||||
| Meta+Shift+Home | Move window to start |
|
| Meta+Shift+Home | Move window to start |
|
||||||
| Meta+Shift+End | Move window to end |
|
| Meta+Shift+End | Move window to end |
|
||||||
| Meta+X | Expand window (Expands focused window vertically; toggles stacked layout for focused column) |
|
| Meta+X | Toggle stacked layout for focused column |
|
||||||
| Meta+Ctrl+Shift+A | Move column left |
|
| Meta+Ctrl+Shift+A | Move column left |
|
||||||
| Meta+Ctrl+Shift+D | Move column right |
|
| Meta+Ctrl+Shift+D | Move column right |
|
||||||
| Meta+Ctrl+Shift+Home | Move column to start |
|
| Meta+Ctrl+Shift+Home | Move column to start |
|
||||||
| Meta+Ctrl+Shift+End | Move column to end |
|
| Meta+Ctrl+Shift+End | Move column to end |
|
||||||
| Meta+Ctrl+X | Expand column (Expands focused column horizontally to fill the screen) |
|
| Meta+Ctrl++ | Increase column width |
|
||||||
| Meta+Alt++ | Expand fully visible columns (Expands fully visible columns to fill the screen) |
|
| Meta+Ctrl+- | Decrease column width |
|
||||||
| Meta+Alt+- | Shrink visible columns (Shrinks fully and partially visible columns, making them fully visible and filling the screen) |
|
|
||||||
| Meta+Alt+Return | Center focused window (Scrolls so that the focused window is centered in the screen) |
|
| Meta+Alt+Return | Center focused window (Scrolls so that the focused window is centered in the screen) |
|
||||||
| Meta+Alt+A | Scroll one column to the left |
|
| Meta+Alt+A | Scroll one column to the left |
|
||||||
| Meta+Alt+D | Scroll one column to the right |
|
| Meta+Alt+D | Scroll one column to the right |
|
||||||
| Meta+Alt+PgUp | Scroll left |
|
|
||||||
| Meta+Alt+PgDown | Scroll right |
|
|
||||||
| Meta+Alt+Home | Scroll to start |
|
| Meta+Alt+Home | Scroll to start |
|
||||||
| Meta+Alt+End | Scroll to end |
|
| Meta+Alt+End | Scroll to end |
|
||||||
| Meta+[N] | Move focus to column N |
|
| Meta+[N] | Move focus to column N |
|
||||||
|
|||||||
@@ -184,7 +184,31 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_manualScrollStep">
|
||||||
|
<property name="text">
|
||||||
|
<string>Manual scroll step size:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="7" column="1">
|
<item row="7" column="1">
|
||||||
|
<widget class="QSpinBox" name="kcfg_manualScrollStep">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> px</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>999</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item row="8" column="1">
|
||||||
<widget class="QCheckBox" name="kcfg_untileOnDrag">
|
<widget class="QCheckBox" name="kcfg_untileOnDrag">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Un-tile windows by dragging them</string>
|
<string>Un-tile windows by dragging them</string>
|
||||||
@@ -192,7 +216,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item row="8" column="1">
|
<item row="9" column="1">
|
||||||
<widget class="QCheckBox" name="kcfg_stackColumnsByDefault">
|
<widget class="QCheckBox" name="kcfg_stackColumnsByDefault">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stack columns by default</string>
|
<string>Stack columns by default</string>
|
||||||
@@ -200,7 +224,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item row="9" column="1">
|
<item row="10" column="1">
|
||||||
<widget class="QCheckBox" name="kcfg_resizeNeighborColumn">
|
<widget class="QCheckBox" name="kcfg_resizeNeighborColumn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Resize neighbor column on edge resize</string>
|
<string>Resize neighbor column on edge resize</string>
|
||||||
@@ -208,7 +232,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item row="10" column="0" colspan="2">
|
<item row="11" column="0" colspan="2">
|
||||||
<spacer name="bottomSpacer_tab_general">
|
<spacer name="bottomSpacer_tab_general">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
}],
|
}],
|
||||||
"Id": "karousel",
|
"Id": "karousel",
|
||||||
"ServiceTypes": ["KWin/Script"],
|
"ServiceTypes": ["KWin/Script"],
|
||||||
"Version": "0.3",
|
"Version": "0.3.1",
|
||||||
"License": "GPLv3",
|
"License": "GPLv3",
|
||||||
"Website": "https://github.com/peterfajdiga/karousel",
|
"Website": "https://github.com/peterfajdiga/karousel",
|
||||||
"BugReportUrl": "https://github.com/peterfajdiga/karousel/issues"
|
"BugReportUrl": "https://github.com/peterfajdiga/karousel/issues"
|
||||||
|
|||||||
335
src/Actions.ts
Normal file
335
src/Actions.ts
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
module Actions {
|
||||||
|
export function init(world: World, config: Config) {
|
||||||
|
return {
|
||||||
|
focusLeft: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
|
if (prevColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prevColumn.focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
focusRight: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const nextColumn = grid.getNextColumn(column);
|
||||||
|
if (nextColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextColumn.focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
focusUp: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const prevWindow = column.getPrevWindow(window);
|
||||||
|
if (prevWindow === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prevWindow.focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
focusDown: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const nextWindow = column.getNextWindow(window);
|
||||||
|
if (nextWindow === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextWindow.focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
focusStart: () => {
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
const firstColumn = grid.getFirstColumn();
|
||||||
|
if (firstColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
firstColumn.focus();
|
||||||
|
grid.container.arrange();
|
||||||
|
},
|
||||||
|
|
||||||
|
focusEnd: () => {
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
const lastColumn = grid.getLastColumn();
|
||||||
|
if (lastColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastColumn.focus();
|
||||||
|
grid.container.arrange();
|
||||||
|
},
|
||||||
|
|
||||||
|
windowMoveLeft: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
if (column.getWindowCount() === 1) {
|
||||||
|
// move from own column into existing column
|
||||||
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
|
if (prevColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.moveToColumn(prevColumn);
|
||||||
|
grid.container.onGridReordered();
|
||||||
|
} else {
|
||||||
|
// move from shared column into own column
|
||||||
|
const newColumn = new Column(grid, grid.getPrevColumn(column));
|
||||||
|
window.moveToColumn(newColumn);
|
||||||
|
}
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
windowMoveRight: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
if (column.getWindowCount() === 1) {
|
||||||
|
// move from own column into existing column
|
||||||
|
const nextColumn = grid.getNextColumn(column);
|
||||||
|
if (nextColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.moveToColumn(nextColumn);
|
||||||
|
grid.container.onGridReordered();
|
||||||
|
} else {
|
||||||
|
// move from shared column into own column
|
||||||
|
const newColumn = new Column(grid, column);
|
||||||
|
window.moveToColumn(newColumn);
|
||||||
|
}
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
windowMoveUp: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
column.moveWindowUp(window);
|
||||||
|
grid.container.arrange(); // TODO (optimization): only arrange moved windows
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
windowMoveDown: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
column.moveWindowDown(window);
|
||||||
|
grid.container.arrange(); // TODO (optimization): only arrange moved windows
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
windowMoveStart: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const newColumn = new Column(grid, null);
|
||||||
|
window.moveToColumn(newColumn);
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
windowMoveEnd: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const newColumn = new Column(grid, grid.getLastColumn());
|
||||||
|
window.moveToColumn(newColumn);
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
windowToggleFloating: () => {
|
||||||
|
const kwinClient = workspace.activeClient;
|
||||||
|
world.toggleFloatingClient(kwinClient);
|
||||||
|
},
|
||||||
|
|
||||||
|
columnMoveLeft: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
grid.moveColumnLeft(column);
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnMoveRight: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
grid.moveColumnRight(column);
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnMoveStart: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
column.moveAfter(null);
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnMoveEnd: () => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
column.moveAfter(grid.getLastColumn());
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnToggleStacked: () => {
|
||||||
|
world.doIfTiledFocused(false, (window, column, grid) => {
|
||||||
|
column.toggleStacked();
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnWidthIncrease: () => {
|
||||||
|
world.doIfTiledFocused(false, (window, column, grid) => {
|
||||||
|
grid.increaseColumnWidth(column);
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnWidthDecrease: () => {
|
||||||
|
world.doIfTiledFocused(false, (window, column, grid) => {
|
||||||
|
grid.decreaseColumnWidth(column);
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
gridScrollLeft: () => {
|
||||||
|
gridScroll(world, -config.manualScrollStep);
|
||||||
|
},
|
||||||
|
|
||||||
|
gridScrollRight: () => {
|
||||||
|
gridScroll(world, config.manualScrollStep);
|
||||||
|
},
|
||||||
|
|
||||||
|
gridScrollStart: () => {
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
const firstColumn = grid.getFirstColumn();
|
||||||
|
if (firstColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
grid.container.scrollToColumn(firstColumn);
|
||||||
|
grid.container.arrange();
|
||||||
|
},
|
||||||
|
|
||||||
|
gridScrollEnd: () => {
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
const lastColumn = grid.getLastColumn();
|
||||||
|
if (lastColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
grid.container.scrollToColumn(lastColumn);
|
||||||
|
grid.container.arrange();
|
||||||
|
},
|
||||||
|
|
||||||
|
gridScrollFocused: () => {
|
||||||
|
const focusedWindow = world.getFocusedWindow();
|
||||||
|
if (focusedWindow === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const column = focusedWindow.column;
|
||||||
|
const grid = column.grid;
|
||||||
|
grid.container.scrollCenterColumn(column);
|
||||||
|
grid.container.arrange();
|
||||||
|
},
|
||||||
|
|
||||||
|
gridScrollLeftColumn: () => {
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
const column = grid.getLeftmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
||||||
|
if (column === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
|
if (prevColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.container.scrollToColumn(prevColumn);
|
||||||
|
grid.container.arrange();
|
||||||
|
},
|
||||||
|
|
||||||
|
gridScrollRightColumn: () => {
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
const column = grid.getRightmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
||||||
|
if (column === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextColumn = grid.getNextColumn(column);
|
||||||
|
if (nextColumn === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.container.scrollToColumn(nextColumn);
|
||||||
|
grid.container.arrange();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initNum(world: World) {
|
||||||
|
return {
|
||||||
|
focusColumn: (columnIndex: number) => {
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
|
if (targetColumn === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
targetColumn.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
windowMoveToColumn: (columnIndex: number) => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
|
if (targetColumn === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
window.moveToColumn(targetColumn);
|
||||||
|
grid.container.onGridReordered();
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnMoveToColumn: (columnIndex: number) => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
|
if (targetColumn === null || targetColumn === column) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (targetColumn.isAfter(column)) {
|
||||||
|
column.moveAfter(targetColumn);
|
||||||
|
} else {
|
||||||
|
column.moveAfter(grid.getPrevColumn(targetColumn));
|
||||||
|
}
|
||||||
|
grid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
columnMoveToDesktop: (desktopIndex: number) => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, oldGrid) => {
|
||||||
|
const desktopNumber = desktopIndex + 1;
|
||||||
|
const newGrid = world.getGridInCurrentActivity(desktopNumber);
|
||||||
|
if (newGrid === null || newGrid === oldGrid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
column.moveToGrid(newGrid, newGrid.getLastColumn());
|
||||||
|
oldGrid.container.arrange();
|
||||||
|
newGrid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
tailMoveToDesktop: (desktopIndex: number) => {
|
||||||
|
world.doIfTiledFocused(true, (window, column, oldGrid) => {
|
||||||
|
const desktopNumber = desktopIndex + 1;
|
||||||
|
const newGrid = world.getGridInCurrentActivity(desktopNumber);
|
||||||
|
if (newGrid === null || newGrid === oldGrid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
oldGrid.evacuateTail(newGrid, column);
|
||||||
|
oldGrid.container.arrange();
|
||||||
|
newGrid.container.arrange();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridScroll(world: World, amount: number) {
|
||||||
|
const scrollAmount = amount;
|
||||||
|
const grid = world.getCurrentGrid();
|
||||||
|
grid.container.adjustScroll(scrollAmount, false);
|
||||||
|
grid.container.arrange();
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Config = {
|
||||||
|
manualScrollStep: number,
|
||||||
|
}
|
||||||
|
}
|
||||||
341
src/actions.ts
341
src/actions.ts
@@ -1,341 +0,0 @@
|
|||||||
function initActions(world: World) {
|
|
||||||
return {
|
|
||||||
focusLeft: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
|
||||||
if (prevColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prevColumn.focus();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
focusRight: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const nextColumn = grid.getNextColumn(column);
|
|
||||||
if (nextColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nextColumn.focus();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
focusUp: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const prevWindow = column.getPrevWindow(window);
|
|
||||||
if (prevWindow === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prevWindow.focus();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
focusDown: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const nextWindow = column.getNextWindow(window);
|
|
||||||
if (nextWindow === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nextWindow.focus();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
focusStart: () => {
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
const firstColumn = grid.getFirstColumn();
|
|
||||||
if (firstColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
firstColumn.focus();
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
|
||||||
|
|
||||||
focusEnd: () => {
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
const lastColumn = grid.getLastColumn();
|
|
||||||
if (lastColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastColumn.focus();
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
|
||||||
|
|
||||||
windowMoveLeft: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
if (column.getWindowCount() === 1) {
|
|
||||||
// move from own column into existing column
|
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
|
||||||
if (prevColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.moveToColumn(prevColumn);
|
|
||||||
grid.container.onGridReordered();
|
|
||||||
} else {
|
|
||||||
// move from shared column into own column
|
|
||||||
const newColumn = new Column(grid, grid.getPrevColumn(column));
|
|
||||||
window.moveToColumn(newColumn);
|
|
||||||
}
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
windowMoveRight: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
if (column.getWindowCount() === 1) {
|
|
||||||
// move from own column into existing column
|
|
||||||
const nextColumn = grid.getNextColumn(column);
|
|
||||||
if (nextColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.moveToColumn(nextColumn);
|
|
||||||
grid.container.onGridReordered();
|
|
||||||
} else {
|
|
||||||
// move from shared column into own column
|
|
||||||
const newColumn = new Column(grid, column);
|
|
||||||
window.moveToColumn(newColumn);
|
|
||||||
}
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
windowMoveUp: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
column.moveWindowUp(window);
|
|
||||||
grid.container.arrange(); // TODO (optimization): only arrange moved windows
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
windowMoveDown: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
column.moveWindowDown(window);
|
|
||||||
grid.container.arrange(); // TODO (optimization): only arrange moved windows
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
windowMoveStart: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const newColumn = new Column(grid, null);
|
|
||||||
window.moveToColumn(newColumn);
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
windowMoveEnd: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const newColumn = new Column(grid, grid.getLastColumn());
|
|
||||||
window.moveToColumn(newColumn);
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
windowToggleFloating: () => {
|
|
||||||
const kwinClient = workspace.activeClient;
|
|
||||||
world.toggleFloatingClient(kwinClient);
|
|
||||||
},
|
|
||||||
|
|
||||||
columnMoveLeft: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
grid.moveColumnLeft(column);
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnMoveRight: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
grid.moveColumnRight(column);
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnMoveStart: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
column.moveAfter(null);
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnMoveEnd: () => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
column.moveAfter(grid.getLastColumn());
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnToggleStacked: () => {
|
|
||||||
world.doIfTiledFocused(false, (window, column, grid) => {
|
|
||||||
column.toggleStacked();
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnWidthIncrease: () => {
|
|
||||||
world.doIfTiledFocused(false, (window, column, grid) => {
|
|
||||||
grid.increaseColumnWidth(column);
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnWidthDecrease: () => {
|
|
||||||
world.doIfTiledFocused(false, (window, column, grid) => {
|
|
||||||
grid.decreaseColumnWidth(column);
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
gridScrollStart: () => {
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
const firstColumn = grid.getFirstColumn();
|
|
||||||
if (firstColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
grid.container.scrollToColumn(firstColumn);
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
|
||||||
|
|
||||||
gridScrollEnd: () => {
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
const lastColumn = grid.getLastColumn();
|
|
||||||
if (lastColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
grid.container.scrollToColumn(lastColumn);
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
|
||||||
|
|
||||||
gridScrollFocused: () => {
|
|
||||||
const focusedWindow = world.getFocusedWindow();
|
|
||||||
if (focusedWindow === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const column = focusedWindow.column;
|
|
||||||
const grid = column.grid;
|
|
||||||
grid.container.scrollCenterColumn(column);
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
|
||||||
|
|
||||||
gridScrollLeftColumn: () => {
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
const column = grid.getLeftmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
|
||||||
if (column === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
|
||||||
if (prevColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.container.scrollToColumn(prevColumn);
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
|
||||||
|
|
||||||
gridScrollRightColumn: () => {
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
const column = grid.getRightmostVisibleColumn(grid.container.getCurrentScrollPos(), true);
|
|
||||||
if (column === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextColumn = grid.getNextColumn(column);
|
|
||||||
if (nextColumn === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.container.scrollToColumn(nextColumn);
|
|
||||||
grid.container.arrange();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function initNumActions(world: World) {
|
|
||||||
return {
|
|
||||||
focusColumn: (columnIndex: number) => {
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
|
||||||
if (targetColumn === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
targetColumn.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
windowMoveToColumn: (columnIndex: number) => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
|
||||||
if (targetColumn === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
window.moveToColumn(targetColumn);
|
|
||||||
grid.container.onGridReordered();
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnMoveToColumn: (columnIndex: number) => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, grid) => {
|
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
|
||||||
if (targetColumn === null || targetColumn === column) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (targetColumn.isAfter(column)) {
|
|
||||||
column.moveAfter(targetColumn);
|
|
||||||
} else {
|
|
||||||
column.moveAfter(grid.getPrevColumn(targetColumn));
|
|
||||||
}
|
|
||||||
grid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
columnMoveToDesktop: (desktopIndex: number) => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, oldGrid) => {
|
|
||||||
const desktopNumber = desktopIndex + 1;
|
|
||||||
const newGrid = world.getGridInCurrentActivity(desktopNumber);
|
|
||||||
if (newGrid === null || newGrid === oldGrid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
column.moveToGrid(newGrid, newGrid.getLastColumn());
|
|
||||||
oldGrid.container.arrange();
|
|
||||||
newGrid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
tailMoveToDesktop: (desktopIndex: number) => {
|
|
||||||
world.doIfTiledFocused(true, (window, column, oldGrid) => {
|
|
||||||
const desktopNumber = desktopIndex + 1;
|
|
||||||
const newGrid = world.getGridInCurrentActivity(desktopNumber);
|
|
||||||
if (newGrid === null || newGrid === oldGrid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
oldGrid.evacuateTail(newGrid, column);
|
|
||||||
oldGrid.container.arrange();
|
|
||||||
newGrid.container.arrange();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridScroll(world: World, amount: number) {
|
|
||||||
const scrollAmount = amount;
|
|
||||||
const grid = world.getCurrentGrid();
|
|
||||||
grid.container.adjustScroll(scrollAmount, false);
|
|
||||||
grid.container.arrange();
|
|
||||||
}
|
|
||||||
|
|
||||||
function canTileEver(kwinClient: AbstractClient) {
|
|
||||||
return kwinClient.resizeable;
|
|
||||||
}
|
|
||||||
|
|
||||||
function canTileNow(kwinClient: AbstractClient) {
|
|
||||||
return canTileEver(kwinClient) && !kwinClient.minimized && kwinClient.desktop > 0 && kwinClient.activities.length === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeTileable(kwinClient: AbstractClient) {
|
|
||||||
if (kwinClient.minimized) {
|
|
||||||
kwinClient.minimized = false;
|
|
||||||
}
|
|
||||||
if (kwinClient.desktop <= 0) {
|
|
||||||
kwinClient.desktop = workspace.currentDesktop;
|
|
||||||
}
|
|
||||||
if (kwinClient.activities.length !== 1) {
|
|
||||||
kwinClient.activities = [workspace.currentActivity];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ type Config = {
|
|||||||
gapsInnerHorizontal: number,
|
gapsInnerHorizontal: number,
|
||||||
gapsInnerVertical: number,
|
gapsInnerVertical: number,
|
||||||
overscroll: number,
|
overscroll: number,
|
||||||
|
manualScrollStep: number,
|
||||||
untileOnDrag: boolean,
|
untileOnDrag: boolean,
|
||||||
stackColumnsByDefault: boolean,
|
stackColumnsByDefault: boolean,
|
||||||
resizeNeighborColumn: boolean,
|
resizeNeighborColumn: boolean,
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ const configDef = [
|
|||||||
"type": "UInt",
|
"type": "UInt",
|
||||||
"default": 18
|
"default": 18
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "manualScrollStep",
|
||||||
|
"type": "UInt",
|
||||||
|
"default": 200
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "untileOnDrag",
|
"name": "untileOnDrag",
|
||||||
"type": "Bool",
|
"type": "Bool",
|
||||||
|
|||||||
@@ -140,6 +140,18 @@ const keyBindings: KeyBinding[] = [
|
|||||||
"defaultKeySequence": "Meta+Alt+D",
|
"defaultKeySequence": "Meta+Alt+D",
|
||||||
"action": "gridScrollRightColumn",
|
"action": "gridScrollRightColumn",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "grid-scroll-left",
|
||||||
|
"description": "Scroll left",
|
||||||
|
"defaultKeySequence": "Meta+Alt+PgUp",
|
||||||
|
"action": "gridScrollLeft",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "grid-scroll-right",
|
||||||
|
"description": "Scroll right",
|
||||||
|
"defaultKeySequence": "Meta+Alt+PgDown",
|
||||||
|
"action": "gridScrollRight",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-start",
|
"name": "grid-scroll-start",
|
||||||
"description": "Scroll to start",
|
"description": "Scroll to start",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ interface KeyBinding {
|
|||||||
description: string;
|
description: string;
|
||||||
comment?: string;
|
comment?: string;
|
||||||
defaultKeySequence: string;
|
defaultKeySequence: string;
|
||||||
action: keyof ReturnType<typeof initActions>;
|
action: keyof ReturnType<typeof Actions.init>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NumKeyBinding {
|
interface NumKeyBinding {
|
||||||
@@ -12,7 +12,7 @@ interface NumKeyBinding {
|
|||||||
comment?: string;
|
comment?: string;
|
||||||
defaultModifiers: string;
|
defaultModifiers: string;
|
||||||
fKeys: boolean;
|
fKeys: boolean;
|
||||||
action: keyof ReturnType<typeof initNumActions>;
|
action: keyof ReturnType<typeof Actions.initNum>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function catchWrap(f: () => void) {
|
function catchWrap(f: () => void) {
|
||||||
@@ -49,13 +49,13 @@ function registerNumKeyBindings(name: string, description: string, modifiers: st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerKeyBindings(world: World) {
|
function registerKeyBindings(world: World, config: Config) {
|
||||||
const actions = initActions(world);
|
const actions = Actions.init(world, config);
|
||||||
for (const binding of keyBindings) {
|
for (const binding of keyBindings) {
|
||||||
registerKeyBinding(binding.name, binding.description, binding.defaultKeySequence, actions[binding.action]);
|
registerKeyBinding(binding.name, binding.description, binding.defaultKeySequence, actions[binding.action]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const numActions = initNumActions(world);
|
const numActions = Actions.initNum(world);
|
||||||
for (const binding of numKeyBindings) {
|
for (const binding of numKeyBindings) {
|
||||||
registerNumKeyBindings(binding.name, binding.description, binding.defaultModifiers, binding.fKeys, numActions[binding.action]);
|
registerNumKeyBindings(binding.name, binding.description, binding.defaultModifiers, binding.fKeys, numActions[binding.action]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Column {
|
class Column {
|
||||||
public grid: Grid;
|
public grid: Grid;
|
||||||
public gridX: number;
|
public gridX: number;
|
||||||
public width: number; // TODO: increase column width to contain transients
|
private width: number; // TODO: increase column width to contain transients
|
||||||
private readonly windows: LinkedList<Window>;
|
private readonly windows: LinkedList<Window>;
|
||||||
private stacked: boolean;
|
private stacked: boolean;
|
||||||
private focusTaker: Window|null;
|
private focusTaker: Window|null;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class Grid {
|
|||||||
if (firstMovedColumn !== null) {
|
if (firstMovedColumn !== null) {
|
||||||
for (const column of this.columns.iteratorFrom(firstMovedColumn)) {
|
for (const column of this.columns.iteratorFrom(firstMovedColumn)) {
|
||||||
column.gridX = x;
|
column.gridX = x;
|
||||||
x += column.width + this.config.gapsInnerHorizontal;
|
x += column.getWidth() + this.config.gapsInnerHorizontal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.width = x - this.config.gapsInnerHorizontal;
|
this.width = x - this.config.gapsInnerHorizontal;
|
||||||
@@ -108,7 +108,7 @@ class Grid {
|
|||||||
let nVisible = 0;
|
let nVisible = 0;
|
||||||
for (const column of this.columns.iterator()) {
|
for (const column of this.columns.iterator()) {
|
||||||
if (column.isVisible(scrollPos, fullyVisible)) {
|
if (column.isVisible(scrollPos, fullyVisible)) {
|
||||||
width += column.width;
|
width += column.getWidth();
|
||||||
nVisible++;
|
nVisible++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,6 @@ class Grid {
|
|||||||
const scrollPos = this.container.getScrollPosForColumn(column);
|
const scrollPos = this.container.getScrollPosForColumn(column);
|
||||||
if (this.width < scrollPos.width) {
|
if (this.width < scrollPos.width) {
|
||||||
column.adjustWidth(scrollPos.width - this.width, false);
|
column.adjustWidth(scrollPos.width - this.width, false);
|
||||||
this.container.arrange();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +169,6 @@ class Grid {
|
|||||||
const scrollPos = this.container.getScrollPosForColumn(column);
|
const scrollPos = this.container.getScrollPosForColumn(column);
|
||||||
if (this.width <= scrollPos.width) {
|
if (this.width <= scrollPos.width) {
|
||||||
column.setWidth(Math.round(column.getWidth() / 2), false);
|
column.setWidth(Math.round(column.getWidth() / 2), false);
|
||||||
this.container.arrange();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +189,8 @@ class Grid {
|
|||||||
const shrinkLeft = leftInvisibleWidth < rightInvisibleWidth;
|
const shrinkLeft = leftInvisibleWidth < rightInvisibleWidth;
|
||||||
const widthDelta = (shrinkLeft ? leftInvisibleWidth : rightInvisibleWidth);
|
const widthDelta = (shrinkLeft ? leftInvisibleWidth : rightInvisibleWidth);
|
||||||
if (shrinkLeft) {
|
if (shrinkLeft) {
|
||||||
this.container.adjustScroll(-widthDelta, false);
|
const maxDelta = column.getWidth() - column.getMinWidth();
|
||||||
|
this.container.adjustScroll(-Math.min(widthDelta, maxDelta), false);
|
||||||
}
|
}
|
||||||
column.adjustWidth(-widthDelta, true);
|
column.adjustWidth(-widthDelta, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scrollCenterColumn(column: Column) {
|
scrollCenterColumn(column: Column) {
|
||||||
const windowCenter = column.getLeft() + column.width / 2;
|
const windowCenter = column.getLeft() + column.getWidth() / 2;
|
||||||
const screenCenter = this.scrollX + this.tilingArea.width / 2;
|
const screenCenter = this.scrollX + this.tilingArea.width / 2;
|
||||||
this.adjustScroll(Math.round(windowCenter - screenCenter), false);
|
this.adjustScroll(Math.round(windowCenter - screenCenter), false);
|
||||||
}
|
}
|
||||||
@@ -127,6 +127,7 @@ class ScrollView {
|
|||||||
// TODO (optimization): only arrange visible windows
|
// TODO (optimization): only arrange visible windows
|
||||||
this.updateArea();
|
this.updateArea();
|
||||||
this.grid.arrange(this.tilingArea.x - this.scrollX);
|
this.grid.arrange(this.tilingArea.x - this.scrollX);
|
||||||
|
this.world.ensureFocusedTransientsVisible(); // TODO: refactor - call from elsewhere
|
||||||
}
|
}
|
||||||
|
|
||||||
public onGridWidthChanged() {
|
public onGridWidthChanged() {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class Window {
|
|||||||
|
|
||||||
arrange(x: number, y: number, width: number, height: number) {
|
arrange(x: number, y: number, width: number, height: number) {
|
||||||
if (this.skipArrange) {
|
if (this.skipArrange) {
|
||||||
// window is being manually resized, prevent fighting with the user
|
// window is maximized, fullscreen, or being manually resized, prevent fighting with the user
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.client.place(x, y, width, height);
|
this.client.place(x, y, width, height);
|
||||||
@@ -94,10 +94,10 @@ class Window {
|
|||||||
if (resizeNeighborColumn && this.column.grid.config.resizeNeighborColumn) {
|
if (resizeNeighborColumn && this.column.grid.config.resizeNeighborColumn) {
|
||||||
const neighborColumn = resizingLeftSide ? this.column.grid.getPrevColumn(this.column) : this.column.grid.getNextColumn(this.column);
|
const neighborColumn = resizingLeftSide ? this.column.grid.getPrevColumn(this.column) : this.column.grid.getNextColumn(this.column);
|
||||||
if (neighborColumn !== null) {
|
if (neighborColumn !== null) {
|
||||||
const oldNeighborWidth = neighborColumn.width;
|
const oldNeighborWidth = neighborColumn.getWidth();
|
||||||
neighborColumn.adjustWidth(-widthDelta, true);
|
neighborColumn.adjustWidth(-widthDelta, true);
|
||||||
if (resizingLeftSide) {
|
if (resizingLeftSide) {
|
||||||
leftEdgeDelta -= neighborColumn.width - oldNeighborWidth;
|
leftEdgeDelta -= neighborColumn.getWidth() - oldNeighborWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
function init() {
|
function init() {
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const world = new World(config);
|
const world = new World(config);
|
||||||
registerKeyBindings(world);
|
registerKeyBindings(world, config);
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class WindowRuleEnforcer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shouldTile(kwinClient: AbstractClient) {
|
shouldTile(kwinClient: AbstractClient) {
|
||||||
return canTileNow(kwinClient) && (
|
return Clients.canTileNow(kwinClient) && (
|
||||||
this.preferTiling.matches(kwinClient) ||
|
this.preferTiling.matches(kwinClient) ||
|
||||||
kwinClient.normalWindow && kwinClient.managed && !this.preferFloating.matches(kwinClient)
|
kwinClient.normalWindow && kwinClient.managed && !this.preferFloating.matches(kwinClient)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ function initWorkspaceSignalHandlers(world: World) {
|
|||||||
|
|
||||||
manager.connect(workspace.clientAdded, (kwinClient: AbstractClient) => {
|
manager.connect(workspace.clientAdded, (kwinClient: AbstractClient) => {
|
||||||
console.assert(!world.hasClient(kwinClient));
|
console.assert(!world.hasClient(kwinClient));
|
||||||
if (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) {
|
||||||
kwinClient.desktop = workspace.currentDesktop;
|
kwinClient.desktop = workspace.currentDesktop;
|
||||||
|
|||||||
@@ -119,6 +119,25 @@ class ClientWrapper {
|
|||||||
this.transients.splice(i, 1);
|
this.transients.splice(i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ensureTransientsVisible(screenSize: QRect) {
|
||||||
|
for (const transient of this.transients) {
|
||||||
|
if (transient.stateManager.getState() instanceof ClientStateFloating) {
|
||||||
|
transient.ensureVisible(screenSize);
|
||||||
|
transient.ensureTransientsVisible(screenSize);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ensureVisible(screenSize: QRect) {
|
||||||
|
const frame = this.kwinClient.frameGeometry;
|
||||||
|
if (frame.left < 0) {
|
||||||
|
frame.x = 0;
|
||||||
|
} else if (frame.right > screenSize.width) {
|
||||||
|
frame.x = screenSize.width - frame.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
destroy(passFocus: boolean) {
|
destroy(passFocus: boolean) {
|
||||||
this.stateManager.destroy(passFocus);
|
this.stateManager.destroy(passFocus);
|
||||||
this.signalManager.destroy();
|
this.signalManager.destroy();
|
||||||
|
|||||||
21
src/world/Clients.ts
Normal file
21
src/world/Clients.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module Clients {
|
||||||
|
export function canTileEver(kwinClient: AbstractClient) {
|
||||||
|
return kwinClient.resizeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canTileNow(kwinClient: AbstractClient) {
|
||||||
|
return canTileEver(kwinClient) && !kwinClient.minimized && kwinClient.desktop > 0 && kwinClient.activities.length === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeTileable(kwinClient: AbstractClient) {
|
||||||
|
if (kwinClient.minimized) {
|
||||||
|
kwinClient.minimized = false;
|
||||||
|
}
|
||||||
|
if (kwinClient.desktop <= 0) {
|
||||||
|
kwinClient.desktop = workspace.currentDesktop;
|
||||||
|
}
|
||||||
|
if (kwinClient.activities.length !== 1) {
|
||||||
|
kwinClient.activities = [workspace.currentActivity];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,12 +38,7 @@ class World {
|
|||||||
marginRight: config.gapsOuterRight,
|
marginRight: config.gapsOuterRight,
|
||||||
overscroll: config.overscroll,
|
overscroll: config.overscroll,
|
||||||
},
|
},
|
||||||
{
|
config,
|
||||||
gapsInnerHorizontal: config.gapsInnerHorizontal,
|
|
||||||
gapsInnerVertical: config.gapsInnerVertical,
|
|
||||||
stackColumnsByDefault: config.stackColumnsByDefault,
|
|
||||||
resizeNeighborColumn: config.resizeNeighborColumn,
|
|
||||||
},
|
|
||||||
workspace.currentActivity,
|
workspace.currentActivity,
|
||||||
workspace.desktops,
|
workspace.desktops,
|
||||||
);
|
);
|
||||||
@@ -118,6 +113,12 @@ class World {
|
|||||||
return transientFor;
|
return transientFor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ensureFocusedTransientsVisible() {
|
||||||
|
this.doIfTiledFocused(true, (window, column, grid) => {
|
||||||
|
window.client.ensureTransientsVisible(grid.container.clientArea);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
minimizeClient(kwinClient: AbstractClient) {
|
minimizeClient(kwinClient: AbstractClient) {
|
||||||
const client = this.clientMap.get(kwinClient);
|
const client = this.clientMap.get(kwinClient);
|
||||||
if (client === undefined) {
|
if (client === undefined) {
|
||||||
@@ -166,8 +167,8 @@ class World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const clientState = client.stateManager.getState();
|
const clientState = client.stateManager.getState();
|
||||||
if (clientState instanceof ClientStateFloating && canTileEver(kwinClient)) {
|
if (clientState instanceof ClientStateFloating && Clients.canTileEver(kwinClient)) {
|
||||||
makeTileable(kwinClient);
|
Clients.makeTileable(kwinClient);
|
||||||
client.stateManager.setState(new ClientStateTiled(this, client), false);
|
client.stateManager.setState(new ClientStateTiled(this, client), false);
|
||||||
} else if (clientState instanceof ClientStateTiled) {
|
} else if (clientState instanceof ClientStateTiled) {
|
||||||
client.stateManager.setState(new ClientStateFloating(), false);
|
client.stateManager.setState(new ClientStateFloating(), false);
|
||||||
|
|||||||
Reference in New Issue
Block a user