https://bugs.kde.org/show_bug.cgi?id=517915

Tanner(Cyborgized With Claude) <[email protected]> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |[email protected]

--- Comment #7 from Tanner(Cyborgized With Claude) <[email protected]> ---
Same root cause, with numbers and a tested patch, from a Plasma 6.7.5 Wayland
session (Bazzite / Fedora 45): DP-2 2560x1440 primary at 0,0, HDMI-A-1
1920x1080 at 2560,0 (tops aligned), a 46 px panel at the bottom of each.

  $ xprop -root _NET_WORKAREA
  _NET_WORKAREA(CARDINAL) = 0, 0, 4480, 1034

1034 = 1080 - 46: the panel at the bottom of the *shorter* monitor, whose edge
lies inside the virtual screen, clips the global work area for the taller
primary too. Workspace::rearrange() does workArea &= adjustClientArea(window,
m_geometry) for every strut; LayerShellV1Window::strutRect() is the exclusive
zone, and adjustClientArea() applies it to the global area as soon as it
intersects it, which a strut always does. Steam's desktop toasts
(steam-for-linux #12468,
https://github.com/ValveSoftware/steam-for-linux/issues/12468) are placed
inside "primary bounds ∩ _NET_WORKAREA", so they rest 360 px above the
primary's panel; the offset window positions in this report are the same
rectangle at work (with top panels it is the y origin that moves).

Agreed that one rectangle can't be right for everyone - but one of the two
wrong choices is cheaper, and it is the one the X11 session makes: kwin-x11's
hasOffscreenXineramaStrut() drops a strut that runs through the offscreen part
of the virtual screen (which is what an X11 panel on a shorter monitor
produces) from the global work area, while the per-output screen areas still
honour it. The big X11 toolkits apply _NET_WORKAREA to the primary monitor
only: GTK3 (gdk_x11_monitor_get_workarea: "we ignore the workarea for anything
but the primary monitor"), Chromium/CEF (x11_display_util.cc ClipWorkArea:
"intersect the work area with the primary display, like GTK does"), and Steam
asks for the primary ("default") monitor's usable rect. For all of them a strut
from a non-primary panel can never be honoured on its own monitor; its only
possible effect is to cut a strip off the primary that nothing reserves.
(Qt-xcb and SDL intersect the rectangle with every screen, so they are the ones
the current rule helps on the secondary - and hurts on the primary just the
same.)

Patch against 6.7.5 (applies to current master with a 3-line offset): in
Workspace::adjustClientArea() a strut only shrinks |area| if its output's edge
coincides with |area|'s edge. For the per-output areas the condition always
holds, so maximize/placement are untouched; only the global rectangle that
becomes _NET_WORKAREA changes, and only for panels on outputs that don't reach
the virtual-screen edge.

--- a/src/workspace.cpp
+++ b/src/workspace.cpp
@@ -2397,16 +2397,24 @@ RectF Workspace::adjustClientArea(Window *window, const
RectF &area) const
     strutTop.setTop(std::max(strutTop.top(), screenArea.top()));
     strutBottom.setBottom(std::min(strutBottom.bottom(),
screenArea.bottom()));

-    if (strutLeft.intersects(area)) {
+    // A strut shrinks |area| only if the output edge it is reserved on is
also an edge of |area|. For an output's
+    // own area that is always the case. For the whole virtual screen (the
single X11 _NET_WORKAREA rectangle) it
+    // is not when the panel sits on an output whose edge lies inside the
virtual screen, e.g. the bottom panel of a
+    // 1080p monitor placed next to a 1440p one: X11 clients apply
_NET_WORKAREA to the primary output only (GTK3,
+    // Chromium/CEF, Steam), so such a strut could only ever cut into a
monitor it does not belong to. The X11
+    // session has the same rule (hasOffscreenXineramaStrut() in kwin-x11: an
X11 strut from such a panel runs
+    // through the offscreen part of the virtual screen); layer-shell
exclusive zones never extend offscreen and
+    // were therefore never exempted, which is why this only shows in the
Wayland session.
+    if (strutLeft.intersects(area) && screenArea.left() <= area.left()) {
         adjustedArea.setLeft(strutLeft.right());
     }
-    if (strutRight.intersects(area)) {
+    if (strutRight.intersects(area) && screenArea.right() >= area.right()) {
         adjustedArea.setRight(strutRight.left());
     }
-    if (strutTop.intersects(area)) {
+    if (strutTop.intersects(area) && screenArea.top() <= area.top()) {
         adjustedArea.setTop(strutTop.bottom());
     }
-    if (strutBottom.intersects(area)) {
+    if (strutBottom.intersects(area) && screenArea.bottom() >= area.bottom())
{
         adjustedArea.setBottom(strutBottom.top());
     }

Tested: kwin 6.7.5 rebuilt with this (Fedora srpm + the patch, installed via
rpm-ostree override), running since 2026-10-17. With both panels visible and
the monitors top-aligned, _NET_WORKAREA is now 0, 0, 4480, 1394; Steam's own
SteamClient.Window.GetDefaultMonitorDimensions() (queried over its CEF
debugging port) reports the usable rect as 2560x1394, which puts its toast
anchor on the primary's panel (2544,1378 instead of 2544,1018); maximized
windows and placement on both outputs unchanged. Happy to turn this into an MR
if there is any appetite for it. Full disclosure: the investigation and the
patch were done with an AI assistant (Claude) working on my machine; the
measurements and the test are from the real session.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to