mirror of
https://github.com/Trensa-Organization/hy3.git
synced 2025-03-15 18:53:40 +01:00
WIP Window Movement
Code is bad but it does mostly work
This commit is contained in:
parent
0e854287ff
commit
0bdf28f3bc
3 changed files with 366 additions and 69 deletions
|
@ -1,14 +1,5 @@
|
||||||
#include "Hy3Layout.hpp"
|
#include "Hy3Layout.hpp"
|
||||||
#include "src/Window.hpp"
|
|
||||||
#include "src/debug/Log.hpp"
|
|
||||||
#include "src/helpers/Vector2D.hpp"
|
|
||||||
#include "src/helpers/Workspace.hpp"
|
|
||||||
#include "src/managers/XWaylandManager.hpp"
|
|
||||||
#include "src/managers/input/InputManager.hpp"
|
|
||||||
#include "src/render/Renderer.hpp"
|
|
||||||
#include <cairo/cairo.h>
|
|
||||||
#include <ctime>
|
|
||||||
#include <memory>
|
|
||||||
#include <src/Compositor.hpp>
|
#include <src/Compositor.hpp>
|
||||||
|
|
||||||
Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {}
|
Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {}
|
||||||
|
@ -23,6 +14,8 @@ Hy3NodeData::Hy3NodeData(Hy3GroupData group): type(Hy3NodeData::Group) {
|
||||||
new(&this->as_group) Hy3GroupData(std::move(group));
|
new(&this->as_group) Hy3GroupData(std::move(group));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout): Hy3NodeData(Hy3GroupData(layout)) {}
|
||||||
|
|
||||||
Hy3NodeData::~Hy3NodeData() {
|
Hy3NodeData::~Hy3NodeData() {
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case Hy3NodeData::Window:
|
case Hy3NodeData::Window:
|
||||||
|
@ -80,6 +73,18 @@ Hy3NodeData& Hy3NodeData::operator=(const Hy3NodeData& from) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hy3NodeData& Hy3NodeData::operator=(CWindow* window) {
|
||||||
|
*this = Hy3NodeData(window);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hy3NodeData& Hy3NodeData::operator=(Hy3GroupLayout layout) {
|
||||||
|
*this = Hy3NodeData(layout);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const {
|
bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const {
|
||||||
if (this->type != rhs.type) return false;
|
if (this->type != rhs.type) return false;
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
|
@ -185,6 +190,59 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Hy3GroupData::hasChild(Hy3Node* node) {
|
||||||
|
Debug::log(LOG, "Searching for child %p of %p", this, node);
|
||||||
|
for (auto child: this->children) {
|
||||||
|
if (child == node) return true;
|
||||||
|
|
||||||
|
if (child->data.type == Hy3NodeData::Group) {
|
||||||
|
if (child->data.as_group.hasChild(node)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Hy3Node::removeChild(Hy3Node* child, bool childSwallows) {
|
||||||
|
if (this->data.type != Hy3NodeData::Group) return false;
|
||||||
|
Hy3GroupData& group = this->data.as_group;
|
||||||
|
|
||||||
|
if (group.children.remove(child)) {
|
||||||
|
if (group.children.empty()) {
|
||||||
|
Debug::log(LOG, "Group %p is empty, removing", this);
|
||||||
|
this->parent->removeChild(this, childSwallows);
|
||||||
|
this->layout->nodes.remove(*this);
|
||||||
|
} else if (childSwallows && group.children.size() == 1) {
|
||||||
|
auto remaining = group.children.front();
|
||||||
|
Debug::log(LOG, "Group %p has only one child(%p), swallowing", this, remaining);
|
||||||
|
swapNodeData(*this, *remaining);
|
||||||
|
this->layout->nodes.remove(*remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapNodeData(Hy3Node& a, Hy3Node& b) {
|
||||||
|
Hy3NodeData aData = std::move(a.data);
|
||||||
|
a.data = b.data;
|
||||||
|
b.data = aData;
|
||||||
|
|
||||||
|
if (a.data.type == Hy3NodeData::Group) {
|
||||||
|
for (auto child: a.data.as_group.children) {
|
||||||
|
child->parent = &a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.data.type == Hy3NodeData::Group) {
|
||||||
|
for (auto child: b.data.as_group.children) {
|
||||||
|
child->parent = &b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int Hy3Layout::getWorkspaceNodeCount(const int& id) {
|
int Hy3Layout::getWorkspaceNodeCount(const int& id) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
@ -341,7 +399,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window) {
|
||||||
} else {
|
} else {
|
||||||
if ((opening_into = this->getWorkspaceRootGroup(window->m_iWorkspaceID)) == nullptr) {
|
if ((opening_into = this->getWorkspaceRootGroup(window->m_iWorkspaceID)) == nullptr) {
|
||||||
this->nodes.push_back({
|
this->nodes.push_back({
|
||||||
.data = Hy3NodeData(Hy3GroupData(Hy3GroupLayout::SplitH)),
|
.data = Hy3GroupLayout::SplitH,
|
||||||
.position = monitor->vecPosition,
|
.position = monitor->vecPosition,
|
||||||
.size = monitor->vecSize,
|
.size = monitor->vecSize,
|
||||||
.workspace_id = window->m_iWorkspaceID,
|
.workspace_id = window->m_iWorkspaceID,
|
||||||
|
@ -359,7 +417,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window) {
|
||||||
|
|
||||||
this->nodes.push_back({
|
this->nodes.push_back({
|
||||||
.parent = opening_into,
|
.parent = opening_into,
|
||||||
.data = Hy3NodeData(window),
|
.data = window,
|
||||||
.workspace_id = window->m_iWorkspaceID,
|
.workspace_id = window->m_iWorkspaceID,
|
||||||
.layout = this,
|
.layout = this,
|
||||||
});
|
});
|
||||||
|
@ -422,7 +480,7 @@ void Hy3Layout::onWindowFocusChange(CWindow* window) {
|
||||||
&& node->parent->data.as_group.children.size() == 1)
|
&& node->parent->data.as_group.children.size() == 1)
|
||||||
{
|
{
|
||||||
auto parent = node->parent;
|
auto parent = node->parent;
|
||||||
std::swap(parent->data, node->data);
|
swapNodeData(*parent, *node);
|
||||||
this->nodes.remove(*node);
|
this->nodes.remove(*node);
|
||||||
node = parent;
|
node = parent;
|
||||||
}
|
}
|
||||||
|
@ -455,40 +513,6 @@ void Hy3Layout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mod
|
||||||
}
|
}
|
||||||
|
|
||||||
std::any Hy3Layout::layoutMessage(SLayoutMessageHeader header, std::string content) {
|
std::any Hy3Layout::layoutMessage(SLayoutMessageHeader header, std::string content) {
|
||||||
if (header.pWindow == nullptr) return "";
|
|
||||||
auto* node = this->getNodeFromWindow(header.pWindow);
|
|
||||||
if (node == nullptr) return "";
|
|
||||||
|
|
||||||
if (content == "splith" || content == "splitv") {
|
|
||||||
Hy3GroupLayout layout = Hy3GroupLayout::SplitH;
|
|
||||||
if (content == "splitv") {
|
|
||||||
layout = Hy3GroupLayout::SplitV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->parent != nullptr
|
|
||||||
&& node->parent->data.as_group.children.size() == 1
|
|
||||||
&& (node->parent->data.as_group.layout == Hy3GroupLayout::SplitH
|
|
||||||
|| node->parent->data.as_group.layout == Hy3GroupLayout::SplitV))
|
|
||||||
{
|
|
||||||
node->parent->data.as_group.layout = layout;
|
|
||||||
node->parent->recalcSizePosRecursive();
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
Hy3NodeData node_data = Hy3NodeData(Hy3GroupData(layout));
|
|
||||||
std::swap(node->data, node_data);
|
|
||||||
|
|
||||||
this->nodes.push_back({
|
|
||||||
.parent = node,
|
|
||||||
.data = node_data,
|
|
||||||
.workspace_id = node->workspace_id,
|
|
||||||
.layout = this,
|
|
||||||
});
|
|
||||||
|
|
||||||
node->data.as_group.children.push_back(&this->nodes.back());
|
|
||||||
node->recalcSizePosRecursive();
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,10 +521,12 @@ SWindowRenderLayoutHints Hy3Layout::requestRenderHints(CWindow* pWindow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hy3Layout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
void Hy3Layout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
||||||
|
Debug::log(LOG, "SwitchWindows: %p %p", pWindowA, pWindowB);
|
||||||
; // empty
|
; // empty
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hy3Layout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
void Hy3Layout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
||||||
|
Debug::log(LOG, "AlterSplitRatio: %p %f", pWindow, delta);
|
||||||
; // empty
|
; // empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,3 +549,225 @@ void Hy3Layout::onEnable() {
|
||||||
|
|
||||||
void Hy3Layout::onDisable() {
|
void Hy3Layout::onDisable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Hy3Layout::makeGroupOn(CWindow* window, Hy3GroupLayout layout) {
|
||||||
|
auto* node = this->getNodeFromWindow(window);
|
||||||
|
if (node == nullptr) return;
|
||||||
|
|
||||||
|
if (node->parent->data.as_group.children.size() == 1
|
||||||
|
&& (node->parent->data.as_group.layout == Hy3GroupLayout::SplitH
|
||||||
|
|| node->parent->data.as_group.layout == Hy3GroupLayout::SplitV))
|
||||||
|
{
|
||||||
|
node->parent->data.as_group.layout = layout;
|
||||||
|
node->parent->recalcSizePosRecursive();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->nodes.push_back({
|
||||||
|
.parent = node,
|
||||||
|
.data = node->data.as_window,
|
||||||
|
.workspace_id = node->workspace_id,
|
||||||
|
.layout = this,
|
||||||
|
});
|
||||||
|
|
||||||
|
node->data = layout;
|
||||||
|
node->data.as_group.children.push_back(&this->nodes.back());
|
||||||
|
node->recalcSizePosRecursive();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hy3Layout::shiftWindow(CWindow* window, ShiftDirection direction) {
|
||||||
|
Debug::log(LOG, "ShiftWindow %p %d", window, direction);
|
||||||
|
auto* node = this->getNodeFromWindow(window);
|
||||||
|
if (node == nullptr) return;
|
||||||
|
|
||||||
|
auto& group = node->parent->data.as_group;
|
||||||
|
|
||||||
|
enum class ShiftAction {
|
||||||
|
ShiftUp,
|
||||||
|
ShiftDown,
|
||||||
|
BreakGroup,
|
||||||
|
};
|
||||||
|
|
||||||
|
ShiftAction action;
|
||||||
|
|
||||||
|
switch (group.layout) {
|
||||||
|
case Hy3GroupLayout::SplitH:
|
||||||
|
case Hy3GroupLayout::Tabbed:
|
||||||
|
switch (direction) {
|
||||||
|
case ShiftDirection::Left:
|
||||||
|
action = ShiftAction::ShiftUp;
|
||||||
|
break;
|
||||||
|
case ShiftDirection::Right:
|
||||||
|
action = ShiftAction::ShiftDown;
|
||||||
|
break;
|
||||||
|
case ShiftDirection::Up:
|
||||||
|
case ShiftDirection::Down:
|
||||||
|
action = ShiftAction::BreakGroup;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Hy3GroupLayout::SplitV:
|
||||||
|
switch (direction) {
|
||||||
|
case ShiftDirection::Up:
|
||||||
|
action = ShiftAction::ShiftUp;
|
||||||
|
break;
|
||||||
|
case ShiftDirection::Down:
|
||||||
|
action = ShiftAction::ShiftDown;
|
||||||
|
break;
|
||||||
|
case ShiftDirection::Left:
|
||||||
|
case ShiftDirection::Right:
|
||||||
|
action = ShiftAction::BreakGroup;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug::log(LOG, "ShiftWindow 2 %d", action);
|
||||||
|
|
||||||
|
Hy3Node* target_group;
|
||||||
|
switch (action) {
|
||||||
|
case ShiftAction::ShiftUp:
|
||||||
|
if (node == group.children.front()) {
|
||||||
|
action = ShiftAction::BreakGroup;
|
||||||
|
} else {
|
||||||
|
auto iter = std::find(group.children.begin(), group.children.end(), node);
|
||||||
|
auto target = *std::prev(iter);
|
||||||
|
if (target->data.type == Hy3NodeData::Group) {
|
||||||
|
target_group = target;
|
||||||
|
goto entergroup;
|
||||||
|
} else {
|
||||||
|
swapNodeData(*node, *target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShiftAction::ShiftDown:
|
||||||
|
if (node == group.children.back()) {
|
||||||
|
action = ShiftAction::BreakGroup;
|
||||||
|
} else {
|
||||||
|
auto iter = std::find(group.children.begin(), group.children.end(), node);
|
||||||
|
auto target = *std::next(iter);
|
||||||
|
if (target->data.type == Hy3NodeData::Group) {
|
||||||
|
target_group = target;
|
||||||
|
goto entergroup;
|
||||||
|
} else {
|
||||||
|
swapNodeData(*node, *target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShiftAction::BreakGroup:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action != ShiftAction::BreakGroup) {
|
||||||
|
node->parent->recalcSizePosRecursive();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto noentergroup;
|
||||||
|
entergroup: {
|
||||||
|
auto common_parent = this->findCommonParentNode(*target_group, *node);
|
||||||
|
if (common_parent == nullptr) {
|
||||||
|
Debug::log(ERR, "Could not find common parent of nodes %p, %p while moving", target_group, node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* parent = node->parent;
|
||||||
|
node->parent = target_group;
|
||||||
|
node->size_ratio = 1.0;
|
||||||
|
|
||||||
|
Hy3GroupData& target_group_data = target_group->data.as_group;
|
||||||
|
switch (target_group_data.layout) {
|
||||||
|
case Hy3GroupLayout::SplitH:
|
||||||
|
case Hy3GroupLayout::Tabbed:
|
||||||
|
switch (direction) {
|
||||||
|
case ShiftDirection::Left:
|
||||||
|
target_group_data.children.push_back(node);
|
||||||
|
break;
|
||||||
|
case ShiftDirection::Right:
|
||||||
|
case ShiftDirection::Up:
|
||||||
|
case ShiftDirection::Down:
|
||||||
|
target_group_data.children.push_front(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Hy3GroupLayout::SplitV:
|
||||||
|
switch (direction) {
|
||||||
|
case ShiftDirection::Up:
|
||||||
|
target_group_data.children.push_back(node);
|
||||||
|
break;
|
||||||
|
case ShiftDirection::Down:
|
||||||
|
case ShiftDirection::Left:
|
||||||
|
case ShiftDirection::Right:
|
||||||
|
target_group_data.children.push_front(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this might cause the target group to get swallowed and invalidate its pointers,
|
||||||
|
// so its done after touching it.
|
||||||
|
parent->removeChild(node, true);
|
||||||
|
common_parent->recalcSizePosRecursive();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
noentergroup:
|
||||||
|
|
||||||
|
// break out of group
|
||||||
|
Hy3Node* breakout_origin = node->parent;
|
||||||
|
target_group = breakout_origin->parent;
|
||||||
|
// break parents until we reach one going the shift direction or nullptr
|
||||||
|
while (target_group != nullptr
|
||||||
|
&& !(((target_group->data.as_group.layout == Hy3GroupLayout::SplitH
|
||||||
|
|| target_group->data.as_group.layout == Hy3GroupLayout::Tabbed)
|
||||||
|
&& (direction == ShiftDirection::Left || direction == ShiftDirection::Right))
|
||||||
|
|| (target_group->data.as_group.layout == Hy3GroupLayout::SplitV
|
||||||
|
&& (direction == ShiftDirection::Up || direction == ShiftDirection::Down))))
|
||||||
|
{
|
||||||
|
breakout_origin = target_group;
|
||||||
|
target_group = breakout_origin->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_group != nullptr) {
|
||||||
|
auto* parent = node->parent;
|
||||||
|
node->parent = target_group;
|
||||||
|
node->size_ratio = 1.0;
|
||||||
|
|
||||||
|
bool insert_after = direction == ShiftDirection::Right || direction == ShiftDirection::Down;
|
||||||
|
|
||||||
|
Hy3GroupData& target_group_data = target_group->data.as_group;
|
||||||
|
|
||||||
|
auto iter = std::find(target_group_data.children.begin(), target_group_data.children.end(), breakout_origin);
|
||||||
|
if (insert_after) {
|
||||||
|
iter = std::next(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
target_group_data.children.insert(iter, node);
|
||||||
|
parent->removeChild(node, true);
|
||||||
|
target_group->recalcSizePosRecursive();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hy3Node* Hy3Layout::findCommonParentNode(Hy3Node& a, Hy3Node& b) {
|
||||||
|
Hy3Node* last_node = nullptr;
|
||||||
|
Hy3Node* searcher = &a;
|
||||||
|
|
||||||
|
while (searcher != nullptr) {
|
||||||
|
if (searcher->data.type == Hy3NodeData::Group) {
|
||||||
|
for (auto child: searcher->data.as_group.children) {
|
||||||
|
if (last_node == child) continue; // dont rescan already scanned tree
|
||||||
|
if (child == &b) return searcher;
|
||||||
|
if (child->data.type == Hy3NodeData::Group && child->data.as_group.hasChild(&b)) {
|
||||||
|
return searcher;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_node = searcher;
|
||||||
|
searcher = searcher->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -12,14 +12,32 @@ enum class Hy3GroupLayout {
|
||||||
Tabbed,
|
Tabbed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ShiftDirection {
|
||||||
|
Left,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Right,
|
||||||
|
};
|
||||||
|
|
||||||
struct Hy3GroupData {
|
struct Hy3GroupData {
|
||||||
Hy3GroupLayout layout = Hy3GroupLayout::SplitH;
|
Hy3GroupLayout layout = Hy3GroupLayout::SplitH;
|
||||||
std::list<Hy3Node*> children;
|
std::list<Hy3Node*> children;
|
||||||
|
|
||||||
|
bool hasChild(Hy3Node* child);
|
||||||
|
|
||||||
Hy3GroupData(Hy3GroupLayout layout);
|
Hy3GroupData(Hy3GroupLayout layout);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Hy3GroupData(Hy3GroupData&&) = default;
|
||||||
|
Hy3GroupData(const Hy3GroupData&) = default;
|
||||||
|
|
||||||
|
friend class Hy3NodeData;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Hy3NodeData {
|
void swapNodeData(Hy3Node& a, Hy3Node& b);
|
||||||
|
|
||||||
|
class Hy3NodeData {
|
||||||
|
public:
|
||||||
enum { Group, Window } type;
|
enum { Group, Window } type;
|
||||||
union {
|
union {
|
||||||
Hy3GroupData as_group;
|
Hy3GroupData as_group;
|
||||||
|
@ -29,12 +47,19 @@ struct Hy3NodeData {
|
||||||
bool operator==(const Hy3NodeData&) const;
|
bool operator==(const Hy3NodeData&) const;
|
||||||
|
|
||||||
Hy3NodeData();
|
Hy3NodeData();
|
||||||
Hy3NodeData(CWindow* window);
|
~Hy3NodeData();
|
||||||
Hy3NodeData(Hy3GroupData group);
|
Hy3NodeData(CWindow*);
|
||||||
|
Hy3NodeData(Hy3GroupLayout);
|
||||||
|
Hy3NodeData& operator=(CWindow*);
|
||||||
|
Hy3NodeData& operator=(Hy3GroupLayout);
|
||||||
|
|
||||||
|
//private: - I give up, C++ wins
|
||||||
|
Hy3NodeData(Hy3GroupData);
|
||||||
Hy3NodeData(const Hy3NodeData&);
|
Hy3NodeData(const Hy3NodeData&);
|
||||||
Hy3NodeData(Hy3NodeData&&);
|
Hy3NodeData(Hy3NodeData&&);
|
||||||
Hy3NodeData& operator=(const Hy3NodeData&);
|
Hy3NodeData& operator=(const Hy3NodeData&);
|
||||||
~Hy3NodeData();
|
|
||||||
|
friend void swapNodeData(Hy3Node&, Hy3Node&);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Hy3Node {
|
struct Hy3Node {
|
||||||
|
@ -48,6 +73,11 @@ struct Hy3Node {
|
||||||
Hy3Layout* layout = nullptr;
|
Hy3Layout* layout = nullptr;
|
||||||
|
|
||||||
void recalcSizePosRecursive(bool force = false);
|
void recalcSizePosRecursive(bool force = false);
|
||||||
|
// remove a child node, returns true on success.
|
||||||
|
// fails if not a group
|
||||||
|
// if only a single child node remains && childSwallows, replace this group with said child.
|
||||||
|
// if no children remain, remove this node from its parent.
|
||||||
|
bool removeChild(Hy3Node* child, bool childSwallows = false);
|
||||||
|
|
||||||
bool operator==(const Hy3Node&) const;
|
bool operator==(const Hy3Node&) const;
|
||||||
};
|
};
|
||||||
|
@ -72,9 +102,12 @@ public:
|
||||||
virtual void onEnable();
|
virtual void onEnable();
|
||||||
virtual void onDisable();
|
virtual void onDisable();
|
||||||
|
|
||||||
|
void makeGroupOn(CWindow*, Hy3GroupLayout);
|
||||||
|
void shiftWindow(CWindow*, ShiftDirection);
|
||||||
|
|
||||||
|
Hy3Node* findCommonParentNode(Hy3Node&, Hy3Node&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// std::list is used over std::vector because it does not invalidate references
|
|
||||||
// when mutated.
|
|
||||||
std::list<Hy3Node> nodes;
|
std::list<Hy3Node> nodes;
|
||||||
CWindow* lastActiveWindow = nullptr;
|
CWindow* lastActiveWindow = nullptr;
|
||||||
|
|
||||||
|
|
48
src/main.cpp
48
src/main.cpp
|
@ -10,28 +10,44 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||||
return HYPRLAND_API_VERSION;
|
return HYPRLAND_API_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
void splith(std::string) {
|
// return a window if a window action makes sense now
|
||||||
SLayoutMessageHeader header;
|
CWindow* window_for_action() {
|
||||||
header.pWindow = g_pCompositor->m_pLastWindow;
|
if (g_pLayoutManager->getCurrentLayout() != g_Hy3Layout.get()) return nullptr;
|
||||||
|
|
||||||
if (!header.pWindow) return;
|
auto* window = g_pCompositor->m_pLastWindow;
|
||||||
|
|
||||||
const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
|
if (!window) return nullptr;
|
||||||
if (workspace->m_bHasFullscreenWindow) return;
|
|
||||||
|
|
||||||
g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splith");
|
const auto workspace = g_pCompositor->getWorkspaceByID(window->m_iWorkspaceID);
|
||||||
|
if (workspace->m_bHasFullscreenWindow) return nullptr;
|
||||||
|
|
||||||
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
void splitv(std::string) {
|
void dispatch_makegroup(std::string arg) {
|
||||||
SLayoutMessageHeader header;
|
CWindow* window = window_for_action();
|
||||||
header.pWindow = g_pCompositor->m_pLastWindow;
|
if (window == nullptr) return;
|
||||||
|
|
||||||
if (!header.pWindow) return;
|
if (arg == "h") {
|
||||||
|
g_Hy3Layout->makeGroupOn(window, Hy3GroupLayout::SplitH);
|
||||||
|
} else if (arg == "v") {
|
||||||
|
g_Hy3Layout->makeGroupOn(window, Hy3GroupLayout::SplitV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
|
void dispatch_movewindow(std::string arg) {
|
||||||
if (workspace->m_bHasFullscreenWindow) return;
|
CWindow* window = window_for_action();
|
||||||
|
if (window == nullptr) return;
|
||||||
|
|
||||||
g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splitv");
|
if (arg == "l") {
|
||||||
|
g_Hy3Layout->shiftWindow(window, ShiftDirection::Left);
|
||||||
|
} else if (arg == "u") {
|
||||||
|
g_Hy3Layout->shiftWindow(window, ShiftDirection::Up);
|
||||||
|
} else if (arg == "d") {
|
||||||
|
g_Hy3Layout->shiftWindow(window, ShiftDirection::Down);
|
||||||
|
} else if (arg == "r") {
|
||||||
|
g_Hy3Layout->shiftWindow(window, ShiftDirection::Right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
|
@ -40,8 +56,8 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
g_Hy3Layout = std::make_unique<Hy3Layout>();
|
g_Hy3Layout = std::make_unique<Hy3Layout>();
|
||||||
HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());
|
HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());
|
||||||
|
|
||||||
HyprlandAPI::addDispatcher(PHANDLE, "splith", splith);
|
HyprlandAPI::addDispatcher(PHANDLE, "hy3_makegroup", dispatch_makegroup);
|
||||||
HyprlandAPI::addDispatcher(PHANDLE, "splitv", splitv);
|
HyprlandAPI::addDispatcher(PHANDLE, "hy3_movewindow", dispatch_movewindow);
|
||||||
|
|
||||||
return {"hy3", "i3 like layout for hyprland", "outfoxxed", "0.1"};
|
return {"hy3", "i3 like layout for hyprland", "outfoxxed", "0.1"};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue