mirror of
https://github.com/Trensa-Organization/hy3.git
synced 2025-03-15 10:43:40 +01:00
Initial work on tab groups
This commit is contained in:
parent
4c000cc03c
commit
5d6b415c7f
8 changed files with 419 additions and 44 deletions
|
@ -11,11 +11,12 @@ if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
|||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm)
|
||||
pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm pango pangocairo)
|
||||
|
||||
add_library(hy3 SHARED
|
||||
src/main.cpp
|
||||
src/Hy3Layout.cpp
|
||||
src/TabGroup.cpp
|
||||
src/SelectionHook.cpp
|
||||
)
|
||||
|
||||
|
|
12
flake.lock
generated
12
flake.lock
generated
|
@ -8,11 +8,11 @@
|
|||
"xdph": "xdph"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1682603803,
|
||||
"narHash": "sha256-NY9nVAdB7UyInu2vPx/DIUVNZ83t4RdP16QY9DTIn4s=",
|
||||
"lastModified": 1684167111,
|
||||
"narHash": "sha256-0JKyr8WOpcXJP5XaLnUSI7e1d7N5Rcpyf72+N4ZEtjo=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "Hyprland",
|
||||
"rev": "f23455e592bca14e0abd9249de467cc71cd2850e",
|
||||
"rev": "5b84b0fb445bc4485510bba516c84141aaeafd04",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -44,11 +44,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1682453498,
|
||||
"narHash": "sha256-WoWiAd7KZt5Eh6n+qojcivaVpnXKqBsVgpixpV2L9CE=",
|
||||
"lastModified": 1683014792,
|
||||
"narHash": "sha256-6Va9iVtmmsw4raBc3QKvQT2KT/NGRWlvUlJj46zN8B8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c8018361fa1d1650ee8d4b96294783cf564e8a7f",
|
||||
"rev": "1a411f23ba299db155a5b45d5e145b85a7aafc42",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
|
||||
nativeBuildInputs = with pkgs; [ cmake pkg-config ];
|
||||
|
||||
buildInputs = [
|
||||
buildInputs = with pkgs; [
|
||||
hyprland.packages.${system}.hyprland.dev
|
||||
pango
|
||||
cairo
|
||||
] ++ hyprland.packages.${system}.hyprland.buildInputs;
|
||||
|
||||
# no noticeable impact on performance and greatly assists debugging
|
||||
|
|
|
@ -41,18 +41,6 @@ Hy3NodeData::~Hy3NodeData() {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -65,7 +53,7 @@ Hy3NodeData::Hy3NodeData(Hy3NodeData&& from): type(from.type) {
|
|||
}
|
||||
}
|
||||
|
||||
Hy3NodeData& Hy3NodeData::operator=(const Hy3NodeData& from) {
|
||||
Hy3NodeData& Hy3NodeData::operator=(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();
|
||||
|
@ -78,7 +66,7 @@ Hy3NodeData& Hy3NodeData::operator=(const Hy3NodeData& from) {
|
|||
this->as_window = from.as_window;
|
||||
break;
|
||||
case Hy3NodeData::Group:
|
||||
new(&this->as_group) Hy3GroupData(from.as_group);
|
||||
new(&this->as_group) Hy3GroupData(std::move(from.as_group));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -121,36 +109,44 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
|
|||
errorNotif();
|
||||
}
|
||||
|
||||
double distortOut;
|
||||
double distortIn;
|
||||
double distort_out;
|
||||
double distort_in;
|
||||
double tab_height_offset;
|
||||
|
||||
const auto* gaps_in = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
|
||||
const auto* gaps_out = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
|
||||
static const auto* gaps_in = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_in")->intValue;
|
||||
static const auto* gaps_out = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_out")->intValue;
|
||||
static const auto* tab_bar_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:bar_height")->intValue;
|
||||
|
||||
tab_height_offset = *gaps_in * 2 + *tab_bar_height;
|
||||
|
||||
if (gaps_in > gaps_out) {
|
||||
distortOut = *gaps_out - 1.0;
|
||||
distort_out = *gaps_out - 1.0;
|
||||
} else {
|
||||
distortOut = *gaps_in - 1.0;
|
||||
distort_out = *gaps_in - 1.0;
|
||||
}
|
||||
|
||||
if (distortOut < 0) distortOut = 0.0;
|
||||
if (distort_out < 0) distort_out = 0.0;
|
||||
|
||||
distortIn = *gaps_in * 2;
|
||||
distort_in = *gaps_in * 2;
|
||||
|
||||
switch (group->layout) {
|
||||
case Hy3GroupLayout::SplitH:
|
||||
child->position.x = this->position.x - distortOut;
|
||||
child->size.x = this->size.x - distortIn;
|
||||
child->position.x = this->position.x - distort_out;
|
||||
child->size.x = this->size.x - distort_in;
|
||||
child->position.y = this->position.y;
|
||||
child->size.y = this->size.y;
|
||||
break;
|
||||
case Hy3GroupLayout::SplitV:
|
||||
child->position.y = this->position.y - distortOut;
|
||||
child->size.y = this->size.y - distortIn;
|
||||
child->position.y = this->position.y - distort_out;
|
||||
child->size.y = this->size.y - distort_in;
|
||||
child->position.x = this->position.x;
|
||||
child->size.x = this->size.x;
|
||||
break;
|
||||
case Hy3GroupLayout::Tabbed:
|
||||
// TODO
|
||||
child->position.y = this->position.y + tab_height_offset;
|
||||
child->size.y = this->size.y - tab_height_offset;
|
||||
child->position.x = this->position.x;
|
||||
child->size.x = this->size.x;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -182,6 +178,7 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
|
|||
offset += child->size.x;
|
||||
child->position.y = this->position.y;
|
||||
child->size.y = this->size.y;
|
||||
//child->setHidden(false);
|
||||
break;
|
||||
case Hy3GroupLayout::SplitV:
|
||||
child->position.y = this->position.y + offset;
|
||||
|
@ -189,11 +186,14 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
|
|||
offset += child->size.y;
|
||||
child->position.x = this->position.x;
|
||||
child->size.x = this->size.x;
|
||||
//child->setHidden(false);
|
||||
break;
|
||||
case Hy3GroupLayout::Tabbed:
|
||||
// TODO: tab bars
|
||||
child->position = this->position;
|
||||
child->size = this->size;
|
||||
child->position.y = this->position.y + 20;
|
||||
child->size.y = this->size.y - 20;
|
||||
child->position.x = this->position.x;
|
||||
child->size.x = this->size.x;
|
||||
//child->setHidden(group->lastFocusedChild != child);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -201,6 +201,62 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
|
|||
}
|
||||
}
|
||||
|
||||
void Hy3Node::setHidden(bool hidden) {
|
||||
switch (this->data.type) {
|
||||
case Hy3NodeData::Window:
|
||||
this->data.as_window->setHidden(hidden);
|
||||
break;
|
||||
case Hy3NodeData::Group:
|
||||
for (auto* child: this->data.as_group.children) {
|
||||
child->setHidden(hidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Hy3Node::isUrgent() {
|
||||
switch (this->data.type) {
|
||||
case Hy3NodeData::Window:
|
||||
return this->data.as_window->m_bIsUrgent;
|
||||
case Hy3NodeData::Group:
|
||||
for (auto* child: this->data.as_group.children) {
|
||||
if (child->isUrgent()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Hy3Node::getTitle() {
|
||||
switch (this->data.type) {
|
||||
case Hy3NodeData::Window:
|
||||
return this->data.as_window->m_szTitle;
|
||||
case Hy3NodeData::Group:
|
||||
std::string title;
|
||||
|
||||
switch (this->data.as_group.layout) {
|
||||
case Hy3GroupLayout::SplitH:
|
||||
title = "[H] ";
|
||||
break;
|
||||
case Hy3GroupLayout::SplitV:
|
||||
title = "[V] ";
|
||||
break;
|
||||
case Hy3GroupLayout::Tabbed:
|
||||
title = "[T] ";
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->data.as_group.lastFocusedChild == nullptr) {
|
||||
title += "Group";
|
||||
} else {
|
||||
title += this->data.as_group.lastFocusedChild->getTitle();
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void Hy3Node::markFocused() {
|
||||
Hy3Node* node = this;
|
||||
|
||||
|
@ -384,8 +440,8 @@ bool Hy3GroupData::hasChild(Hy3Node* node) {
|
|||
|
||||
void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) {
|
||||
Hy3NodeData aData = std::move(a.data);
|
||||
a.data = b.data;
|
||||
b.data = aData;
|
||||
a.data = std::move(b.data);
|
||||
b.data = std::move(aData);
|
||||
|
||||
if (a.data.type == Hy3NodeData::Group) {
|
||||
for (auto child: a.data.as_group.children) {
|
||||
|
@ -687,6 +743,10 @@ void Hy3Layout::onWindowFocusChange(CWindow* window) {
|
|||
auto* node = this->getNodeFromWindow(window);
|
||||
if (node == nullptr) return;
|
||||
|
||||
if (node->parent != nullptr && node->parent->data.as_group.layout == Hy3GroupLayout::Tabbed) {
|
||||
node->parent->recalcSizePosRecursive();
|
||||
}
|
||||
|
||||
node->markFocused();
|
||||
}
|
||||
|
||||
|
@ -1066,6 +1126,8 @@ void Hy3Layout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
|||
this->applyNodeDataToWindow(node);
|
||||
}
|
||||
|
||||
std::unique_ptr<HOOK_CALLBACK_FN> renderHookPtr = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::renderHook);
|
||||
|
||||
void Hy3Layout::onEnable() {
|
||||
for (auto &window : g_pCompositor->m_vWindows) {
|
||||
if (window->isHidden()
|
||||
|
@ -1077,10 +1139,12 @@ void Hy3Layout::onEnable() {
|
|||
this->onWindowCreatedTiling(window.get());
|
||||
}
|
||||
|
||||
HyprlandAPI::registerCallbackStatic(PHANDLE, "render", renderHookPtr.get());
|
||||
selection_hook::enable();
|
||||
}
|
||||
|
||||
void Hy3Layout::onDisable() {
|
||||
HyprlandAPI::unregisterCallback(PHANDLE, renderHookPtr.get());
|
||||
selection_hook::disable();
|
||||
this->nodes.clear();
|
||||
}
|
||||
|
@ -1198,7 +1262,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, boo
|
|||
|
||||
// if we haven't gone up any levels and the group is in the same direction
|
||||
// there's no reason to wrap the root group.
|
||||
if (shiftMatchesLayout(group.layout, direction)) break;
|
||||
if (group.layout != Hy3GroupLayout::Tabbed && shiftMatchesLayout(group.layout, direction)) break;
|
||||
|
||||
if (group.layout != Hy3GroupLayout::Tabbed
|
||||
&& group.children.size() == 2
|
||||
|
@ -1413,3 +1477,48 @@ std::string Hy3Node::debugNode() {
|
|||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// Recursively render tabs on all tab groups.
|
||||
void renderTabsRecursive(Hy3Node& node);
|
||||
|
||||
// Render tabs for the provided node, blindly assuming it is a tab group.
|
||||
void renderTabs(Hy3Node& node);
|
||||
|
||||
void Hy3Layout::renderHook(void*, std::any data) {
|
||||
auto render_stage = std::any_cast<eRenderStage>(data);
|
||||
if (render_stage == RENDER_POST_WINDOWS) {
|
||||
auto* monitor = g_pHyprOpenGL->m_RenderData.pMonitor;
|
||||
auto workspace = monitor->activeWorkspace;
|
||||
auto* root = g_Hy3Layout->getWorkspaceRootGroup(workspace);
|
||||
|
||||
if (root != nullptr) renderTabsRecursive(*root);
|
||||
}
|
||||
}
|
||||
|
||||
void renderTabsRecursive(Hy3Node& node) {
|
||||
if (node.data.type == Hy3NodeData::Group) {
|
||||
for (auto* child: node.data.as_group.children) {
|
||||
if (node.data.as_group.layout != Hy3GroupLayout::Tabbed
|
||||
|| node.data.as_group.lastFocusedChild == child)
|
||||
{
|
||||
renderTabsRecursive(*child);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.data.as_group.layout == Hy3GroupLayout::Tabbed) {
|
||||
renderTabs(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderTabs(Hy3Node& node) {
|
||||
auto& group = node.data.as_group;
|
||||
|
||||
if (!group.tab_bar) {
|
||||
group.tab_bar = std::unique_ptr<Hy3TabGroup>(new Hy3TabGroup(node));
|
||||
} else {
|
||||
group.tab_bar->updateWithGroup(node);
|
||||
}
|
||||
|
||||
group.tab_bar->renderTabBar();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
struct Hy3Node;
|
||||
#include "TabGroup.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||
|
||||
|
@ -23,6 +26,7 @@ struct Hy3GroupData {
|
|||
Hy3GroupLayout layout = Hy3GroupLayout::SplitH;
|
||||
std::list<Hy3Node*> children;
|
||||
Hy3Node* lastFocusedChild = nullptr;
|
||||
std::unique_ptr<Hy3TabGroup> tab_bar;
|
||||
|
||||
bool hasChild(Hy3Node* child);
|
||||
|
||||
|
@ -30,7 +34,6 @@ struct Hy3GroupData {
|
|||
|
||||
private:
|
||||
Hy3GroupData(Hy3GroupData&&) = default;
|
||||
Hy3GroupData(const Hy3GroupData&) = default;
|
||||
|
||||
friend class Hy3NodeData;
|
||||
};
|
||||
|
@ -54,9 +57,8 @@ public:
|
|||
|
||||
//private: - I give up, C++ wins
|
||||
Hy3NodeData(Hy3GroupData);
|
||||
Hy3NodeData(const Hy3NodeData&);
|
||||
Hy3NodeData(Hy3NodeData&&);
|
||||
Hy3NodeData& operator=(const Hy3NodeData&);
|
||||
Hy3NodeData& operator=(Hy3NodeData&&);
|
||||
};
|
||||
|
||||
struct Hy3Node {
|
||||
|
@ -76,6 +78,9 @@ struct Hy3Node {
|
|||
void raiseToTop();
|
||||
Hy3Node* getFocusedNode();
|
||||
void updateDecos();
|
||||
void setHidden(bool hidden);
|
||||
bool isUrgent();
|
||||
std::string getTitle();
|
||||
|
||||
bool operator==(const Hy3Node&) const;
|
||||
|
||||
|
@ -126,6 +131,8 @@ public:
|
|||
Hy3Node* getWorkspaceRootGroup(const int&);
|
||||
Hy3Node* getWorkspaceFocusedNode(const int&);
|
||||
|
||||
static void renderHook(void*, std::any);
|
||||
|
||||
std::list<Hy3Node> nodes;
|
||||
private:
|
||||
struct {
|
||||
|
|
198
src/TabGroup.cpp
Normal file
198
src/TabGroup.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
#include "globals.hpp"
|
||||
#include "TabGroup.hpp"
|
||||
#include "Hy3Layout.hpp"
|
||||
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
void Hy3TabBar::updateWithGroupEntries(Hy3Node& group_node) {
|
||||
if (group_node.data.type != Hy3NodeData::Group) return;
|
||||
auto& group = group_node.data.as_group;
|
||||
|
||||
auto entries_iter = this->entries.begin();
|
||||
auto group_iter = group.children.begin();
|
||||
|
||||
auto* root_node = &group_node;
|
||||
while (root_node->parent != nullptr) root_node = root_node->parent;
|
||||
Hy3Node* focused_node = root_node->getFocusedNode();
|
||||
|
||||
while (entries_iter != this->entries.end()) {
|
||||
if (group_iter == group.children.end()) {
|
||||
needs_redraw = true;
|
||||
|
||||
while (entries_iter != this->entries.end()) {
|
||||
entries_iter = this->entries.erase(entries_iter);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
auto& entry = *entries_iter;
|
||||
auto& node = **group_iter;
|
||||
|
||||
std::string title = node.getTitle();
|
||||
bool urgent = node.isUrgent();
|
||||
bool focused = focused_node == &group_node
|
||||
|| focused_node == &node
|
||||
|| (node.data.type == Hy3NodeData::Group && node.data.as_group.hasChild(focused_node));
|
||||
|
||||
if (entry.urgent != urgent
|
||||
|| entry.focused != focused
|
||||
|| entry.window_title != title)
|
||||
this->needs_redraw = true;
|
||||
|
||||
entry.window_title = std::move(title);
|
||||
entry.urgent = urgent;
|
||||
entry.focused = focused;
|
||||
|
||||
entries_iter = std::next(entries_iter);
|
||||
group_iter = std::next(group_iter);
|
||||
}
|
||||
|
||||
while (group_iter != group.children.end()) {
|
||||
needs_redraw = true;
|
||||
|
||||
auto& node = **group_iter;
|
||||
|
||||
this->entries.push_back({
|
||||
.window_title = node.getTitle(),
|
||||
.urgent = node.isUrgent(),
|
||||
.focused = focused_node == &group_node
|
||||
|| focused_node == &node
|
||||
|| (node.data.type == Hy3NodeData::Group && node.data.as_group.hasChild(focused_node)),
|
||||
});
|
||||
|
||||
group_iter = std::next(group_iter);
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3TabBar::setPos(Vector2D pos) {
|
||||
if (pos == this->pos) return;
|
||||
needs_redraw = true;
|
||||
this->pos = pos;
|
||||
}
|
||||
|
||||
void Hy3TabBar::setSize(Vector2D size) {
|
||||
this->size = size;
|
||||
}
|
||||
|
||||
void Hy3TabBar::prepareTexture() {
|
||||
auto bar_width = this->size.x;
|
||||
auto bar_height = this->size.y;
|
||||
|
||||
if (needs_redraw || this->texture.m_iTexID == 0) {
|
||||
static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
|
||||
auto rounding = *rounding_setting;
|
||||
|
||||
auto cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, this->size.x, this->size.y);
|
||||
auto cairo = cairo_create(cairo_surface);
|
||||
|
||||
// clear pixmap
|
||||
cairo_save(cairo);
|
||||
cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint(cairo);
|
||||
cairo_restore(cairo);
|
||||
|
||||
auto swidth = (double) bar_width / (double) this->entries.size();
|
||||
size_t i = 0;
|
||||
|
||||
for (auto& entry: this->entries) {
|
||||
auto width = swidth;
|
||||
auto x = i * width;
|
||||
|
||||
if (entry.focused) {
|
||||
cairo_set_source_rgba(cairo, 0.0, 1.0, 0.7, 0.5);
|
||||
} else {
|
||||
cairo_set_source_rgba(cairo, 0.2, 0.7, 1.0, 0.5);
|
||||
}
|
||||
|
||||
if (i == this->entries.size() - 1) {
|
||||
cairo_move_to(cairo, x + width - rounding, rounding);
|
||||
cairo_arc(cairo, x + width - rounding, rounding, rounding, -90.0 * (M_PI / 180.0), 0.0);
|
||||
cairo_rectangle(cairo, x + width - rounding, rounding, rounding, bar_height - rounding * 2);
|
||||
cairo_move_to(cairo, x + width - rounding, bar_height - rounding);
|
||||
cairo_arc(cairo, x + width - rounding, bar_height - rounding, rounding, 0.0, 90.0 * (M_PI / 180.0));
|
||||
width -= rounding;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
cairo_move_to(cairo, x + rounding, rounding);
|
||||
cairo_arc(cairo, x + rounding, rounding, rounding, -180.0 * (M_PI / 180.0), -90.0 * (M_PI / 180.0));
|
||||
cairo_rectangle(cairo, x, rounding, rounding, bar_height - rounding * 2);
|
||||
cairo_move_to(cairo, x + rounding, bar_height - rounding);
|
||||
cairo_arc(cairo, x + rounding, bar_height - rounding, rounding, -270.0 * (M_PI / 180.0), -180.0 * (M_PI / 180.0));
|
||||
x += rounding;
|
||||
width -= rounding;
|
||||
}
|
||||
|
||||
cairo_rectangle(cairo, x, 0, width, bar_height);
|
||||
cairo_fill(cairo);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
auto data = cairo_image_surface_get_data(cairo_surface);
|
||||
this->texture.allocate();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, this->texture.m_iTexID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
#ifdef GLES32
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bar_width, bar_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
cairo_destroy(cairo);
|
||||
cairo_surface_destroy(cairo_surface);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, this->texture.m_iTexID);
|
||||
}
|
||||
}
|
||||
|
||||
Hy3TabGroup::Hy3TabGroup(Hy3Node& node) {
|
||||
this->pos.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
|
||||
this->size.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
|
||||
Debug::log(LOG, "registered anims");
|
||||
this->pos.registerVar();
|
||||
this->size.registerVar();
|
||||
|
||||
this->updateWithGroup(node);
|
||||
this->pos.warp(false);
|
||||
this->size.warp(false);
|
||||
}
|
||||
|
||||
void Hy3TabGroup::updateWithGroup(Hy3Node& node) {
|
||||
static const auto* gaps_in = &HyprlandAPI::getConfigValue(PHANDLE, "general:gaps_in")->intValue;
|
||||
static const auto* bar_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:bar_height")->intValue;
|
||||
|
||||
auto tpos = node.position + Vector2D(*gaps_in, *gaps_in);
|
||||
auto tsize = Vector2D(node.size.x - *gaps_in * 2, *bar_height);
|
||||
|
||||
if (this->pos.goalv() != tpos) this->pos = tpos;
|
||||
if (this->size.goalv() != tsize) this->size = tsize;
|
||||
|
||||
this->bar.updateWithGroupEntries(node);
|
||||
}
|
||||
|
||||
void Hy3TabGroup::renderTabBar() {
|
||||
|
||||
auto* monitor = g_pHyprOpenGL->m_RenderData.pMonitor;
|
||||
auto scale = monitor->scale;
|
||||
|
||||
auto pos = this->pos.vec();
|
||||
auto size = this->size.vec();
|
||||
|
||||
auto scaled_pos = Vector2D(std::round(pos.x * scale), std::round(pos.y * scale));
|
||||
auto scaled_size = Vector2D(std::round(size.x * scale), std::round(size.y * scale));
|
||||
auto box = wlr_box { scaled_pos.x, scaled_pos.y, scaled_size.x, scaled_size.y };
|
||||
|
||||
this->bar.setPos(scaled_pos);
|
||||
this->bar.setSize(scaled_size);
|
||||
|
||||
this->bar.prepareTexture();
|
||||
g_pHyprOpenGL->renderTexture(this->bar.texture, &box, 1.0);
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
}
|
54
src/TabGroup.hpp
Normal file
54
src/TabGroup.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <hyprland/src/helpers/AnimatedVariable.hpp>
|
||||
#include <hyprland/src/helpers/Vector2D.hpp>
|
||||
#include <vector>
|
||||
|
||||
class Hy3TabGroup;
|
||||
|
||||
#include "Hy3Layout.hpp"
|
||||
#include <hyprland/src/render/Texture.hpp>
|
||||
|
||||
struct Hy3TabBarEntry {
|
||||
std::string window_title;
|
||||
bool urgent = false;
|
||||
bool focused = false;
|
||||
};
|
||||
|
||||
class Hy3TabBar {
|
||||
public:
|
||||
CTexture texture;
|
||||
|
||||
void updateWithGroupEntries(Hy3Node&);
|
||||
void setPos(Vector2D);
|
||||
void setSize(Vector2D);
|
||||
|
||||
// Redraw the texture if necessary, and bind it to GL_TEXTURE_2D
|
||||
void prepareTexture();
|
||||
private:
|
||||
bool needs_redraw = true;
|
||||
|
||||
std::vector<Hy3TabBarEntry> entries;
|
||||
// scaled pos/size
|
||||
Vector2D pos;
|
||||
Vector2D size;
|
||||
};
|
||||
|
||||
class Hy3TabGroup {
|
||||
public:
|
||||
Hy3TabBar bar;
|
||||
CAnimatedVariable pos;
|
||||
CAnimatedVariable size;
|
||||
|
||||
// initialize a group with the given node. UB if node is not a group.
|
||||
Hy3TabGroup(Hy3Node&);
|
||||
|
||||
// update tab bar with node position and data. UB if node is not a group.
|
||||
void updateWithGroup(Hy3Node&);
|
||||
// render the scaled tab bar on the current monitor.
|
||||
void renderTabBar();
|
||||
|
||||
private:
|
||||
// moving a Hy3TabGroup will unregister any active animations
|
||||
Hy3TabGroup(Hy3TabGroup&&) = delete;
|
||||
};
|
|
@ -45,6 +45,8 @@ void dispatch_makegroup(std::string arg) {
|
|||
g_Hy3Layout->makeGroupOnWorkspace(workspace, Hy3GroupLayout::SplitH);
|
||||
} else if (arg == "v") {
|
||||
g_Hy3Layout->makeGroupOnWorkspace(workspace, Hy3GroupLayout::SplitV);
|
||||
} else if (arg == "tab") {
|
||||
g_Hy3Layout->makeGroupOnWorkspace(workspace, Hy3GroupLayout::Tabbed);
|
||||
} else if (arg == "opposite") {
|
||||
g_Hy3Layout->makeOppositeGroupOnWorkspace(workspace);
|
||||
}
|
||||
|
@ -104,6 +106,8 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
selection_hook::init();
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:no_gaps_when_only", SConfigValue{.intValue = 0});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:bar_height", SConfigValue{.intValue = 15});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:rounding", SConfigValue{.intValue = 3});
|
||||
|
||||
g_Hy3Layout = std::make_unique<Hy3Layout>();
|
||||
HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());
|
||||
|
|
Loading…
Add table
Reference in a new issue