Add new functions

- move to scratch
- restore (move selected to new workspace)
- close
This commit is contained in:
LordGrimmauld 2024-03-11 13:33:26 +01:00
parent 293a12d0b7
commit f3b60a4a2a
10 changed files with 255 additions and 35 deletions

View File

@ -43,6 +43,10 @@ set(PROJECT_SOURCES
Keys/JumpOutputKeyListener.h Keys/JumpOutputKeyListener.h
Keys/PrevOutputKeyListener.h Keys/PrevOutputKeyListener.h
Keys/NextOutputKeyListener.h Keys/NextOutputKeyListener.h
Keys/CloseKeyListener.h
Keys/MoveToScratchpadKeyListener.h
Keys/MoveToScratchpadKeyListener.h
Keys/RestoreKeyListener.h
) )
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)

58
Keys/CloseKeyListener.h Normal file
View File

@ -0,0 +1,58 @@
//
// Created by grimmauld on 11.03.24.
//
#ifndef SWAYMUX_CLOSEKEYLISTENER_H
#define SWAYMUX_CLOSEKEYLISTENER_H
#include "AbstractKeyListener.h"
class CloseKeyListener : public AbstractKeyListener {
public:
explicit CloseKeyListener(MainWindow *pWindow) : window(pWindow) {}
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
auto selectedNodes = window->model->getSelectedNodes(window->ui->treeView);
std::set<int> containersToKill;
for (auto* container: selectedNodes) {
auto containers = container->accumulateContainers();
for (auto* containerToMove : container->accumulateContainers()) {
containersToKill.insert(containerToMove->node.id);
}
}
if (containersToKill.empty())
return;
Formatter cmd;
for (auto id: containersToKill) {
cmd << "[con_id=" << id << "] kill ; ";
}
std::cout << cmd.str() << "\n";
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
std::cout << resp.msg << "\n";
usleep(100000); // give sway time to react. Not great but works i guess.
window->updateModel();
}
std::string getDescription() override {
return "Close selected windows";
}
std::string getKeyText() override {
return "Q / DEL";
}
[[nodiscard]] bool canAcceptKey(int key) const override {
return key == Qt::Key_Q || key == Qt::Key_Delete;
}
private:
MainWindow *window;
};
#endif //SWAYMUX_CLOSEKEYLISTENER_H

View File

@ -0,0 +1,61 @@
//
// Created by grimmauld on 11.03.24.
//
#ifndef SWAYMUX_MOVETOSCRATCHPADKEYLISTENER_H
#define SWAYMUX_MOVETOSCRATCHPADKEYLISTENER_H
#include "AbstractKeyListener.h"
#include "../mainwindow.h"
#include "../sway_bindings/Formatter.h"
#include "../tree/SwayTreeModel.h"
class MoveToScratchpadKeyListener : public AbstractKeyListener {
public:
explicit MoveToScratchpadKeyListener(MainWindow *pWindow) : window(pWindow) {}
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
auto selectedNodes = window->model->getSelectedNodes(window->ui->treeView);
std::set<int> containersToScratch;
for (auto* container: selectedNodes) {
auto containers = container->accumulateContainers();
for (auto* containerToMove : container->accumulateContainers()) {
containersToScratch.insert(containerToMove->node.id);
}
}
if (containersToScratch.empty())
return;
Formatter cmd;
for (auto id: containersToScratch) {
cmd << "[con_id=" << id << "] move scratchpad ; ";
}
std::cout << cmd.str() << "\n";
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
std::cout << resp.msg << "\n";
usleep(100000); // give sway time to react. Not great but works i guess.
window->updateModel();
}
std::string getDescription() override {
return "Move selected windows to scratchpad";
}
std::string getKeyText() override {
return "-";
}
[[nodiscard]] bool canAcceptKey(int key) const override {
return key == Qt::Key_Minus;
}
private:
MainWindow *window;
};
#endif //SWAYMUX_MOVETOSCRATCHPADKEYLISTENER_H

65
Keys/RestoreKeyListener.h Normal file
View File

@ -0,0 +1,65 @@
//
// Created by grimmauld on 11.03.24.
//
#ifndef SWAYMUX_RESTOREKEYLISTENER_H
#define SWAYMUX_RESTOREKEYLISTENER_H
#include "AbstractKeyListener.h"
#include "../mainwindow.h"
#include "../sway_bindings/Formatter.h"
#include "../tree/SwayTreeModel.h"
class RestoreKeyListener : public AbstractKeyListener {
public:
explicit RestoreKeyListener(MainWindow *pWindow) : window(pWindow) {}
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
auto selectedNodes = window->model->getSelectedNodes(window->ui->treeView);
std::set<int> containersToScratch;
for (auto* container: selectedNodes) {
auto containers = container->accumulateContainers();
for (auto* containerToMove : container->accumulateContainers()) {
containersToScratch.insert(containerToMove->node.id);
}
}
if (containersToScratch.empty())
return;
Formatter cmd;
auto used_workspaces = window->model->getRoot()->accumulateWorkspaces();
int i = 1; // workspace 1 is the first one. We don't expect our users to be programmers.
for (; used_workspaces.contains(std::to_string(i)); ++i) {}
for (auto id: containersToScratch) {
cmd << "[con_id=" << id << "] move workspace " << i << " ; ";
}
std::cout << cmd.str() << "\n";
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
std::cout << resp.msg << "\n";
usleep(100000); // give sway time to react. Not great but works i guess.
window->updateModel();
}
std::string getDescription() override {
return "Restore selected windows to a new workspace";
}
std::string getKeyText() override {
return "+";
}
[[nodiscard]] bool canAcceptKey(int key) const override {
return key == Qt::Key_Plus;
}
private:
MainWindow *window;
};
#endif //SWAYMUX_RESTOREKEYLISTENER_H

View File

@ -69,7 +69,7 @@ public:
return; return;
for (auto id: containersToMove) { for (auto id: containersToMove) {
cmd << "[con_id=" << id << "] focus , move container workspace " << newWorkspace << " ; "; cmd << "[con_id=" << id << "] move container workspace " << newWorkspace << " ; ";
} }
cmd << "workspace number " << newWorkspace; cmd << "workspace number " << newWorkspace;

View File

@ -8,7 +8,9 @@
#include "Keys/SwitchToKeybindListener.h" #include "Keys/SwitchToKeybindListener.h"
#include "Keys/PrevOutputKeyListener.h" #include "Keys/PrevOutputKeyListener.h"
#include "Keys/NextOutputKeyListener.h" #include "Keys/NextOutputKeyListener.h"
#include "Keys/NextOutputKeyListener.h" #include "Keys/CloseKeyListener.h"
#include "Keys/MoveToScratchpadKeyListener.h"
#include "Keys/RestoreKeyListener.h"
#include <QTimer> #include <QTimer>
#include <iostream> #include <iostream>
@ -18,19 +20,9 @@ MainWindow::MainWindow(QWidget *parent)
ui->setupUi(this); ui->setupUi(this);
model = new SwayTreeModel(ui->treeView); model = new SwayTreeModel(ui->treeView);
// modelUpdateTimer = new QTimer(this);
// connect(modelUpdateTimer, &QTimer::timeout, this, QOverload<>::of(&MainWindow::update));
// modelUpdateTimer->start(1000);
ui->statusbar->showMessage(QString::fromStdString("Press ? for keybind listing")); ui->statusbar->showMessage(QString::fromStdString("Press ? for keybind listing"));
ui->treeView->setModel(model);
ui->treeView->expandAll();
ui->treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->treeView->selectionModel()->setCurrentIndex(model->findFocusedWindowIndex(), QItemSelectionModel::ClearAndSelect); updateModel();
for (int c = 0; c < model->columnCount(); ++c)
ui->treeView->resizeColumnToContents(c);
swayTreeKeyHandler = new KeyHandler(); swayTreeKeyHandler = new KeyHandler();
swayTreeKeyHandler->addListener(new HelpKeyListener(ui->help_page)); swayTreeKeyHandler->addListener(new HelpKeyListener(ui->help_page));
@ -39,6 +31,9 @@ MainWindow::MainWindow(QWidget *parent)
swayTreeKeyHandler->addListener(new SwitchToKeybindListener(model, ui->treeView)); swayTreeKeyHandler->addListener(new SwitchToKeybindListener(model, ui->treeView));
swayTreeKeyHandler->addListener(new PrevOutputKeyListener(model, ui->treeView)); swayTreeKeyHandler->addListener(new PrevOutputKeyListener(model, ui->treeView));
swayTreeKeyHandler->addListener(new NextOutputKeyListener(model, ui->treeView)); swayTreeKeyHandler->addListener(new NextOutputKeyListener(model, ui->treeView));
swayTreeKeyHandler->addListener(new CloseKeyListener(this));
swayTreeKeyHandler->addListener(new MoveToScratchpadKeyListener(this));
swayTreeKeyHandler->addListener(new RestoreKeyListener(this));
closeHelpKeyHandler = new KeyHandler(ui->tree_page); closeHelpKeyHandler = new KeyHandler(ui->tree_page);
closeHelpKeyHandler->addListener(new CloseHelpKeyListener(ui->tree_page)); closeHelpKeyHandler->addListener(new CloseHelpKeyListener(ui->tree_page));
@ -58,8 +53,25 @@ MainWindow::~MainWindow() {
delete closeHelpKeyHandler; delete closeHelpKeyHandler;
} }
void MainWindow::keyPressEvent(QKeyEvent *event) { void MainWindow::updateModel() const {
if (event->key() == Qt::Key_W) { ui->treeView->setModel(nullptr);
qDebug() << "hi"; auto *focused = model->getRoot() == nullptr ? nullptr : model->getRoot()->findFocused();
} int id;
} if (focused != nullptr)
id = focused->node.id;
model->generateRoot();
if (focused == nullptr)
focused = model->getRoot()->findFocused();
else
focused = model->getRoot()->findById(id);
if (focused != nullptr)
focused->node.focused = true;
ui->treeView->setModel(model);
ui->treeView->expandAll();
ui->treeView->selectionModel()->setCurrentIndex(model->findIndexByNode(focused), QItemSelectionModel::ClearAndSelect);
for (int c = 0; c < model->columnCount(); ++c)
ui->treeView->resizeColumnToContents(c);
}

View File

@ -20,11 +20,12 @@ public:
explicit MainWindow(QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override; ~MainWindow() override;
void keyPressEvent(QKeyEvent *event) override; void updateModel() const;
SwayTreeModel* model;
Ui::MainWindow *ui;
private: private:
Ui::MainWindow *ui;
SwayTreeModel* model;
// QTimer* modelUpdateTimer{}; // QTimer* modelUpdateTimer{};
KeyHandler* swayTreeKeyHandler; KeyHandler* swayTreeKeyHandler;
KeyHandler* closeHelpKeyHandler; KeyHandler* closeHelpKeyHandler;

View File

@ -72,13 +72,13 @@ public:
return matching; return matching;
} }
[[nodiscard]] const T *findChildRecursive(std::function<bool(const T *)> test) const { [[nodiscard]] T *findChildRecursive(std::function<bool(const T *)> test) {
if (test((const T *) this)) if (test((T *) this))
return (const T*) this; return (T*) this;
for (int i = 0; i < childCount(); ++i) { for (int i = 0; i < childCount(); ++i) {
auto *c = child(i); auto *c = child(i);
const T *r = c->findChildRecursive(test); T *r = c->findChildRecursive(test);
if (r != nullptr) if (r != nullptr)
return r; return r;
} }

View File

@ -27,6 +27,10 @@ public:
Q_DISABLE_COPY_MOVE(SwayTreeModel) Q_DISABLE_COPY_MOVE(SwayTreeModel)
explicit SwayTreeModel(QObject *parent = nullptr) : AbstractTreeModel<SwayTreeNode>(parent) { explicit SwayTreeModel(QObject *parent = nullptr) : AbstractTreeModel<SwayTreeNode>(parent) {
rootItem = nullptr;
}
void generateRoot() {
auto res = sway.sendIPC(SWAY_GET_TREE); auto res = sway.sendIPC(SWAY_GET_TREE);
auto rep = json::parse(res.msg); auto rep = json::parse(res.msg);
rootItem = new SwayTreeNode(rep); rootItem = new SwayTreeNode(rep);
@ -34,11 +38,11 @@ public:
~SwayTreeModel() override = default; ~SwayTreeModel() override = default;
explicit SwayTreeModel(SwayTreeNode * rootItem, QObject *parent = nullptr) : rootItem(rootItem), explicit SwayTreeModel(SwayTreeNode *rootItem, QObject *parent = nullptr) : rootItem(rootItem),
AbstractTreeModel<SwayTreeNode>( AbstractTreeModel<SwayTreeNode>(
parent) {}; parent) {};
[[nodiscard]] const SwayTreeNode *getRoot() const override { [[nodiscard]] SwayTreeNode *getRoot() const override {
return rootItem; return rootItem;
}; };
@ -47,14 +51,15 @@ public:
return findIndexByNode(getRoot()->findFocused()); return findIndexByNode(getRoot()->findFocused());
} }
[[nodiscard]] std::set<SwayTreeNode*> getSelectedNodes(const QTreeView* treeView) const; [[nodiscard]] std::set<SwayTreeNode *> getSelectedNodes(const QTreeView *treeView) const;
[[nodiscard]] SwayTreeNode * getSelectedNode(const QModelIndex &i) const; [[nodiscard]] SwayTreeNode *getSelectedNode(const QModelIndex &i) const;
[[nodiscard]] QModelIndex findIndexByNode(const SwayTreeNode *node) const; [[nodiscard]] QModelIndex findIndexByNode(const SwayTreeNode *node) const;
private: private:
SwayTreeNode * rootItem; SwayTreeNode *rootItem;
}; };
#endif //SWAYMUX_SWAYTREEMODEL_H #endif //SWAYMUX_SWAYTREEMODEL_H

View File

@ -106,7 +106,7 @@ struct SwayRecord {
const NodeOrientation::NodeOrientation orientation; const NodeOrientation::NodeOrientation orientation;
const bool urgent; const bool urgent;
const bool sticky; const bool sticky;
const bool focused; bool focused;
[[nodiscard]] bool operator<(const SwayRecord &other) const { [[nodiscard]] bool operator<(const SwayRecord &other) const {
return this->id < other.id; return this->id < other.id;
@ -130,16 +130,20 @@ private:
class SwayTreeNode : public AbstractTreeNode<SwayTreeNode> { class SwayTreeNode : public AbstractTreeNode<SwayTreeNode> {
public: public:
const SwayRecord node; SwayRecord node;
explicit SwayTreeNode(const json &rep, SwayTreeNode *parent = nullptr) : node(SwayRecord(rep)), explicit SwayTreeNode(const json &rep, SwayTreeNode *parent = nullptr) : node(SwayRecord(rep)),
AbstractTreeNode(parent) { AbstractTreeNode(parent) {
for (const auto &child: rep["nodes"]) { for (const auto &child: rep["nodes"]) {
if (child.contains("app_id") && !child["app_id"].is_null() && ((std::string) child["app_id"]) == "swaymux")
continue;
auto childNode = std::make_unique<SwayTreeNode>(child, this); auto childNode = std::make_unique<SwayTreeNode>(child, this);
this->appendChild(childNode); this->appendChild(childNode);
} }
for (const auto &child: rep["floating_nodes"]) { for (const auto &child: rep["floating_nodes"]) {
if (child.contains("app_id") && !child["app_id"].is_null() && ((std::string) child["app_id"]) == "swaymux")
continue;
auto childNode = std::make_unique<SwayTreeNode>(child, this); auto childNode = std::make_unique<SwayTreeNode>(child, this);
this->appendChild(childNode); this->appendChild(childNode);
} }
@ -160,7 +164,7 @@ public:
[[nodiscard]] int columnCount() const override { return 1; }; [[nodiscard]] int columnCount() const override { return 1; };
[[nodiscard]] const SwayTreeNode *findFocused() const { [[nodiscard]] SwayTreeNode *findFocused() {
std::function<bool(const SwayTreeNode *)> focused = [](const SwayTreeNode *testNode) { std::function<bool(const SwayTreeNode *)> focused = [](const SwayTreeNode *testNode) {
return testNode->node.focused; return testNode->node.focused;
}; };
@ -191,6 +195,12 @@ public:
return result; return result;
} }
[[nodiscard]] SwayTreeNode * findById(const int id) {
return const_cast<SwayTreeNode *>(findChildRecursive([id](const SwayTreeNode *test) {
return test->node.id == id;
}));
}
private: private:
[[nodiscard]] static std::function<bool(const SwayTreeNode *)> matchNodeType(NodeType::NodeType type) { [[nodiscard]] static std::function<bool(const SwayTreeNode *)> matchNodeType(NodeType::NodeType type) {
return matchNodeType(std::vector{type}); return matchNodeType(std::vector{type});
@ -204,6 +214,10 @@ private:
}); });
}; };
} }
[[nodiscard]] bool operator==(const SwayTreeNode * other) const {
return this->node == other->node;
}
}; };