Add Nebula.Windows with Sway IPC backend

Introduces a new `core/windows` module (`Nebula.Windows`) with `WindowService`, window/workspace models, and a Sway IPC backend for live window tracking and control (focus, close, move/resize, snap, maximize/restore, minimize, workspace switch). The desktop shell now links this module, uses compositor focus for top-bar active app text, and adds an Open Windows section in the launcher with focus/close actions.

Also updates application metadata handling to parse `StartupWMClass` and map window `app_id`/class to friendly names and icons, and revises Sway config/docs for the new floating-first Desktop 0.2 behavior with temporary compositor-provided decorations.
This commit is contained in:
2026-08-26 18:20:56 +12:00
parent 8c07c10050
commit 2f59d3c115
29 changed files with 2177 additions and 35 deletions
+84
View File
@@ -0,0 +1,84 @@
#include "WorkspaceModel.hpp"
#include <utility>
WorkspaceModel::WorkspaceModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int WorkspaceModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return m_workspaces.size();
}
int WorkspaceModel::count() const
{
return m_workspaces.size();
}
QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_workspaces.size())
return {};
const WorkspaceInfo &workspace = m_workspaces.at(index.row());
switch (role) {
case WorkspaceIdRole:
return workspace.id;
case NameRole:
case Qt::DisplayRole:
return workspace.name;
case NumberRole:
return workspace.number;
case FocusedRole:
return workspace.focused;
case VisibleRole:
return workspace.visible;
case OutputRole:
return workspace.output;
case WindowCountRole:
return workspace.windowCount;
default:
return {};
}
}
QHash<int, QByteArray> WorkspaceModel::roleNames() const
{
return {
{WorkspaceIdRole, QByteArrayLiteral("workspaceId")},
{NameRole, QByteArrayLiteral("name")},
{NumberRole, QByteArrayLiteral("number")},
{FocusedRole, QByteArrayLiteral("focused")},
{VisibleRole, QByteArrayLiteral("visible")},
{OutputRole, QByteArrayLiteral("output")},
{WindowCountRole, QByteArrayLiteral("windowCount")},
};
}
void WorkspaceModel::setWorkspaces(QVector<WorkspaceInfo> workspaces)
{
beginResetModel();
m_workspaces = std::move(workspaces);
endResetModel();
emit countChanged();
}
const WorkspaceInfo *WorkspaceModel::workspaceAt(int row) const
{
if (row < 0 || row >= m_workspaces.size())
return nullptr;
return &m_workspaces.at(row);
}
const WorkspaceInfo *WorkspaceModel::focusedWorkspace() const
{
for (const WorkspaceInfo &workspace : m_workspaces) {
if (workspace.focused)
return &workspace;
}
return nullptr;
}