Add floating traffic-light window chrome
Introduces a dedicated layer-shell `WindowChromeSurface` that renders macOS-style traffic-light controls over the focused Sway window titlebar, replacing the old top-bar window controls. Adds theme tokens and a reusable `TrafficLightButton` component, updates shell QML/CMake wiring, and adjusts Sway titlebar padding/title format so window titles do not overlap the overlay. Window tracking was extended with focused-window geometry/deco/fullscreen properties plus backend refresh support so the chrome follows window movement and state changes in near real time.
This commit is contained in:
@@ -236,6 +236,52 @@ bool SwayWindowBackend::switchWorkspace(const QString &workspaceId)
|
||||
return run(QStringLiteral("workspace \"%1\"").arg(quoteCriteriaValue(workspaceId)));
|
||||
}
|
||||
|
||||
bool SwayWindowBackend::updateFocusedGeometry()
|
||||
{
|
||||
if (!m_ipc->isConnected() || m_focusedWindowId == 0)
|
||||
return false;
|
||||
|
||||
const QJsonDocument tree = m_ipc->request(SwayIpcClient::GetTree);
|
||||
if (!tree.isObject())
|
||||
return false;
|
||||
|
||||
QVector<WindowInfo> windows;
|
||||
QVector<WorkspaceInfo> workspaces;
|
||||
collect(tree.object(), {}, {}, false, &windows, &workspaces);
|
||||
|
||||
for (WindowInfo &window : windows) {
|
||||
if (window.id != m_focusedWindowId)
|
||||
continue;
|
||||
for (WindowInfo &cached : m_windows) {
|
||||
if (cached.id != window.id)
|
||||
continue;
|
||||
if (cached.x == window.x
|
||||
&& cached.y == window.y
|
||||
&& cached.width == window.width
|
||||
&& cached.height == window.height
|
||||
&& cached.decoX == window.decoX
|
||||
&& cached.decoY == window.decoY
|
||||
&& cached.decoWidth == window.decoWidth
|
||||
&& cached.decoHeight == window.decoHeight
|
||||
&& cached.fullscreen == window.fullscreen)
|
||||
return false;
|
||||
cached.x = window.x;
|
||||
cached.y = window.y;
|
||||
cached.width = window.width;
|
||||
cached.height = window.height;
|
||||
cached.decoX = window.decoX;
|
||||
cached.decoY = window.decoY;
|
||||
cached.decoWidth = window.decoWidth;
|
||||
cached.decoHeight = window.decoHeight;
|
||||
cached.fullscreen = window.fullscreen;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SwayWindowBackend::tryConnect()
|
||||
{
|
||||
if (m_ipc->isConnected())
|
||||
@@ -422,7 +468,8 @@ bool SwayWindowBackend::isShellChrome(const QJsonObject &node)
|
||||
const QString name = node.value(QStringLiteral("name")).toString();
|
||||
if (name == QLatin1String("Nebula Desktop")
|
||||
|| name == QLatin1String("Nebula Top Bar")
|
||||
|| name == QLatin1String("Nebula Launcher")) {
|
||||
|| name == QLatin1String("Nebula Launcher")
|
||||
|| name == QLatin1String("Nebula Window Chrome")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -491,6 +538,11 @@ void SwayWindowBackend::collect(const QJsonObject &node,
|
||||
window.y = rect.value(QStringLiteral("y")).toInt();
|
||||
window.width = rect.value(QStringLiteral("width")).toInt();
|
||||
window.height = rect.value(QStringLiteral("height")).toInt();
|
||||
const QJsonObject deco = node.value(QStringLiteral("deco_rect")).toObject();
|
||||
window.decoX = deco.value(QStringLiteral("x")).toInt();
|
||||
window.decoY = deco.value(QStringLiteral("y")).toInt();
|
||||
window.decoWidth = deco.value(QStringLiteral("width")).toInt();
|
||||
window.decoHeight = deco.value(QStringLiteral("height")).toInt();
|
||||
windows->append(window);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
bool resizeWindow(qint64 windowId, int width, int height) override;
|
||||
bool snapWindow(qint64 windowId, SnapEdge edge) override;
|
||||
bool switchWorkspace(const QString &workspaceId) override;
|
||||
bool updateFocusedGeometry() override;
|
||||
|
||||
private:
|
||||
void tryConnect();
|
||||
|
||||
Reference in New Issue
Block a user