From e4ea19cd098d52cd28ef24051507cc69b0df001e Mon Sep 17 00:00:00 2001 From: Andrew Zambazos Date: Wed, 26 Aug 2026 23:00:11 +1200 Subject: [PATCH] Fix Sway floating frame geometry handling Use the floating container geometry whenever a view is inside a `floating_con`, so frame/deco/content coordinates stay stable and window chrome no longer jumps during refreshes. Also remove the custom `title_format` left-padding (and its related comment) from the Sway config so title text is no longer artificially offset. --- compositor/sway/nebula-sway.conf | 2 -- core/windows/backends/sway/SwayWindowBackend.cpp | 12 +++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compositor/sway/nebula-sway.conf b/compositor/sway/nebula-sway.conf index 2152557..a30173a 100644 --- a/compositor/sway/nebula-sway.conf +++ b/compositor/sway/nebula-sway.conf @@ -47,7 +47,6 @@ focus_follows_mouse yes # so they can be identified, dragged, and resized with the mouse. # # Nebula overlays traffic-light controls on the focused window title bar. -# Horizontal padding keeps the Sway title text clear of those buttons. # Menu-style chrome (application name, future File/Edit) stays in the top bar. # # This is temporary infrastructure until Nebula owns server-side decorations. @@ -59,7 +58,6 @@ titlebar_border_thickness 1 default_border normal 1 default_floating_border normal 1 hide_edge_borders none -title_format " %title" # class border backgr. text indicator child_border client.focused #3d4d62 #1a222e #e8ecf2 #7ea0c4 #3d4d62 diff --git a/core/windows/backends/sway/SwayWindowBackend.cpp b/core/windows/backends/sway/SwayWindowBackend.cpp index 33c975f..6945de1 100644 --- a/core/windows/backends/sway/SwayWindowBackend.cpp +++ b/core/windows/backends/sway/SwayWindowBackend.cpp @@ -75,7 +75,17 @@ void applyFrameGeometry(WindowInfo &window, const QJsonObject &node, const QJson int decoHeight = deco.value(QStringLiteral("height")).toInt(); int contentY = content.value(QStringLiteral("y")).toInt(); - if (decoHeight <= 0 && contentY <= 0 && !parent.isEmpty()) { + // Floating views live inside a floating_con whose rect includes Sway's + // server-side title bar. The child view rect is the client content rect. + // Always use the wrapper while it exists so refreshes cannot make chrome + // jump between frame and content coordinates. + if (nodeIsFloating(parent)) { + rect = parent.value(QStringLiteral("rect")).toObject(); + deco = parent.value(QStringLiteral("deco_rect")).toObject(); + content = parent.value(QStringLiteral("window_rect")).toObject(); + decoHeight = deco.value(QStringLiteral("height")).toInt(); + contentY = content.value(QStringLiteral("y")).toInt(); + } else if (decoHeight <= 0 && contentY <= 0 && !parent.isEmpty()) { const QJsonObject parentDeco = parent.value(QStringLiteral("deco_rect")).toObject(); const QJsonObject parentContent = parent.value(QStringLiteral("window_rect")).toObject(); const int parentDecoHeight = parentDeco.value(QStringLiteral("height")).toInt();