Define version 1.0, reduce unnecessary navigation actions
This commit is contained in:
parent
4e6afa08fd
commit
144be992b1
14 changed files with 83 additions and 48 deletions
|
@ -1,6 +1,6 @@
|
|||
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_AUTOMOC ON)
|
||||
|
|
|
@ -14,14 +14,14 @@ public:
|
|||
explicit CloseKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||
|
||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||
auto containersToKill = getSelectedContainerIds();
|
||||
auto containersToKill = getSelectedContainers();
|
||||
|
||||
if (containersToKill.empty())
|
||||
return;
|
||||
|
||||
Formatter cmd;
|
||||
for (auto id: containersToKill) {
|
||||
cmd << "[con_id=" << id << "] kill ; ";
|
||||
for (auto node: containersToKill) {
|
||||
cmd << "[con_id=" << node->node.id << "] kill ; ";
|
||||
}
|
||||
|
||||
std::cout << cmd.str() << "\n";
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
if (selectedOutput != nullptr)
|
||||
cmd << "focus output " << selectedOutput->node.name << " , ";
|
||||
|
||||
cmd << "workspace number " << createNewWorkspaceId();
|
||||
cmd << "workspace " << createNewWorkspaceId({});
|
||||
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
|
||||
std::cout << resp.msg << "\n";
|
||||
QApplication::quit();
|
||||
|
|
|
@ -18,28 +18,57 @@ protected:
|
|||
window->updateModel();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<int> getSelectedContainerIds() const {
|
||||
std::set<int> containerIds;
|
||||
[[nodiscard]] std::set<const SwayTreeNode *> getSelectedContainers() const {
|
||||
std::set<const SwayTreeNode *> containerIds;
|
||||
auto selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
||||
|
||||
for (auto *container: selectedNodes) {
|
||||
auto containers = container->accumulateContainers();
|
||||
for (auto *containerToMove: container->accumulateContainers()) {
|
||||
containerIds.insert(containerToMove->node.id);
|
||||
containerIds.insert(containerToMove);
|
||||
}
|
||||
}
|
||||
|
||||
return containerIds;
|
||||
}
|
||||
|
||||
[[nodiscard]] int createNewWorkspaceId() const {
|
||||
auto used_workspaces = getModel()->getRoot()->accumulateWorkspaces();
|
||||
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) {}
|
||||
return newWorkspace;
|
||||
[[nodiscard]] std::string createNewWorkspaceId(const std::set<const SwayTreeNode *> &allowedContainers) const {
|
||||
std::set<std::string> candidates;
|
||||
|
||||
for (auto *con: allowedContainers) {
|
||||
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 selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
||||
|
||||
|
@ -56,11 +85,11 @@ protected:
|
|||
protected:
|
||||
MainWindow *window;
|
||||
|
||||
[[nodiscard]] SwayTreeModel* getModel() const {
|
||||
[[nodiscard]] SwayTreeModel *getModel() const {
|
||||
return this->window->model;
|
||||
}
|
||||
|
||||
[[nodiscard]] QTreeView* getTreeView() const {
|
||||
[[nodiscard]] QTreeView *getTreeView() const {
|
||||
return window->ui->treeView;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,14 +16,14 @@ public:
|
|||
explicit MoveToScratchpadKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||
|
||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||
std::set<int> containersToScratch = getSelectedContainerIds();
|
||||
auto containersToScratch = getSelectedContainers();
|
||||
|
||||
if (containersToScratch.empty())
|
||||
return;
|
||||
|
||||
Formatter cmd;
|
||||
for (auto id: containersToScratch) {
|
||||
cmd << "[con_id=" << id << "] move scratchpad ; ";
|
||||
for (auto node: containersToScratch) {
|
||||
cmd << "[con_id=" << node->node.id << "] move scratchpad ; ";
|
||||
}
|
||||
|
||||
std::cout << cmd.str() << "\n";
|
||||
|
|
|
@ -16,16 +16,16 @@ public:
|
|||
explicit RestoreKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||
|
||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||
std::set<int> containersToRestore = getSelectedContainerIds();
|
||||
auto containersToRestore = getSelectedContainers();
|
||||
|
||||
if (containersToRestore.empty())
|
||||
return;
|
||||
|
||||
Formatter cmd;
|
||||
int newWorkspaceId = createNewWorkspaceId();
|
||||
auto newWorkspaceId = createNewWorkspaceId(containersToRestore);
|
||||
|
||||
for (auto id: containersToRestore) {
|
||||
cmd << "[con_id=" << id << "] move workspace " << newWorkspaceId << " ; ";
|
||||
for (auto node: containersToRestore) {
|
||||
cmd << "[con_id=" << node->node.id << "] move workspace " << newWorkspaceId << " ; ";
|
||||
}
|
||||
|
||||
std::cout << cmd.str() << "\n";
|
||||
|
|
|
@ -11,18 +11,17 @@
|
|||
#include "../tree/SwayTreeModel.h"
|
||||
#include "../sway_bindings/swayoutputs.h"
|
||||
|
||||
class SwitchToKeybindListener : public AbstractKeyListener {
|
||||
class SwitchToKeybindListener : public MainWindowAwareKeyListener {
|
||||
public:
|
||||
explicit SwitchToKeybindListener(SwayTreeModel *swayTreeModel, QTreeView *treeView) : swayTreeModel(
|
||||
swayTreeModel), treeView(treeView) {}
|
||||
explicit SwitchToKeybindListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
|
||||
|
||||
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
|
||||
auto *root = swayTreeModel->getRoot();
|
||||
auto *root = getModel()->getRoot();
|
||||
if (root == nullptr)
|
||||
return;
|
||||
|
||||
Formatter cmd;
|
||||
auto selectedNodes = swayTreeModel->getSelectedNodes(treeView);
|
||||
auto const selectedNodes = getModel()->getSelectedNodes(getTreeView());
|
||||
if (selectedNodes.empty())
|
||||
return;
|
||||
|
||||
|
@ -52,10 +51,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
auto used_workspaces = root->accumulateWorkspaces();
|
||||
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) {}
|
||||
|
||||
auto newWorkspace = createNewWorkspaceId(selectedNodes);
|
||||
|
||||
std::set<int> containersToMove;
|
||||
for (auto* container: selectedNodes) {
|
||||
|
@ -72,7 +68,7 @@ public:
|
|||
cmd << "[con_id=" << id << "] move container workspace " << newWorkspace << " ; ";
|
||||
}
|
||||
|
||||
cmd << "workspace number " << newWorkspace;
|
||||
cmd << "workspace " << newWorkspace;
|
||||
|
||||
std::cout << cmd.str() << "\n";
|
||||
auto resp = SwayTreeModel::sway.sendIPC(swaymsg(0, cmd.str()));
|
||||
|
@ -91,10 +87,6 @@ public:
|
|||
[[nodiscard]] bool canAcceptKey(int key) const override {
|
||||
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.
|
||||
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
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709968316,
|
||||
"narHash": "sha256-4rZEtEDT6jcgRaqxsatBeds7x1PoEiEjb6QNGb4mNrk=",
|
||||
"lastModified": 1711370797,
|
||||
"narHash": "sha256-2xu0jVSjuKhN97dqc4bVtvEH52Rwh6+uyI1XCnzoUyI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0e7f98a5f30166cbed344569426850b21e4091d4",
|
||||
"rev": "c726225724e681b3626acc941c6f95d2b0602087",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -30,7 +30,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
swayTreeKeyHandler->addListener(new HelpKeyListener(ui->help_page));
|
||||
swayTreeKeyHandler->addListener(new CloseSwaymuxKeyListener());
|
||||
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 NextOutputKeyListener(model, ui->treeView));
|
||||
swayTreeKeyHandler->addListener(new CloseKeyListener(this));
|
||||
|
|
|
@ -55,6 +55,10 @@ namespace NodeType {
|
|||
static QString toQString(NodeType nodeType) {
|
||||
return QString::fromStdString(toString(nodeType));
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool isContainer(NodeType type) {
|
||||
return type == con || type == floating_con;
|
||||
}
|
||||
}
|
||||
|
||||
namespace NodeLayout {
|
||||
|
|
|
@ -19,8 +19,8 @@ QModelIndex SwayTreeModel::findIndexByNode(const SwayTreeNode* node) const {
|
|||
return idx;
|
||||
}
|
||||
|
||||
std::set<SwayTreeNode *> SwayTreeModel::getSelectedNodes(const QTreeView *treeView) const {
|
||||
std::set<SwayTreeNode *> selectedNodes;
|
||||
std::set<const SwayTreeNode *> SwayTreeModel::getSelectedNodes(const QTreeView *treeView) const {
|
||||
std::set<const SwayTreeNode *> selectedNodes;
|
||||
if (rootItem == nullptr)
|
||||
return selectedNodes;
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
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;
|
||||
|
||||
|
|
|
@ -73,8 +73,12 @@ public:
|
|||
return accumulateMatchingChildrenRecursive(matchNodeType({NodeType::con, NodeType::floating_con}));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<std::string> accumulateWorkspaces() const {
|
||||
auto workspaces = accumulateMatchingChildrenRecursive(matchNodeType(NodeType::workspace));
|
||||
[[nodiscard]] std::set<SwayTreeNode*> accumulateWorkspaces() const {
|
||||
return accumulateMatchingChildrenRecursive(matchNodeType(NodeType::workspace));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<std::string> accumulateWorkspacesStr() const {
|
||||
auto workspaces = accumulateWorkspaces();
|
||||
std::set<std::string> result;
|
||||
std::transform(workspaces.begin(), workspaces.end(), std::inserter(result, result.begin()),
|
||||
[](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:
|
||||
[[nodiscard]] static std::function<bool(const SwayTreeNode *)> matchNodeType(NodeType::NodeType type) {
|
||||
return matchNodeType(std::vector{type});
|
||||
|
|
Loading…
Reference in a new issue