Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
465945429a | ||
|
|
1d7636508b | ||
|
|
47213a71f5 | ||
|
|
75a548977c | ||
|
|
d746b91a88 | ||
|
|
a0d9c49287 | ||
|
|
862cc445bd | ||
|
|
5019a5d702 | ||
|
|
36c7cab137 | ||
|
|
df3c1f4512 | ||
|
|
5f3eaf1eec | ||
|
|
4a680177f6 | ||
|
|
8d807c979b | ||
|
|
c8e37aeb87 | ||
|
|
ad0fe7472c | ||
|
|
a51e45667c | ||
|
|
6615fe6f93 | ||
|
|
6e69139b80 | ||
|
|
97430d5043 |
@@ -51,7 +51,7 @@ Here's the default ones:
|
||||
| (unassigned) | Move window to the previous position in grid |
|
||||
| Meta+Shift+Home | Move window to start |
|
||||
| Meta+Shift+End | Move window to end |
|
||||
| Meta+X | Toggle stacked layout for focused column (One window in the column visible, others shaded; not supported on Wayland) |
|
||||
| Meta+X | Toggle stacked layout for focused column (Only the active window visible) |
|
||||
| Meta+Ctrl+Shift+A | Move column left |
|
||||
| Meta+Ctrl+Shift+D | Move column right |
|
||||
| Meta+Ctrl+Shift+Home | Move column to start |
|
||||
@@ -59,6 +59,7 @@ Here's the default ones:
|
||||
| Meta+Ctrl++ | Increase column width |
|
||||
| Meta+Ctrl+- | Decrease column width |
|
||||
| Meta+R | Cycle through preset column widths |
|
||||
| Meta+Shift+R | Cycle through preset column widths in reverse |
|
||||
| Meta+Ctrl+X | Equalize widths of visible columns |
|
||||
| Meta+Ctrl+A | Squeeze left column onto the screen (Clashes with default KDE shortcuts, may require manual remapping) |
|
||||
| Meta+Ctrl+D | Squeeze right column onto the screen |
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<string>Stack columns by default</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>New columns start in stacked mode (one window in the column visible, others shaded). Not supported on Wayland.</string>
|
||||
<string>New columns start in stacked mode (only the active window visible)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -280,14 +280,14 @@
|
||||
</item>
|
||||
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_manualScrollStep">
|
||||
<widget class="QLabel" name="label_stackOffsetX">
|
||||
<property name="text">
|
||||
<string>Manual scroll step size:</string>
|
||||
<string>Horizontal offset for stacked columns:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_manualScrollStep">
|
||||
<widget class="QSpinBox" name="kcfg_stackOffsetX">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
@@ -301,6 +301,48 @@
|
||||
</item>
|
||||
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_stackOffsetY">
|
||||
<property name="text">
|
||||
<string>Vertical offset for stacked columns:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_stackOffsetY">
|
||||
<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="0">
|
||||
<widget class="QLabel" name="label_manualScrollStep">
|
||||
<property name="text">
|
||||
<string>Manual scroll step size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" 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="9" column="0">
|
||||
<widget class="QLabel" name="label_presetWidths">
|
||||
<property name="text">
|
||||
<string>Preset widths:</string>
|
||||
@@ -310,7 +352,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="kcfg_presetWidths">
|
||||
<property name="toolTip">
|
||||
<string>Comma-separated list of widths. Supported units: "px" and "%".</string>
|
||||
@@ -318,14 +360,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="8" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_offScreenOpacity">
|
||||
<property name="text">
|
||||
<string>Obscured window opacity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_offScreenOpacity">
|
||||
<property name="suffix">
|
||||
<string> %</string>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"Name": "Peter Fajdiga"
|
||||
}],
|
||||
"Id": "karousel",
|
||||
"Version": "0.11",
|
||||
"Version": "0.12",
|
||||
"License": "GPLv3",
|
||||
"Website": "https://github.com/peterfajdiga/karousel",
|
||||
"BugReportUrl": "https://github.com/peterfajdiga/karousel/issues"
|
||||
|
||||
@@ -5,6 +5,8 @@ type Config = {
|
||||
gapsOuterRight: number;
|
||||
gapsInnerHorizontal: number;
|
||||
gapsInnerVertical: number;
|
||||
stackOffsetX: number;
|
||||
stackOffsetY: number;
|
||||
manualScrollStep: number;
|
||||
presetWidths: string;
|
||||
offScreenOpacity: number;
|
||||
|
||||
@@ -3,6 +3,10 @@ const defaultWindowRules = `[
|
||||
"class": "(org\\\\.kde\\\\.)?plasmashell",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\\\.kde\\\\.)?polkit-kde-authentication-agent-1",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\\\.kde\\\\.)?kded6",
|
||||
"tile": false
|
||||
@@ -80,6 +84,16 @@ const configDef = [
|
||||
type: "UInt",
|
||||
default: 8,
|
||||
},
|
||||
{
|
||||
name: "stackOffsetX",
|
||||
type: "UInt",
|
||||
default: 8,
|
||||
},
|
||||
{
|
||||
name: "stackOffsetY",
|
||||
type: "UInt",
|
||||
default: 32,
|
||||
},
|
||||
{
|
||||
name: "manualScrollStep",
|
||||
type: "UInt",
|
||||
|
||||
2
src/lib/extern/kwin.ts
vendored
2
src/lib/extern/kwin.ts
vendored
@@ -54,7 +54,6 @@ type Output = { __brand: "Output" };
|
||||
type KwinClient = {
|
||||
__brand: "KwinClient";
|
||||
|
||||
readonly shadeable: boolean;
|
||||
readonly caption: string;
|
||||
readonly minSize: Readonly<QmlSize>;
|
||||
readonly transient: boolean;
|
||||
@@ -79,7 +78,6 @@ type KwinClient = {
|
||||
skipSwitcher: boolean;
|
||||
keepAbove: boolean;
|
||||
keepBelow: boolean;
|
||||
shade: boolean;
|
||||
minimized: boolean;
|
||||
frameGeometry: QmlRect;
|
||||
desktops: KwinDesktop[]; // empty array means all desktops
|
||||
|
||||
@@ -306,7 +306,7 @@ class Actions {
|
||||
if (firstColumn === null) {
|
||||
return;
|
||||
}
|
||||
grid.desktop.scrollToColumn(firstColumn);
|
||||
grid.desktop.scrollToColumn(firstColumn, false);
|
||||
}
|
||||
|
||||
public readonly gridScrollEnd = (cm: ClientManager, dm: DesktopManager) => {
|
||||
@@ -315,11 +315,16 @@ class Actions {
|
||||
if (lastColumn === null) {
|
||||
return;
|
||||
}
|
||||
grid.desktop.scrollToColumn(lastColumn);
|
||||
grid.desktop.scrollToColumn(lastColumn, false);
|
||||
}
|
||||
|
||||
public readonly gridScrollFocused = (cm: ClientManager, dm: DesktopManager, window: Window, column: Column, grid: Grid) => {
|
||||
grid.desktop.scrollCenterRange(column);
|
||||
const scrollAmount = Range.minus(column, grid.desktop.getCurrentVisibleRange());
|
||||
if (scrollAmount !== 0) {
|
||||
grid.desktop.adjustScroll(scrollAmount, true);
|
||||
} else {
|
||||
grid.desktop.scrollToColumn(column, true);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly gridScrollLeftColumn = (cm: ClientManager, dm: DesktopManager) => {
|
||||
@@ -334,7 +339,7 @@ class Actions {
|
||||
return;
|
||||
}
|
||||
|
||||
grid.desktop.scrollToColumn(leftColumn);
|
||||
grid.desktop.scrollToColumn(leftColumn, false);
|
||||
}
|
||||
|
||||
public readonly gridScrollRightColumn = (cm: ClientManager, dm: DesktopManager) => {
|
||||
@@ -349,7 +354,7 @@ class Actions {
|
||||
return;
|
||||
}
|
||||
|
||||
grid.desktop.scrollToColumn(rightColumn);
|
||||
grid.desktop.scrollToColumn(rightColumn, false);
|
||||
}
|
||||
|
||||
public readonly screenSwitch = (cm: ClientManager, dm: DesktopManager) => {
|
||||
|
||||
@@ -106,7 +106,7 @@ function getKeyBindings(world: World, actions: Actions): KeyBinding[] {
|
||||
{
|
||||
name: "column-toggle-stacked",
|
||||
description: "Toggle stacked layout for focused column",
|
||||
comment: "One window in the column visible, others shaded; not supported on Wayland",
|
||||
comment: "Only the active window visible",
|
||||
defaultKeySequence: "Meta+X",
|
||||
action: () => world.doIfTiledFocused(actions.columnToggleStacked),
|
||||
},
|
||||
|
||||
@@ -219,42 +219,28 @@ class Column {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.stacked && this.windows.length() >= 2 && this.canStack()) {
|
||||
if (this.stacked && this.windows.length() >= 2) {
|
||||
this.arrangeStacked(x);
|
||||
return;
|
||||
}
|
||||
let y = this.grid.desktop.tilingArea.y;
|
||||
for (const window of this.windows.iterator()) {
|
||||
window.client.setShade(false);
|
||||
window.arrange(x, y, this.width, window.height);
|
||||
y += window.height + this.grid.config.gapsInnerVertical;
|
||||
}
|
||||
}
|
||||
|
||||
public arrangeStacked(x: number) {
|
||||
const expandedWindow = this.getFocusTaker();
|
||||
let collapsedHeight;
|
||||
for (const window of this.windows.iterator()) {
|
||||
if (window === expandedWindow) {
|
||||
window.client.setShade(false);
|
||||
} else {
|
||||
window.client.setShade(true);
|
||||
collapsedHeight = window.client.kwinClient.frameGeometry.height;
|
||||
}
|
||||
}
|
||||
const nWindows = this.windows.length();
|
||||
const windowWidth = this.width - (nWindows - 1) * this.grid.config.stackOffsetX;
|
||||
const windowHeight = this.grid.desktop.tilingArea.height - (nWindows - 1) * this.grid.config.stackOffsetY;
|
||||
|
||||
const nCollapsed = this.getWindowCount() - 1;
|
||||
const expandedHeight = this.grid.desktop.tilingArea.height - nCollapsed * (collapsedHeight! + this.grid.config.gapsInnerVertical);
|
||||
let y = this.grid.desktop.tilingArea.y;
|
||||
let windowX = x;
|
||||
let windowY = this.grid.desktop.tilingArea.y;
|
||||
for (const window of this.windows.iterator()) {
|
||||
if (window === expandedWindow) {
|
||||
window.arrange(x, y, this.width, expandedHeight);
|
||||
y += expandedHeight;
|
||||
} else {
|
||||
window.arrange(x, y, this.width, window.height);
|
||||
y += collapsedHeight!;
|
||||
}
|
||||
y += this.grid.config.gapsInnerVertical;
|
||||
window.arrange(windowX, windowY, windowWidth, windowHeight);
|
||||
windowX += this.grid.config.stackOffsetX;
|
||||
windowY += this.grid.config.stackOffsetY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,15 +252,6 @@ class Column {
|
||||
this.grid.desktop.onLayoutChanged();
|
||||
}
|
||||
|
||||
private canStack() {
|
||||
for (const window of this.windows.iterator()) {
|
||||
if (!window.client.kwinClient.shadeable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public onWindowAdded(window: Window, bottom: boolean) {
|
||||
if (bottom) {
|
||||
this.windows.insertEnd(window);
|
||||
|
||||
@@ -73,9 +73,8 @@ class Desktop {
|
||||
}
|
||||
|
||||
public scrollCenterRange(range: Range) {
|
||||
const windowCenter = range.getLeft() + range.getWidth() / 2;
|
||||
const screenCenter = this.scrollX + this.tilingArea.width / 2;
|
||||
this.adjustScroll(Math.round(windowCenter - screenCenter), true);
|
||||
const scrollAmount = Range.minus(range, this.getCurrentVisibleRange());
|
||||
this.adjustScroll(scrollAmount, true);
|
||||
}
|
||||
|
||||
public scrollCenterVisible(focusedColumn: Column) {
|
||||
@@ -91,11 +90,11 @@ class Desktop {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scrollToColumn(focusedColumn);
|
||||
this.scrollToColumn(focusedColumn, false);
|
||||
}
|
||||
|
||||
public scrollToColumn(column: Column) {
|
||||
if (this.dirtyScroll || !Range.contains(this.getCurrentVisibleRange(), column)) {
|
||||
public scrollToColumn(column: Column, force: boolean) {
|
||||
if (force || this.dirtyScroll || !Range.contains(this.getCurrentVisibleRange(), column)) {
|
||||
this.config.scroller.scrollToColumn(this, column);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ class Grid {
|
||||
lastFocusedColumn.restoreToTiled();
|
||||
}
|
||||
this.lastFocusedColumn = column;
|
||||
this.desktop.scrollToColumn(column);
|
||||
this.desktop.scrollToColumn(column, false);
|
||||
}
|
||||
|
||||
public onScreenSizeChanged() {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
type LayoutConfig = {
|
||||
gapsInnerHorizontal: number;
|
||||
gapsInnerVertical: number;
|
||||
stackOffsetX: number;
|
||||
stackOffsetY: number;
|
||||
offScreenOpacity: number;
|
||||
stackColumnsByDefault: boolean;
|
||||
resizeNeighborColumn: boolean;
|
||||
|
||||
@@ -20,6 +20,12 @@ namespace Range {
|
||||
child.getRight() <= parent.getRight();
|
||||
}
|
||||
|
||||
export function minus(a: Range, b: Range) {
|
||||
const aCenter = a.getLeft() + a.getWidth() / 2;
|
||||
const bCenter = b.getLeft() + b.getWidth() / 2;
|
||||
return Math.round(aCenter - bCenter);
|
||||
}
|
||||
|
||||
class Basic {
|
||||
constructor(
|
||||
private readonly x: number,
|
||||
|
||||
@@ -8,11 +8,17 @@ class Window {
|
||||
constructor(client: ClientWrapper, column: Column) {
|
||||
this.client = client;
|
||||
this.height = client.kwinClient.frameGeometry.height;
|
||||
|
||||
let maximizedMode = this.client.getMaximizedMode();
|
||||
if (maximizedMode === undefined) {
|
||||
maximizedMode = MaximizedMode.Unmaximized; // defaulting to unmaximized, as this is set in Tiled.prepareClientForTiling
|
||||
}
|
||||
this.focusedState = {
|
||||
fullScreen: false,
|
||||
maximizedMode: MaximizedMode.Unmaximized,
|
||||
fullScreen: this.client.kwinClient.fullScreen,
|
||||
maximizedMode: maximizedMode,
|
||||
};
|
||||
this.skipArrange = false;
|
||||
|
||||
this.skipArrange = this.client.kwinClient.fullScreen || maximizedMode !== MaximizedMode.Unmaximized;
|
||||
this.column = column;
|
||||
column.onWindowAdded(this, true);
|
||||
}
|
||||
@@ -54,10 +60,6 @@ class Window {
|
||||
}
|
||||
|
||||
public focus() {
|
||||
if (this.client.isShaded()) {
|
||||
// workaround for KWin deactivating clients when unshading immediately after activation
|
||||
this.client.setShade(false);
|
||||
}
|
||||
this.client.focus();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ class WindowRuleEnforcer {
|
||||
!kwinClient.transient &&
|
||||
kwinClient.managed &&
|
||||
kwinClient.pid > -1 &&
|
||||
!kwinClient.fullScreen &&
|
||||
!Clients.isFullScreenGeometry(kwinClient) &&
|
||||
!this.preferFloating.matches(kwinClient)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ class ClientManager {
|
||||
constructState = () => new ClientState.Docked(this.world, kwinClient);
|
||||
} else if (
|
||||
Clients.canTileEver(kwinClient) &&
|
||||
!kwinClient.fullScreen &&
|
||||
!Clients.isFullScreenGeometry(kwinClient) &&
|
||||
this.windowRuleEnforcer.shouldTile(kwinClient)
|
||||
) {
|
||||
Clients.makeTileable(kwinClient);
|
||||
|
||||
@@ -108,16 +108,6 @@ class ClientWrapper {
|
||||
});
|
||||
}
|
||||
|
||||
public setShade(shade: boolean) {
|
||||
this.manipulatingGeometry.do(() => {
|
||||
this.kwinClient.shade = shade;
|
||||
});
|
||||
}
|
||||
|
||||
public isShaded() {
|
||||
return this.kwinClient.shade;
|
||||
}
|
||||
|
||||
public getMaximizedMode() {
|
||||
return this.maximizedMode;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace Clients {
|
||||
];
|
||||
|
||||
export function canTileEver(kwinClient: KwinClient) {
|
||||
return kwinClient.moveable &&
|
||||
kwinClient.resizeable &&
|
||||
const shapeable = (kwinClient.moveable && kwinClient.resizeable) || kwinClient.fullScreen; // full-screen windows may become shapeable after exiting full-screen mode
|
||||
return shapeable &&
|
||||
!kwinClient.popupWindow &&
|
||||
!prohibitedClasses.includes(kwinClient.resourceClass);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ class World {
|
||||
const layoutConfig = {
|
||||
gapsInnerHorizontal: config.gapsInnerHorizontal,
|
||||
gapsInnerVertical: config.gapsInnerVertical,
|
||||
stackOffsetX: config.stackOffsetX,
|
||||
stackOffsetY: config.stackOffsetY,
|
||||
offScreenOpacity: config.offScreenOpacity / 100.0,
|
||||
stackColumnsByDefault: config.stackColumnsByDefault,
|
||||
resizeNeighborColumn: config.resizeNeighborColumn,
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace ClientState {
|
||||
});
|
||||
});
|
||||
|
||||
let moving = false;
|
||||
let resizing = false;
|
||||
let resizeStartWidth = 0;
|
||||
let resizeNeighbor: { column: Column, startWidth: number } | undefined;
|
||||
@@ -78,6 +79,8 @@ namespace ClientState {
|
||||
world.do((clientManager, desktopManager) => {
|
||||
clientManager.floatClient(client);
|
||||
});
|
||||
} else {
|
||||
moving = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -99,6 +102,10 @@ namespace ClientState {
|
||||
});
|
||||
|
||||
manager.connect(kwinClient.interactiveMoveResizeFinished, () => {
|
||||
if (moving) {
|
||||
moving = false;
|
||||
world.do(() => window.column.grid.desktop.onLayoutChanged()); // move the dragged window back to its position
|
||||
}
|
||||
if (resizing) {
|
||||
resizing = false;
|
||||
resizeNeighbor = undefined;
|
||||
@@ -160,7 +167,15 @@ namespace ClientState {
|
||||
});
|
||||
|
||||
manager.connect(kwinClient.fullScreenChanged, () => {
|
||||
world.do(() => window.onFullScreenChanged(kwinClient.fullScreen));
|
||||
world.do((clientManager, desktopManager) => {
|
||||
// some clients only turn out to be untileable after exiting full-screen mode
|
||||
if (!Clients.canTileEver(kwinClient)) {
|
||||
clientManager.floatClient(client);
|
||||
return;
|
||||
}
|
||||
|
||||
window.onFullScreenChanged(kwinClient.fullScreen);
|
||||
});
|
||||
});
|
||||
|
||||
manager.connect(kwinClient.tileChanged, () => {
|
||||
@@ -205,7 +220,6 @@ namespace ClientState {
|
||||
client.kwinClient.keepBelow = true;
|
||||
}
|
||||
client.kwinClient.keepAbove = false;
|
||||
client.setFullScreen(false);
|
||||
if (client.kwinClient.tile !== null) {
|
||||
client.setMaximize(false, true); // disable quick tile mode
|
||||
}
|
||||
@@ -222,7 +236,6 @@ namespace ClientState {
|
||||
if (config.offScreenOpacity < 1.0) {
|
||||
client.kwinClient.opacity = 1.0;
|
||||
}
|
||||
client.setShade(false);
|
||||
client.setFullScreen(false);
|
||||
if (client.kwinClient.tile === null) {
|
||||
client.setMaximize(false, false);
|
||||
|
||||
@@ -11,13 +11,33 @@ tests.register("Center focused", 1, () => {
|
||||
Assert.assert(workspaceMock.activeWindow === client2);
|
||||
Assert.columnsFillTilingArea([client0, client1, client2]);
|
||||
|
||||
// center client2
|
||||
qtMock.fireShortcut("karousel-grid-scroll-focused");
|
||||
Assert.centered(config, screen, client2);
|
||||
Assert.centered(config, tilingArea, client2);
|
||||
Assert.fullyVisible(client1.frameGeometry);
|
||||
Assert.fullyVisible(client2.frameGeometry);
|
||||
|
||||
qtMock.fireShortcut("karousel-focus-left");
|
||||
Assert.centered(config, screen, client2, { message: "No scrolling should have occured" });
|
||||
// undo center client2
|
||||
qtMock.fireShortcut("karousel-grid-scroll-focused");
|
||||
Assert.columnsFillTilingArea([client0, client1, client2]);
|
||||
|
||||
// center client2
|
||||
qtMock.fireShortcut("karousel-grid-scroll-focused");
|
||||
Assert.centered(config, tilingArea, client2);
|
||||
Assert.fullyVisible(client1.frameGeometry);
|
||||
Assert.fullyVisible(client2.frameGeometry);
|
||||
|
||||
// focus client1 (no scrolling should occur)
|
||||
qtMock.fireShortcut("karousel-focus-left");
|
||||
Assert.centered(config, tilingArea, client2, { message: "No scrolling should have occured" });
|
||||
Assert.fullyVisible(client1.frameGeometry);
|
||||
Assert.fullyVisible(client2.frameGeometry);
|
||||
|
||||
// center client1
|
||||
qtMock.fireShortcut("karousel-grid-scroll-focused");
|
||||
Assert.columnsFillTilingArea([client0, client1, client2]);
|
||||
|
||||
// undo center client1 (no scrolling should occur, because all clients are already visible and centered)
|
||||
qtMock.fireShortcut("karousel-grid-scroll-focused");
|
||||
Assert.columnsFillTilingArea([client0, client1, client2]);
|
||||
});
|
||||
|
||||
34
src/tests/flows/dragTiled.ts
Normal file
34
src/tests/flows/dragTiled.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
tests.register("Drag tiled window, untile", 20, () => {
|
||||
const config = getDefaultConfig();
|
||||
config.untileOnDrag = true;
|
||||
const { qtMock, workspaceMock, world } = init(config);
|
||||
const clientManager = getClientManager(world);
|
||||
|
||||
const [client0, client1] = workspaceMock.createClients(2);
|
||||
Assert.tiledClient(clientManager, client0);
|
||||
Assert.tiledClient(clientManager, client1);
|
||||
Assert.grid(config, tilingArea, 100, [[client0], [client1]], true);
|
||||
|
||||
workspaceMock.moveWindow(client0, new MockQmlPoint(10, 10));
|
||||
Assert.notTiledClient(clientManager, client0);
|
||||
Assert.tiledClient(clientManager, client1);
|
||||
Assert.grid(config, tilingArea, 100, [[client1]], true);
|
||||
});
|
||||
|
||||
tests.register("Drag tiled window, keep tiled", 20, () => {
|
||||
const config = getDefaultConfig();
|
||||
config.untileOnDrag = false;
|
||||
const { qtMock, workspaceMock, world } = init(config);
|
||||
const clientManager = getClientManager(world);
|
||||
|
||||
const [client0, client1] = workspaceMock.createClients(2);
|
||||
Assert.tiledClient(clientManager, client0);
|
||||
Assert.tiledClient(clientManager, client1);
|
||||
Assert.grid(config, tilingArea, 100, [[client0], [client1]], true);
|
||||
|
||||
const move = new MockQmlPoint(10, 10);
|
||||
workspaceMock.moveWindow(client0, move, move, move, move, move, move, move, move, move); // many moves in order to trigger externalFrameGeometryChangedRateLimiter
|
||||
Assert.tiledClient(clientManager, client0);
|
||||
Assert.tiledClient(clientManager, client1);
|
||||
Assert.grid(config, tilingArea, 100, [[client0], [client1]], true);
|
||||
});
|
||||
@@ -8,7 +8,7 @@ tests.register("External resize", 1, () => {
|
||||
|
||||
function getTiledFrame(width: number) {
|
||||
return new MockQmlRect(
|
||||
Math.round((screen.width - width) / 2),
|
||||
tilingArea.left + Math.round((tilingArea.width - width) / 2),
|
||||
tilingArea.top,
|
||||
width,
|
||||
tilingArea.height,
|
||||
|
||||
@@ -12,7 +12,7 @@ tests.register("Focus and move windows", 1, () => {
|
||||
|
||||
function testLayout(shortcutName: string, grid: KwinClient[][]) {
|
||||
qtMock.fireShortcut(shortcutName);
|
||||
Assert.grid(config, screen, 100, grid, true, { skip: 1 });
|
||||
Assert.grid(config, tilingArea, 100, grid, true, [], { skip: 1 });
|
||||
}
|
||||
|
||||
function testFocus(shortcutName: string, expectedFocus: KwinClient) {
|
||||
|
||||
@@ -6,13 +6,13 @@ tests.register("LazyScroller", 20, () => {
|
||||
const { qtMock, workspaceMock, world } = init(config);
|
||||
|
||||
const [client1] = workspaceMock.createClientsWithWidths(300);
|
||||
Assert.grid(config, screen, 300, [[client1]], true);
|
||||
Assert.grid(config, tilingArea, 300, [[client1]], true);
|
||||
|
||||
const [client2] = workspaceMock.createClientsWithWidths(300);
|
||||
Assert.grid(config, screen, 300, [[client1], [client2]], true);
|
||||
Assert.grid(config, tilingArea, 300, [[client1], [client2]], true);
|
||||
|
||||
const [client3] = workspaceMock.createClientsWithWidths(300);
|
||||
Assert.grid(config, screen, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.grid(config, tilingArea, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.equal(client3.frameGeometry.right, tilingArea.right);
|
||||
|
||||
runOneOf(
|
||||
@@ -20,7 +20,7 @@ tests.register("LazyScroller", 20, () => {
|
||||
() => qtMock.fireShortcut("karousel-focus-2"),
|
||||
() => qtMock.fireShortcut("karousel-focus-left"),
|
||||
);
|
||||
Assert.grid(config, screen, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.grid(config, tilingArea, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.equal(client3.frameGeometry.right, tilingArea.right);
|
||||
|
||||
runOneOf(
|
||||
@@ -30,18 +30,18 @@ tests.register("LazyScroller", 20, () => {
|
||||
() => qtMock.fireShortcut("karousel-focus-start"),
|
||||
);
|
||||
workspaceMock.activeWindow = client1;
|
||||
Assert.grid(config, screen, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.grid(config, tilingArea, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.equal(client1.frameGeometry.left, tilingArea.left);
|
||||
|
||||
qtMock.fireShortcut("karousel-grid-scroll-focused");
|
||||
Assert.grid(config, screen, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.grid(config, screen, 300, [[client1]], true);
|
||||
Assert.grid(config, tilingArea, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.grid(config, tilingArea, 300, [[client1]], true);
|
||||
|
||||
runOneOf(
|
||||
() => workspaceMock.activeWindow = client2,
|
||||
() => qtMock.fireShortcut("karousel-focus-2"),
|
||||
() => qtMock.fireShortcut("karousel-focus-right"),
|
||||
);
|
||||
Assert.grid(config, screen, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.grid(config, tilingArea, 300, [[client1], [client2], [client3]], false);
|
||||
Assert.equal(client1.frameGeometry.left, tilingArea.left);
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ tests.register("Maximization", 100, () => {
|
||||
Assert.assert(clientManager.hasClient(kwinClient));
|
||||
});
|
||||
|
||||
const columnLeftX = screen.width/2 - 300/2;
|
||||
const columnLeftX = tilingArea.left + tilingArea.width/2 - 300/2;
|
||||
const columnTopY = tilingArea.top;
|
||||
const columnHeight = tilingArea.height;
|
||||
Assert.rect(kwinClient.frameGeometry, columnLeftX, columnTopY, 300, columnHeight);
|
||||
@@ -66,7 +66,7 @@ tests.register("Re-maximize disabled", 100, () => {
|
||||
});
|
||||
|
||||
const columnsWidth = 300 + 400 + config.gapsInnerHorizontal;
|
||||
const column1LeftX = screen.width/2 - columnsWidth/2;
|
||||
const column1LeftX = tilingArea.left + tilingArea.width/2 - columnsWidth/2;
|
||||
const column2LeftX = column1LeftX + 300 + config.gapsInnerHorizontal;
|
||||
const columnTopY = tilingArea.top;
|
||||
const columnHeight = tilingArea.height;
|
||||
@@ -111,7 +111,7 @@ tests.register("Re-maximize enabled", 100, () => {
|
||||
});
|
||||
|
||||
const columnsWidth = 300 + 400 + config.gapsInnerHorizontal;
|
||||
const column1LeftX = screen.width/2 - columnsWidth/2;
|
||||
const column1LeftX = tilingArea.left + tilingArea.width/2 - columnsWidth/2;
|
||||
const column2LeftX = column1LeftX + 300 + config.gapsInnerHorizontal;
|
||||
const columnTopY = tilingArea.top;
|
||||
const columnHeight = tilingArea.height;
|
||||
@@ -143,3 +143,72 @@ tests.register("Re-maximize enabled", 100, () => {
|
||||
Assert.rect(client1.frameGeometry, column1LeftX, columnTopY, 300, columnHeight);
|
||||
Assert.equalRects(client2.frameGeometry, screen);
|
||||
});
|
||||
|
||||
tests.register("Start full-screen", 100, () => {
|
||||
const config = getDefaultConfig();
|
||||
config.reMaximize = true;
|
||||
const { qtMock, workspaceMock, world } = init(config);
|
||||
|
||||
const [windowedClient] = workspaceMock.createClientsWithWidths(300);
|
||||
const fullScreenClient = new MockKwinClient(new MockQmlRect(0, 0, 400, 200));
|
||||
fullScreenClient.resourceClass = "full-screen-app";
|
||||
fullScreenClient.fullScreen = true;
|
||||
workspaceMock.createWindows(fullScreenClient);
|
||||
|
||||
world.do((clientManager, desktopManager) => {
|
||||
Assert.assert(clientManager.hasClient(windowedClient));
|
||||
Assert.assert(clientManager.hasClient(fullScreenClient));
|
||||
});
|
||||
|
||||
Assert.centered(config, tilingArea, windowedClient);
|
||||
Assert.equalRects(fullScreenClient.frameGeometry, screen);
|
||||
Assert.equal(Workspace.activeWindow, fullScreenClient);
|
||||
|
||||
{
|
||||
qtMock.fireShortcut("karousel-focus-left");
|
||||
const opts = { message: "fullScreenClient is not in the grid, so we can't move focus directionally" };
|
||||
Assert.centered(config, tilingArea, windowedClient, opts);
|
||||
Assert.equalRects(fullScreenClient.frameGeometry, screen, opts);
|
||||
Assert.equal(Workspace.activeWindow, fullScreenClient, opts);
|
||||
}
|
||||
|
||||
{
|
||||
qtMock.fireShortcut("karousel-focus-1");
|
||||
const opts = { message: "fullScreenClient is not in grid, so it should stay full-screen" };
|
||||
Assert.centered(config, tilingArea, windowedClient, opts);
|
||||
Assert.equalRects(fullScreenClient.frameGeometry, screen, opts);
|
||||
Assert.equal(Workspace.activeWindow, windowedClient);
|
||||
}
|
||||
});
|
||||
|
||||
tests.register("Start full-screen (force tiling)", 100, () => {
|
||||
const config = getDefaultConfig();
|
||||
config.reMaximize = true;
|
||||
config.windowRules = '[{ "class": "full-screen-app", "tile": true }]';
|
||||
const { qtMock, workspaceMock, world } = init(config);
|
||||
|
||||
const column1Width = 300;
|
||||
const [windowedClient] = workspaceMock.createClientsWithWidths(column1Width);
|
||||
const fullScreenClient = new MockKwinClient(new MockQmlRect(0, 0, 400, 200));
|
||||
fullScreenClient.resourceClass = "full-screen-app";
|
||||
fullScreenClient.fullScreen = true;
|
||||
workspaceMock.createWindows(fullScreenClient);
|
||||
|
||||
world.do((clientManager, desktopManager) => {
|
||||
Assert.assert(clientManager.hasClient(windowedClient));
|
||||
Assert.assert(clientManager.hasClient(fullScreenClient));
|
||||
});
|
||||
Assert.equalRects(fullScreenClient.frameGeometry, screen);
|
||||
Assert.equal(Workspace.activeWindow, fullScreenClient);
|
||||
|
||||
const column2Width = tilingArea.width;
|
||||
const column1LeftX = tilingArea.left;
|
||||
const column2LeftX = column1LeftX + column1Width + gapH;
|
||||
const columnTopY = tilingArea.top;
|
||||
const columnHeight = tilingArea.height;
|
||||
qtMock.fireShortcut("karousel-focus-left");
|
||||
const opts = { message: "fullScreenClient should be restored from full-screen mode to tiled mode" };
|
||||
Assert.rect(windowedClient.frameGeometry, column1LeftX, columnTopY, column1Width, columnHeight, opts);
|
||||
Assert.rect(fullScreenClient.frameGeometry, column2LeftX, columnTopY, column2Width, columnHeight, opts);
|
||||
Assert.equal(Workspace.activeWindow, windowedClient);
|
||||
});
|
||||
|
||||
@@ -5,35 +5,48 @@ tests.register("Pin", 20, () => {
|
||||
const screenHalfLeft = new MockQmlRect(0, 0, screen.width/2, screen.height);
|
||||
const screenHalfRight = new MockQmlRect(screen.width/2, 0, screen.width/2, screen.height);
|
||||
|
||||
const tilingAreaHalfLeft = new MockQmlRect(
|
||||
tilingArea.x,
|
||||
tilingArea.y,
|
||||
screen.width/2 - config.gapsOuterLeft - config.gapsOuterRight,
|
||||
tilingArea.height,
|
||||
);
|
||||
const tilingAreaHalfRight = new MockQmlRect(
|
||||
screen.width/2 + config.gapsOuterLeft,
|
||||
tilingArea.y,
|
||||
screen.width/2 - config.gapsOuterLeft - config.gapsOuterRight,
|
||||
tilingArea.height,
|
||||
);
|
||||
|
||||
const [pinned, tiled1, tiled2] = workspaceMock.createClients(3);
|
||||
Assert.grid(config, screen, 100, [ [pinned], [tiled1], [tiled2] ], true);
|
||||
Assert.grid(config, tilingArea, 100, [ [pinned], [tiled1], [tiled2] ], true);
|
||||
|
||||
pinned.pin(screenHalfLeft);
|
||||
Assert.equalRects(pinned.frameGeometry, screenHalfLeft);
|
||||
Assert.grid(config, screenHalfRight, 100, [ [tiled1], [tiled2] ], true);
|
||||
Assert.grid(config, tilingAreaHalfRight, 100, [ [tiled1], [tiled2] ], true);
|
||||
|
||||
pinned.pin(screenHalfRight);
|
||||
Assert.equalRects(pinned.frameGeometry, screenHalfRight);
|
||||
Assert.grid(config, screenHalfLeft, 100, [ [tiled1], [tiled2] ], true);
|
||||
Assert.grid(config, tilingAreaHalfLeft, 100, [ [tiled1], [tiled2] ], true);
|
||||
|
||||
pinned.unpin();
|
||||
Assert.equalRects(pinned.frameGeometry, screenHalfRight);
|
||||
Assert.grid(config, screen, 100, [ [tiled1], [tiled2] ], true);
|
||||
Assert.grid(config, tilingArea, 100, [ [tiled1], [tiled2] ], true);
|
||||
|
||||
pinned.pin(screenHalfRight);
|
||||
Assert.equalRects(pinned.frameGeometry, screenHalfRight);
|
||||
Assert.grid(config, screenHalfLeft, 100, [ [tiled1], [tiled2] ], true);
|
||||
Assert.grid(config, tilingAreaHalfLeft, 100, [ [tiled1], [tiled2] ], true);
|
||||
|
||||
pinned.minimized = true;
|
||||
Assert.grid(config, screen, 100, [ [tiled1], [tiled2] ], true);
|
||||
Assert.grid(config, tilingArea, 100, [ [tiled1], [tiled2] ], true);
|
||||
|
||||
pinned.minimized = false;
|
||||
Assert.equalRects(pinned.frameGeometry, screenHalfRight);
|
||||
Assert.grid(config, screenHalfLeft, 100, [ [tiled1], [tiled2] ], true);
|
||||
Assert.grid(config, tilingAreaHalfLeft, 100, [ [tiled1], [tiled2] ], true);
|
||||
|
||||
workspaceMock.activeWindow = pinned;
|
||||
qtMock.fireShortcut("karousel-window-toggle-floating");
|
||||
Assert.assert(pinned.tile === null);
|
||||
pinned.frameGeometry = new MockQmlRect(10, 20, 100, 200); // This is needed because the window's preferredWidth can change when pinning, because frameGeometryChanged can fire before tileChanged. TODO: Ensure pinned window keeps its preferredWidth.
|
||||
Assert.grid(config, screen, 100, [ [tiled1], [tiled2], [pinned] ], true);
|
||||
Assert.grid(config, tilingArea, 100, [ [tiled1], [tiled2], [pinned] ], true);
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ tests.register("Preset Widths default", 1, () => {
|
||||
|
||||
function getRect(columnWidth: number) {
|
||||
return new MockQmlRect(
|
||||
(screen.width - columnWidth) / 2,
|
||||
tilingArea.left + (tilingArea.width - columnWidth) / 2,
|
||||
tilingArea.top,
|
||||
columnWidth,
|
||||
tilingArea.height,
|
||||
@@ -43,7 +43,7 @@ tests.register("Preset Widths custom", 1, () => {
|
||||
|
||||
function getRect(columnWidth: number) {
|
||||
return new MockQmlRect(
|
||||
(screen.width - columnWidth) / 2,
|
||||
tilingArea.left + (tilingArea.width - columnWidth) / 2,
|
||||
tilingArea.top,
|
||||
columnWidth,
|
||||
tilingArea.height,
|
||||
|
||||
30
src/tests/flows/stacked.ts
Normal file
30
src/tests/flows/stacked.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
tests.register("Stacked", 5, () => {
|
||||
const config = getDefaultConfig();
|
||||
const { qtMock, workspaceMock, world } = init(config);
|
||||
|
||||
const [leftTop, leftBottom, rightTop, rightBottom] = workspaceMock.createClients(4);
|
||||
const grid = [[leftTop, leftBottom], [rightTop, rightBottom]];
|
||||
workspaceMock.activeWindow = rightBottom;
|
||||
qtMock.fireShortcut("karousel-window-move-left");
|
||||
workspaceMock.activeWindow = leftBottom;
|
||||
qtMock.fireShortcut("karousel-window-move-left");
|
||||
Assert.grid(config, tilingArea, 100, grid, true);
|
||||
|
||||
qtMock.fireShortcut("karousel-column-toggle-stacked");
|
||||
Assert.grid(config, tilingArea, 100, grid, true, [0]);
|
||||
|
||||
qtMock.fireShortcut("karousel-focus-up");
|
||||
Assert.grid(config, tilingArea, 100, grid, true, [0]);
|
||||
|
||||
qtMock.fireShortcut("karousel-focus-down");
|
||||
Assert.grid(config, tilingArea, 100, grid, true, [0]);
|
||||
|
||||
qtMock.fireShortcut("karousel-window-move-up");
|
||||
Assert.grid(config, tilingArea, 100, [[leftBottom, leftTop], [rightTop, rightBottom]], true, [0]);
|
||||
|
||||
qtMock.fireShortcut("karousel-window-move-down");
|
||||
Assert.grid(config, tilingArea, 100, grid, true, [0]);
|
||||
|
||||
qtMock.fireShortcut("karousel-column-toggle-stacked");
|
||||
Assert.grid(config, tilingArea, 100, grid, true);
|
||||
});
|
||||
@@ -1,4 +1,7 @@
|
||||
tests.register("WindowRuleEnforcer", 1, () => {
|
||||
screen = new MockQmlRect(0, 0, 800, 600);
|
||||
Workspace = new MockWorkspace();
|
||||
|
||||
const testCases = [
|
||||
{ tiledByDefault: true, resourceClass: "unknown", caption: "anything", shouldTile: true },
|
||||
{ tiledByDefault: false, resourceClass: "unknown", caption: "anything", shouldTile: false },
|
||||
@@ -25,6 +28,7 @@ tests.register("WindowRuleEnforcer", 1, () => {
|
||||
return {
|
||||
normalWindow: normalWindow,
|
||||
transient: false,
|
||||
clientGeometry: new MockQmlRect(0, 0, 200, 200),
|
||||
managed: true,
|
||||
pid: 100,
|
||||
moveable: true,
|
||||
|
||||
@@ -4,6 +4,7 @@ tests.register("Clients.canTileEver", 1, () => {
|
||||
{ clientProperties: { resourceClass: "app", caption: "Title", moveable: false }, tileable: false },
|
||||
{ clientProperties: { resourceClass: "app", caption: "Caption", resizeable: false }, tileable: false },
|
||||
{ clientProperties: { resourceClass: "app", caption: "Caption", normalWindow: false, popupWindow: true }, tileable: false },
|
||||
{ clientProperties: { resourceClass: "app", caption: "Caption", moveable: false, resizeable: false, fullScreen: true }, tileable: true },
|
||||
{ clientProperties: { resourceClass: "ksmserver-logout-greeter", caption: "Caption" }, tileable: false },
|
||||
{ clientProperties: { resourceClass: "xwaylandvideobridge", caption: "" }, tileable: false },
|
||||
];
|
||||
@@ -24,6 +25,7 @@ tests.register("Clients.canTileEver", 1, () => {
|
||||
pid: 100,
|
||||
moveable: true,
|
||||
resizeable: true,
|
||||
fullScreen: false,
|
||||
popupWindow: false,
|
||||
minimized: false,
|
||||
desktops: [1],
|
||||
|
||||
@@ -125,39 +125,51 @@ namespace Assert {
|
||||
|
||||
export function grid(
|
||||
config: Config,
|
||||
screen: QmlRect,
|
||||
tilingArea: QmlRect,
|
||||
columnWidth: number,
|
||||
grid: KwinClient[][],
|
||||
centered: boolean,
|
||||
stackedColumns: number[] = [],
|
||||
{ message, skip=0 }: Options = {},
|
||||
) {
|
||||
const nColumns = grid.length;
|
||||
const columnHeight = screen.height - config.gapsOuterTop - config.gapsOuterBottom;
|
||||
const columnsWidth = nColumns * columnWidth + (nColumns-1) * config.gapsInnerHorizontal;
|
||||
const startX = centered ?
|
||||
screen.x + (screen.width - columnsWidth) / 2 :
|
||||
tilingArea.x + (tilingArea.width - columnsWidth) / 2 :
|
||||
grid[0][0].frameGeometry.x;
|
||||
|
||||
// assumes uniformly sized windows within columns of uniform width
|
||||
function getRectInGrid(column: number, window: number, nColumns: number, nWindows: number) {
|
||||
const windowHeight = (columnHeight - config.gapsInnerVertical * (nWindows-1)) / nWindows;
|
||||
const windowHeight = (tilingArea.height - config.gapsInnerVertical * (nWindows-1)) / nWindows;
|
||||
return new MockQmlRect(
|
||||
startX + column * (columnWidth + config.gapsInnerHorizontal),
|
||||
screen.y + config.gapsOuterTop + (windowHeight + config.gapsInnerVertical) * window,
|
||||
tilingArea.y + (windowHeight + config.gapsInnerVertical) * window,
|
||||
columnWidth,
|
||||
(columnHeight - config.gapsInnerVertical * (nWindows-1)) / nWindows,
|
||||
(tilingArea.height - config.gapsInnerVertical * (nWindows-1)) / nWindows,
|
||||
);
|
||||
}
|
||||
|
||||
function getRectInGridStacked(column: number, window: number, nColumns: number, nWindows: number) {
|
||||
const columnX = startX + column * (columnWidth + config.gapsInnerHorizontal);
|
||||
return new MockQmlRect(
|
||||
columnX + window * config.stackOffsetX,
|
||||
tilingArea.y + window * config.stackOffsetY,
|
||||
columnWidth - (nWindows-1) * config.stackOffsetX,
|
||||
tilingArea.height - (nWindows-1) * config.stackOffsetY,
|
||||
);
|
||||
}
|
||||
|
||||
for (let iColumn = 0; iColumn < nColumns; iColumn++) {
|
||||
const column = grid[iColumn];
|
||||
const stacked = stackedColumns.includes(iColumn);
|
||||
const getRect = stacked ? getRectInGridStacked : getRectInGrid;
|
||||
const nWindows = column.length;
|
||||
for (let iWindow = 0; iWindow < nWindows; iWindow++) {
|
||||
const window = column[iWindow];
|
||||
equalRects(
|
||||
window.frameGeometry,
|
||||
getRectInGrid(iColumn, iWindow, nColumns, nWindows),
|
||||
{ message: appendMessage(`window ${iWindow}, column ${iColumn}`, message), skip: skip+1 },
|
||||
getRect(iColumn, iWindow, nColumns, nWindows),
|
||||
{ message: appendMessage(`column ${iColumn}, window ${iWindow}`, message), skip: skip+1 },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -165,16 +177,17 @@ namespace Assert {
|
||||
|
||||
export function centered(
|
||||
config: Config,
|
||||
screen: QmlRect,
|
||||
tilingArea: QmlRect,
|
||||
client:KwinClient,
|
||||
{ message, skip=0 }: Options = {},
|
||||
) {
|
||||
grid(
|
||||
config,
|
||||
screen,
|
||||
tilingArea,
|
||||
client.frameGeometry.width,
|
||||
[[client]],
|
||||
true,
|
||||
[],
|
||||
{ message: appendMessage("Window not centered", message), skip: skip+1 },
|
||||
);
|
||||
}
|
||||
@@ -219,4 +232,26 @@ namespace Assert {
|
||||
}
|
||||
equal(columns[columns.length-1].frameGeometry.right, tilingArea.right, options);
|
||||
}
|
||||
|
||||
export function tiledClient(
|
||||
clientManager: ClientManager,
|
||||
client: KwinClient,
|
||||
{ message, skip=0 }: Options = {},
|
||||
) {
|
||||
assert(
|
||||
clientManager.findTiledWindow(client) !== null,
|
||||
{ message: message, skip: skip+1 },
|
||||
);
|
||||
}
|
||||
|
||||
export function notTiledClient(
|
||||
clientManager: ClientManager,
|
||||
client: KwinClient,
|
||||
{ message, skip=0 }: Options = {},
|
||||
) {
|
||||
assert(
|
||||
clientManager.findTiledWindow(client) === null,
|
||||
{ message: message, skip: skip+1 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ function init(config: Config) {
|
||||
|
||||
function getGridBounds(clientLeft: KwinClient, clientRight: KwinClient) {
|
||||
const columnsWidth = clientRight.frameGeometry.right - clientLeft.frameGeometry.left;
|
||||
const left = Math.floor((screen.width - columnsWidth) / 2);
|
||||
const left = tilingArea.left + Math.floor((tilingArea.width - columnsWidth) / 2);
|
||||
const right = left + columnsWidth;
|
||||
return { left, right };
|
||||
}
|
||||
@@ -44,3 +44,10 @@ function getWindowHeight(windowsInColumn: number) {
|
||||
const totalGaps = (windowsInColumn-1) * gapV;
|
||||
return Math.round((tilingArea.height - totalGaps) / windowsInColumn);
|
||||
}
|
||||
|
||||
function getClientManager(world: World): ClientManager {
|
||||
// don't do this outside of tests
|
||||
let clientManager;
|
||||
world.do((cm, dm) => clientManager = cm);
|
||||
return clientManager!;
|
||||
}
|
||||
|
||||
@@ -3,18 +3,15 @@ class MockKwinClient {
|
||||
|
||||
private static readonly borderThickness = 10;
|
||||
|
||||
public readonly shadeable: boolean = false;
|
||||
public caption = "App";
|
||||
public minSize: Readonly<QmlSize> = new MockQmlSize(0, 0);
|
||||
public readonly transient: boolean;
|
||||
public readonly move: boolean = false;
|
||||
public move: boolean = false;
|
||||
public resize: boolean = false;
|
||||
public readonly moveable: boolean = true;
|
||||
public readonly resizeable: boolean = true;
|
||||
public readonly fullScreenable: boolean = true;
|
||||
public readonly maximizable: boolean = true;
|
||||
public readonly output: Output = { __brand: "Output" };
|
||||
public readonly resourceClass = "app";
|
||||
public resourceClass = "app";
|
||||
public readonly dock: boolean = false;
|
||||
public readonly normalWindow: boolean = true;
|
||||
public readonly managed: boolean = true;
|
||||
@@ -28,7 +25,6 @@ class MockKwinClient {
|
||||
public skipSwitcher: boolean = false;
|
||||
public keepAbove: boolean = false;
|
||||
public keepBelow: boolean = false;
|
||||
public shade: boolean = false;
|
||||
private _minimized: boolean = false;
|
||||
private _desktops: KwinDesktop[] = [];
|
||||
private _tile: Tile|null = null;
|
||||
@@ -96,6 +92,14 @@ class MockKwinClient {
|
||||
}
|
||||
}
|
||||
|
||||
public get moveable() {
|
||||
return !this._fullScreen;
|
||||
}
|
||||
|
||||
public get resizeable() {
|
||||
return !this._fullScreen;
|
||||
}
|
||||
|
||||
public get fullScreen() {
|
||||
return this._fullScreen;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,28 @@ class MockWorkspace {
|
||||
};
|
||||
}
|
||||
|
||||
public moveWindow(window: MockKwinClient, ...deltas: QmlPoint[]) {
|
||||
const frame = window.getFrameGeometryCopy();
|
||||
window.move = true;
|
||||
window.interactiveMoveResizeStarted.fire();
|
||||
|
||||
for (const delta of deltas) {
|
||||
if (delta.x !== 0) {
|
||||
frame.x += delta.x;
|
||||
}
|
||||
if (delta.y !== 0) {
|
||||
frame.y += delta.y;
|
||||
}
|
||||
runOneOf(
|
||||
() => window.frameGeometry.set(frame),
|
||||
() => window.frameGeometry = frame,
|
||||
);
|
||||
}
|
||||
|
||||
window.move = false;
|
||||
window.interactiveMoveResizeFinished.fire();
|
||||
}
|
||||
|
||||
public resizeWindow(window: MockKwinClient, edgeResize: boolean, leftEdge: boolean, topEdge: boolean, ...deltas: QmlSize[]) {
|
||||
const frame = window.getFrameGeometryCopy();
|
||||
if (edgeResize) {
|
||||
@@ -94,7 +116,7 @@ class MockWorkspace {
|
||||
runOneOf(
|
||||
() => window.frameGeometry.set(frame),
|
||||
() => window.frameGeometry = frame,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
window.resize = false;
|
||||
|
||||
Reference in New Issue
Block a user