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/PrevOutputKeyListener.h
Keys/NextOutputKeyListener.h
Keys/CloseKeyListener.h
Keys/MoveToScratchpadKeyListener.h
Keys/MoveToScratchpadKeyListener.h
Keys/RestoreKeyListener.h
)
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;
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;

View File

@ -8,7 +8,9 @@
#include "Keys/SwitchToKeybindListener.h"
#include "Keys/PrevOutputKeyListener.h"
#include "Keys/NextOutputKeyListener.h"
#include "Keys/NextOutputKeyListener.h"
#include "Keys/CloseKeyListener.h"
#include "Keys/MoveToScratchpadKeyListener.h"
#include "Keys/RestoreKeyListener.h"
#include <QTimer>
#include <iostream>
@ -18,19 +20,9 @@ MainWindow::MainWindow(QWidget *parent)
ui->setupUi(this);
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->treeView->setModel(model);
ui->treeView->expandAll();
ui->treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->treeView->selectionModel()->setCurrentIndex(model->findFocusedWindowIndex(), QItemSelectionModel::ClearAndSelect);
for (int c = 0; c < model->columnCount(); ++c)
ui->treeView->resizeColumnToContents(c);
updateModel();
swayTreeKeyHandler = new KeyHandler();
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 PrevOutputKeyListener(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->addListener(new CloseHelpKeyListener(ui->tree_page));
@ -58,8 +53,25 @@ MainWindow::~MainWindow() {
delete closeHelpKeyHandler;
}
void MainWindow::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_W) {
qDebug() << "hi";
}
}
void MainWindow::updateModel() const {
ui->treeView->setModel(nullptr);
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);
~MainWindow() override;
void keyPressEvent(QKeyEvent *event) override;
void updateModel() const;
SwayTreeModel* model;
Ui::MainWindow *ui;
private:
Ui::MainWindow *ui;
SwayTreeModel* model;
// QTimer* modelUpdateTimer{};
KeyHandler* swayTreeKeyHandler;
KeyHandler* closeHelpKeyHandler;

View File

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

View File

@ -27,6 +27,10 @@ public:
Q_DISABLE_COPY_MOVE(SwayTreeModel)
explicit SwayTreeModel(QObject *parent = nullptr) : AbstractTreeModel<SwayTreeNode>(parent) {
rootItem = nullptr;
}
void generateRoot() {
auto res = sway.sendIPC(SWAY_GET_TREE);
auto rep = json::parse(res.msg);
rootItem = new SwayTreeNode(rep);
@ -34,11 +38,11 @@ public:
~SwayTreeModel() override = default;
explicit SwayTreeModel(SwayTreeNode * rootItem, QObject *parent = nullptr) : rootItem(rootItem),
AbstractTreeModel<SwayTreeNode>(
parent) {};
explicit SwayTreeModel(SwayTreeNode *rootItem, QObject *parent = nullptr) : rootItem(rootItem),
AbstractTreeModel<SwayTreeNode>(
parent) {};
[[nodiscard]] const SwayTreeNode *getRoot() const override {
[[nodiscard]] SwayTreeNode *getRoot() const override {
return rootItem;
};
@ -47,14 +51,15 @@ public:
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;
private:
SwayTreeNode * rootItem;
SwayTreeNode *rootItem;
};
#endif //SWAYMUX_SWAYTREEMODEL_H

View File

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