mirror of
https://github.com/Trensa-Organization/hy3.git
synced 2025-03-15 18:53:40 +01:00
Initial commit
Some progress already but have to commit somewhere
This commit is contained in:
commit
b171721e66
9 changed files with 814 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
build/
|
||||
compile_commands.json
|
29
CMakeLists.txt
Normal file
29
CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
cmake_minimum_required(VERSION 3.19)
|
||||
project(Hy3 VERSION "0.1")
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
add_compile_definitions(WLR_USE_UNSTABLE)
|
||||
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith)
|
||||
|
||||
# nix workaround
|
||||
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
|
||||
${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
endif()
|
||||
|
||||
IF(NOT DEFINED ENV{HYPRLAND_HEADERS})
|
||||
message(FATAL_ERROR "$HYPRLAND_HEADERS is unset")
|
||||
ENDIF()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(DEPS REQUIRED pixman-1 libdrm)
|
||||
|
||||
add_library(hy3 SHARED
|
||||
src/main.cpp
|
||||
src/Hy3Layout.cpp
|
||||
src/Hy3SpawnLocDecoration.cpp
|
||||
)
|
||||
|
||||
target_include_directories(hy3 PRIVATE
|
||||
${DEPS_INCLUDE_DIRS}
|
||||
$ENV{HYPRLAND_HEADERS}
|
||||
)
|
8
compile_commands_bear.sh
Executable file
8
compile_commands_bear.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
rm -rf build
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake ..
|
||||
bear -- make
|
||||
mv compile_commands.json ..
|
||||
cd ..
|
||||
sed -i 's/-std=gnu++23/-std=gnu++2b/g' compile_commands.json
|
6
compile_commands_cmake.sh
Executable file
6
compile_commands_cmake.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
|
||||
mv compile_commands.json ..
|
||||
cd ..
|
||||
sed -i 's/-std=gnu++23/-std=gnu++2b/g' compile_commands.json
|
132
flake.lock
generated
Normal file
132
flake.lock
generated
Normal file
|
@ -0,0 +1,132 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1678901627,
|
||||
"narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"wlroots": "wlroots",
|
||||
"xdph": "xdph"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1680645538,
|
||||
"narHash": "sha256-H9gAx2U3XKVoI2WjwbOXULL4TYj9y7ctxBB4up0v9tI=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "Hyprland",
|
||||
"rev": "a80ba54bbc6a423ab0e79730442e09aea832d9d6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "Hyprland",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-protocols": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"hyprland",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1671839510,
|
||||
"narHash": "sha256-+PY1qqJfmZzzROgcIY4I7AkCwpnC+qBIYk2eFoA9RWc=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "b8f55e02a328c47ed373133c52483bbfa20a1b75",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1680487167,
|
||||
"narHash": "sha256-9FNIqrxDZgSliGGN2XJJSvcDYmQbgOANaZA4UWnTdg4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "53dad94e874c9586e71decf82d972dfb640ef044",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"hyprland": "hyprland",
|
||||
"nixpkgs": [
|
||||
"hyprland",
|
||||
"nixpkgs"
|
||||
]
|
||||
}
|
||||
},
|
||||
"wlroots": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1680629978,
|
||||
"narHash": "sha256-2iVx5zqU2CpMgmtVadsHSkhkAsoxAWKQp6RQqt2OgQY=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "835208db98a29431fa687c9506f4b43fe645ff65",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"xdph": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": [
|
||||
"hyprland",
|
||||
"hyprland-protocols"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"hyprland",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1673116118,
|
||||
"narHash": "sha256-eR0yDSkR2XYMesfdRWJs25kAdXET2mbNNHu5t+KUcKA=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "d479c846531fd0e1d2357c9588b8310a2b859ef2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
51
flake.nix
Normal file
51
flake.nix
Normal file
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
inputs = {
|
||||
hyprland.url = "github:hyprwm/Hyprland";
|
||||
nixpkgs.follows = "hyprland/nixpkgs";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, hyprland, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system: let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
hyprpkgs = hyprland.packages.${system};
|
||||
in {
|
||||
packages.default = pkgs.gcc12Stdenv.mkDerivation {
|
||||
pname = "hy3";
|
||||
version = "0.1";
|
||||
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cmake
|
||||
pkg-config
|
||||
];
|
||||
|
||||
#HYPRLAND_HEADERS = hyprpkgs.hyprland.src; - TODO
|
||||
};
|
||||
|
||||
devShells.default = pkgs.mkShell.override { stdenv = pkgs.gcc12Stdenv; } {
|
||||
name = "hy3-shell";
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cmake
|
||||
pkg-config
|
||||
|
||||
clang-tools_15
|
||||
bear
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
hyprpkgs.wlroots-hyprland
|
||||
libdrm
|
||||
pixman
|
||||
];
|
||||
|
||||
inputsFrom = [
|
||||
hyprpkgs.hyprland
|
||||
hyprpkgs.wlroots-hyprland
|
||||
];
|
||||
|
||||
#HYPRLAND_HEADERS = hyprpkgs.hyprland.src; - TODO
|
||||
};
|
||||
});
|
||||
}
|
452
src/Hy3Layout.cpp
Normal file
452
src/Hy3Layout.cpp
Normal file
|
@ -0,0 +1,452 @@
|
|||
#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>
|
||||
|
||||
Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {}
|
||||
|
||||
Hy3NodeData::Hy3NodeData(): Hy3NodeData((CWindow*)nullptr) {}
|
||||
|
||||
Hy3NodeData::Hy3NodeData(CWindow *window): type(Hy3NodeData::Window) {
|
||||
this->as_window = window;
|
||||
}
|
||||
|
||||
Hy3NodeData::Hy3NodeData(Hy3GroupData group): type(Hy3NodeData::Group) {
|
||||
new(&this->as_group) Hy3GroupData(std::move(group));
|
||||
}
|
||||
|
||||
Hy3NodeData::~Hy3NodeData() {
|
||||
switch (this->type) {
|
||||
case Hy3NodeData::Window:
|
||||
break;
|
||||
case Hy3NodeData::Group:
|
||||
this->as_group.~Hy3GroupData();
|
||||
|
||||
// who ever thought calling the dtor after a move was a good idea?
|
||||
this->type = Hy3NodeData::Window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Hy3NodeData::Hy3NodeData(const Hy3NodeData& from): type(from.type) {
|
||||
Debug::log(LOG, "Copy CTor type matches? %d is group? %d", this->type == from.type, this->type == Hy3NodeData::Group);
|
||||
switch (from.type) {
|
||||
case Hy3NodeData::Window:
|
||||
this->as_window = from.as_window;
|
||||
break;
|
||||
case Hy3NodeData::Group:
|
||||
new(&this->as_group) Hy3GroupData(from.as_group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Hy3NodeData::Hy3NodeData(Hy3NodeData&& from): type(from.type) {
|
||||
Debug::log(LOG, "Move CTor type matches? %d is group? %d", this->type == from.type, this->type == Hy3NodeData::Group);
|
||||
switch (from.type) {
|
||||
case Hy3NodeData::Window:
|
||||
this->as_window = from.as_window;
|
||||
break;
|
||||
case Hy3NodeData::Group:
|
||||
new(&this->as_group) Hy3GroupData(std::move(from.as_group));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Hy3NodeData& Hy3NodeData::operator=(const Hy3NodeData& from) {
|
||||
Debug::log(LOG, "operator= type matches? %d is group? %d", this->type == from.type, this->type == Hy3NodeData::Group);
|
||||
if (this->type == Hy3NodeData::Group) {
|
||||
this->as_group.~Hy3GroupData();
|
||||
}
|
||||
|
||||
this->type = from.type;
|
||||
|
||||
switch (this->type) {
|
||||
case Hy3NodeData::Window:
|
||||
this->as_window = from.as_window;
|
||||
break;
|
||||
case Hy3NodeData::Group:
|
||||
new(&this->as_group) Hy3GroupData(from.as_group);
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const {
|
||||
if (this->type != rhs.type) return false;
|
||||
switch (this->type) {
|
||||
case Hy3NodeData::Window:
|
||||
return this->as_window == rhs.as_window;
|
||||
case Hy3NodeData::Group:
|
||||
return this->as_group.children == rhs.as_group.children;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Hy3Node::operator==(const Hy3Node& rhs) const {
|
||||
return this->data == rhs.data;
|
||||
}
|
||||
|
||||
void Hy3Node::recalcSizePosRecursive(bool force) {
|
||||
if (this->data.type != Hy3NodeData::Group) {
|
||||
this->layout->applyNodeDataToWindow(this, force);
|
||||
return;
|
||||
}
|
||||
|
||||
auto* group = &this->data.as_group;
|
||||
int constraint;
|
||||
switch (group->layout) {
|
||||
case Hy3GroupLayout::SplitH:
|
||||
constraint = this->size.x;
|
||||
break;
|
||||
case Hy3GroupLayout::SplitV:
|
||||
constraint = this->size.y;
|
||||
break;
|
||||
case Hy3GroupLayout::Tabbed:
|
||||
break;
|
||||
}
|
||||
|
||||
double offset = 0;
|
||||
|
||||
for(auto child: group->children) {
|
||||
switch (group->layout) {
|
||||
case Hy3GroupLayout::SplitH:
|
||||
child->position.x = this->position.x + offset;
|
||||
child->size.x = child->size_ratio * ((double) constraint / group->children.size());
|
||||
offset += child->size.x;
|
||||
child->position.y = this->position.y;
|
||||
child->size.y = this->size.y;
|
||||
break;
|
||||
case Hy3GroupLayout::SplitV:
|
||||
child->position.y = this->position.y + offset;
|
||||
child->size.y = child->size_ratio * ((double) constraint / group->children.size());
|
||||
offset += child->size.y;
|
||||
child->position.x = this->position.x;
|
||||
child->size.x = this->size.x;
|
||||
break;
|
||||
case Hy3GroupLayout::Tabbed:
|
||||
// TODO: tab bars
|
||||
child->position = this->position;
|
||||
child->size = this->size;
|
||||
break;
|
||||
}
|
||||
|
||||
child->recalcSizePosRecursive(force);
|
||||
}
|
||||
}
|
||||
|
||||
int Hy3Layout::getWorkspaceNodeCount(const int& id) {
|
||||
int count = 0;
|
||||
|
||||
for (auto& node: this->nodes) {
|
||||
if (node.workspace_id == id && node.valid) count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Layout::getNodeFromWindow(CWindow* window) {
|
||||
for (auto& node: this->nodes) {
|
||||
if (node.data.type == Hy3NodeData::Window && node.data.as_window == window) {
|
||||
return &node;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Hy3Node* Hy3Layout::getWorkspaceRootGroup(const int& id) {
|
||||
for (auto& node: this->nodes) {
|
||||
if (node.parent == nullptr && node.data.type == Hy3NodeData::Group) {
|
||||
return &node;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Hy3Layout::applyNodeDataToWindow(Hy3Node* node, bool force) {
|
||||
if (node->data.type != Hy3NodeData::Window) return;
|
||||
CWindow* window = node->data.as_window;
|
||||
|
||||
CMonitor* monitor = nullptr;
|
||||
|
||||
if (g_pCompositor->isWorkspaceSpecial(node->workspace_id)) {
|
||||
for (auto& m: g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceID == node->workspace_id) {
|
||||
monitor = m.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
monitor = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(node->workspace_id)->m_iMonitorID);
|
||||
}
|
||||
|
||||
if (monitor == nullptr) {
|
||||
Debug::log(ERR, "Orphaned Node %x (workspace ID: %i)!!", node, node->workspace_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// for gaps outer
|
||||
const bool display_left = STICKS(node->position.x, monitor->vecPosition.x + monitor->vecReservedTopLeft.x);
|
||||
const bool display_right = STICKS(node->position.x + node->size.x, monitor->vecPosition.x + monitor->vecSize.x - monitor->vecReservedBottomRight.x);
|
||||
const bool display_top = STICKS(node->position.y, monitor->vecPosition.y + monitor->vecReservedTopLeft.y);
|
||||
const bool display_bottom = STICKS(node->position.y + node->size.y, monitor->vecPosition.y + monitor->vecSize.y - monitor->vecReservedBottomRight.y);
|
||||
|
||||
const auto* border_size = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
const auto* gaps_in = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
|
||||
const auto* gaps_out = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
|
||||
static auto* const single_window_no_gaps = &g_pConfigManager->getConfigValuePtr("plugin:hy3:no_gaps_when_only")->intValue;
|
||||
|
||||
if (!g_pCompositor->windowExists(window) || !window->m_bIsMapped) {
|
||||
Debug::log(ERR, "Node %p holding invalid window %p!!", node, window);
|
||||
this->onWindowRemovedTiling(window);
|
||||
return;
|
||||
}
|
||||
|
||||
window->m_vSize = node->size;
|
||||
window->m_vPosition = node->position;
|
||||
|
||||
auto calcPos = window->m_vPosition + Vector2D(*border_size, *border_size);
|
||||
auto calcSize = window->m_vSize - Vector2D(2 * *border_size, 2 * *border_size);
|
||||
|
||||
const auto workspace_node_count = this->getWorkspaceNodeCount(window->m_iWorkspaceID);
|
||||
|
||||
if (*single_window_no_gaps
|
||||
&& !g_pCompositor->isWorkspaceSpecial(window->m_iWorkspaceID)
|
||||
&& (workspace_node_count == 1
|
||||
|| (window->m_bIsFullscreen
|
||||
&& g_pCompositor->getWorkspaceByID(window->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)))
|
||||
{
|
||||
window->m_vRealPosition = window->m_vPosition;
|
||||
window->m_vRealSize = window->m_vSize;
|
||||
|
||||
window->updateWindowDecos();
|
||||
|
||||
window->m_sSpecialRenderData.rounding = false;
|
||||
window->m_sSpecialRenderData.border = false;
|
||||
window->m_sSpecialRenderData.decorate = false;
|
||||
} else {
|
||||
window->m_sSpecialRenderData.rounding = true;
|
||||
window->m_sSpecialRenderData.border = true;
|
||||
window->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
Vector2D offset_topleft(
|
||||
display_left ? *gaps_out : *gaps_in,
|
||||
display_top ? *gaps_out : *gaps_in
|
||||
);
|
||||
|
||||
Vector2D offset_bottomright(
|
||||
display_right ? *gaps_out : *gaps_in,
|
||||
display_bottom ? *gaps_out : *gaps_in
|
||||
);
|
||||
|
||||
calcPos = calcPos + offset_topleft;
|
||||
calcSize = calcSize - offset_topleft - offset_bottomright;
|
||||
|
||||
const auto reserved_area = window->getFullWindowReservedArea();
|
||||
calcPos = calcPos + reserved_area.topLeft;
|
||||
calcSize = calcSize - (reserved_area.topLeft - reserved_area.bottomRight);
|
||||
|
||||
window->m_vRealPosition = calcPos;
|
||||
window->m_vRealSize = calcSize;
|
||||
Debug::log(LOG, "Set size (%f %f)", calcSize.x, calcSize.y);
|
||||
|
||||
g_pXWaylandManager->setWindowSize(window, calcSize);
|
||||
|
||||
if (force) {
|
||||
g_pHyprRenderer->damageWindow(window);
|
||||
|
||||
window->m_vRealPosition.warp();
|
||||
window->m_vRealPosition.warp();
|
||||
|
||||
g_pHyprRenderer->damageWindow(window);
|
||||
}
|
||||
|
||||
window->updateWindowDecos();
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::onWindowCreatedTiling(CWindow* window) {
|
||||
if (window->m_bIsFloating) return;
|
||||
|
||||
auto* monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
|
||||
|
||||
Hy3Node* opening_into;
|
||||
Hy3Node* opening_after;
|
||||
|
||||
if (g_pCompositor->m_pLastWindow != nullptr
|
||||
&& !g_pCompositor->m_pLastWindow->m_bIsFloating
|
||||
&& g_pCompositor->m_pLastWindow != window
|
||||
&& g_pCompositor->m_pLastWindow->m_iWorkspaceID == window->m_iWorkspaceID
|
||||
&& g_pCompositor->m_pLastWindow->m_bIsMapped)
|
||||
{
|
||||
opening_after = this->getNodeFromWindow(g_pCompositor->m_pLastWindow);
|
||||
} else {
|
||||
opening_after = this->getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
|
||||
}
|
||||
|
||||
if (opening_after != nullptr) {
|
||||
opening_into = opening_after->parent;
|
||||
} else {
|
||||
if ((opening_into = this->getWorkspaceRootGroup(window->m_iWorkspaceID)) == nullptr) {
|
||||
this->nodes.push_back({
|
||||
.data = Hy3NodeData(Hy3GroupData(Hy3GroupLayout::SplitH)),
|
||||
.position = monitor->vecPosition,
|
||||
.size = monitor->vecSize,
|
||||
.workspace_id = window->m_iWorkspaceID,
|
||||
.layout = this,
|
||||
});
|
||||
|
||||
opening_into = &this->nodes.back();
|
||||
}
|
||||
}
|
||||
|
||||
if (opening_into->data.type != Hy3NodeData::Group) {
|
||||
Debug::log(ERR, "opening_into node %p was not of type Group", opening_into);
|
||||
return;
|
||||
}
|
||||
|
||||
this->nodes.push_back({
|
||||
.parent = opening_into,
|
||||
.data = Hy3NodeData(window),
|
||||
.workspace_id = window->m_iWorkspaceID,
|
||||
.layout = this,
|
||||
});
|
||||
|
||||
auto& node = this->nodes.back();
|
||||
|
||||
if (opening_after == nullptr) {
|
||||
opening_into->data.as_group.children.push_back(&node);
|
||||
} else {
|
||||
auto& children = opening_into->data.as_group.children;
|
||||
auto iter = std::find(children.begin(), children.end(), opening_after);
|
||||
auto iter2 = std::next(iter);
|
||||
children.insert(iter2, &node);
|
||||
}
|
||||
Debug::log(LOG, "open new window %p(node: %p:%p) on winodow %p in %p", window, &node, node.data.as_window, opening_after, opening_into);
|
||||
|
||||
opening_into->recalcSizePosRecursive();
|
||||
}
|
||||
|
||||
void Hy3Layout::onWindowRemovedTiling(CWindow* window) {
|
||||
auto* node = this->getNodeFromWindow(window);
|
||||
Debug::log(LOG, "remove tiling %p (window %p)", node, window);
|
||||
|
||||
if (node == nullptr) {
|
||||
Debug::log(ERR, "onWindowRemovedTiling node null?");
|
||||
return;
|
||||
}
|
||||
|
||||
window->m_sSpecialRenderData.rounding = true;
|
||||
window->m_sSpecialRenderData.border = true;
|
||||
window->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
if (window->m_bIsFullscreen) {
|
||||
g_pCompositor->setWindowFullscreen(window, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
auto* parent = node->parent;
|
||||
|
||||
parent->data.as_group.children.remove(node);
|
||||
this->nodes.remove(*node);
|
||||
|
||||
while (parent != nullptr && parent->data.as_group.children.empty()) {
|
||||
auto* child = parent;
|
||||
parent = parent->parent;
|
||||
|
||||
if (parent != nullptr) parent->data.as_group.children.remove(child);
|
||||
this->nodes.remove(*child);
|
||||
}
|
||||
|
||||
if (parent != nullptr) parent->recalcSizePosRecursive();
|
||||
}
|
||||
|
||||
bool Hy3Layout::isWindowTiled(CWindow* window) {
|
||||
return this->getNodeFromWindow(window) != nullptr;
|
||||
}
|
||||
|
||||
void Hy3Layout::recalculateMonitor(const int& eIdleInhibitMode) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void Hy3Layout::recalculateWindow(CWindow* pWindow) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void Hy3Layout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void Hy3Layout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 "";
|
||||
}
|
||||
|
||||
SWindowRenderLayoutHints Hy3Layout::requestRenderHints(CWindow* pWindow) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void Hy3Layout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void Hy3Layout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
std::string Hy3Layout::getLayoutName() {
|
||||
return "custom";
|
||||
}
|
||||
|
||||
void Hy3Layout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void Hy3Layout::onEnable() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
|
||||
continue;
|
||||
|
||||
this->onWindowCreatedTiling(w.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3Layout::onDisable() {
|
||||
}
|
85
src/Hy3Layout.hpp
Normal file
85
src/Hy3Layout.hpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <src/layout/IHyprLayout.hpp>
|
||||
|
||||
class Hy3Layout;
|
||||
struct Hy3Node;
|
||||
|
||||
enum class Hy3GroupLayout {
|
||||
SplitH,
|
||||
SplitV,
|
||||
Tabbed,
|
||||
};
|
||||
|
||||
struct Hy3GroupData {
|
||||
Hy3GroupLayout layout = Hy3GroupLayout::SplitH;
|
||||
std::list<Hy3Node*> children;
|
||||
|
||||
Hy3GroupData(Hy3GroupLayout layout);
|
||||
};
|
||||
|
||||
struct Hy3NodeData {
|
||||
enum { Group, Window } type;
|
||||
union {
|
||||
Hy3GroupData as_group;
|
||||
CWindow* as_window;
|
||||
};
|
||||
|
||||
bool operator==(const Hy3NodeData&) const;
|
||||
|
||||
Hy3NodeData();
|
||||
Hy3NodeData(CWindow* window);
|
||||
Hy3NodeData(Hy3GroupData group);
|
||||
Hy3NodeData(const Hy3NodeData&);
|
||||
Hy3NodeData(Hy3NodeData&&);
|
||||
Hy3NodeData& operator=(const Hy3NodeData&);
|
||||
~Hy3NodeData();
|
||||
};
|
||||
|
||||
struct Hy3Node {
|
||||
Hy3Node* parent = nullptr;
|
||||
Hy3NodeData data;
|
||||
Vector2D position;
|
||||
Vector2D size;
|
||||
float size_ratio = 1.0;
|
||||
int workspace_id = -1;
|
||||
bool valid = true;
|
||||
Hy3Layout* layout = nullptr;
|
||||
|
||||
void recalcSizePosRecursive(bool force = false);
|
||||
|
||||
bool operator==(const Hy3Node&) const;
|
||||
};
|
||||
|
||||
class Hy3Layout: public IHyprLayout {
|
||||
public:
|
||||
virtual void onWindowCreatedTiling(CWindow*);
|
||||
virtual void onWindowRemovedTiling(CWindow*);
|
||||
virtual bool isWindowTiled(CWindow*);
|
||||
virtual void recalculateMonitor(const int&);
|
||||
virtual void recalculateWindow(CWindow*);
|
||||
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
|
||||
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
|
||||
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
|
||||
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
||||
virtual void switchWindows(CWindow*, CWindow*);
|
||||
virtual void alterSplitRatio(CWindow*, float, bool);
|
||||
virtual std::string getLayoutName();
|
||||
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
|
||||
|
||||
virtual void onEnable();
|
||||
virtual void onDisable();
|
||||
|
||||
private:
|
||||
// std::list is used over std::vector because it does not invalidate references
|
||||
// when mutated.
|
||||
std::list<Hy3Node> nodes;
|
||||
|
||||
int getWorkspaceNodeCount(const int&);
|
||||
Hy3Node* getNodeFromWindow(CWindow*);
|
||||
Hy3Node* getWorkspaceRootGroup(const int&);
|
||||
void applyNodeDataToWindow(Hy3Node*, bool force = false);
|
||||
|
||||
friend struct Hy3Node;
|
||||
};
|
49
src/main.cpp
Normal file
49
src/main.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include <src/plugins/PluginAPI.hpp>
|
||||
|
||||
#include "Hy3Layout.hpp"
|
||||
#include "src/Compositor.hpp"
|
||||
|
||||
inline HANDLE PHANDLE = nullptr;
|
||||
inline std::unique_ptr<Hy3Layout> g_Hy3Layout;
|
||||
|
||||
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||
return HYPRLAND_API_VERSION;
|
||||
}
|
||||
|
||||
void splith(std::string) {
|
||||
SLayoutMessageHeader header;
|
||||
header.pWindow = g_pCompositor->m_pLastWindow;
|
||||
|
||||
if (!header.pWindow) return;
|
||||
|
||||
const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
|
||||
if (workspace->m_bHasFullscreenWindow) return;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splith");
|
||||
}
|
||||
|
||||
void splitv(std::string) {
|
||||
SLayoutMessageHeader header;
|
||||
header.pWindow = g_pCompositor->m_pLastWindow;
|
||||
|
||||
if (!header.pWindow) return;
|
||||
|
||||
const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
|
||||
if (workspace->m_bHasFullscreenWindow) return;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splitv");
|
||||
}
|
||||
|
||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||
PHANDLE = handle;
|
||||
|
||||
g_Hy3Layout = std::make_unique<Hy3Layout>();
|
||||
HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());
|
||||
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "splith", splith);
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "splitv", splitv);
|
||||
|
||||
return {"hy3", "i3 like layout for hyprland", "outfoxxed", "0.1"};
|
||||
}
|
||||
|
||||
APICALL EXPORT void PLUGIN_EXIT() {}
|
Loading…
Add table
Reference in a new issue