diff --git a/CMakeLists.txt b/CMakeLists.txt index 80fe64d..b137ca7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,9 @@ set(PROJECT_SOURCES Keys/MoveToScratchpadKeyListener.h Keys/RestoreKeyListener.h Keys/MainWindowAwareKeyListener.h + Keys/ToggleDetailsKeyListener.h + sway_bindings/SwayRecords.cpp + sway_bindings/SwayRecords.h ) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) diff --git a/Keys/MainWindowAwareKeyListener.h b/Keys/MainWindowAwareKeyListener.h index bc316d2..1a48201 100644 --- a/Keys/MainWindowAwareKeyListener.h +++ b/Keys/MainWindowAwareKeyListener.h @@ -53,7 +53,7 @@ protected: return nullptr; } -private: +protected: MainWindow *window; [[nodiscard]] SwayTreeModel* getModel() const { diff --git a/Keys/SwitchToKeybindListener.h b/Keys/SwitchToKeybindListener.h index 37a147f..acbdc48 100644 --- a/Keys/SwitchToKeybindListener.h +++ b/Keys/SwitchToKeybindListener.h @@ -85,7 +85,7 @@ public: } std::string getKeyText() override { - return "ENTER"; + return "Enter"; } [[nodiscard]] bool canAcceptKey(int key) const override { diff --git a/Keys/ToggleDetailsKeyListener.h b/Keys/ToggleDetailsKeyListener.h new file mode 100644 index 0000000..b353b19 --- /dev/null +++ b/Keys/ToggleDetailsKeyListener.h @@ -0,0 +1,34 @@ +// +// Created by grimmauld on 12.03.24. +// + +#ifndef SWAYMUX_TOGGLEDETAILSKEYLISTENER_H +#define SWAYMUX_TOGGLEDETAILSKEYLISTENER_H + +#include "MainWindowAwareKeyListener.h" + +class ToggleDetailsKeyListener : public MainWindowAwareKeyListener { +public: + explicit ToggleDetailsKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {} + + void handleKeyEvent(const QKeyEvent *keyEvent) const override { + if (window->ui->windowDetails->isHidden()) + window->ui->windowDetails->show(); + else + window->ui->windowDetails->hide(); + } + + std::string getDescription() override { + return "toggle window detail view"; + } + + std::string getKeyText() override { + return "Tab"; + } + + [[nodiscard]] bool canAcceptKey(int key) const override { + return key == Qt::Key_Tab; + } +}; + +#endif //SWAYMUX_TOGGLEDETAILSKEYLISTENER_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 7d541bc..9edc41c 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -11,6 +11,7 @@ #include "Keys/CloseKeyListener.h" #include "Keys/MoveToScratchpadKeyListener.h" #include "Keys/RestoreKeyListener.h" +#include "Keys/ToggleDetailsKeyListener.h" #include #include @@ -34,6 +35,7 @@ MainWindow::MainWindow(QWidget *parent) swayTreeKeyHandler->addListener(new CloseKeyListener(this)); swayTreeKeyHandler->addListener(new MoveToScratchpadKeyListener(this)); swayTreeKeyHandler->addListener(new RestoreKeyListener(this)); + swayTreeKeyHandler->addListener(new ToggleDetailsKeyListener(this)); closeHelpKeyHandler = new KeyHandler(ui->tree_page); closeHelpKeyHandler->addListener(new CloseHelpKeyListener(ui->tree_page)); @@ -44,6 +46,12 @@ MainWindow::MainWindow(QWidget *parent) ui->tableView->setModel(swayTreeKeyHandler); ui->tableView->resizeColumnsToContents(); ui->tableView->installEventFilter(closeHelpKeyHandler); + + ui->windowDetails->hide(); + selChanged(); + + connect( ui->treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(selChanged()), Qt::DirectConnection ) ; } MainWindow::~MainWindow() { @@ -54,6 +62,7 @@ MainWindow::~MainWindow() { } void MainWindow::updateModel() const { + ui->windowDetails->setModel(nullptr); ui->treeView->setModel(nullptr); auto *focused = model->getRoot() == nullptr ? nullptr : model->getRoot()->findFocused(); int id; @@ -74,4 +83,15 @@ void MainWindow::updateModel() const { ui->treeView->selectionModel()->setCurrentIndex(model->findIndexByNode(focused), QItemSelectionModel::ClearAndSelect); for (int c = 0; c < model->columnCount(); ++c) ui->treeView->resizeColumnToContents(c); + + selChanged(); } + +void MainWindow::selChanged() const { + auto current = ui->treeView->selectionModel()->currentIndex(); + auto *selected = model->getSelectedNode(current); + ui->windowDetails->setModel(nullptr); + ui->windowDetails->setModel(&selected->node); + ui->windowDetails->resizeColumnsToContents(); + ui->windowDetails->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); +} \ No newline at end of file diff --git a/mainwindow.h b/mainwindow.h index 9f18a92..2992ce8 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -23,9 +23,9 @@ public: SwayTreeModel* model; Ui::MainWindow *ui; - +public slots: + void selChanged() const; private: - // QTimer* modelUpdateTimer{}; KeyHandler* swayTreeKeyHandler; KeyHandler* closeHelpKeyHandler; }; diff --git a/mainwindow.ui b/mainwindow.ui index 8d20a4d..8552e95 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -26,6 +26,11 @@ 0 + + + 20 + + @@ -41,13 +46,10 @@ - - - - 20 - - - + + + + @@ -59,14 +61,8 @@ - - - - - 20 - - - + + diff --git a/sway_bindings/SwayRecords.cpp b/sway_bindings/SwayRecords.cpp new file mode 100644 index 0000000..9271a35 --- /dev/null +++ b/sway_bindings/SwayRecords.cpp @@ -0,0 +1,23 @@ +// +// Created by grimmauld on 12.03.24. +// + +#include "SwayRecords.h" + +QVariant SwayRecord::data(const QModelIndex &index, int role) const { + if (!index.isValid() || role != Qt::DisplayRole) + return {}; + + switch (index.column()) { + case 0: + return QString::fromStdString(jsonFields[index.row()].first); + case 1: + return QString::fromStdString(jsonFields[index.row()].second); + default: + return {}; + } +} + +bool SwayRecord::shouldIgnoreKey(const std::string &key) { + return key == "floating_nodes" || key == "nodes"; +} diff --git a/sway_bindings/SwayRecords.h b/sway_bindings/SwayRecords.h new file mode 100644 index 0000000..838b3d0 --- /dev/null +++ b/sway_bindings/SwayRecords.h @@ -0,0 +1,224 @@ +// +// Created by grimmauld on 12.03.24. +// + +#ifndef SWAYMUX_SWAYRECORDS_H +#define SWAYMUX_SWAYRECORDS_H + + +#include +#include +#include +#include + +using json = nlohmann::json; + +#include "Sway.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; + } + + static std::string toString(NodeType nodeType) { + switch (nodeType) { + case output: + return "output"; + case workspace: + return "workspace"; + case con: + return "con"; + case floating_con: + return "floating_con"; + default: + return "root"; + } + } + + + static QString toQString(NodeType nodeType) { + return QString::fromStdString(toString(nodeType)); + } +} + +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; + } + + static std::string toString(NodeLayout nodeLayout) { + switch (nodeLayout) { + case splith: + return "splith"; + case splitv: + return "splitv"; + case stacked: + return "stacked"; + case tabbed: + return "tabbed"; + default: + return "output"; + } + } + + static QString toQString(NodeLayout nodeLayout) { + return QString::fromStdString(toString(nodeLayout)); + } +} + +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; + } + + static std::string toString(NodeOrientation nodeOrientation) { + switch (nodeOrientation) { + case vertical: + return "vertical"; + case horizontal: + return "horizontal"; + default: + return "none"; + } + } + + static QString toQString(NodeOrientation nodeOrientation) { + return QString::fromStdString(toString(nodeOrientation)); + } +} + +struct SwayRecord : public QAbstractTableModel { + 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), + QAbstractTableModel(nullptr){} + + [[nodiscard]] static bool shouldIgnoreKey(const std::string &key); + + explicit SwayRecord(const json &rep) : + id(rep["id"]), + name(getName(rep)), + 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"]), + QAbstractTableModel(nullptr) { + for (json::const_iterator it = rep.cbegin(); it != rep.cend(); ++it) { + if (!SwayRecord::shouldIgnoreKey(it.key())) + jsonFields.emplace_back(it.key(), it.value().dump()); + } + }; + 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; + 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; + } + + [[nodiscard]] int rowCount(const QModelIndex &parent) const override { + return (int) jsonFields.size(); + } + + [[nodiscard]] int columnCount(const QModelIndex &parent) const override { + return 2; + } + + [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; + + [[nodiscard]] QVariant headerData(int section, Qt::Orientation qtOrientation, + int role) const override { + if (qtOrientation != Qt::Horizontal || role != Qt::DisplayRole) + return QVariant{}; + + switch (section) { + case 0: + return "Field"; + case 1: + return "State"; + default: + return QVariant{}; + } + } + +private: + std::vector> jsonFields; + + static std::string getName(const json& rep) { + if(rep["name"].is_null()) + return "Untitled Container"; + std::string internal = rep["name"]; + if (internal == "__i3" && NodeType::fromString(rep["type"]) == NodeType::output) + return "Virtual Display"; + if (internal == "__i3_scratch" && NodeType::fromString(rep["type"]) == NodeType::workspace) + return "Scratchpad"; + return internal; + } +}; + + +#endif //SWAYMUX_SWAYRECORDS_H diff --git a/sway_bindings/swaymsg.h b/sway_bindings/swaymsg.h index 8024bd4..d40b836 100644 --- a/sway_bindings/swaymsg.h +++ b/sway_bindings/swaymsg.h @@ -20,7 +20,7 @@ struct swaymsg { 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(std::malloc(payload_len)); + this->msg = new char[payload_len]; std::memcpy(this->msg, msg, payload_len); buff = new unsigned char [size()]; diff --git a/tree/swaytree.h b/tree/swaytree.h index b5e0851..38af2bc 100644 --- a/tree/swaytree.h +++ b/tree/swaytree.h @@ -9,124 +9,11 @@ #include #include + using json = nlohmann::json; +#include "../sway_bindings/SwayRecords.h" #include "AbstractTreeNode.h" -#include "../sway_bindings/Sway.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(getName(rep)), - 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; - 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; - } -private: - static std::string getName(const json& rep) { - if(rep["name"].is_null()) - return "Untitled Container"; - std::string internal = rep["name"]; - if (internal == "__i3" && NodeType::fromString(rep["type"]) == NodeType::output) - return "Virtual Display"; - if (internal == "__i3_scratch" && NodeType::fromString(rep["type"]) == NodeType::workspace) - return "Scratchpad"; - return internal; - } -}; class SwayTreeNode : public AbstractTreeNode { public: @@ -151,8 +38,7 @@ public: explicit SwayTreeNode(SwayTreeNode *parent = nullptr) : node(SwayRecord()), AbstractTreeNode(parent) {}; - explicit SwayTreeNode(SwayRecord node, SwayTreeNode *parent = nullptr) : node(std::move(node)), - 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;