sway tree
This commit is contained in:
parent
f4a81cfa32
commit
4a6989f5ea
19 changed files with 570 additions and 95 deletions
|
@ -22,6 +22,14 @@ set(PROJECT_SOURCES
|
||||||
${TS_FILES}
|
${TS_FILES}
|
||||||
tree/pstree.cpp
|
tree/pstree.cpp
|
||||||
tree/PsTreeModel.cpp
|
tree/PsTreeModel.cpp
|
||||||
|
sway_bindings/Formatter.h
|
||||||
|
sway_bindings/Sway.cpp
|
||||||
|
tree/swaytree.h
|
||||||
|
tree/swaytree.cpp
|
||||||
|
tree/AbstractTreeModel.h
|
||||||
|
tree/AbstractTreeModel.h
|
||||||
|
tree/SwayTreeModel.h
|
||||||
|
tree/SwayTreeModel.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||||
|
|
16
main.cpp
16
main.cpp
|
@ -1,6 +1,6 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "tree/pstree.h"
|
#include "sway_bindings/Sway.h"
|
||||||
#include "tree/PsTreeModel.h"
|
#include "tree/swaytree.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
@ -9,11 +9,23 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
|
#include<iostream>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
auto sway = Sway();
|
||||||
|
auto resp = sway.sendIPC(SWAY_GET_TREE);
|
||||||
|
json rep = json::parse(resp.msg);
|
||||||
|
auto rootRecord = SwayRecord(rep);
|
||||||
|
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
QCoreApplication::setOrganizationName("Grimmauld");
|
QCoreApplication::setOrganizationName("Grimmauld");
|
||||||
QCoreApplication::setApplicationName("SwayMux");
|
QCoreApplication::setApplicationName("SwayMux");
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "./ui_mainwindow.h"
|
#include "./ui_mainwindow.h"
|
||||||
#include "tree/PsTreeModel.h"
|
#include "tree/PsTreeModel.h"
|
||||||
|
#include "tree/SwayTreeModel.h"
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
: QMainWindow(parent), ui(new Ui::MainWindow) {
|
: QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
model = new PsTreeModel(ui->treeView);
|
model = new SwayTreeModel(ui->treeView);
|
||||||
modelUpdateTimer = new QTimer(this);
|
modelUpdateTimer = new QTimer(this);
|
||||||
connect(modelUpdateTimer, &QTimer::timeout, this, QOverload<>::of(&MainWindow::update));
|
connect(modelUpdateTimer, &QTimer::timeout, this, QOverload<>::of(&MainWindow::update));
|
||||||
modelUpdateTimer->start(1000);
|
modelUpdateTimer->start(1000);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include "tree/PsTreeModel.h"
|
#include "tree/PsTreeModel.h"
|
||||||
|
#include "tree/SwayTreeModel.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -22,7 +23,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
PsTreeModel* model;
|
SwayTreeModel* model;
|
||||||
QTimer* modelUpdateTimer;
|
QTimer* modelUpdateTimer;
|
||||||
};
|
};
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<widget class="QTreeView" name="treeView">
|
<widget class="QTreeView" name="treeView">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<pointsize>24</pointsize>
|
<pointsize>20</pointsize>
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
41
sway_bindings/Formatter.h
Normal file
41
sway_bindings/Formatter.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
// https://stackoverflow.com/questions/12261915/how-to-throw-stdexceptions-with-variable-messages
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPCSWAYTEST_FORMATTER_H
|
||||||
|
#define IPCSWAYTEST_FORMATTER_H
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
class Formatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Formatter() = default;
|
||||||
|
~Formatter() = default;
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
Formatter & operator << (const Type & value)
|
||||||
|
{
|
||||||
|
stream_ << value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str() const { return stream_.str(); }
|
||||||
|
explicit operator std::string () const { return stream_.str(); }
|
||||||
|
|
||||||
|
enum ConvertToString
|
||||||
|
{
|
||||||
|
to_str
|
||||||
|
};
|
||||||
|
std::string operator >> (ConvertToString) { return stream_.str(); }
|
||||||
|
|
||||||
|
Formatter(const Formatter &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::stringstream stream_;
|
||||||
|
// Formatter & operator = (Formatter &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //IPCSWAYTEST_FORMATTER_H
|
37
sway_bindings/Sway.cpp
Normal file
37
sway_bindings/Sway.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Sway.h"
|
||||||
|
|
||||||
|
swaymsg Sway::sendIPC(const swaymsg &query) const {
|
||||||
|
if (send(socketfd, query.asBuffer(), query.size(), 0) == -1) {
|
||||||
|
throw std::runtime_error("Swaysock: Error on send() call");
|
||||||
|
}
|
||||||
|
|
||||||
|
return swaymsg::fromSock(socketfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sway::Sway() : socketfd(socket(AF_UNIX, SOCK_STREAM, 0)) {
|
||||||
|
initializeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sway::initializeSocket() const {
|
||||||
|
auto *sockaddr = std::getenv("SWAYSOCK");
|
||||||
|
if (sockaddr == nullptr) {
|
||||||
|
throw std::runtime_error("Binding socket: reading SWAYSOCK env var failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socketfd == -1) {
|
||||||
|
throw std::runtime_error("Binding socket: could not get file descriptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un swaysock{};
|
||||||
|
swaysock.sun_family = AF_UNIX;
|
||||||
|
strcpy(swaysock.sun_path, sockaddr);
|
||||||
|
auto dlen = strlen(swaysock.sun_path) + sizeof(swaysock.sun_family);
|
||||||
|
|
||||||
|
if (connect(socketfd, (struct sockaddr *) &swaysock, dlen) == -1) {
|
||||||
|
throw std::runtime_error("Binding socket: could not connect to socket");
|
||||||
|
}
|
||||||
|
}
|
23
sway_bindings/Sway.h
Normal file
23
sway_bindings/Sway.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPCSWAYTEST_SWAY_H
|
||||||
|
#define IPCSWAYTEST_SWAY_H
|
||||||
|
|
||||||
|
#include "swaymsg.h"
|
||||||
|
|
||||||
|
class Sway {
|
||||||
|
protected:
|
||||||
|
const int socketfd;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Sway();
|
||||||
|
|
||||||
|
void initializeSocket() const;
|
||||||
|
|
||||||
|
[[nodiscard]] swaymsg sendIPC(const swaymsg& query) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //IPCSWAYTEST_SWAY_H
|
103
sway_bindings/swaymsg.h
Normal file
103
sway_bindings/swaymsg.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPCSWAYTEST_SWAYMSG_H
|
||||||
|
#define IPCSWAYTEST_SWAYMSG_H
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "Formatter.h"
|
||||||
|
|
||||||
|
struct swaymsg {
|
||||||
|
explicit swaymsg(const unsigned int payloadType, const char *msg) : swaymsg(payloadType, msg,
|
||||||
|
msg == nullptr ? 0 : strlen(msg)) {};
|
||||||
|
|
||||||
|
explicit swaymsg(const unsigned int payloadType, const char *msg, const unsigned int payload_len)
|
||||||
|
: payload_len(payload_len), payload_type(payloadType) {
|
||||||
|
|
||||||
|
this->msg = static_cast<char *>(std::malloc(payload_len));
|
||||||
|
std::memcpy(this->msg, msg, payload_len);
|
||||||
|
|
||||||
|
buff = new unsigned char [size()];
|
||||||
|
std::memcpy(buff, magic, strlen(magic));
|
||||||
|
std::memcpy(buff + (unsigned int) strlen(magic), &payload_len, sizeof(payload_len));
|
||||||
|
std::memcpy(buff + (unsigned int) strlen(magic) + sizeof(payload_len), &payload_type, sizeof(payload_type));
|
||||||
|
std::memcpy(buff + (unsigned int) strlen(magic) + sizeof(payload_len) + sizeof(payload_type), msg, payload_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit swaymsg(const unsigned int payloadType) : swaymsg(payloadType, nullptr) {}
|
||||||
|
|
||||||
|
[[nodiscard]] static swaymsg fromSock(const int sockfd) {
|
||||||
|
char buff[6];
|
||||||
|
size_t dlen;
|
||||||
|
if ((dlen = recv(sockfd, buff, 6, 0)) != 6) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for magic: " << dlen
|
||||||
|
>> Formatter::to_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(buff, magic, 6) != 0) {
|
||||||
|
throw std::runtime_error("Swaysock: magic did not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int payloadType;
|
||||||
|
unsigned int payloadLen;
|
||||||
|
static_assert(sizeof(payloadType) == 4);
|
||||||
|
static_assert(sizeof(payloadLen) == 4);
|
||||||
|
|
||||||
|
if ((dlen = recv(sockfd, &payloadLen, sizeof(payloadLen), 0)) != sizeof(payloadLen)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for len: " << dlen >> Formatter::to_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dlen = recv(sockfd, &payloadType, sizeof(payloadType), 0)) != sizeof(payloadType)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for type: " << dlen
|
||||||
|
>> Formatter::to_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
char msgBuff[payloadLen];
|
||||||
|
if ((dlen = recv(sockfd, msgBuff, payloadLen, 0)) != payloadLen) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for message: " << dlen
|
||||||
|
>> Formatter::to_str);
|
||||||
|
}
|
||||||
|
return swaymsg(payloadType, msgBuff, payloadLen);
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const static char *magic = "i3-ipc";
|
||||||
|
const unsigned int payload_len;
|
||||||
|
const unsigned int payload_type;
|
||||||
|
char *msg;
|
||||||
|
unsigned char *buff = nullptr;
|
||||||
|
|
||||||
|
static_assert(sizeof(payload_len) == 4);
|
||||||
|
static_assert(sizeof(payload_type) == 4);
|
||||||
|
|
||||||
|
[[nodiscard]] size_t size() const {
|
||||||
|
return (int) strlen(magic) + sizeof(payload_len) + sizeof(payload_type) + payload_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] void *asBuffer() const {
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
~swaymsg() {
|
||||||
|
delete buff;
|
||||||
|
delete msg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const swaymsg SWAY_EXIT = swaymsg(0, "exit");
|
||||||
|
static const swaymsg SWAY_GET_WORKSPACES = swaymsg(1);
|
||||||
|
static const swaymsg SWAY_GET_OUTPUTS = swaymsg(3);
|
||||||
|
static const swaymsg SWAY_GET_TREE = swaymsg(4);
|
||||||
|
static const swaymsg SWAY_GET_VERSION = swaymsg(7);
|
||||||
|
static const swaymsg SWAY_GET_CONFIG = swaymsg(9);
|
||||||
|
static const swaymsg SWAY_GET_INPUTS = swaymsg(100);
|
||||||
|
|
||||||
|
|
||||||
|
#endif //IPCSWAYTEST_SWAYMSG_H
|
91
tree/AbstractTreeModel.h
Normal file
91
tree/AbstractTreeModel.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SWAYMUX_ABSTRACTTREEMODEL_H
|
||||||
|
#define SWAYMUX_ABSTRACTTREEMODEL_H
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include "AbstractTreeNode.h"
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class AbstractTreeModel : public QAbstractItemModel {
|
||||||
|
static_assert(std::is_base_of<AbstractTreeNode<T>, T>::value,
|
||||||
|
"Tree model subject class is not derived from AbstractTreeNode");
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_DISABLE_COPY_MOVE(AbstractTreeModel)
|
||||||
|
|
||||||
|
explicit AbstractTreeModel(QObject *parent = nullptr): QAbstractItemModel(parent) {};
|
||||||
|
|
||||||
|
~AbstractTreeModel() override = default;
|
||||||
|
|
||||||
|
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override {
|
||||||
|
if (!index.isValid() || role != Qt::DisplayRole)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto *item = static_cast<const T *>(index.internalPointer());
|
||||||
|
return item->data(index.column());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override {
|
||||||
|
return index.isValid()
|
||||||
|
? QAbstractItemModel::flags(index) : Qt::ItemFlags(Qt::NoItemFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override {
|
||||||
|
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
|
||||||
|
return QVariant{};
|
||||||
|
|
||||||
|
return T{}.headerData(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QModelIndex index(int row, int column,
|
||||||
|
const QModelIndex &parent = {}) const override {
|
||||||
|
if (!hasIndex(row, column, parent))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const T *parentItem = parent.isValid()
|
||||||
|
? static_cast<T *>(parent.internalPointer())
|
||||||
|
: getRoot();
|
||||||
|
|
||||||
|
if (auto *childItem = parentItem->child(row))
|
||||||
|
return createIndex(row, column, childItem);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QModelIndex parent(const QModelIndex &index) const override {
|
||||||
|
if (!index.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto *childItem = static_cast<T *>(index.internalPointer());
|
||||||
|
T *parentItem = childItem->parentItem();
|
||||||
|
|
||||||
|
return parentItem != getRoot()
|
||||||
|
? createIndex(parentItem->row(), 0, parentItem) : QModelIndex{};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int rowCount(const QModelIndex &parent = {}) const override {
|
||||||
|
if (parent.column() > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const T *parentItem = parent.isValid()
|
||||||
|
? static_cast<const T *>(parent.internalPointer())
|
||||||
|
: getRoot();
|
||||||
|
|
||||||
|
return parentItem->childCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int columnCount(const QModelIndex &parent = {}) const override {
|
||||||
|
if (parent.isValid())
|
||||||
|
return static_cast<T *>(parent.internalPointer())->columnCount();
|
||||||
|
return T{}.columnCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual const T* getRoot() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SWAYMUX_ABSTRACTTREEMODEL_H
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class AbstractTreeNode {
|
class AbstractTreeNode {
|
||||||
// static_assert(std::is_base_of<AbstractTreeNode, T>::value, "Derived not derived from BaseClass");
|
|
||||||
public:
|
public:
|
||||||
std::vector<std::unique_ptr<T>> children{};
|
std::vector<std::unique_ptr<T>> children{};
|
||||||
|
|
||||||
|
|
|
@ -4,76 +4,17 @@
|
||||||
|
|
||||||
#include "PsTreeModel.h"
|
#include "PsTreeModel.h"
|
||||||
|
|
||||||
PsTreeModel::PsTreeModel(QObject *parent) : QAbstractItemModel(parent), rootItem(get_process_records()) {}
|
|
||||||
|
|
||||||
QModelIndex PsTreeModel::index(int row, int column, const QModelIndex &parent) const {
|
|
||||||
if (!hasIndex(row, column, parent))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const ProcessTreeNode *parentItem = parent.isValid()
|
|
||||||
? static_cast<ProcessTreeNode *>(parent.internalPointer())
|
|
||||||
: &rootItem;
|
|
||||||
|
|
||||||
if (auto *childItem = parentItem->child(row))
|
|
||||||
return createIndex(row, column, childItem);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex PsTreeModel::parent(const QModelIndex &index) const {
|
|
||||||
if (!index.isValid())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
auto *childItem = static_cast<ProcessTreeNode *>(index.internalPointer());
|
|
||||||
ProcessTreeNode *parentItem = childItem->parentItem();
|
|
||||||
|
|
||||||
return parentItem != &rootItem
|
|
||||||
? createIndex(parentItem->row(), 0, parentItem) : QModelIndex{};
|
|
||||||
}
|
|
||||||
|
|
||||||
int PsTreeModel::rowCount(const QModelIndex &parent) const {
|
|
||||||
if (parent.column() > 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const ProcessTreeNode *parentItem = parent.isValid()
|
|
||||||
? static_cast<const ProcessTreeNode *>(parent.internalPointer())
|
|
||||||
: &rootItem;
|
|
||||||
|
|
||||||
return parentItem->childCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
int PsTreeModel::columnCount(const QModelIndex &parent) const {
|
|
||||||
if (parent.isValid())
|
|
||||||
return static_cast<ProcessTreeNode *>(parent.internalPointer())->columnCount();
|
|
||||||
return ProcessTreeNode{}.columnCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant PsTreeModel::data(const QModelIndex &index, int role) const {
|
|
||||||
if (!index.isValid() || role != Qt::DisplayRole)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const auto *item = static_cast<const ProcessTreeNode *>(index.internalPointer());
|
|
||||||
return item->data(index.column());
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::ItemFlags PsTreeModel::flags(const QModelIndex &index) const {
|
|
||||||
return index.isValid()
|
|
||||||
? QAbstractItemModel::flags(index) : Qt::ItemFlags(Qt::NoItemFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant PsTreeModel::headerData(int section, Qt::Orientation orientation,
|
|
||||||
int role) const {
|
|
||||||
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
|
|
||||||
return QVariant{};
|
|
||||||
|
|
||||||
return ProcessTreeNode{}.headerData(section);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PsTreeModel::update() {
|
void PsTreeModel::update() {
|
||||||
auto changes = update_process_records(&rootItem);
|
/*
|
||||||
|
auto* root = getRoot();
|
||||||
|
auto changes = update_process_records(root);
|
||||||
|
|
||||||
QList<QPersistentModelIndex> changedParents{};
|
QList<QPersistentModelIndex> changedParents{};
|
||||||
for(auto* node: changes) {
|
for(auto* node: changes) {
|
||||||
changedParents.push_back(createIndex(node->row(), 0, node));
|
changedParents.push_back(createIndex(node->row(), 0, node));
|
||||||
}
|
}
|
||||||
layoutAboutToBeChanged(changedParents);
|
layoutAboutToBeChanged(changedParents);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PsTreeModel::PsTreeModel(QObject *parent) : PsTreeModel(get_process_records(), parent) {}
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include "pstree.h"
|
#include "pstree.h"
|
||||||
|
#include "AbstractTreeModel.h"
|
||||||
|
|
||||||
class PsTreeModel : public QAbstractItemModel {
|
class PsTreeModel : public AbstractTreeModel<ProcessTreeNode> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_DISABLE_COPY_MOVE(PsTreeModel)
|
Q_DISABLE_COPY_MOVE(PsTreeModel)
|
||||||
|
|
||||||
|
@ -19,26 +19,16 @@ public:
|
||||||
|
|
||||||
~PsTreeModel() override = default;
|
~PsTreeModel() override = default;
|
||||||
|
|
||||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
|
explicit PsTreeModel(ProcessTreeNode * rootItem, QObject *parent = nullptr) : rootItem(rootItem), AbstractTreeModel<ProcessTreeNode>(parent) {};
|
||||||
|
|
||||||
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation,
|
|
||||||
int role = Qt::DisplayRole) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] QModelIndex index(int row, int column,
|
|
||||||
const QModelIndex &parent = {}) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] QModelIndex parent(const QModelIndex &index) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] int rowCount(const QModelIndex &parent = {}) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] int columnCount(const QModelIndex &parent = {}) const override;
|
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
[[nodiscard]] const ProcessTreeNode *getRoot() const override {
|
||||||
|
return rootItem;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProcessTreeNode rootItem;
|
const ProcessTreeNode* rootItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
5
tree/SwayTreeModel.cpp
Normal file
5
tree/SwayTreeModel.cpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SwayTreeModel.h"
|
49
tree/SwayTreeModel.h
Normal file
49
tree/SwayTreeModel.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SWAYMUX_SWAYTREEMODEL_H
|
||||||
|
#define SWAYMUX_SWAYTREEMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <utility>
|
||||||
|
#include "pstree.h"
|
||||||
|
#include "AbstractTreeModel.h"
|
||||||
|
#include "swaytree.h"
|
||||||
|
#include "../sway_bindings/Sway.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
class SwayTreeModel : public AbstractTreeModel<SwayTreeNode> {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline static Sway sway = Sway();
|
||||||
|
|
||||||
|
Q_DISABLE_COPY_MOVE(SwayTreeModel)
|
||||||
|
|
||||||
|
explicit SwayTreeModel(QObject *parent = nullptr) : AbstractTreeModel<SwayTreeNode>(parent) {
|
||||||
|
auto res = sway.sendIPC(SWAY_GET_TREE);
|
||||||
|
auto rep = json::parse(res.msg);
|
||||||
|
rootItem = new SwayTreeNode(rep);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SwayTreeModel() override = default;
|
||||||
|
|
||||||
|
explicit SwayTreeModel(SwayTreeNode * rootItem, QObject *parent = nullptr) : rootItem(rootItem),
|
||||||
|
AbstractTreeModel<SwayTreeNode>(
|
||||||
|
parent) {};
|
||||||
|
|
||||||
|
[[nodiscard]] const SwayTreeNode *getRoot() const override {
|
||||||
|
return rootItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
SwayTreeNode * rootItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //SWAYMUX_SWAYTREEMODEL_H
|
|
@ -48,9 +48,9 @@ void populateTree(ProcessTreeNode *node, std::map<pid_t, std::set<ProcessRecord>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessTreeNode get_process_records() {
|
ProcessTreeNode * get_process_records() {
|
||||||
ProcessTreeNode root = ProcessTreeNode(); // rootPrc
|
auto* root = new ProcessTreeNode(); // rootPrc
|
||||||
update_process_records(&root);
|
update_process_records(root);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,9 @@ void printTree(const ProcessTreeNode &node, const std::string &prefix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void printTree() {
|
void printTree() {
|
||||||
printTree(get_process_records(), "");
|
auto* tree = get_process_records();
|
||||||
|
printTree(*tree, "");
|
||||||
|
delete tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ProcessTreeNode::data(int column) const {
|
QVariant ProcessTreeNode::data(int column) const {
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
|
|
||||||
ProcessRecord(std::string name, pid_t pid, pid_t ppid) : name(std::move(name)), pid(pid), ppid(ppid) {}
|
ProcessRecord(std::string name, pid_t pid, pid_t ppid) : name(std::move(name)), pid(pid), ppid(ppid) {}
|
||||||
|
|
||||||
ProcessRecord() : name("root"), pid(0), ppid(-1) {}
|
ProcessRecord() : name("rootItem"), pid(0), ppid(-1) {}
|
||||||
|
|
||||||
[[nodiscard]] bool operator<(const ProcessRecord &other) const {
|
[[nodiscard]] bool operator<(const ProcessRecord &other) const {
|
||||||
return this->pid < other.pid;
|
return this->pid < other.pid;
|
||||||
|
@ -43,6 +43,9 @@ public:
|
||||||
|
|
||||||
class ProcessTreeNode : public AbstractTreeNode<ProcessTreeNode> {
|
class ProcessTreeNode : public AbstractTreeNode<ProcessTreeNode> {
|
||||||
public:
|
public:
|
||||||
|
ProcessTreeNode(ProcessTreeNode& node) = delete; // default constructor to make the static asserts shut up
|
||||||
|
ProcessTreeNode(const ProcessTreeNode& node) = delete; // default constructor to make the static asserts shut up
|
||||||
|
|
||||||
explicit ProcessTreeNode(ProcessTreeNode *parent = nullptr) : proc(ProcessRecord()), AbstractTreeNode(parent) {}
|
explicit ProcessTreeNode(ProcessTreeNode *parent = nullptr) : proc(ProcessRecord()), AbstractTreeNode(parent) {}
|
||||||
|
|
||||||
const ProcessRecord proc;
|
const ProcessRecord proc;
|
||||||
|
@ -67,7 +70,7 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
ProcessTreeNode get_process_records();
|
ProcessTreeNode * get_process_records();
|
||||||
|
|
||||||
void insert_process_record(const std::filesystem::path &status_path, std::map<pid_t, ProcessRecord> &buff);
|
void insert_process_record(const std::filesystem::path &status_path, std::map<pid_t, ProcessRecord> &buff);
|
||||||
|
|
||||||
|
|
14
tree/swaytree.cpp
Normal file
14
tree/swaytree.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "swaytree.h"
|
||||||
|
|
||||||
|
QVariant SwayTreeNode::data(int column) const {
|
||||||
|
// TODO: maybe add a more elaborate representation
|
||||||
|
return QString::fromStdString(node.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SwayTreeNode::headerData(int column) const {
|
||||||
|
return "Title";
|
||||||
|
}
|
155
tree/swaytree.h
Normal file
155
tree/swaytree.h
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SWAYMUX_SWAYTREE_H
|
||||||
|
#define SWAYMUX_SWAYTREE_H
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
#include "AbstractTreeNode.h"
|
||||||
|
|
||||||
|
namespace NodeType {
|
||||||
|
enum NodeType {
|
||||||
|
root, output, workspace, con, floating_con
|
||||||
|
};
|
||||||
|
|
||||||
|
static NodeType fromString(const std::string &str) {
|
||||||
|
if (str == "output") {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
if (str == "workspace") {
|
||||||
|
return workspace;
|
||||||
|
}
|
||||||
|
if (str == "con") {
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
if (str == "floating_con") {
|
||||||
|
return floating_con;
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace NodeLayout {
|
||||||
|
enum NodeLayout {
|
||||||
|
splith, splitv, stacked, tabbed, output
|
||||||
|
};
|
||||||
|
|
||||||
|
static NodeLayout fromString(const std::string &str) {
|
||||||
|
if (str == "splith") {
|
||||||
|
return splith;
|
||||||
|
}
|
||||||
|
if (str == "splitv") {
|
||||||
|
return splitv;
|
||||||
|
}
|
||||||
|
if (str == "stacked") {
|
||||||
|
return stacked;
|
||||||
|
}
|
||||||
|
if (str == "tabbed") {
|
||||||
|
return tabbed;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace NodeOrientation {
|
||||||
|
enum NodeOrientation {
|
||||||
|
vertical, horizontal, none
|
||||||
|
};
|
||||||
|
|
||||||
|
static NodeOrientation fromString(const std::string &str) {
|
||||||
|
if (str == "vertical") {
|
||||||
|
return vertical;
|
||||||
|
}
|
||||||
|
if (str == "horizontal") {
|
||||||
|
return horizontal;
|
||||||
|
}
|
||||||
|
return none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SwayRecord {
|
||||||
|
explicit SwayRecord() :
|
||||||
|
id(0),
|
||||||
|
name("rootItem"),
|
||||||
|
type(NodeType::root),
|
||||||
|
current_border_width(0),
|
||||||
|
layout(NodeLayout::output),
|
||||||
|
orientation(NodeOrientation::none),
|
||||||
|
urgent(false),
|
||||||
|
sticky(false),
|
||||||
|
focused(false) {}
|
||||||
|
|
||||||
|
explicit SwayRecord(const json &rep) :
|
||||||
|
id(rep["id"]),
|
||||||
|
name(rep["name"]),
|
||||||
|
type(NodeType::fromString(rep["type"])),
|
||||||
|
border(rep["border"]),
|
||||||
|
current_border_width(rep["current_border_width"]),
|
||||||
|
layout(NodeLayout::fromString((rep["layout"]))),
|
||||||
|
orientation(NodeOrientation::fromString(rep["orientation"])),
|
||||||
|
urgent(rep["urgent"]),
|
||||||
|
sticky(rep["sticky"]),
|
||||||
|
focused(rep["focused"]) {};
|
||||||
|
|
||||||
|
const int id;
|
||||||
|
const std::string name;
|
||||||
|
const NodeType::NodeType type;
|
||||||
|
const std::string border;
|
||||||
|
const int current_border_width;
|
||||||
|
const NodeLayout::NodeLayout layout;
|
||||||
|
const NodeOrientation::NodeOrientation orientation;
|
||||||
|
const bool urgent;
|
||||||
|
const bool sticky;
|
||||||
|
const bool focused;
|
||||||
|
|
||||||
|
[[nodiscard]] bool operator<(const SwayRecord &other) const {
|
||||||
|
return this->id < other.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool operator==(const SwayRecord &other) const {
|
||||||
|
return this->id == other.id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SwayTreeNode : public AbstractTreeNode<SwayTreeNode> {
|
||||||
|
public:
|
||||||
|
const SwayRecord node;
|
||||||
|
|
||||||
|
explicit SwayTreeNode(const json &rep, SwayTreeNode *parent = nullptr) : node(SwayRecord(rep)),
|
||||||
|
AbstractTreeNode(parent) {
|
||||||
|
for (const auto &child: rep["nodes"]) {
|
||||||
|
auto childNode = std::make_unique<SwayTreeNode>(child, this);
|
||||||
|
this->appendChild(childNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (const auto &child: rep["floating_nodes"]) {
|
||||||
|
auto childNode = std::make_unique<SwayTreeNode>(child, this);
|
||||||
|
this->appendChild(childNode);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit SwayTreeNode(SwayTreeNode *parent = nullptr) : node(SwayRecord()), AbstractTreeNode(parent) {};
|
||||||
|
|
||||||
|
explicit SwayTreeNode(SwayRecord node, SwayTreeNode *parent = nullptr) : node(std::move(node)),
|
||||||
|
AbstractTreeNode(parent) {};
|
||||||
|
|
||||||
|
[[nodiscard]] bool operator<(const SwayTreeNode &other) const {
|
||||||
|
return this->node < other.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QVariant data(int column) const override;
|
||||||
|
|
||||||
|
[[nodiscard]] QVariant headerData(int column) const override;
|
||||||
|
|
||||||
|
[[nodiscard]] int columnCount() const override { return 1; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SWAYMUX_SWAYTREE_H
|
Loading…
Reference in a new issue