Add text in tab bars

This commit is contained in:
outfoxxed 2023-06-04 17:28:26 -07:00
parent 7061981a1e
commit 1a490734ba
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
5 changed files with 140 additions and 19 deletions

View file

@ -496,6 +496,7 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout) {
this->data.as_group.group_focused = false;
this->data.as_group.focused_child = node;
this->recalcSizePosRecursive();
this->updateTabBarRecursive();
return node;
}
@ -583,6 +584,15 @@ void Hy3Node::updateTabBar() {
}
}
void Hy3Node::updateTabBarRecursive() {
auto* node = this;
while (node != nullptr) {
node->updateTabBar();
node = node->parent;
}
}
void Hy3Node::updateDecos() {
switch (this->data.type) {
case Hy3NodeData::Window:
@ -1243,6 +1253,7 @@ void Hy3Layout::replaceWindowDataWith(CWindow* from, CWindow* to) {
}
std::unique_ptr<HOOK_CALLBACK_FN> renderHookPtr = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::renderHook);
std::unique_ptr<HOOK_CALLBACK_FN> windowTitleHookPtr = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::windowTitleHook);
std::unique_ptr<HOOK_CALLBACK_FN> tickHookPtr = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::tickHook);
void Hy3Layout::onEnable() {
@ -1257,12 +1268,14 @@ void Hy3Layout::onEnable() {
}
HyprlandAPI::registerCallbackStatic(PHANDLE, "render", renderHookPtr.get());
HyprlandAPI::registerCallbackStatic(PHANDLE, "windowTitle", windowTitleHookPtr.get());
HyprlandAPI::registerCallbackStatic(PHANDLE, "tick", tickHookPtr.get());
selection_hook::enable();
}
void Hy3Layout::onDisable() {
HyprlandAPI::unregisterCallback(PHANDLE, renderHookPtr.get());
HyprlandAPI::unregisterCallback(PHANDLE, windowTitleHookPtr.get());
HyprlandAPI::unregisterCallback(PHANDLE, tickHookPtr.get());
selection_hook::disable();
this->nodes.clear();
@ -1594,6 +1607,14 @@ void Hy3Layout::renderHook(void*, std::any data) {
}
}
void Hy3Layout::windowTitleHook(void*, std::any data) {
CWindow* window = std::any_cast<CWindow*>(data);
if (window == nullptr) return;
auto* node = g_Hy3Layout->getNodeFromWindow(window);
node->updateTabBarRecursive();
}
void Hy3Layout::tickHook(void*, std::any) {
auto& tab_groups = g_Hy3Layout->tab_groups;
auto entry = tab_groups.begin();

View file

@ -84,6 +84,8 @@ struct Hy3Node {
Hy3Node* getFocusedNode();
void updateDecos();
void setHidden(bool hidden);
void updateTabBar();
void updateTabBarRecursive();
bool isUrgent();
bool isIndirectlyFocused();
std::string getTitle();
@ -100,9 +102,6 @@ struct Hy3Node {
Hy3Node* intoGroup(Hy3GroupLayout);
static void swapData(Hy3Node&, Hy3Node&);
private:
void updateTabBar();
};
class Hy3Layout: public IHyprLayout {
@ -141,6 +140,7 @@ public:
Hy3Node* getWorkspaceFocusedNode(const int&);
static void renderHook(void*, std::any);
static void windowTitleHook(void*, std::any);
static void tickHook(void*, std::any);
std::list<Hy3Node> nodes;

View file

@ -4,6 +4,7 @@
#include <hyprland/src/Compositor.hpp>
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <hyprland/src/helpers/Color.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprland/src/render/OpenGL.hpp>
@ -47,27 +48,63 @@ void Hy3TabBarEntry::setUrgent(bool urgent) {
}
}
void Hy3TabBarEntry::setWindowTitle(std::string title) {
if (this->window_title != title) {
this->window_title = title;
this->tab_bar.dirty = true;
}
}
void Hy3TabBarEntry::prepareTexture(float scale, wlr_box& box) {
static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
static const auto* s_rounding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
static const auto* render_text = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:render_text")->intValue;
static const auto* text_font = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_font")->strValue;
static const auto* text_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_height")->intValue;
static const auto* text_padding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_padding")->intValue;
static const auto* col_active = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.active")->intValue;
static const auto* col_urgent = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.urgent")->intValue;
static const auto* col_inactive = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.inactive")->intValue;
static const auto* col_text_active = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.active")->intValue;
static const auto* col_text_urgent = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.urgent")->intValue;
static const auto* col_text_inactive = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.inactive")->intValue;
auto width = box.width;
auto height = box.height;
auto rounding = std::min((double) *rounding_setting, std::min(width * 0.5, height * 0.5));
auto rounding = std::min((double) *s_rounding, std::min(width * 0.5, height * 0.5));
if (this->texture.m_iTexID == 0
|| this->last_render_rounding != rounding
|| this->last_render_focused != focused
|| this->last_render_urgent != urgent
|| !wlr_box_equal(&this->last_render_box, &box)
|| this->last_render.x != box.x
|| this->last_render.y != box.y
|| this->last_render.focused != this->focused
|| this->last_render.urgent != this->urgent
|| this->last_render.window_title != this->window_title
|| this->last_render.rounding != rounding
|| this->last_render.text_font != *text_font
|| this->last_render.text_height != *text_height
|| this->last_render.text_padding != *text_padding
|| this->last_render.col_active != *col_active
|| this->last_render.col_urgent != *col_urgent
|| this->last_render.col_inactive != *col_inactive
|| this->last_render.col_text_active != *col_text_active
|| this->last_render.col_text_urgent != *col_text_urgent
|| this->last_render.col_text_inactive != *col_text_inactive
) {
this->last_render_rounding = rounding;
this->last_render_focused = this->focused;
this->last_render_urgent = this->urgent;
this->last_render_box = box;
this->last_render.x = box.x;
this->last_render.y = box.y;
this->last_render.focused = this->focused;
this->last_render.urgent = this->urgent;
this->last_render.window_title = this->window_title;
this->last_render.rounding = rounding;
this->last_render.text_font = *text_font;
this->last_render.text_height = *text_height;
this->last_render.text_padding = *text_padding;
this->last_render.col_active = *col_active;
this->last_render.col_urgent = *col_urgent;
this->last_render.col_inactive = *col_inactive;
this->last_render.col_text_active = *col_text_active;
this->last_render.col_text_urgent = *col_text_urgent;
this->last_render.col_text_inactive = *col_text_inactive;
auto cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
auto cairo = cairo_create(cairo_surface);
@ -104,6 +141,45 @@ void Hy3TabBarEntry::prepareTexture(float scale, wlr_box& box) {
// draw
cairo_fill(cairo);
// render window title
if (*render_text) {
PangoLayout* layout = pango_cairo_create_layout(cairo);
pango_layout_set_text(layout, this->window_title.c_str(), -1);
PangoFontDescription* font_desc = pango_font_description_from_string(text_font->c_str());
pango_font_description_set_size(font_desc, *text_height * scale * PANGO_SCALE);
pango_layout_set_font_description(layout, font_desc);
pango_font_description_free(font_desc);
int padding = *text_padding * scale;
int width = box.width - padding * 2;
pango_layout_set_width(layout, width * PANGO_SCALE);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
CColor c;
if (this->focused) {
c = CColor(*col_text_active);
} else if (this->urgent) {
c = CColor(*col_text_urgent);
} else {
c = CColor(*col_text_inactive);
}
cairo_set_source_rgba(cairo, c.r, c.g, c.b, c.a);
int layout_width, layout_height;
pango_layout_get_size(layout, &layout_width, &layout_height);
auto y_offset = (height / 2.0) - (((double)layout_height / PANGO_SCALE) / 2.0);
cairo_move_to(cairo, padding, y_offset);
pango_cairo_show_layout(cairo, layout);
g_object_unref(layout);
}
// flush cairo
cairo_surface_flush(cairo_surface);
auto data = cairo_image_surface_get_data(cairo_surface);
this->texture.allocate();
@ -205,6 +281,7 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
auto& parent_group = parent->data.as_group;
entry->setFocused(parent_group.focused_child == *node || (parent_group.group_focused && parent->isIndirectlyFocused()));
entry->setUrgent((*node)->isUrgent());
entry->setWindowTitle((*node)->getTitle());
node = std::next(node);
if (entry != this->entries.end()) entry = std::next(entry);

View file

@ -21,10 +21,25 @@ struct Hy3TabBarEntry {
CAnimatedVariable width; // 0.0-1.0 of total bar
Hy3TabBar& tab_bar;
Hy3Node& node; // only used for comparioson. do not deref.
wlr_box last_render_box;
float last_render_rounding = 0.0;
bool last_render_focused = false;
bool last_render_urgent = false;
struct {
int x, y;
float rounding = 0.0;
float scale = 0.0;
bool focused = false;
bool urgent = false;
std::string window_title;
std::string text_font;
int text_height = 0;
int text_padding = 0;
int col_active = 0;
int col_urgent = 0;
int col_inactive = 0;
int col_text_active = 0;
int col_text_urgent = 0;
int col_text_inactive = 0;
} last_render;
Hy3TabBarEntry(Hy3TabBar&, Hy3Node&);
bool operator==(const Hy3Node&) const;
@ -32,6 +47,7 @@ struct Hy3TabBarEntry {
void setFocused(bool);
void setUrgent(bool);
void setWindowTitle(std::string);
void prepareTexture(float, wlr_box&);
};

View file

@ -108,11 +108,18 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:no_gaps_when_only", SConfigValue{.intValue = 0});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:height", SConfigValue{.intValue = 15});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:padding", SConfigValue{.intValue = 5});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:from_top", SConfigValue{.intValue = 0});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:rounding", SConfigValue{.intValue = 3});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:render_text", SConfigValue{.intValue = 1});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:text_font", SConfigValue{.strValue = "Sans"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:text_height", SConfigValue{.intValue = 8});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:text_padding", SConfigValue{.intValue = 3});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.active", SConfigValue{.intValue = 0xff32b4ff});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.urgent", SConfigValue{.intValue = 0xffff4f4f});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.inactive", SConfigValue{.intValue = 0x80808080});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:from_top", SConfigValue{.intValue = 0});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:rounding", SConfigValue{.intValue = 3});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.active", SConfigValue{.intValue = 0xff000000});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.urgent", SConfigValue{.intValue = 0xff000000});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.inactive", SConfigValue{.intValue = 0xff000000});
g_Hy3Layout = std::make_unique<Hy3Layout>();
HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());