From 6c698c9c8285ed173518cc55e029252fb56d7ae7 Mon Sep 17 00:00:00 2001 From: Peter Fajdiga Date: Sun, 22 Feb 2026 00:05:21 +0100 Subject: [PATCH] Fix frameGeometry, clientGeometry, minSize problems (issue 152) --- src/lib/layout/Column.ts | 2 +- src/lib/layout/Window.ts | 4 ++-- src/lib/utils/functions.ts | 18 ++++++++++++++++++ src/lib/utils/math.ts | 17 +++++++++++++++++ src/lib/world/ClientWrapper.ts | 12 ++++++------ src/lib/world/Clients.ts | 4 ++-- src/lib/world/PinManager.ts | 2 +- src/lib/world/World.ts | 2 +- src/lib/world/clientState/Floating.ts | 6 +++--- src/lib/world/clientState/Tiled.ts | 11 ++++++++--- 10 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/lib/layout/Column.ts b/src/lib/layout/Column.ts index 5cf1fde..4081749 100644 --- a/src/lib/layout/Column.ts +++ b/src/lib/layout/Column.ts @@ -79,7 +79,7 @@ class Column { public getMinWidth() { let maxMinWidth = Column.minWidth; for (const window of this.windows.iterator()) { - const minWidth = window.client.kwinClient.minSize.width; + const minWidth = window.client.kwinClient.minSize.width.ceil(); if (minWidth > maxMinWidth) { maxMinWidth = minWidth; } diff --git a/src/lib/layout/Window.ts b/src/lib/layout/Window.ts index f27bdf9..b1c262d 100644 --- a/src/lib/layout/Window.ts +++ b/src/lib/layout/Window.ts @@ -7,7 +7,7 @@ class Window { constructor(client: ClientWrapper, column: Column) { this.client = client; - this.height = client.kwinClient.frameGeometry.height; + this.height = client.kwinClient.frameGeometry.height.round(); let maximizedMode = this.client.getMaximizedMode(); if (maximizedMode === undefined) { @@ -123,7 +123,7 @@ class Window { public onFrameGeometryChanged() { const newGeometry = this.client.kwinClient.frameGeometry; - this.column.setWidth(newGeometry.width, true); + this.column.setWidth(newGeometry.width.round(), true); this.column.grid.desktop.onLayoutChanged(); } diff --git a/src/lib/utils/functions.ts b/src/lib/utils/functions.ts index 6e67820..d1db205 100644 --- a/src/lib/utils/functions.ts +++ b/src/lib/utils/functions.ts @@ -1,3 +1,21 @@ +interface Number { + round(this: number): number; + floor(this: number): number; + ceil(this: number): number; +} + +Number.prototype.round = function() { + return Math.round(this); +}; + +Number.prototype.floor = function() { + return Math.floor(this); +}; + +Number.prototype.ceil = function() { + return Math.ceil(this); +}; + interface Function { partial( this: (...args: [...H, ...T]) => R, diff --git a/src/lib/utils/math.ts b/src/lib/utils/math.ts index 18d0366..0745731 100644 --- a/src/lib/utils/math.ts +++ b/src/lib/utils/math.ts @@ -38,3 +38,20 @@ function rectContainsPoint(rect: QmlRect, point: QmlPoint) { rect.y <= point.y && rectBottom(rect) >= point.y; } + +function roundQtRect(rect: QmlRect) { + return Qt.rect( + rect.x.round(), + rect.y.round(), + rect.width.round(), + rect.height.round(), + ); +} + +function rectRightRound(rect: QmlRect) { + return rect.x.round() + rect.width.round(); +} + +function rectBottomRound(rect: QmlRect) { + return rect.y.round() + rect.height.round(); +} diff --git a/src/lib/world/ClientWrapper.ts b/src/lib/world/ClientWrapper.ts index e6767e5..4929eb4 100644 --- a/src/lib/world/ClientWrapper.ts +++ b/src/lib/world/ClientWrapper.ts @@ -21,7 +21,7 @@ class ClientWrapper { } this.signalManager = ClientWrapper.initSignalManager(this); this.rulesSignalManager = rulesSignalManager; - this.preferredWidth = kwinClient.frameGeometry.width; + this.preferredWidth = kwinClient.frameGeometry.width.round(); this.manipulatingGeometry = new Doer(); this.lastPlacement = null; this.stateManager = new ClientState.Manager(constructInitialState(this)); @@ -49,10 +49,10 @@ class ClientWrapper { if (Clients.isOnOneOfVirtualDesktops(this.kwinClient, kwinDesktops)) { const frame = this.kwinClient.frameGeometry; this.kwinClient.frameGeometry = Qt.rect( - frame.x + dx, - frame.y + dy, - frame.width, - frame.height, + frame.x.round() + dx, + frame.y.round() + dy, + frame.width.round(), + frame.height.round(), ); } @@ -142,7 +142,7 @@ class ClientWrapper { if (!Clients.isOnVirtualDesktop(this.kwinClient, Workspace.currentDesktop)) { return; } - const frame = this.kwinClient.frameGeometry; + const frame = roundQtRect(this.kwinClient.frameGeometry); if (frame.x < screenSize.x) { frame.x = screenSize.x; } else if (rectRight(frame) > rectRight(screenSize)) { diff --git a/src/lib/world/Clients.ts b/src/lib/world/Clients.ts index 230a029..6e950a0 100644 --- a/src/lib/world/Clients.ts +++ b/src/lib/world/Clients.ts @@ -47,8 +47,8 @@ namespace Clients { export function isFullScreenGeometry(kwinClient: KwinClient) { const fullScreenArea = Workspace.clientArea(ClientAreaOption.FullScreenArea, kwinClient.output, getKwinDesktopApprox(kwinClient)); - return kwinClient.clientGeometry.width >= fullScreenArea.width && - kwinClient.clientGeometry.height >= fullScreenArea.height; + return kwinClient.clientGeometry.width.round() >= fullScreenArea.width && + kwinClient.clientGeometry.height.round() >= fullScreenArea.height; } export function isOnVirtualDesktop(kwinClient: KwinClient, kwinDesktop: KwinDesktop) { diff --git a/src/lib/world/PinManager.ts b/src/lib/world/PinManager.ts index 0c4cf20..8d94a82 100644 --- a/src/lib/world/PinManager.ts +++ b/src/lib/world/PinManager.ts @@ -23,7 +23,7 @@ class PinManager { const newLots: PinManager.Lot[] = []; for (const lot of lots) { - lot.split(newLots, client.frameGeometry); + lot.split(newLots, roundQtRect(client.frameGeometry)); } lots = newLots; } diff --git a/src/lib/world/World.ts b/src/lib/world/World.ts index 6842279..3565e67 100644 --- a/src/lib/world/World.ts +++ b/src/lib/world/World.ts @@ -111,7 +111,7 @@ class World { if (tiledWindow === null) { return; } - const cursorAlreadyInFocus = rectContainsPoint(Workspace.activeWindow.frameGeometry, Workspace.cursorPos); + const cursorAlreadyInFocus = rectContainsPoint(roundQtRect(Workspace.activeWindow.frameGeometry), Workspace.cursorPos); if (cursorAlreadyInFocus) { return; } diff --git a/src/lib/world/clientState/Floating.ts b/src/lib/world/clientState/Floating.ts index 6eebc6f..a1d6c4d 100644 --- a/src/lib/world/clientState/Floating.ts +++ b/src/lib/world/clientState/Floating.ts @@ -30,10 +30,10 @@ namespace ClientState { const clientRect = client.kwinClient.frameGeometry; const width = client.preferredWidth; client.place( - clientRect.x, - clientRect.y, + clientRect.x.round(), + clientRect.y.round(), width, - Math.min(clientRect.height, Math.round(placementArea.height / 2)), + Math.min(clientRect.height.round(), Math.round(placementArea.height / 2)), ); } diff --git a/src/lib/world/clientState/Tiled.ts b/src/lib/world/clientState/Tiled.ts index fb3daa7..040cf35 100644 --- a/src/lib/world/clientState/Tiled.ts +++ b/src/lib/world/clientState/Tiled.ts @@ -123,7 +123,12 @@ namespace ClientState { return; } - const newGeometry = client.kwinClient.frameGeometry; + const newGeometry = roundQtRect(client.kwinClient.frameGeometry); + if (rectEquals(oldGeometry, newGeometry)) { + // no real changes, nothing to do + return; + } + const oldCenterX = oldGeometry.x + oldGeometry.width/2; const oldCenterY = oldGeometry.y + oldGeometry.height/2; const newCenterX = newGeometry.x + newGeometry.width/2; @@ -193,9 +198,9 @@ namespace ClientState { private static getResizeNeighborColumn(window: Window) { const kwinClient = window.client.kwinClient; const column = window.column; - if (Workspace.cursorPos.x > rectRight(kwinClient.clientGeometry)) { + if (Workspace.cursorPos.x > rectRightRound(kwinClient.clientGeometry)) { return column.grid.getRightColumn(column); - } else if (Workspace.cursorPos.x < kwinClient.clientGeometry.x) { + } else if (Workspace.cursorPos.x < kwinClient.clientGeometry.x.round()) { return column.grid.getLeftColumn(column); } else { return null;