Define version 1.0, reduce unnecessary navigation actions
This commit is contained in:
parent
4e6afa08fd
commit
144be992b1
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
project(swaymux VERSION 0.1 LANGUAGES CXX)
|
project(swaymux VERSION 1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
@ -14,14 +14,14 @@ public:
|
|||||||
explicit CloseKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
explicit CloseKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||||
|
|
||||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||||
auto containersToKill = getSelectedContainerIds();
|
auto containersToKill = getSelectedContainers();
|
||||||
|
|
||||||
if (containersToKill.empty())
|
if (containersToKill.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Formatter cmd;
|
Formatter cmd;
|
||||||
for (auto id: containersToKill) {
|
for (auto node: containersToKill) {
|
||||||
cmd << "[con_id=" << id << "] kill ; ";
|
cmd << "[con_id=" << node->node.id << "] kill ; ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << cmd.str() << "\n";
|
std::cout << cmd.str() << "\n";
|
||||||
|
@ -23,7 +23,7 @@ public:
|
|||||||
if (selectedOutput != nullptr)
|
if (selectedOutput != nullptr)
|
||||||
cmd << "focus output " << selectedOutput->node.name << " , ";
|
cmd << "focus output " << selectedOutput->node.name << " , ";
|
||||||
|
|
||||||
cmd << "workspace number " << createNewWorkspaceId();
|
cmd << "workspace " << createNewWorkspaceId({});
|
||||||
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
|
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
|
||||||
std::cout << resp.msg << "\n";
|
std::cout << resp.msg << "\n";
|
||||||
QApplication::quit();
|
QApplication::quit();
|
||||||
|
@ -18,28 +18,57 @@ protected:
|
|||||||
window->updateModel();
|
window->updateModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::set<int> getSelectedContainerIds() const {
|
[[nodiscard]] std::set<const SwayTreeNode *> getSelectedContainers() const {
|
||||||
std::set<int> containerIds;
|
std::set<const SwayTreeNode *> containerIds;
|
||||||
auto selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
auto selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
||||||
|
|
||||||
for (auto *container: selectedNodes) {
|
for (auto *container: selectedNodes) {
|
||||||
auto containers = container->accumulateContainers();
|
auto containers = container->accumulateContainers();
|
||||||
for (auto *containerToMove: container->accumulateContainers()) {
|
for (auto *containerToMove: container->accumulateContainers()) {
|
||||||
containerIds.insert(containerToMove->node.id);
|
containerIds.insert(containerToMove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return containerIds;
|
return containerIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] int createNewWorkspaceId() const {
|
[[nodiscard]] std::string createNewWorkspaceId(const std::set<const SwayTreeNode *> &allowedContainers) const {
|
||||||
auto used_workspaces = getModel()->getRoot()->accumulateWorkspaces();
|
std::set<std::string> candidates;
|
||||||
int newWorkspace = 1; // workspace 1 is the first one. We don't expect our users to be programmers.
|
|
||||||
for (; used_workspaces.contains(std::to_string(newWorkspace)); ++newWorkspace) {}
|
for (auto *con: allowedContainers) {
|
||||||
return newWorkspace;
|
const auto *workspace = con->findWorkspace();
|
||||||
|
if (workspace == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (allowedContainers.contains(workspace)) {
|
||||||
|
candidates.insert(workspace->node.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto containers = workspace->accumulateContainers();
|
||||||
|
if (std::all_of(containers.begin(), containers.end(), [allowedContainers](const SwayTreeNode *container) {
|
||||||
|
return allowedContainers.contains(container);
|
||||||
|
})) {
|
||||||
|
candidates.insert(workspace->node.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!candidates.empty()) {
|
||||||
|
auto res = std::min_element(candidates.begin(), candidates.end());
|
||||||
|
return *res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newWorkspace = 0;
|
||||||
|
SwayTreeNode* workspaceNode;
|
||||||
|
do {
|
||||||
|
newWorkspace++;
|
||||||
|
workspaceNode = getModel()->getRoot()->findWorkspaceByName(std::to_string(newWorkspace));
|
||||||
|
} while (workspaceNode != nullptr && workspaceNode->childCount() != 0);
|
||||||
|
|
||||||
|
return std::to_string(newWorkspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const SwayTreeNode* findSelectedValidOutput() const {
|
[[nodiscard]] const SwayTreeNode *findSelectedValidOutput() const {
|
||||||
auto availableOutputs = SwayOutputList(SwayTreeModel::sway);
|
auto availableOutputs = SwayOutputList(SwayTreeModel::sway);
|
||||||
auto selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
auto selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
||||||
|
|
||||||
@ -56,11 +85,11 @@ protected:
|
|||||||
protected:
|
protected:
|
||||||
MainWindow *window;
|
MainWindow *window;
|
||||||
|
|
||||||
[[nodiscard]] SwayTreeModel* getModel() const {
|
[[nodiscard]] SwayTreeModel *getModel() const {
|
||||||
return this->window->model;
|
return this->window->model;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] QTreeView* getTreeView() const {
|
[[nodiscard]] QTreeView *getTreeView() const {
|
||||||
return window->ui->treeView;
|
return window->ui->treeView;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -16,14 +16,14 @@ public:
|
|||||||
explicit MoveToScratchpadKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
explicit MoveToScratchpadKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||||
|
|
||||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||||
std::set<int> containersToScratch = getSelectedContainerIds();
|
auto containersToScratch = getSelectedContainers();
|
||||||
|
|
||||||
if (containersToScratch.empty())
|
if (containersToScratch.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Formatter cmd;
|
Formatter cmd;
|
||||||
for (auto id: containersToScratch) {
|
for (auto node: containersToScratch) {
|
||||||
cmd << "[con_id=" << id << "] move scratchpad ; ";
|
cmd << "[con_id=" << node->node.id << "] move scratchpad ; ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << cmd.str() << "\n";
|
std::cout << cmd.str() << "\n";
|
||||||
|
@ -16,16 +16,16 @@ public:
|
|||||||
explicit RestoreKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
explicit RestoreKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||||
|
|
||||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||||
std::set<int> containersToRestore = getSelectedContainerIds();
|
auto containersToRestore = getSelectedContainers();
|
||||||
|
|
||||||
if (containersToRestore.empty())
|
if (containersToRestore.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Formatter cmd;
|
Formatter cmd;
|
||||||
int newWorkspaceId = createNewWorkspaceId();
|
auto newWorkspaceId = createNewWorkspaceId(containersToRestore);
|
||||||
|
|
||||||
for (auto id: containersToRestore) {
|
for (auto node: containersToRestore) {
|
||||||
cmd << "[con_id=" << id << "] move workspace " << newWorkspaceId << " ; ";
|
cmd << "[con_id=" << node->node.id << "] move workspace " << newWorkspaceId << " ; ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << cmd.str() << "\n";
|
std::cout << cmd.str() << "\n";
|
||||||
|
@ -11,18 +11,17 @@
|
|||||||
#include "../tree/SwayTreeModel.h"
|
#include "../tree/SwayTreeModel.h"
|
||||||
#include "../sway_bindings/swayoutputs.h"
|
#include "../sway_bindings/swayoutputs.h"
|
||||||
|
|
||||||
class SwitchToKeybindListener : public AbstractKeyListener {
|
class SwitchToKeybindListener : public MainWindowAwareKeyListener {
|
||||||
public:
|
public:
|
||||||
explicit SwitchToKeybindListener(SwayTreeModel *swayTreeModel, QTreeView *treeView) : swayTreeModel(
|
explicit SwitchToKeybindListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||||
swayTreeModel), treeView(treeView) {}
|
|
||||||
|
|
||||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||||
auto *root = swayTreeModel->getRoot();
|
auto *root = getModel()->getRoot();
|
||||||
if (root == nullptr)
|
if (root == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Formatter cmd;
|
Formatter cmd;
|
||||||
auto selectedNodes = swayTreeModel->getSelectedNodes(treeView);
|
auto const selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
||||||
if (selectedNodes.empty())
|
if (selectedNodes.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -52,10 +51,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto used_workspaces = root->accumulateWorkspaces();
|
auto newWorkspace = createNewWorkspaceId(selectedNodes);
|
||||||
int newWorkspace = 1; // workspace 1 is the first one. We don't expect our users to be programmers.
|
|
||||||
for (; used_workspaces.contains(std::to_string(newWorkspace)); ++newWorkspace) {}
|
|
||||||
|
|
||||||
|
|
||||||
std::set<int> containersToMove;
|
std::set<int> containersToMove;
|
||||||
for (auto* container: selectedNodes) {
|
for (auto* container: selectedNodes) {
|
||||||
@ -72,7 +68,7 @@ public:
|
|||||||
cmd << "[con_id=" << id << "] move container workspace " << newWorkspace << " ; ";
|
cmd << "[con_id=" << id << "] move container workspace " << newWorkspace << " ; ";
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd << "workspace number " << newWorkspace;
|
cmd << "workspace " << newWorkspace;
|
||||||
|
|
||||||
std::cout << cmd.str() << "\n";
|
std::cout << cmd.str() << "\n";
|
||||||
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
|
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
|
||||||
@ -91,10 +87,6 @@ public:
|
|||||||
[[nodiscard]] bool canAcceptKey(int key) const override {
|
[[nodiscard]] bool canAcceptKey(int key) const override {
|
||||||
return key == Qt::Key_Enter || key == Qt::Key_Return;
|
return key == Qt::Key_Enter || key == Qt::Key_Return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
SwayTreeModel *swayTreeModel;
|
|
||||||
QTreeView *treeView;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@ Swaymux aims at making navigation in sway easier. To achieve this, swaymux provi
|
|||||||
This main interface is primarily inspired by tmux.
|
This main interface is primarily inspired by tmux.
|
||||||
Swaymux can be navigated using the keyboard, with keybindings that closely follow the tmux bindings.
|
Swaymux can be navigated using the keyboard, with keybindings that closely follow the tmux bindings.
|
||||||
|
|
||||||
This project is *not* feature-complete, far from it. So far swaymux supports listing and navigating into outputs, workspaces and containers, creating a new workspace, or creating a workspace with all currently marked containers.
|
This project is *not* feature-complete, far from it. So far swaymux supports listing and navigating into outputs, workspaces and containers, creating a new workspace, or creating a workspace with all currently marked containers. The user can close applications without first focusing their windows, as well as view debug information (e.g. whether a window uses native wayland or xwayland). The scratchpad is supported too, both for dumping and retrieving windows from swaymux.
|
||||||
|
|
||||||
Planned features and fixes include closing windows from within swaymux without specifically jumping to them, better keyboard navigation through the sway tree in the main interface, a closer look at performance tweaking, as well as maybe even iconification of containers where applicable.
|
Planned features and fixes include a closer look at performance tweaking, as well as maybe iconification of containers where applicable.
|
||||||
|
|
||||||
|
|
||||||
# Installing
|
# Installing
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1709968316,
|
"lastModified": 1711370797,
|
||||||
"narHash": "sha256-4rZEtEDT6jcgRaqxsatBeds7x1PoEiEjb6QNGb4mNrk=",
|
"narHash": "sha256-2xu0jVSjuKhN97dqc4bVtvEH52Rwh6+uyI1XCnzoUyI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "0e7f98a5f30166cbed344569426850b21e4091d4",
|
"rev": "c726225724e681b3626acc941c6f95d2b0602087",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -30,7 +30,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
swayTreeKeyHandler->addListener(new HelpKeyListener(ui->help_page));
|
swayTreeKeyHandler->addListener(new HelpKeyListener(ui->help_page));
|
||||||
swayTreeKeyHandler->addListener(new CloseSwaymuxKeyListener());
|
swayTreeKeyHandler->addListener(new CloseSwaymuxKeyListener());
|
||||||
swayTreeKeyHandler->addListener(new CreateWorkspaceKeyListener(this));
|
swayTreeKeyHandler->addListener(new CreateWorkspaceKeyListener(this));
|
||||||
swayTreeKeyHandler->addListener(new SwitchToKeybindListener(model, ui->treeView));
|
swayTreeKeyHandler->addListener(new SwitchToKeybindListener(this));
|
||||||
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 CloseKeyListener(this));
|
||||||
|
@ -55,6 +55,10 @@ namespace NodeType {
|
|||||||
static QString toQString(NodeType nodeType) {
|
static QString toQString(NodeType nodeType) {
|
||||||
return QString::fromStdString(toString(nodeType));
|
return QString::fromStdString(toString(nodeType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static inline bool isContainer(NodeType type) {
|
||||||
|
return type == con || type == floating_con;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NodeLayout {
|
namespace NodeLayout {
|
||||||
|
@ -19,8 +19,8 @@ QModelIndex SwayTreeModel::findIndexByNode(const SwayTreeNode* node) const {
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<SwayTreeNode *> SwayTreeModel::getSelectedNodes(const QTreeView *treeView) const {
|
std::set<const SwayTreeNode *> SwayTreeModel::getSelectedNodes(const QTreeView *treeView) const {
|
||||||
std::set<SwayTreeNode *> selectedNodes;
|
std::set<const SwayTreeNode *> selectedNodes;
|
||||||
if (rootItem == nullptr)
|
if (rootItem == nullptr)
|
||||||
return selectedNodes;
|
return selectedNodes;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public:
|
|||||||
return findIndexByNode(getRoot()->findFocused());
|
return findIndexByNode(getRoot()->findFocused());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::set<SwayTreeNode *> getSelectedNodes(const QTreeView *treeView) const;
|
[[nodiscard]] std::set<const SwayTreeNode *> getSelectedNodes(const QTreeView *treeView) const;
|
||||||
|
|
||||||
[[nodiscard]] SwayTreeNode *getSelectedNode(const QModelIndex &i) const;
|
[[nodiscard]] SwayTreeNode *getSelectedNode(const QModelIndex &i) const;
|
||||||
|
|
||||||
|
@ -73,8 +73,12 @@ public:
|
|||||||
return accumulateMatchingChildrenRecursive(matchNodeType({NodeType::con, NodeType::floating_con}));
|
return accumulateMatchingChildrenRecursive(matchNodeType({NodeType::con, NodeType::floating_con}));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::set<std::string> accumulateWorkspaces() const {
|
[[nodiscard]] std::set<SwayTreeNode*> accumulateWorkspaces() const {
|
||||||
auto workspaces = accumulateMatchingChildrenRecursive(matchNodeType(NodeType::workspace));
|
return accumulateMatchingChildrenRecursive(matchNodeType(NodeType::workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::set<std::string> accumulateWorkspacesStr() const {
|
||||||
|
auto workspaces = accumulateWorkspaces();
|
||||||
std::set<std::string> result;
|
std::set<std::string> result;
|
||||||
std::transform(workspaces.begin(), workspaces.end(), std::inserter(result, result.begin()),
|
std::transform(workspaces.begin(), workspaces.end(), std::inserter(result, result.begin()),
|
||||||
[](const SwayTreeNode *workspace) { return workspace->node.name; });
|
[](const SwayTreeNode *workspace) { return workspace->node.name; });
|
||||||
@ -87,6 +91,12 @@ public:
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] SwayTreeNode * findWorkspaceByName(const std::string& name) {
|
||||||
|
return const_cast<SwayTreeNode *>(findChildRecursive([name](const SwayTreeNode *test) {
|
||||||
|
return test->node.name == name && test->node.type == NodeType::workspace;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
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});
|
||||||
|
Loading…
Reference in New Issue
Block a user