Add kwin patches

master
Jacopo De Simoi 7 months ago
parent 4a2c33f517
commit 0b97969044
  1. 45
      kde-plasma/kwin/0001-Implement-moveRelative.patch
  2. 55
      kde-plasma/kwin/0002-Make-output-yield-tiling-constants.patch
  3. 51
      kde-plasma/kwin/0003-Adjust-screen-area-for-tiling-gaps.patch
  4. 86
      kde-plasma/kwin/0004-Add-user-actions-for-quick-third-tiling.patch
  5. 25
      kde-plasma/kwin/0005-Force-maximized-windows-to-cast-a-shadow.patch
  6. 134
      kde-plasma/kwin/0006-Add-Quicktiles-at-thirds.patch
  7. 33
      kde-plasma/kwin/0007-Add-padding-to-qulcktiles.patch
  8. 46
      kde-plasma/kwin/0008-Use-geometry-relative-to-the-cutout.patch
  9. 35
      kde-plasma/kwin/0009-Make-vertical-gap-twice-as-big-between-windows.patch
  10. 200
      kde-plasma/kwin/0010-Implement-core-panning-methods.patch
  11. 68
      kde-plasma/kwin/0011-Remove-the-logic-for-tiles-on-different-screens.patch
  12. 290
      kde-plasma/kwin/0012-Implement-Incremental-wide-placement.patch
  13. 44
      kde-plasma/kwin/0013-Remove-wrap-around-when-switching-focus-horizontally.patch
  14. 28
      kde-plasma/kwin/0014-Allow-windows-outside-left-right-screen-boundary.patch
  15. 42
      kde-plasma/kwin/0015-Adjust-output-detection-for-hyper-wide.patch
  16. 196
      kde-plasma/kwin/0016-Introduce-the-Pan-helper-effect.patch
  17. 66
      kde-plasma/kwin/0017-Remove-boundary-checking-in-the-position-effect.patch
  18. 40
      kde-plasma/kwin/0018-Add-paint_screen-flag-to-prevent-artifacts.patch
  19. 33
      kde-plasma/kwin/0019-Allow-loading-the-keymap-from-a-file.patch
  20. 25
      kde-plasma/kwin/0020-temporary-build-fix.patch

@ -0,0 +1,45 @@
From 605ebb66085a7f004f7ed6f5851a416d56a790e8 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Wed, 18 Dec 2024 11:59:09 -0500
Subject: [PATCH 01/20] Implement moveRelative
---
src/window.cpp | 5 +++++
src/window.h | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/src/window.cpp b/src/window.cpp
index d70e9bccfe..64ad8d977c 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -3499,6 +3499,11 @@ void Window::setMoveResizeGeometry(const QRectF &geo)
setMoveResizeOutput(workspace()->outputAt(geo.center()));
}
+void Window::moveRelative(const QPointF &point)
+{
+ move(m_frameGeometry.topLeft() + point);
+}
+
Output *Window::moveResizeOutput() const
{
return m_moveResizeOutput;
diff --git a/src/window.h b/src/window.h
index 8e15cf8079..2f935e4c19 100644
--- a/src/window.h
+++ b/src/window.h
@@ -718,6 +718,11 @@ public:
*/
void move(const QPointF &topLeft);
+ /**
+ * Moves the window so that the new topLeft corner of the frame is moved by @p point.
+ */
+ void moveRelative(const QPointF &point);
+
/**
* Resizes the window to have a new @p size but stay with the top-left corner in the same position.
*/
--
2.49.1

@ -0,0 +1,55 @@
From 56f9b3e2d262e2b4deae68fd62992aada45d2a2e Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Mon, 23 Jun 2025 09:40:54 +0200
Subject: [PATCH 02/20] Make output yield tiling constants
in order to have pixel-perfect placement, the tile gap size and border
size must depend on the output size and scaling.
---
src/core/output.cpp | 10 ++++++++++
src/core/output.h | 8 ++++++++
2 files changed, 18 insertions(+)
diff --git a/src/core/output.cpp b/src/core/output.cpp
index d884b68fe1..9763561e2c 100644
--- a/src/core/output.cpp
+++ b/src/core/output.cpp
@@ -451,6 +451,16 @@ qreal Output::scale() const
return m_state.scale;
}
+qreal Output::defaultPadding() const
+{
+ return 4. / scale();
+}
+
+qreal Output::defaultBorder() const
+{
+ return 1. / scale();
+}
+
QRect Output::geometry() const
{
return QRect(m_state.position, pixelSize() / scale());
diff --git a/src/core/output.h b/src/core/output.h
index 0122bc34ed..15f03f5630 100644
--- a/src/core/output.h
+++ b/src/core/output.h
@@ -251,6 +251,14 @@ public:
*/
bool isEnabled() const;
+ /**
+ * Returns default-padding and cutout size of this output in device
+ independent pixels.
+ */
+
+ qreal defaultPadding() const;
+ qreal defaultBorder() const;
+
/**
* Returns geometry of this output in device independent pixels.
*/
--
2.49.1

@ -0,0 +1,51 @@
From 23374adae557911d1e403c560c1f61aeb0004e44 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Wed, 18 Dec 2024 15:11:22 -0500
Subject: [PATCH 03/20] Adjust screen area for tiling + gaps
---
src/workspace.cpp | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/workspace.cpp b/src/workspace.cpp
index 0283608c89..bd64f4f248 100644
--- a/src/workspace.cpp
+++ b/src/workspace.cpp
@@ -2271,22 +2271,30 @@ void Workspace::rearrange()
*/
QRectF Workspace::clientArea(clientAreaOption opt, const Output *output, const VirtualDesktop *desktop) const
{
+ qreal border = output->defaultBorder() + output->defaultPadding();
+
switch (opt) {
case MaximizeArea:
- case PlacementArea:
+ case PlacementArea: {
if (auto desktopIt = m_screenAreas.constFind(desktop); desktopIt != m_screenAreas.constEnd()) {
if (auto outputIt = desktopIt->constFind(output); outputIt != desktopIt->constEnd()) {
- return *outputIt;
+ auto screenArea = *outputIt;
+
+ return screenArea - QMarginsF(border, border, border, border);
}
}
return output->geometryF();
+ }
case MaximizeFullArea:
case FullScreenArea:
case MovementArea:
case ScreenArea:
return output->geometryF();
- case WorkArea:
- return m_workAreas.value(desktop, m_geometry);
+ case WorkArea: {
+ auto workArea = m_workAreas.value(desktop, m_geometry);
+
+ return workArea - QMarginsF(border, border, border, border);
+ }
case FullArea:
return m_geometry;
default:
--
2.49.1

@ -0,0 +1,86 @@
From 3b9c72ad9b8b745a823d8a8fd7f11d57ef94b0fb Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Sat, 4 Jan 2025 22:57:57 -0500
Subject: [PATCH 04/20] Add user actions for quick third-tiling
---
src/effect/globals.h | 7 +++++++
src/scripting/workspace_wrapper.cpp | 5 +++++
src/scripting/workspace_wrapper.h | 5 +++++
src/useractions.cpp | 10 ++++++++++
4 files changed, 27 insertions(+)
diff --git a/src/effect/globals.h b/src/effect/globals.h
index b602c07256..819a097580 100644
--- a/src/effect/globals.h
+++ b/src/effect/globals.h
@@ -198,6 +198,13 @@ enum class QuickTileFlag {
Custom = 1 << 4,
Horizontal = Left | Right,
Vertical = Top | Bottom,
+ Third1 = 1 << 5,
+ Third2 = 1 << 6,
+ Third3 = 1 << 7,
+ Third12 = Third1 | Third2,
+ Third23 = Third2 | Third3,
+ Thirds = Third1 | Third2 | Third3,
+ HorizontalComplete = Horizontal | Thirds,
};
Q_ENUM_NS(QuickTileFlag)
Q_DECLARE_FLAGS(QuickTileMode, QuickTileFlag)
diff --git a/src/scripting/workspace_wrapper.cpp b/src/scripting/workspace_wrapper.cpp
index d1e504b3ac..c9b34876ba 100644
--- a/src/scripting/workspace_wrapper.cpp
+++ b/src/scripting/workspace_wrapper.cpp
@@ -191,6 +191,11 @@ SLOTWRAPPER(slotSwitchToBelowScreen)
}
SLOTWRAPPER(slotWindowQuickTileLeft, QuickTileFlag::Left)
+SLOTWRAPPER(slotWindowQuickTileThird1, QuickTileFlag::Third1)
+SLOTWRAPPER(slotWindowQuickTileThird12, QuickTileFlag::Third12)
+SLOTWRAPPER(slotWindowQuickTileThird2, QuickTileFlag::Third2)
+SLOTWRAPPER(slotWindowQuickTileThird23, QuickTileFlag::Third23)
+SLOTWRAPPER(slotWindowQuickTileThird3, QuickTileFlag::Third3)
SLOTWRAPPER(slotWindowQuickTileRight, QuickTileFlag::Right)
SLOTWRAPPER(slotWindowQuickTileTop, QuickTileFlag::Top)
SLOTWRAPPER(slotWindowQuickTileBottom, QuickTileFlag::Bottom)
diff --git a/src/scripting/workspace_wrapper.h b/src/scripting/workspace_wrapper.h
index c1a7db63e7..352208f9e4 100644
--- a/src/scripting/workspace_wrapper.h
+++ b/src/scripting/workspace_wrapper.h
@@ -357,6 +357,11 @@ public Q_SLOTS:
void slotWindowShrinkVertical();
void slotWindowQuickTileLeft();
void slotWindowQuickTileRight();
+ void slotWindowQuickTileThird1();
+ void slotWindowQuickTileThird12();
+ void slotWindowQuickTileThird2();
+ void slotWindowQuickTileThird23();
+ void slotWindowQuickTileThird3();
void slotWindowQuickTileTop();
void slotWindowQuickTileBottom();
void slotWindowQuickTileTopLeft();
diff --git a/src/useractions.cpp b/src/useractions.cpp
index 7691e5eb03..6e841d96cd 100644
--- a/src/useractions.cpp
+++ b/src/useractions.cpp
@@ -942,6 +942,16 @@ void Workspace::initShortcuts()
Qt::META | Qt::Key_Left, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Left));
initShortcut("Window Quick Tile Right", i18n("Quick Tile Window to the Right"),
Qt::META | Qt::Key_Right, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Right));
+ initShortcut("Window Quick Tile Left Third", i18n("Quick Tile Window to the Left Third"),
+ 0, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Third1));
+ initShortcut("Window Quick Tile Left Two-Thirds", i18n("Quick Tile Window to the Left Two-Thirds"),
+ 0, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Third12));
+ initShortcut("Window Quick Tile Right Two-Thirds", i18n("Quick Tile Window to the Right Two-Thirds"),
+ 0, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Third23));
+ initShortcut("Window Quick Tile Center Third", i18n("Quick Tile Window to the Center Third"),
+ 0, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Third2));
+ initShortcut("Window Quick Tile Right Third", i18n("Quick Tile Window to the Right Third"),
+ 0, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Third3));
initShortcut("Window Quick Tile Top", i18n("Quick Tile Window to the Top"),
Qt::META | Qt::Key_Up, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Top));
initShortcut("Window Quick Tile Bottom", i18n("Quick Tile Window to the Bottom"),
--
2.49.1

@ -0,0 +1,25 @@
From 482eda79d03b7eeb127390bb6d1f91438cc5d053 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Sun, 5 Jan 2025 01:05:09 -0500
Subject: [PATCH 05/20] Force maximized windows to cast a shadow
---
src/window.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/window.cpp b/src/window.cpp
index 64ad8d977c..4eca4627dd 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -289,7 +289,7 @@ SurfaceItem *Window::surfaceItem() const
bool Window::wantsShadowToBeRendered() const
{
- return !isFullScreen() && maximizeMode() != MaximizeFull;
+ return !isFullScreen();
}
bool Window::isClient() const
--
2.49.1

@ -0,0 +1,134 @@
From 4fc4c8b801315a7eb90b8fe8bf7c30b957ec4fcc Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Wed, 1 Oct 2025 20:24:58 -0400
Subject: [PATCH 06/20] Add Quicktiles at thirds
---
src/tiles/quicktile.cpp | 53 +++++++++++++++++++++++++++++++++++++++++
src/tiles/quicktile.h | 18 ++++++++++++++
2 files changed, 71 insertions(+)
diff --git a/src/tiles/quicktile.cpp b/src/tiles/quicktile.cpp
index 8c8dc93952..507df27ed1 100644
--- a/src/tiles/quicktile.cpp
+++ b/src/tiles/quicktile.cpp
@@ -38,6 +38,13 @@ QuickRootTile::QuickRootTile(TileManager *tiling, VirtualDesktop *desktop)
m_leftVerticalTile = createTile(QRectF(0, 0, 0.5, 1), QuickTileFlag::Left);
m_rightVerticalTile = createTile(QRectF(0.5, 0, 0.5, 1), QuickTileFlag::Right);
+
+ m_third1VerticalTile = createTile(QRectF(0, 0, 1. / 3., 1), QuickTileFlag::Third1);
+ m_third12VerticalTile = createTile(QRectF(0, 0, 2. / 3., 1), QuickTileFlag::Third1 | QuickTileFlag::Third2);
+ m_third2VerticalTile = createTile(QRectF(1. / 3., 0, 1. / 3., 1), QuickTileFlag::Third2);
+ m_third23VerticalTile = createTile(QRectF(1. / 3., 0, 2. / 3., 1), QuickTileFlag::Third2 | QuickTileFlag::Third3);
+ m_third3VerticalTile = createTile(QRectF(2. / 3., 0, 1. / 3., 1), QuickTileFlag::Third3);
+
m_topHorizontalTile = createTile(QRectF(0, 0, 1, 0.5), QuickTileFlag::Top);
m_bottomHorizontalTile = createTile(QRectF(0, 0.5, 1, 0.5), QuickTileFlag::Bottom);
@@ -45,6 +52,18 @@ QuickRootTile::QuickRootTile(TileManager *tiling, VirtualDesktop *desktop)
m_topRightTile = createTile(QRectF(0.5, 0, 0.5, 0.5), QuickTileFlag::Top | QuickTileFlag::Right);
m_bottomLeftTile = createTile(QRectF(0, 0.5, 0.5, 0.5), QuickTileFlag::Bottom | QuickTileFlag::Left);
m_bottomRightTile = createTile(QRectF(0.5, 0.5, 0.5, 0.5), QuickTileFlag::Bottom | QuickTileFlag::Right);
+
+ m_topThird1Tile = createTile(QRectF(0, 0, 1. / 3., 0.5), QuickTileFlag::Top | QuickTileFlag::Third1);
+ m_topThird12Tile = createTile(QRectF(0, 0, 2. / 3., 0.5), QuickTileFlag::Top | QuickTileFlag::Third1 | QuickTileFlag::Third2);
+ m_topThird2Tile = createTile(QRectF(1. / 3., 0, 1. / 3., 0.5), QuickTileFlag::Top | QuickTileFlag::Third2);
+ m_topThird23Tile = createTile(QRectF(1. / 3., 0, 2. / 3., 0.5), QuickTileFlag::Top | QuickTileFlag::Third2 | QuickTileFlag::Third3);
+ m_topThird3Tile = createTile(QRectF(2. / 3., 0, 1. / 3., 0.5), QuickTileFlag::Top | QuickTileFlag::Third3);
+
+ m_bottomThird1Tile = createTile(QRectF(0, 0.5, 1. / 3., 0.5), QuickTileFlag::Bottom | QuickTileFlag::Third1);
+ m_bottomThird12Tile = createTile(QRectF(0, 0.5, 2. / 3., 0.5), QuickTileFlag::Bottom | QuickTileFlag::Third1 | QuickTileFlag::Third2);
+ m_bottomThird2Tile = createTile(QRectF(1. / 3., 0.5, 1. / 3., 0.5), QuickTileFlag::Bottom | QuickTileFlag::Third2);
+ m_bottomThird23Tile = createTile(QRectF(1. / 3., 0.5, 2. / 3., 0.5), QuickTileFlag::Bottom | QuickTileFlag::Third2 | QuickTileFlag::Third3);
+ m_bottomThird3Tile = createTile(QRectF(2. / 3., 0.5, 1. / 3., 0.5), QuickTileFlag::Bottom | QuickTileFlag::Third3);
}
QuickRootTile::~QuickRootTile()
@@ -93,6 +112,17 @@ Tile *QuickRootTile::tileForMode(QuickTileMode mode)
return m_leftVerticalTile;
case QuickTileMode(QuickTileFlag::Right):
return m_rightVerticalTile;
+ case QuickTileMode(QuickTileFlag::Third1):
+ return m_third1VerticalTile;
+ case QuickTileMode(QuickTileFlag::Third2):
+ return m_third2VerticalTile;
+ case QuickTileMode(QuickTileFlag::Third3):
+ return m_third3VerticalTile;
+ case QuickTileMode(QuickTileFlag::Third1 | QuickTileFlag::Third2):
+ return m_third12VerticalTile;
+ case QuickTileMode(QuickTileFlag::Third2 | QuickTileFlag::Third3):
+ return m_third23VerticalTile;
+
case QuickTileMode(QuickTileFlag::Top):
return m_topHorizontalTile;
case QuickTileMode(QuickTileFlag::Bottom):
@@ -105,6 +135,29 @@ Tile *QuickRootTile::tileForMode(QuickTileMode mode)
return m_bottomLeftTile;
case QuickTileMode(QuickTileFlag::Right | QuickTileFlag::Bottom):
return m_bottomRightTile;
+ case QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Third1):
+ return m_topThird1Tile;
+ case QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Third2):
+ return m_topThird2Tile;
+ case QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Third3):
+ return m_topThird3Tile;
+ case QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Third1 | QuickTileFlag::Third2):
+ return m_topThird12Tile;
+ case QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Third2 | QuickTileFlag::Third3):
+ return m_topThird23Tile;
+ case QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Third1):
+ return m_bottomThird1Tile;
+ case QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Third2):
+ return m_bottomThird2Tile;
+ case QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Third3):
+ return m_bottomThird3Tile;
+ case QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Third1 | QuickTileFlag::Third2):
+ return m_bottomThird12Tile;
+ case QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Third2 | QuickTileFlag::Third3):
+ return m_bottomThird23Tile;
+ case QuickTileMode(QuickTileFlag::Horizontal):
+ case QuickTileMode(QuickTileFlag::Vertical):
+ return this;
default:
return nullptr;
}
diff --git a/src/tiles/quicktile.h b/src/tiles/quicktile.h
index 6abb622740..4a75874f6d 100644
--- a/src/tiles/quicktile.h
+++ b/src/tiles/quicktile.h
@@ -45,6 +45,12 @@ private:
Tile *m_leftVerticalTile = nullptr;
Tile *m_rightVerticalTile = nullptr;
+ Tile *m_third1VerticalTile = nullptr;
+ Tile *m_third12VerticalTile = nullptr;
+ Tile *m_third2VerticalTile = nullptr;
+ Tile *m_third23VerticalTile = nullptr;
+ Tile *m_third3VerticalTile = nullptr;
+
Tile *m_topHorizontalTile = nullptr;
Tile *m_bottomHorizontalTile = nullptr;
@@ -52,6 +58,18 @@ private:
Tile *m_topRightTile = nullptr;
Tile *m_bottomLeftTile = nullptr;
Tile *m_bottomRightTile = nullptr;
+
+ Tile *m_topThird1Tile = nullptr;
+ Tile *m_topThird12Tile = nullptr;
+ Tile *m_topThird2Tile = nullptr;
+ Tile *m_topThird23Tile = nullptr;
+ Tile *m_topThird3Tile = nullptr;
+
+ Tile *m_bottomThird1Tile = nullptr;
+ Tile *m_bottomThird12Tile = nullptr;
+ Tile *m_bottomThird2Tile = nullptr;
+ Tile *m_bottomThird23Tile = nullptr;
+ Tile *m_bottomThird3Tile = nullptr;
};
} // namespace KWin
--
2.49.1

@ -0,0 +1,33 @@
From 124e9a52b8b2051cbc37a1d603cfc8a0622feee3 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Wed, 1 Mar 2023 12:36:23 -0500
Subject: [PATCH 07/20] Add padding to qulcktiles
---
src/tiles/quicktile.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/tiles/quicktile.cpp b/src/tiles/quicktile.cpp
index 507df27ed1..c5c255e648 100644
--- a/src/tiles/quicktile.cpp
+++ b/src/tiles/quicktile.cpp
@@ -10,6 +10,7 @@
#include "quicktile.h"
#include "tilemanager.h"
#include "virtualdesktops.h"
+#include "core/output.h"
namespace KWin
{
@@ -25,7 +26,7 @@ QuickRootTile::QuickRootTile(TileManager *tiling, VirtualDesktop *desktop)
auto createTile = [this](const QRectF &geometry, QuickTileMode tileMode) {
Tile *tile = createChildAt<Tile>(geometry, childCount());
- tile->setPadding(0.0);
+ tile->setPadding(m_tiling->output()->defaultPadding());
tile->setQuickTileMode(tileMode);
connect(tile, &Tile::relativeGeometryChanged, this, [this, tile]() {
--
2.49.1

@ -0,0 +1,46 @@
From 401840537e09859db6811661995cabf0f7fc3fe9 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Tue, 24 Jun 2025 13:19:24 +0200
Subject: [PATCH 08/20] Use geometry relative to the cutout
---
src/tiles/tile.cpp | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/src/tiles/tile.cpp b/src/tiles/tile.cpp
index d7377d9d18..3c3ba61632 100644
--- a/src/tiles/tile.cpp
+++ b/src/tiles/tile.cpp
@@ -153,20 +153,19 @@ QRectF Tile::relativeGeometry() const
QRectF Tile::absoluteGeometry() const
{
- const QRectF geom = m_tiling->output()->geometryF();
- return QRectF(std::round(geom.x() + m_relativeGeometry.x() * geom.width()),
- std::round(geom.y() + m_relativeGeometry.y() * geom.height()),
- std::round(m_relativeGeometry.width() * geom.width()),
- std::round(m_relativeGeometry.height() * geom.height()));
-}
+ qreal cutoutSize = m_tiling->output()->defaultPadding() + m_tiling->output()->defaultBorder();
+ const QMarginsF cutout = QMarginsF(cutoutSize, cutoutSize, cutoutSize, cutoutSize);
+ const QRectF geom = m_tiling->output()->geometryF() - cutout;
+ return QRectF(geom.x() + m_relativeGeometry.x() * geom.width(),
+ geom.y() + m_relativeGeometry.y() * geom.height(),
+ m_relativeGeometry.width() * geom.width(),
+ m_relativeGeometry.height() * geom.height());
+} // the code in master is rounding, but why???
QRectF Tile::absoluteGeometryInScreen() const
{
const QRectF geom = m_tiling->output()->geometryF();
- return QRectF(std::round(m_relativeGeometry.x() * geom.width()),
- std::round(m_relativeGeometry.y() * geom.height()),
- std::round(m_relativeGeometry.width() * geom.width()),
- std::round(m_relativeGeometry.height() * geom.height()));
+ return absoluteGeometry().translated(-geom.topLeft());
}
QRectF Tile::windowGeometry() const
--
2.49.1

@ -0,0 +1,35 @@
From 2b19ce4d9b8a24edd60271e61a6972b08cf28364 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Tue, 20 Jun 2023 18:11:43 -0400
Subject: [PATCH 09/20] Make vertical gap twice as big between windows
---
src/tiles/tile.cpp | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/tiles/tile.cpp b/src/tiles/tile.cpp
index 3c3ba61632..2a3f22a4b4 100644
--- a/src/tiles/tile.cpp
+++ b/src/tiles/tile.cpp
@@ -178,7 +178,17 @@ QRectF Tile::windowGeometry() const
effectiveMargins.setBottom(m_relativeGeometry.bottom() < 1.0 ? m_padding / 2.0 : m_padding);
const auto geom = absoluteGeometry();
- return geom.intersected(workspace()->clientArea(MaximizeArea, m_tiling->output(), m_desktop)) - effectiveMargins;
+ // This below is the original return value. Find out if this is actually ok
+ // return geom.intersected(workspace()->clientArea(MaximizeArea, m_tiling->output(), m_desktop)) - effectiveMargins;
+
+ auto margins = QMarginsF(m_padding, m_padding, m_padding, m_padding);
+ if (quickTileMode() & QuickTileFlag::Top) {
+ margins += QMarginsF(0,0,0,m_padding);
+ } else if (quickTileMode() & QuickTileFlag::Bottom) {
+ margins += QMarginsF(0,m_padding,0,0);
+ }
+ return geom.intersected(workspace()->clientArea(MaximizeArea, m_tiling->output(), m_desktop)) - margins;
+
}
QRectF Tile::maximizedWindowGeometry() const
--
2.49.1

@ -0,0 +1,200 @@
From a782b7db8d28bf67650458356507a09698c0098f Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Mon, 21 Nov 2022 15:31:57 -0500
Subject: [PATCH 10/20] Implement core panning methods
Introduce methods used to pan windows horizontally by a certain pixel
amount. Panning applies to all windows which belong to a specified
screen:
- the main method is ~panWindows~, which iterates on all windows and
pans those that belong to the specified screen of the required amount.
- there are 4 slots used to pan all windows on the current screen by
1/2 and 1/3 of its size left or right. These slots are accessible via
user actions
- Finally, there is a method to ensure a given window is visible (this
slot is called upon client activation)
Fix compilation
screen() has been removed and replaced by some method that returns a pointer to a KWin::output; this may lead to some trouble
Prevent focused panel to move everything
[hyper-wide] Ensure selected window is visible
this is weird; it should not be necessary
stash with definition of panWindows
[hyper-wide] Fix pan windows with fractional scaling
Fix ensureVisible
---
src/effect/effecthandler.cpp | 1 +
src/placement.cpp | 75 ++++++++++++++++++++++++++++++++++++
src/useractions.cpp | 8 ++++
src/workspace.cpp | 1 +
src/workspace.h | 7 ++++
5 files changed, 92 insertions(+)
diff --git a/src/effect/effecthandler.cpp b/src/effect/effecthandler.cpp
index 84c45f62cf..2492f7ba22 100644
--- a/src/effect/effecthandler.cpp
+++ b/src/effect/effecthandler.cpp
@@ -779,6 +779,7 @@ void EffectsHandler::activateWindow(EffectWindow *effectWindow)
auto window = effectWindow->window();
if (window->isClient()) {
Workspace::self()->activateWindow(window, true);
+ Workspace::self()->slotEnsureClientVisible(window);
}
}
diff --git a/src/placement.cpp b/src/placement.cpp
index 6c984282e5..7e68c8e108 100644
--- a/src/placement.cpp
+++ b/src/placement.cpp
@@ -13,7 +13,9 @@
#include "placement.h"
#include "cursor.h"
#include "options.h"
+#include "core/outputbackend.h"
#include "rules.h"
+#include "core/output.h"
#include "virtualdesktops.h"
#include "window.h"
#include "workspace.h"
@@ -741,6 +743,79 @@ void Window::shrinkVertical()
}
}
+void Workspace::panWindows(KWin::Output *output, qreal pixels, bool shiftActive)
+{ // In case we have problems, here we moved from using indices for
+ // screens to using pointers; this may lead to trouble in testing.
+
+ // shiftActive is UNUSED
+ const auto &clients = Workspace::self()->windows();
+ for (int i = clients.size() - 1; i >= 0; i--) {
+ Window *client = clients.at(i);
+ if ((!client->isOnCurrentDesktop()) || (client->isMinimized()) || (client->isOnAllDesktops()) || (!client->isMovable()) || (client->output() != output))
+ continue;
+ // refactor usind client->isOnOutput
+ client->moveRelative(QPointF(pixels, 0 ));
+ }
+}
+
+ // TODO:
+ // find current screen with screens()->current()
+ // move only clients on current screen
+ // refactor this in a generic method and make the slots call it;
+ // genericmethod should look like
+ //
+ // slotPanWindows( int screen, int pixels, bool shiftActive)
+
+ // The shift amount is given by the size of the window + 2*gapSize
+ // The size of the window + 2*gapsize should be the (width of the screen - 2*screenBorder - 2*gapSize)/2
+
+void Workspace::slotPanWindowsHalfScreenRight()
+{
+ auto currentOutput = workspace()->activeOutput();
+ qreal width = currentOutput->geometryF().width();
+ qreal halfWidth = (width - 2. * currentOutput->defaultPadding() - 2. * currentOutput->defaultBorder()) / 2.;
+ panWindows(currentOutput, halfWidth, false);
+}
+
+void Workspace::slotPanWindowsHalfScreenLeft()
+{
+ auto currentOutput = workspace()->activeOutput();
+ qreal width = currentOutput->geometryF().width();
+ qreal halfWidth = (width - 2. * currentOutput->defaultPadding() - 2. * currentOutput->defaultBorder()) / 2.;
+ panWindows(currentOutput, -halfWidth, false);
+}
+
+void Workspace::slotPanWindowsThirdScreenRight()
+{
+ auto currentOutput = workspace()->activeOutput();
+ qreal width = currentOutput->geometryF().width();
+ qreal thirdWidth = (width - 2. * currentOutput->defaultPadding() - 2. * currentOutput->defaultBorder()) / 3.;
+ panWindows(currentOutput, thirdWidth, false);
+}
+
+void Workspace::slotPanWindowsThirdScreenLeft()
+{
+ auto currentOutput = workspace()->activeOutput();
+ qreal width = currentOutput->geometryF().width();
+ qreal thirdWidth = (width - 2. * currentOutput->defaultPadding() - 2. * currentOutput->defaultBorder()) / 3.;
+ panWindows(currentOutput, -thirdWidth, false);
+}
+
+void Workspace::slotEnsureClientVisible( KWin::Window* activatedClient )
+{
+ // This also should be made screen-aware
+ if ((!activatedClient) || activatedClient->isDesktop() || activatedClient->isDock())
+ return;
+ auto activatedOutput = activatedClient->output();
+ QRectF screenGeo = activatedClient->output()->geometryF();
+ QRectF clientGeo = activatedClient->frameGeometry();
+ // activateScreen does not seem to be extremely reliable… Perhaps windows that exist before kwin is started are
+ if (clientGeo.left() < screenGeo.left() + activatedOutput->defaultBorder() + activatedOutput->defaultPadding() * 2.)
+ panWindows(activatedOutput, screenGeo.left() - clientGeo.left() + activatedOutput->defaultPadding() * 2. + activatedOutput->defaultBorder(), false);
+ else if (clientGeo.right() > screenGeo.right() - activatedOutput->defaultBorder() - activatedOutput->defaultPadding() * 2.)
+ panWindows(activatedOutput, screenGeo.right() - clientGeo.right() - activatedOutput->defaultPadding() * 2. - activatedOutput->defaultBorder(), false);
+}
+
void Workspace::quickTileWindow(QuickTileMode mode)
{
if (!m_activeWindow) {
diff --git a/src/useractions.cpp b/src/useractions.cpp
index 6e841d96cd..f60ec14a0d 100644
--- a/src/useractions.cpp
+++ b/src/useractions.cpp
@@ -952,6 +952,14 @@ void Workspace::initShortcuts()
0, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Third2));
initShortcut("Window Quick Tile Right Third", i18n("Quick Tile Window to the Right Third"),
0, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Third3));
+ initShortcut("Pan Windows Right Half", i18n("Pan Windows to the right by half the screen"),
+ 0, &Workspace::slotPanWindowsHalfScreenRight);
+ initShortcut("Pan Windows Left Half", i18n("Pan Windows to the left by half the screen"),
+ 0, &Workspace::slotPanWindowsHalfScreenLeft);
+ initShortcut("Pan Windows Right Third", i18n("Pan Windows to the right by third the screen"),
+ 0, &Workspace::slotPanWindowsThirdScreenRight);
+ initShortcut("Pan Windows Left Third", i18n("Pan Windows to the left by third the screen"),
+ 0, &Workspace::slotPanWindowsThirdScreenLeft);
initShortcut("Window Quick Tile Top", i18n("Quick Tile Window to the Top"),
Qt::META | Qt::Key_Up, std::bind(&Workspace::quickTileWindow, this, QuickTileFlag::Top));
initShortcut("Window Quick Tile Bottom", i18n("Quick Tile Window to the Bottom"),
diff --git a/src/workspace.cpp b/src/workspace.cpp
index bd64f4f248..6f0d1ff3e8 100644
--- a/src/workspace.cpp
+++ b/src/workspace.cpp
@@ -177,6 +177,7 @@ void Workspace::init()
connect(options, &Options::configChanged, m_screenEdges.get(), &ScreenEdges::reconfigure);
connect(VirtualDesktopManager::self(), &VirtualDesktopManager::layoutChanged, m_screenEdges.get(), &ScreenEdges::updateLayout);
connect(this, &Workspace::windowActivated, m_screenEdges.get(), &ScreenEdges::checkBlocking);
+ connect(this, &Workspace::windowActivated, this, &Workspace::slotEnsureClientVisible);
connect(this, &Workspace::windowRemoved, m_focusChain.get(), &FocusChain::remove);
connect(this, &Workspace::windowActivated, m_focusChain.get(), &FocusChain::setActiveWindow);
diff --git a/src/workspace.h b/src/workspace.h
index 04fe2e0864..2f41dc8302 100644
--- a/src/workspace.h
+++ b/src/workspace.h
@@ -522,6 +522,13 @@ public Q_SLOTS:
void slotWindowShrinkHorizontal();
void slotWindowShrinkVertical();
+ void panWindows(KWin::Output *output, qreal pixels, bool shiftActive);
+ void slotPanWindowsHalfScreenRight();
+ void slotPanWindowsHalfScreenLeft();
+ void slotPanWindowsThirdScreenRight();
+ void slotPanWindowsThirdScreenLeft();
+ void slotEnsureClientVisible( KWin::Window* );
+
void slotIncreaseWindowOpacity();
void slotLowerWindowOpacity();
--
2.49.1

@ -0,0 +1,68 @@
From 243bf425dab979a150e2b18458b2643b4de58178 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Thu, 5 Jun 2025 22:23:24 -0400
Subject: [PATCH 11/20] Remove the logic for tiles on different screens
---
src/window.cpp | 38 +-------------------------------------
1 file changed, 1 insertion(+), 37 deletions(-)
diff --git a/src/window.cpp b/src/window.cpp
index 4eca4627dd..5ceea0c812 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -3727,7 +3727,7 @@ void Window::handleQuickTileShortcut(QuickTileMode mode)
} else {
// If the window is asked to be tiled in a screen corner, don't combine the new mode with the old one.
QuickTileMode combined;
- switch (mode) {
+ switch (mode) { // We should add the thirds here I suppose
case QuickTileMode(QuickTileFlag::Left):
case QuickTileMode(QuickTileFlag::Top):
case QuickTileMode(QuickTileFlag::Right):
@@ -3737,42 +3737,6 @@ void Window::handleQuickTileShortcut(QuickTileMode mode)
default:
combined = mode;
}
-
- // If trying to tile to the side that the window is already tiled to move the window to the next
- // screen near the tile if it exists and swap the tile side, otherwise toggle the mode (set QuickTileFlag::None)
- if (combined == oldMode) {
- Output *currentOutput = moveResizeOutput();
- Output *nextOutput = currentOutput;
- Output *candidateOutput = currentOutput;
- if ((mode & QuickTileFlag::Horizontal) == QuickTileMode(QuickTileFlag::Left)) {
- candidateOutput = workspace()->findOutput(nextOutput, Workspace::DirectionWest);
- } else if ((mode & QuickTileFlag::Horizontal) == QuickTileMode(QuickTileFlag::Right)) {
- candidateOutput = workspace()->findOutput(nextOutput, Workspace::DirectionEast);
- }
- bool shiftHorizontal = candidateOutput != nextOutput;
- nextOutput = candidateOutput;
- if ((mode & QuickTileFlag::Vertical) == QuickTileMode(QuickTileFlag::Top)) {
- candidateOutput = workspace()->findOutput(nextOutput, Workspace::DirectionNorth);
- } else if ((mode & QuickTileFlag::Vertical) == QuickTileMode(QuickTileFlag::Bottom)) {
- candidateOutput = workspace()->findOutput(nextOutput, Workspace::DirectionSouth);
- }
- bool shiftVertical = candidateOutput != nextOutput;
- nextOutput = candidateOutput;
-
- if (nextOutput != currentOutput) {
- // Move to other screen
- tileAtPoint = nextOutput->geometry().center();
-
- // Swap sides
- if (shiftHorizontal) {
- combined = (~combined & QuickTileFlag::Horizontal) | (combined & QuickTileFlag::Vertical);
- }
- if (shiftVertical) {
- combined = (~combined & QuickTileFlag::Vertical) | (combined & QuickTileFlag::Horizontal);
- }
- }
- }
-
mode = combined;
}
}
--
2.49.1

@ -0,0 +1,290 @@
From 0511ab9f21bc31b64a917030fef6c46f5060b971 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <jacopods@gmail.com>
Date: Sun, 28 Oct 2018 02:26:37 -0400
Subject: [PATCH 12/20] Implement Incremental wide-placement
[hyper-wide] Fix placement with fractional scaling
[squashme] Fix compilation
---
src/placement.cpp | 149 ++++++++++++++++++++++++++++++++++------------
1 file changed, 112 insertions(+), 37 deletions(-)
diff --git a/src/placement.cpp b/src/placement.cpp
index 7e68c8e108..cd480901b5 100644
--- a/src/placement.cpp
+++ b/src/placement.cpp
@@ -162,13 +162,24 @@ std::optional<PlacementCommand> Placement::placeSmart(const Window *window, cons
* with ideas from xfce.
*/
+ // this is messed up when we introduce floats, and I still want
+ // pixel perfect placement. Thus, we scale back to ints using the
+ // output scale
+
const QSizeF size = window->size();
if (size.isEmpty()) {
return std::nullopt;
}
+ auto windowOutput = window->output();
+
+ const qreal scale = windowOutput->scale();
+ int gapSize = std::round(windowOutput->defaultPadding() * scale);
+ int screenBorder = std::round(windowOutput->defaultBorder() * scale);
+
const int none = 0, h_wrong = -1, w_wrong = -2; // overlap types
long int overlap, min_overlap = 0;
+ int panning, min_panning = 0;
int x_optimal, y_optimal;
int possible;
VirtualDesktop *const desktop = window->isOnCurrentDesktop() ? VirtualDesktopManager::self()->currentDesktop() : window->desktops().front();
@@ -178,46 +189,70 @@ std::optional<PlacementCommand> Placement::placeSmart(const Window *window, cons
int basket; // temp holder
// get the maximum allowed windows space
- int x = area.left();
- int y = area.top();
+
+ QRectF preMaxRect = area;
+ preMaxRect.setWidth(preMaxRect.width() * 10);
+
+ const QRectF maxRect = preMaxRect;
+ int mrh = maxRect.height() * scale;
+
+ // Our first guess is the topleft corner
+ int x = std::round(maxRect.left() * scale) + gapSize;
+ int y = std::round(maxRect.top() * scale) + gapSize;
x_optimal = x;
y_optimal = y;
// client gabarit
- int ch = std::ceil(size.height());
- int cw = std::ceil(size.width());
+ int ch = std::round(size.height() * scale);
+ int cw = std::round(size.width() * scale);
// Explicitly converts those to int to avoid accidentally
// mixing ints and qreal in the calculations below.
- int area_xr = std::floor(area.x() + area.width());
- int area_yb = std::floor(area.y() + area.height());
+ int area_xr = std::round((area.x() + area.width()) * scale);
+ int area_yb = std::round((area.y() + area.height()) * scale);
+ int maxRect_xr = std::round((maxRect.x() + maxRect.width()) * scale);
+ int maxRect_yb = std::round((maxRect.y() + maxRect.height()) * scale);
+ // This is needed so that we can set the optimal value the first time
+ // Could we not set overlap to ∞?
bool first_pass = true; // CT lame flag. Don't like it. What else would do?
// loop over possible positions
do {
// test if enough room in x and y directions
- if (y + ch > area_yb && ch < area.height()) {
+ // h_wrong (height wrong) means that the client would overflow
+ // from the bottom of the availabe area
+ //
+ // w_wrong (width wrong) means that the client would overflow
+ // from the right of the available area
+ if (y + ch > maxRect_yb && ch < mrh) {
overlap = h_wrong; // this throws the algorithm to an exit
- } else if (x + cw > area_xr) {
+ // since we exhausted all possible
+ // positions
+ } else if (x + cw > maxRect_xr) {
overlap = w_wrong;
} else {
+ // we start computing the overlap with all other windows
+ // present on the same desktop.
overlap = none; // initialize
+ panning = qMax(0, x + cw - area_xr);
cxl = x;
cxr = x + cw;
cyt = y;
cyb = y + ch;
+ // These above are left top right and bottom
for (auto l = workspace()->stackingOrder().constBegin(); l != workspace()->stackingOrder().constEnd(); ++l) {
auto client = *l;
- if (isIrrelevant(client, window, desktop)) {
+ if (isIrrelevant(client, window, desktop)
+ || client->isDock()) {
continue;
}
- xl = client->x();
- yt = client->y();
- xr = xl + client->width();
- yb = yt + client->height();
-
+ xl = std::round(client->x() * scale);
+ yt = std::round(client->y() * scale);
+ xr = std::round((client->x() + client->width()) * scale);
+ yb = std::round((client->y() + client->height()) * scale);
+ // FIXME: should account for gaps!
// if windows overlap, calc the overall overlapping
if ((cxl < xr) && (cxr > xl) && (cyt < yb) && (cyb > yt)) {
xl = std::max(cxl, xl);
@@ -234,9 +269,13 @@ std::optional<PlacementCommand> Placement::placeSmart(const Window *window, cons
}
}
}
+ // JDS: up to here we computed overlap as the sum of the area
+ // overlapping with each window already present on the desktop
+ // area
- // CT first time we get no overlap we stop.
- if (overlap == none) {
+ if ((overlap == none) && (panning == 0)) {
+ // Bingo: the spot is free and we do not need to pan; set
+ // optimal positions and break from the cycle
x_optimal = x;
y_optimal = y;
break;
@@ -245,22 +284,40 @@ std::optional<PlacementCommand> Placement::placeSmart(const Window *window, cons
if (first_pass) {
first_pass = false;
min_overlap = overlap;
+ min_panning = maxRect_xr;
+ // Why is it not setting x_optimal, y_optimal?
}
// CT save the best position and the minimum overlap up to now
- else if (overlap >= none && overlap < min_overlap) {
+ else if ((overlap >= none) && ((overlap < min_overlap) || ((overlap == min_overlap) && (panning < min_panning)))) {
min_overlap = overlap;
+ min_panning = panning;
x_optimal = x;
y_optimal = y;
}
+ if ((overlap == none) && (panning > 0)) {
+ overlap = w_wrong;
+ }
+
+ // JDS now we need to decide whether it makes sense to loop
+
// really need to loop? test if there's any overlap
if (overlap > none) {
+ // we are here if overlap is not w_wrong nor h_wrong this
+ // means that the client still fits inside the area, but
+ // overlaps with some of the other clients. We try to move
+ // it around.
+
+ // Start from the right.
+ possible = maxRect_xr;
- possible = area_xr;
if (possible - cw > x) {
possible -= cw;
}
+ // JDS now ~possible~ is the last possible x before I get
+ // out of the desktop
+
// compare to the position of each client on the same desk
for (auto l = workspace()->stackingOrder().constBegin(); l != workspace()->stackingOrder().constEnd(); ++l) {
auto client = *l;
@@ -268,32 +325,44 @@ std::optional<PlacementCommand> Placement::placeSmart(const Window *window, cons
continue;
}
- xl = client->x();
- yt = client->y();
- xr = xl + client->width();
- yb = yt + client->height();
+ xl = std::round(client->x() * scale);
+ yt = std::round(client->y() * scale);
+ xr = std::round((client->x() + client->width()) * scale + 2 * gapSize);
+ yb = std::round((client->y() + client->height()) * scale);
// if not enough room above or under the current tested client
// determine the first non-overlapped x position
- if ((y < yb) && (yt < ch + y)) {
+ if ((y < yb) && (y + ch > yt)) {
+ // The tested client could be the one getting in
+ // our way earlier on
+ // If this clause succeeds, the tested client was
+ // in our way before; if possible, Try and place
+ // it either to the right or to the left of it
if ((xr > x) && (possible > xr)) {
possible = xr;
}
- basket = xl - cw;
+ basket = xl - cw - 2*gapSize;
if ((basket > x) && (possible > basket)) {
possible = basket;
}
- }
+ } // else our client sits completely above or below
+ // the tested client and the tested client can be
+ // safely ignored. Of course if we got here it means
+ // that some overlap existed, so at least one client
+ // would test positive to the above if clause
}
x = possible;
}
-
// ... else ==> not enough x dimension (overlap was wrong on horizontal)
else if (overlap == w_wrong) {
- x = area.left();
- possible = area_yb;
+ // if we overflow to the right, reset x to the left side
+ // and set possible to be either the bottom of the area or
+ // just as low so that the window would touch the bottom
+ // of the screen with the bottom side
+ x = maxRect.left() * scale;
+ possible = maxRect_yb;
if (possible - ch > y) {
possible -= ch;
@@ -306,10 +375,10 @@ std::optional<PlacementCommand> Placement::placeSmart(const Window *window, cons
continue;
}
- xl = client->x();
- yt = client->y();
- xr = xl + client->width();
- yb = yt + client->height();
+ xl = std::round(client->x() * scale);
+ yt = std::round(client->y() * scale);
+ xr = std::round((client->x() + client->width()) * scale);
+ yb = std::round((client->y() + client->height()) * scale + 4 * gapSize); // this (incorrectly) assumes that the mid vertical gap is twice the gapsize
// if not enough room to the left or right of the current tested client
// determine the first non-overlapped y position
@@ -317,20 +386,26 @@ std::optional<PlacementCommand> Placement::placeSmart(const Window *window, cons
possible = yb;
}
- basket = yt - ch;
+ basket = yt - ch - 4 * gapSize;
if ((basket > y) && (possible > basket)) {
possible = basket;
}
}
+ if (y == possible) {
+ // we exhausted the possible positions
+ break;
+ }
y = possible;
}
- } while ((overlap != none) && (overlap != h_wrong) && (y < area_yb));
+ } while (((overlap != none) || (panning > 0)) && (overlap != h_wrong) && (y < maxRect_yb));
- if (ch >= area.height()) {
- y_optimal = area.top();
+ if (ch >= mrh) {
+ y_optimal = maxRect.top() * scale;
}
- return QPointF(x_optimal, y_optimal);
+ // place the window
+
+ return QPointF(x_optimal / scale, y_optimal / scale);
}
QPoint Workspace::cascadeOffset(const QRectF &area) const
--
2.49.1

@ -0,0 +1,44 @@
From 326da58552445f2b267b2a748806dd97e9c6a6aa Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <jacopods@gmail.com>
Date: Fri, 5 Apr 2019 22:23:10 -0400
Subject: [PATCH 13/20] Remove wrap-around when switching focus horizontally
Now, this is not a necessity, but more often than not I do not want to
wrap around, especially if the desktop is stretched very wide
---
src/useractions.cpp | 19 +------------------
1 file changed, 1 insertion(+), 18 deletions(-)
diff --git a/src/useractions.cpp b/src/useractions.cpp
index f60ec14a0d..e92eb95292 100644
--- a/src/useractions.cpp
+++ b/src/useractions.cpp
@@ -1610,24 +1610,7 @@ void Workspace::switchWindow(Direction direction)
// Center of the active window
QPoint curPos(window->x() + window->width() / 2, window->y() + window->height() / 2);
- if (!switchWindow(window, direction, curPos, desktop)) {
- auto opposite = [&] {
- switch (direction) {
- case DirectionNorth:
- return QPoint(curPos.x(), geometry().height());
- case DirectionSouth:
- return QPoint(curPos.x(), 0);
- case DirectionEast:
- return QPoint(0, curPos.y());
- case DirectionWest:
- return QPoint(geometry().width(), curPos.y());
- default:
- Q_UNREACHABLE();
- }
- };
-
- switchWindow(window, direction, opposite(), desktop);
- }
+ switchWindow(window, direction, curPos, desktop);
}
bool Workspace::switchWindow(Window *window, Direction direction, QPoint curPos, VirtualDesktop *desktop)
--
2.49.1

@ -0,0 +1,28 @@
From adccb3d9f6613d12b723ff5bd39cb0fdbbba65b5 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <jacopods@gmail.com>
Date: Fri, 24 May 2019 09:33:47 +0200
Subject: [PATCH 14/20] Allow windows outside left|right screen boundary
---
src/window.cpp | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/window.cpp b/src/window.cpp
index 5ceea0c812..afde7610e6 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -4232,11 +4232,6 @@ void Window::checkWorkspacePosition(QRectF oldGeometry, const VirtualDesktop *ol
void Window::checkOffscreenPosition(QRectF *geom, const QRectF &screenArea)
{
- if (geom->left() > screenArea.right()) {
- geom->moveLeft(screenArea.right() - screenArea.width() / 4);
- } else if (geom->right() < screenArea.left()) {
- geom->moveRight(screenArea.left() + screenArea.width() / 4);
- }
if (geom->top() > screenArea.bottom()) {
geom->moveTop(screenArea.bottom() - screenArea.height() / 4);
} else if (geom->bottom() < screenArea.top()) {
--
2.49.1

@ -0,0 +1,42 @@
From d1afa2a57ba8d647559bf44b5cba8b3806b1c5cc Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Sun, 30 Apr 2023 23:09:34 -0400
Subject: [PATCH 15/20] Adjust output detection for hyper-wide
---
src/window.cpp | 3 ++-
src/workspace.cpp | 4 +++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/window.cpp b/src/window.cpp
index afde7610e6..6442eb44b1 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -246,7 +246,8 @@ bool Window::isOnActiveOutput() const
bool Window::isOnOutput(Output *output) const
{
- return output->geometry().intersects(frameGeometry().toRect());
+ return (output->geometry().bottom() >= frameGeometry().top() &&
+ output->geometry().top() <= frameGeometry().top());
}
Shadow *Window::shadow() const
diff --git a/src/workspace.cpp b/src/workspace.cpp
index 6f0d1ff3e8..b58d5b151f 100644
--- a/src/workspace.cpp
+++ b/src/workspace.cpp
@@ -1045,7 +1045,9 @@ Output *Workspace::outputAt(const QPointF &pos) const
for (Output *output : std::as_const(m_outputs)) {
const QRectF geo = output->geometry();
-
+ if ((geo.bottom() >= pos.y()) && (geo.top() <= pos.y())) {
+ return output;
+ }
const QPointF closestPoint(std::clamp(pos.x(), geo.x(), geo.x() + geo.width() - 1),
std::clamp(pos.y(), geo.y(), geo.y() + geo.height() - 1));
--
2.49.1

@ -0,0 +1,196 @@
From ca4cd3cc88680e912752d05ad9863ecbeaf1bf85 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <jacopods@protonmail.com>
Date: Thu, 17 Jun 2021 23:00:47 -0400
Subject: [PATCH 16/20] Introduce the Pan helper effect
Fix installation of panhelper effect
Fix panhelper effect
---
src/plugins/CMakeLists.txt | 1 +
src/plugins/panhelper/CMakeLists.txt | 1 +
.../panhelper/package/contents/code/main.js | 122 ++++++++++++++++++
src/plugins/panhelper/package/metadata.json | 22 ++++
4 files changed, 146 insertions(+)
create mode 100644 src/plugins/panhelper/CMakeLists.txt
create mode 100644 src/plugins/panhelper/package/contents/code/main.js
create mode 100644 src/plugins/panhelper/package/metadata.json
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 794522aee2..173705f3f7 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -84,6 +84,7 @@ add_subdirectory(mousemark)
add_subdirectory(nightlight)
add_subdirectory(outputlocator)
add_subdirectory(overview)
+add_subdirectory(panhelper)
add_subdirectory(qpa)
add_subdirectory(scale)
add_subdirectory(screenedge)
diff --git a/src/plugins/panhelper/CMakeLists.txt b/src/plugins/panhelper/CMakeLists.txt
new file mode 100644
index 0000000000..5095de2e67
--- /dev/null
+++ b/src/plugins/panhelper/CMakeLists.txt
@@ -0,0 +1 @@
+kwin_add_scripted_effect(panhelper package)
diff --git a/src/plugins/panhelper/package/contents/code/main.js b/src/plugins/panhelper/package/contents/code/main.js
new file mode 100644
index 0000000000..0ca5576c5f
--- /dev/null
+++ b/src/plugins/panhelper/package/contents/code/main.js
@@ -0,0 +1,122 @@
+/********************************************************************
+ This file is part of the KDE project.
+
+ Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
+ Copyright (C) 2016 Marco Martin <mart@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+/*global effect, effects, animate, animationTime, Effect*/
+class panHelperEffect {
+ constructor() {
+ effect.configChanged.connect(this.loadConfig.bind(this));
+
+ effects.windowAdded.connect(this.manage.bind(this));
+ for (const window of effects.stackingOrder) {
+ this.manage(window);
+ }
+
+ this.loadConfig();
+ }
+
+ loadConfig() {
+ "use strict";
+ this.duration = animationTime(250);
+ }
+
+ manage(window) {
+ window.windowFrameGeometryChanged.connect(this.geometryChange.bind(this));
+ }
+
+ geometryChange(window, oldGeometry) {
+ "use strict";
+
+ var newGeometry = window.geometry;
+
+ // act only on windows whose width does not change substantially (allow some room for rounding errors)
+ if ((Math.abs(newGeometry.width - oldGeometry.width) >4) ||
+ (Math.abs(newGeometry.height - oldGeometry.height) >1)) {
+ return;
+ }
+
+
+ //only do the transition for far enough windows that are moved horizontally
+ var disty = Math.abs(oldGeometry.y - newGeometry.y);
+ var distx = Math.abs(oldGeometry.x - newGeometry.x);
+ if (!((disty == 0) ^ (distx == 0))) {
+ // ignore
+ return
+ }
+ if (((distx != 0 ) && (distx < newGeometry.width / 6)) ||
+ ((disty != 0 ) && (disty < newGeometry.height / 6))) {
+ if (window.moveAnimation) {
+ delete window.moveAnimation;
+ }
+ return;
+ }
+ var couldRetarget = false;
+
+ if (window.moveAnimation) {
+ if (window.moveAnimation[0]) {
+ couldRetarget = retarget(window.moveAnimation[0], {
+ value1: newGeometry.width,
+ value2: newGeometry.height
+ }, this.duration);
+ }
+ if (couldRetarget && window.moveAnimation[1]) {
+ couldRetarget = retarget(window.moveAnimation[1], {
+ value1: newGeometry.x + newGeometry.width / 2,
+ value2: newGeometry.y + newGeometry.height / 2
+ }, this.duration);
+ }
+ if (!couldRetarget) {
+ cancel(window.moveAnimation[0]);
+ cancel(window.moveAnimation[1]);
+ delete window.moveAnimation;
+ }
+ }
+
+ if (!couldRetarget) {
+ window.moveAnimation = animate({
+ window: window,
+ duration: this.duration,
+ animations: [{
+ type: Effect.Size,
+ curve: QEasingCurve.OutCubic,
+ to: {
+ value1: newGeometry.width,
+ value2: newGeometry.height
+ },
+ from: {
+ value1: oldGeometry.width,
+ value2: oldGeometry.height
+ }
+ }, {
+ type: Effect.Position,
+ curve: QEasingCurve.OutCubic,
+ to: {
+ value1: newGeometry.x + newGeometry.width / 2,
+ value2: newGeometry.y + newGeometry.height / 2
+ },
+ from: {
+ value1: oldGeometry.x + oldGeometry.width / 2,
+ value2: oldGeometry.y + oldGeometry.height / 2
+ }
+ }]
+ });
+ }
+ }
+
+}
+new panHelperEffect();
diff --git a/src/plugins/panhelper/package/metadata.json b/src/plugins/panhelper/package/metadata.json
new file mode 100644
index 0000000000..14f7d37882
--- /dev/null
+++ b/src/plugins/panhelper/package/metadata.json
@@ -0,0 +1,22 @@
+{
+ "KPackageStructure": "KWin/Effect",
+ "KPlugin": {
+ "Authors": [
+ {
+ "Email": "wilderjds@protonmail.com",
+ "Name": "Jacopo De Simoi"
+ }
+ ],
+ "Category": "Window Pan Animation",
+ "Description": "Make windows smoothly pan when they are moved (KDE6 version)",
+ "EnabledByDefault": true,
+ "Icon": "preferences-system-windows-effect-scale",
+ "Id": "panhelper",
+ "License": "GPL",
+ "Name": "Pan Helper",
+ "Version": "1"
+ },
+ "X-KDE-Ordering": "60",
+ "X-KWin-Exclusive-Category": "toplevel-pan-animation",
+ "X-Plasma-API": "javascript"
+}
--
2.49.1

@ -0,0 +1,66 @@
From 73d06f88f2dd16738574c578aad7a72054fadd8f Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Sat, 22 Oct 2022 22:03:42 -0400
Subject: [PATCH 17/20] Remove boundary checking in the position effect
In order for the pan-helper effect to work, we need to drop the
boundary checking in the position effect.
This seems not to have any adverse effects on my machine; some drivers
might not like the fact that windows have negative coordinates.
---
src/effect/animationeffect.cpp | 29 +++++++++++------------------
1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/src/effect/animationeffect.cpp b/src/effect/animationeffect.cpp
index 621da89a9b..409d09db51 100644
--- a/src/effect/animationeffect.cpp
+++ b/src/effect/animationeffect.cpp
@@ -570,18 +570,14 @@ void AnimationEffect::paintWindow(const RenderTarget &renderTarget, const Render
case Position: {
const QRectF geo = w->frameGeometry();
const float prgrs = progress(anim);
- if (anim.from[0] >= 0.0 && anim.to[0] >= 0.0) {
- float dest = interpolated(anim, 0);
- const qreal x[2] = {xCoord(geo, metaData(SourceAnchor, anim.meta)),
+ float dest = interpolated(anim, 0);
+ const qreal x[2] = {xCoord(geo, metaData(SourceAnchor, anim.meta)),
xCoord(geo, metaData(TargetAnchor, anim.meta))};
- data.translate(dest - (x[0] + prgrs * (x[1] - x[0])));
- }
- if (anim.from[1] >= 0.0 && anim.to[1] >= 0.0) {
- float dest = interpolated(anim, 1);
- const qreal y[2] = {yCoord(geo, metaData(SourceAnchor, anim.meta)),
+ data.translate(dest - (x[0] + prgrs * (x[1] - x[0])));
+ dest = interpolated(anim, 1);
+ const qreal y[2] = {yCoord(geo, metaData(SourceAnchor, anim.meta)),
yCoord(geo, metaData(TargetAnchor, anim.meta))};
- data.translate(0.0, dest - (y[0] + prgrs * (y[1] - y[0])));
- }
+ data.translate(0.0, dest - (y[0] + prgrs * (y[1] - y[0])));
break;
}
case Rotation: {
@@ -858,14 +854,11 @@ void AnimationEffect::updateLayerRepaints()
y[0] = anim.from[1];
y[1] = anim.to[1];
} else {
- if (anim.from[0] >= 0.0 && anim.to[0] >= 0.0) {
- x[0] = anim.from[0] - xCoord(r, metaData(SourceAnchor, anim.meta));
- x[1] = anim.to[0] - xCoord(r, metaData(TargetAnchor, anim.meta));
- }
- if (anim.from[1] >= 0.0 && anim.to[1] >= 0.0) {
- y[0] = anim.from[1] - yCoord(r, metaData(SourceAnchor, anim.meta));
- y[1] = anim.to[1] - yCoord(r, metaData(TargetAnchor, anim.meta));
- }
+ x[0] = anim.from[0] - xCoord(r, metaData(SourceAnchor, anim.meta));
+ x[1] = anim.to[0] - xCoord(r, metaData(TargetAnchor, anim.meta));
+
+ y[0] = anim.from[1] - yCoord(r, metaData(SourceAnchor, anim.meta));
+ y[1] = anim.to[1] - yCoord(r, metaData(TargetAnchor, anim.meta));
}
r = window->expandedGeometry().toRect();
rects.push_back(r.translated(x[0], y[0]));
--
2.49.1

@ -0,0 +1,40 @@
From 24fc0c2cf458e5a9e4b27310862b21758f9a71e6 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <jacopods@protonmail.com>
Date: Mon, 28 Jun 2021 23:40:39 -0400
Subject: [PATCH 18/20] Add paint_screen flag to prevent artifacts
As far as I understand I am abusing the Position effect; there are
some assumption in the original implementation that do not work with
my setting, so I need to add a flag to force full repaints for the
duration of the effect.
---
src/effect/animationeffect.cpp | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/effect/animationeffect.cpp b/src/effect/animationeffect.cpp
index 409d09db51..445fc4cd1f 100644
--- a/src/effect/animationeffect.cpp
+++ b/src/effect/animationeffect.cpp
@@ -475,6 +475,10 @@ void AnimationEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data,
continue;
}
+ if (anim.attribute == Position) {
+ data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
+ }
+
if (anim.frozenTime < 0) {
anim.timeLine.advance(presentTime);
}
@@ -578,6 +582,8 @@ void AnimationEffect::paintWindow(const RenderTarget &renderTarget, const Render
const qreal y[2] = {yCoord(geo, metaData(SourceAnchor, anim.meta)),
yCoord(geo, metaData(TargetAnchor, anim.meta))};
data.translate(0.0, dest - (y[0] + prgrs * (y[1] - y[0])));
+ // modify region if necessary
+ w->addRepaintFull();
break;
}
case Rotation: {
--
2.49.1

@ -0,0 +1,33 @@
From 686789f83acd0bc99e91c1e1dfaf768284556c09 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Tue, 12 Nov 2024 22:41:42 -0500
Subject: [PATCH 19/20] Allow loading the keymap from a file
Make this right
---
src/xkb.cpp | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/xkb.cpp b/src/xkb.cpp
index 0cf6ac5816..3e8a6a0d72 100644
--- a/src/xkb.cpp
+++ b/src/xkb.cpp
@@ -580,6 +580,15 @@ xkb_keymap *Xkb::loadKeymapFromConfig()
if (!m_configGroup.isValid()) {
return nullptr;
}
+
+ if (m_configGroup.hasKey("KeymapFile")) {
+ auto keymapFile = m_configGroup.readEntry("KeymapFile");
+ QFile qf(keymapFile);
+ qf.open(QIODevice::ReadOnly);
+ QByteArray keymap_data = qf.readAll();
+ qCDebug(KWIN_XKB) << "Loading keymap from" << keymapFile;
+ return xkb_keymap_new_from_string(m_context, keymap_data, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ }
const QByteArray model = m_configGroup.readEntry("Model", "pc104").toLatin1();
const QByteArray layout = m_configGroup.readEntry("LayoutList").toLatin1();
const QByteArray variant = m_configGroup.readEntry("VariantList").toLatin1();
--
2.49.1

@ -0,0 +1,25 @@
From 4c7870369fc78bd803febe19ee8ee8b95d988d72 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Sat, 31 May 2025 11:30:10 -0400
Subject: [PATCH 20/20] temporary build fix
---
CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f31cc8e413..bec737bd27 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -202,7 +202,7 @@ else()
set(HAVE_WL_DISPLAY_SET_DEFAULT_MAX_BUFFER_SIZE 0)
endif()
if (Wayland_VERSION VERSION_GREATER_EQUAL 1.23.90)
- set(HAVE_WL_FIXES 1)
+ set(HAVE_WL_FIXES 0)
else()
set(HAVE_WL_FIXES 0)
endif()
--
2.49.1
Loading…
Cancel
Save