diff --git a/core/windows/WindowService.cpp b/core/windows/WindowService.cpp index 8862ae3..f6c6c61 100644 --- a/core/windows/WindowService.cpp +++ b/core/windows/WindowService.cpp @@ -156,6 +156,16 @@ int WindowService::focusedWindowTitleBarHeight() const return m_focusedWindowTitleBarHeight; } +int WindowService::focusedWorkspaceX() const +{ + return m_focusedWorkspaceX; +} + +int WindowService::focusedWorkspaceY() const +{ + return m_focusedWorkspaceY; +} + bool WindowService::focusWindow(const QString &windowId) { return m_backend->focusWindow(parseWindowId(windowId)); @@ -333,6 +343,8 @@ void WindowService::publishFocusedGeometry(const WindowInfo *focused) int decoHeight = 0; int titleBarY = 0; int titleBarHeight = 0; + int workspaceX = 0; + int workspaceY = 0; bool fullscreen = false; if (focused && !focused->minimized) { @@ -349,13 +361,19 @@ void WindowService::publishFocusedGeometry(const WindowInfo *focused) titleBarHeight = focused->decoHeight; if (titleBarHeight <= 0) titleBarHeight = focused->contentY; - if (titleBarHeight <= 0) + if (titleBarHeight < 16 || titleBarHeight > 48) titleBarHeight = 32; - if (focused->decoHeight > 0 || focused->contentY > 0) - titleBarY = focused->y + focused->decoY; - else - titleBarY = focused->y - titleBarHeight; + // Frame rect from the floating container starts at the title bar. + titleBarY = focused->y + focused->decoY; + + const WorkspaceInfo *workspace = m_workspaces->workspaceByName(focused->workspace); + if (!workspace) + workspace = m_workspaces->focusedWorkspace(); + if (workspace) { + workspaceX = workspace->x; + workspaceY = workspace->y; + } } if (m_focusedWindowFullscreen != fullscreen) { @@ -372,7 +390,9 @@ void WindowService::publishFocusedGeometry(const WindowInfo *focused) || m_focusedWindowDecoWidth != decoWidth || m_focusedWindowDecoHeight != decoHeight || m_focusedWindowTitleBarY != titleBarY - || m_focusedWindowTitleBarHeight != titleBarHeight) { + || m_focusedWindowTitleBarHeight != titleBarHeight + || m_focusedWorkspaceX != workspaceX + || m_focusedWorkspaceY != workspaceY) { m_focusedWindowX = x; m_focusedWindowY = y; m_focusedWindowWidth = width; @@ -383,6 +403,8 @@ void WindowService::publishFocusedGeometry(const WindowInfo *focused) m_focusedWindowDecoHeight = decoHeight; m_focusedWindowTitleBarY = titleBarY; m_focusedWindowTitleBarHeight = titleBarHeight; + m_focusedWorkspaceX = workspaceX; + m_focusedWorkspaceY = workspaceY; emit focusedWindowGeometryChanged(); } } diff --git a/core/windows/WindowService.hpp b/core/windows/WindowService.hpp index 24729e7..1155f42 100644 --- a/core/windows/WindowService.hpp +++ b/core/windows/WindowService.hpp @@ -39,6 +39,8 @@ class WindowService : public QObject Q_PROPERTY(int focusedWindowDecoHeight READ focusedWindowDecoHeight NOTIFY focusedWindowGeometryChanged) Q_PROPERTY(int focusedWindowTitleBarY READ focusedWindowTitleBarY NOTIFY focusedWindowGeometryChanged) Q_PROPERTY(int focusedWindowTitleBarHeight READ focusedWindowTitleBarHeight NOTIFY focusedWindowGeometryChanged) + Q_PROPERTY(int focusedWorkspaceX READ focusedWorkspaceX NOTIFY focusedWindowGeometryChanged) + Q_PROPERTY(int focusedWorkspaceY READ focusedWorkspaceY NOTIFY focusedWindowGeometryChanged) public: enum SnapEdge { @@ -73,6 +75,8 @@ public: int focusedWindowDecoHeight() const; int focusedWindowTitleBarY() const; int focusedWindowTitleBarHeight() const; + int focusedWorkspaceX() const; + int focusedWorkspaceY() const; Q_INVOKABLE bool focusWindow(const QString &windowId); Q_INVOKABLE bool closeWindow(const QString &windowId); @@ -124,5 +128,7 @@ private: int m_focusedWindowDecoHeight = 0; int m_focusedWindowTitleBarY = 0; int m_focusedWindowTitleBarHeight = 0; + int m_focusedWorkspaceX = 0; + int m_focusedWorkspaceY = 0; QTimer *m_geometryTimer = nullptr; }; diff --git a/core/windows/WorkspaceModel.cpp b/core/windows/WorkspaceModel.cpp index f345dca..c154cb3 100644 --- a/core/windows/WorkspaceModel.cpp +++ b/core/windows/WorkspaceModel.cpp @@ -82,3 +82,14 @@ const WorkspaceInfo *WorkspaceModel::focusedWorkspace() const } return nullptr; } + +const WorkspaceInfo *WorkspaceModel::workspaceByName(const QString &name) const +{ + if (name.isEmpty()) + return nullptr; + for (const WorkspaceInfo &workspace : m_workspaces) { + if (workspace.name == name) + return &workspace; + } + return nullptr; +} diff --git a/core/windows/WorkspaceModel.hpp b/core/windows/WorkspaceModel.hpp index 30126a4..abc7c8d 100644 --- a/core/windows/WorkspaceModel.hpp +++ b/core/windows/WorkspaceModel.hpp @@ -35,6 +35,7 @@ public: void setWorkspaces(QVector workspaces); const WorkspaceInfo *workspaceAt(int row) const; const WorkspaceInfo *focusedWorkspace() const; + const WorkspaceInfo *workspaceByName(const QString &name) const; signals: void countChanged(); diff --git a/core/windows/backends/sway/SwayWindowBackend.cpp b/core/windows/backends/sway/SwayWindowBackend.cpp index 6945de1..3d34713 100644 --- a/core/windows/backends/sway/SwayWindowBackend.cpp +++ b/core/windows/backends/sway/SwayWindowBackend.cpp @@ -66,38 +66,16 @@ bool nodeLooksLikeView(const QJsonObject &node) return !properties.isEmpty(); } -void applyFrameGeometry(WindowInfo &window, const QJsonObject &node, const QJsonObject &parent) +void applyFrameGeometry(WindowInfo &window, const QJsonObject &node, const QJsonObject &frame) { - QJsonObject rect = node.value(QStringLiteral("rect")).toObject(); - QJsonObject deco = node.value(QStringLiteral("deco_rect")).toObject(); - QJsonObject content = node.value(QStringLiteral("window_rect")).toObject(); + const bool useFrame = !frame.isEmpty() + && (frame.value(QStringLiteral("type")).toString() == QLatin1String("floating_con") + || nodeIsFloating(frame)); + const QJsonObject &source = useFrame ? frame : node; - int decoHeight = deco.value(QStringLiteral("height")).toInt(); - int contentY = content.value(QStringLiteral("y")).toInt(); - - // 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(); - const int parentContentY = parentContent.value(QStringLiteral("y")).toInt(); - if (parentDecoHeight > 0 || parentContentY > 0) { - rect = parent.value(QStringLiteral("rect")).toObject(); - deco = parentDeco; - content = parentContent; - decoHeight = parentDecoHeight; - contentY = parentContentY; - } - } + const QJsonObject rect = source.value(QStringLiteral("rect")).toObject(); + const QJsonObject deco = source.value(QStringLiteral("deco_rect")).toObject(); + const QJsonObject content = source.value(QStringLiteral("window_rect")).toObject(); window.x = rect.value(QStringLiteral("x")).toInt(); window.y = rect.value(QStringLiteral("y")).toInt(); @@ -106,9 +84,9 @@ void applyFrameGeometry(WindowInfo &window, const QJsonObject &node, const QJson window.decoX = deco.value(QStringLiteral("x")).toInt(); window.decoY = deco.value(QStringLiteral("y")).toInt(); window.decoWidth = deco.value(QStringLiteral("width")).toInt(); - window.decoHeight = decoHeight; + window.decoHeight = deco.value(QStringLiteral("height")).toInt(); window.contentX = content.value(QStringLiteral("x")).toInt(); - window.contentY = contentY; + window.contentY = content.value(QStringLiteral("y")).toInt(); } } // namespace @@ -530,7 +508,7 @@ bool SwayWindowBackend::isShellChrome(const QJsonObject &node) } void SwayWindowBackend::collect(const QJsonObject &node, - const QJsonObject &parent, + const QJsonObject &frame, const QString &workspace, const QString &output, bool onScratchpad, @@ -568,6 +546,10 @@ void SwayWindowBackend::collect(const QJsonObject &node, } } + QJsonObject nextFrame = frame; + if (type == QLatin1String("floating_con")) + nextFrame = node; + if (nodeLooksLikeView(node) && !isShellChrome(node)) { WindowInfo window; window.id = jsonId(node.value(QStringLiteral("id"))); @@ -580,18 +562,18 @@ void SwayWindowBackend::collect(const QJsonObject &node, window.workspace = nextWorkspace; window.output = nextOutput; window.focused = node.value(QStringLiteral("focused")).toBool(); - window.floating = nodeIsFloating(node) || nodeIsFloating(parent); + window.floating = nodeIsFloating(node) || nodeIsFloating(nextFrame); window.fullscreen = node.value(QStringLiteral("fullscreen_mode")).toInt() > 0; window.minimized = nextScratchpad; - applyFrameGeometry(window, node, parent); + applyFrameGeometry(window, node, nextFrame); windows->append(window); } const QJsonArray nodes = node.value(QStringLiteral("nodes")).toArray(); for (const QJsonValue &child : nodes) - collect(child.toObject(), node, nextWorkspace, nextOutput, nextScratchpad, windows, workspaces); + collect(child.toObject(), nextFrame, nextWorkspace, nextOutput, nextScratchpad, windows, workspaces); const QJsonArray floating = node.value(QStringLiteral("floating_nodes")).toArray(); for (const QJsonValue &child : floating) - collect(child.toObject(), node, nextWorkspace, nextOutput, nextScratchpad, windows, workspaces); + collect(child.toObject(), nextFrame, nextWorkspace, nextOutput, nextScratchpad, windows, workspaces); } diff --git a/core/windows/backends/sway/SwayWindowBackend.hpp b/core/windows/backends/sway/SwayWindowBackend.hpp index 1eed31a..276a329 100644 --- a/core/windows/backends/sway/SwayWindowBackend.hpp +++ b/core/windows/backends/sway/SwayWindowBackend.hpp @@ -44,7 +44,7 @@ private: const WindowInfo *findWindow(qint64 windowId) const; static bool isShellChrome(const QJsonObject &node); static void collect(const QJsonObject &node, - const QJsonObject &parent, + const QJsonObject &frame, const QString &workspace, const QString &output, bool onScratchpad, diff --git a/shells/desktop/shell/qml/surfaces/WindowChromeSurface.qml b/shells/desktop/shell/qml/surfaces/WindowChromeSurface.qml index 86aa064..268e97f 100644 --- a/shells/desktop/shell/qml/surfaces/WindowChromeSurface.qml +++ b/shells/desktop/shell/qml/surfaces/WindowChromeSurface.qml @@ -10,14 +10,15 @@ Window { readonly property bool active: WindowService.hasFocusedWindow && !WindowService.focusedWindowFullscreen && !ShellState.launcherOpen - readonly property int chromeX: WindowService.focusedWindowX + Theme.windowChromeInset + readonly property int chromeX: WindowService.focusedWindowX + + Theme.windowChromeInset + - WindowService.focusedWorkspaceX readonly property int chromeY: { - const barY = WindowService.focusedWindowTitleBarY - const barH = Math.max(WindowService.focusedWindowTitleBarHeight, height) - return barY + Math.round((barH - height) / 2) + const barH = WindowService.focusedWindowTitleBarHeight + const centered = WindowService.focusedWindowTitleBarY + + Math.max(0, Math.round((barH - height) / 2)) + return centered - WindowService.focusedWorkspaceY } - property real renderedChromeX: chromeX - property real renderedChromeY: chromeY title: qsTr("Nebula Window Chrome") color: "transparent" @@ -29,25 +30,11 @@ Window { LayerShell.Window.scope: "nebula-window-chrome" LayerShell.Window.layer: LayerShell.Window.LayerTop LayerShell.Window.anchors: LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorTop - LayerShell.Window.margins.left: Math.max(0, Math.round(renderedChromeX)) - LayerShell.Window.margins.top: Math.max(0, Math.round(renderedChromeY)) + LayerShell.Window.margins.left: Math.max(0, chromeX) + LayerShell.Window.margins.top: Math.max(0, chromeY) LayerShell.Window.exclusionZone: 0 LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone - Behavior on renderedChromeX { - NumberAnimation { - duration: 34 - easing.type: Easing.OutQuad - } - } - - Behavior on renderedChromeY { - NumberAnimation { - duration: 34 - easing.type: Easing.OutQuad - } - } - WindowControls { id: controls anchors.centerIn: parent