From 910fcc0f257e260120dac0197293b0ecfa6e11cf Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 28 May 2023 23:19:35 -0700 Subject: [PATCH] Move tab create/update/delete to relevant locations Also tab close animation --- src/Hy3Layout.cpp | 80 +++++++++++++++++++++++++++++++++++++++-------- src/Hy3Layout.hpp | 11 +++++-- src/TabGroup.cpp | 74 +++++++++++++++++-------------------------- src/TabGroup.hpp | 24 +++++++------- 4 files changed, 118 insertions(+), 71 deletions(-) diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp index e97898e..efe6b27 100644 --- a/src/Hy3Layout.cpp +++ b/src/Hy3Layout.cpp @@ -18,6 +18,20 @@ void errorNotif() { Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {} +Hy3GroupData::Hy3GroupData(Hy3GroupData&& from) { + this->layout = from.layout; + this->children = std::move(from.children); + this->group_focused = from.group_focused; + this->focused_child = from.focused_child; + from.focused_child = nullptr; + this->tab_bar = from.tab_bar; + from.tab_bar = nullptr; +} + +Hy3GroupData::~Hy3GroupData() { + if (this->tab_bar != nullptr) this->tab_bar->bar.beginDestroy(); +} + Hy3NodeData::Hy3NodeData(): Hy3NodeData((CWindow*)nullptr) {} Hy3NodeData::Hy3NodeData(CWindow *window): type(Hy3NodeData::Window) { @@ -151,6 +165,8 @@ void Hy3Node::recalcSizePosRecursive(bool force) { break; } + this->updateTabBar(); + child->recalcSizePosRecursive(force); return; } @@ -200,6 +216,8 @@ void Hy3Node::recalcSizePosRecursive(bool force) { child->recalcSizePosRecursive(force); } + + this->updateTabBar(); } void Hy3Node::setHidden(bool hidden) { @@ -227,6 +245,17 @@ bool Hy3Node::isUrgent() { } } +bool Hy3Node::isIndirectlyFocused() { + Hy3Node* node = this; + + while (node->parent != nullptr) { + if (node->parent->data.as_group.focused_child != node) return false; + node = node->parent; + } + + return true; +} + std::string Hy3Node::getTitle() { switch (this->data.type) { case Hy3NodeData::Window: @@ -272,14 +301,30 @@ void Hy3Node::markFocused() { this->data.as_group.focused_child = nullptr; } + auto* node2 = node; + while (node2->parent != nullptr) { + node2->parent->data.as_group.focused_child = node2; + node2->parent->data.as_group.group_focused = false; + node2 = node2->parent; + } + while (node->parent != nullptr) { - node->parent->data.as_group.focused_child = node; - node->parent->data.as_group.group_focused = false; + node->parent->updateTabBar(); node = node->parent; } + while (node2->parent != nullptr) { + node2->parent->data.as_group.focused_child = node2; + node2->parent->data.as_group.group_focused = false; + node2->parent->updateTabBar(); + node2 = node2->parent; + } if (oldfocus != nullptr) { oldfocus->updateDecos(); + while (oldfocus != nullptr) { + oldfocus->updateTabBar(); + oldfocus = oldfocus->parent; + } } } @@ -462,6 +507,20 @@ void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) { } } +void Hy3Node::updateTabBar() { + if (this->data.type == Hy3NodeData::Group) { + auto& group = this->data.as_group; + + if (group.layout == Hy3GroupLayout::Tabbed) { + if (group.tab_bar == nullptr) group.tab_bar = &this->layout->tab_groups.emplace_back(*this); + group.tab_bar->updateWithGroup(*this); + } else if (group.tab_bar != nullptr) { + group.tab_bar->bar.beginDestroy(); + group.tab_bar = nullptr; + } + } +} + void Hy3Node::updateDecos() { switch (this->data.type) { case Hy3NodeData::Window: @@ -1495,11 +1554,12 @@ void renderTabs(Hy3Node& node); void Hy3Layout::renderHook(void*, std::any data) { auto render_stage = std::any_cast(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); + auto& tab_groups = g_Hy3Layout->tab_groups; + auto entry = tab_groups.begin(); + while (entry != tab_groups.end()) { + if (entry->bar.destroy) tab_groups.erase(entry++); + else entry++->renderTabBar(); + } } } @@ -1522,11 +1582,5 @@ void renderTabsRecursive(Hy3Node& node) { void renderTabs(Hy3Node& node) { auto& group = node.data.as_group; - if (!group.tab_bar) { - group.tab_bar = Hy3TabGroup::new_(node); - } else { - group.tab_bar->updateWithGroup(node); - } - group.tab_bar->renderTabBar(); } diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp index 1dc286c..1196471 100644 --- a/src/Hy3Layout.hpp +++ b/src/Hy3Layout.hpp @@ -27,14 +27,16 @@ struct Hy3GroupData { std::list children; bool group_focused = true; Hy3Node* focused_child = nullptr; - std::shared_ptr tab_bar; + Hy3TabGroup* tab_bar = nullptr; bool hasChild(Hy3Node* child); Hy3GroupData(Hy3GroupLayout layout); + ~Hy3GroupData(); private: - Hy3GroupData(Hy3GroupData&&) = default; + Hy3GroupData(Hy3GroupData&&); + Hy3GroupData(const Hy3GroupData&) = delete; friend class Hy3NodeData; }; @@ -81,6 +83,7 @@ struct Hy3Node { void updateDecos(); void setHidden(bool hidden); bool isUrgent(); + bool isIndirectlyFocused(); std::string getTitle(); bool operator==(const Hy3Node&) const; @@ -95,6 +98,9 @@ struct Hy3Node { Hy3Node* intoGroup(Hy3GroupLayout); static void swapData(Hy3Node&, Hy3Node&); + +private: + void updateTabBar(); }; class Hy3Layout: public IHyprLayout { @@ -135,6 +141,7 @@ public: static void renderHook(void*, std::any); std::list nodes; + std::list tab_groups; private: struct { bool started = false; diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp index ce664f4..5b3681b 100644 --- a/src/TabGroup.cpp +++ b/src/TabGroup.cpp @@ -5,7 +5,7 @@ #include #include -Hy3TabBarEntry::Hy3TabBarEntry(std::shared_ptr tab_group, Hy3Node& node): tab_group(tab_group), node(node) { +Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) { this->offset.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE); this->width.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE); @@ -24,25 +24,24 @@ bool Hy3TabBarEntry::operator==(const Hy3TabBarEntry& entry) const { return this->node == entry.node; } -void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) { +void Hy3TabBarEntry::prepareTexture(float scale, wlr_box& box) { static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue; - auto width = size.x * scale; - auto height = size.y * scale; + auto width = box.width; + auto height = box.height; auto rounding = std::min((double) *rounding_setting, std::min(width * 0.5, height * 0.5)); - if (this->needs_redraw - || this->texture.m_iTexID == 0 - || this->last_render_rounding == rounding - || this->last_render_scale == scale - || this->last_render_size == size - || true // todo + 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->needs_redraw = false; this->last_render_rounding = rounding; - this->last_render_scale = scale; - this->last_render_size = size; + this->last_render_focused = this->focused; + this->last_render_urgent = this->urgent; + this->last_render_box = box; auto cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); auto cairo = cairo_create(cairo_surface); @@ -95,17 +94,6 @@ void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) { } } -void Hy3TabBarEntry::animateRemoval() { - if (this->width.goalf() == 0.0) return; - this->width = 0.0; - - // not removing the callback is required for soundness, as the animation will - // be deleted once the callback ends. - this->width.setCallbackOnEnd([this](void*) { - this->tab_group->bar.entries.remove(*this); - }, false); -} - Hy3TabBar::Hy3TabBar() { this->vertical_pos.create(AVARTYPE_FLOAT, 1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE); this->fade_opacity.create(AVARTYPE_FLOAT, 1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE); @@ -120,6 +108,12 @@ Hy3TabBar::Hy3TabBar() { this->fade_opacity = 1.0; } +void Hy3TabBar::beginDestroy() { + this->vertical_pos = 1.0; + this->fade_opacity = 0.0; + this->fade_opacity.setCallbackOnEnd([this](void*) { this->destroy = true; }); +} + void Hy3TabBar::focusNode(Hy3Node* node) { this->focused_node = node; @@ -180,7 +174,7 @@ void Hy3TabBar::updateNodeList(std::list& nodes) { entry = *moved; removed_entries.erase(moved); } else { - entry = this->entries.emplace(entry, this->group.lock(), **node); + entry = this->entries.emplace(entry, *this, **node); } } @@ -190,10 +184,7 @@ void Hy3TabBar::updateNodeList(std::list& nodes) { } // set stats from node data - auto* root = *node; - while (root->parent != nullptr) root = root->parent; - auto* focused = root->getFocusedNode(); - entry->focused = focused == *node; + entry->focused = (*node)->isIndirectlyFocused(); entry->urgent = (*node)->isUrgent(); node = std::next(node); @@ -202,7 +193,8 @@ void Hy3TabBar::updateNodeList(std::list& nodes) { // initiate remove animations for any removed entries for (auto& entry: removed_entries) { - entry->animateRemoval(); + if (entry->width.goalf() != 0.0) entry->width = 0.0; + if (entry->width.fl() == 0.0) this->entries.erase(entry); } } @@ -251,27 +243,20 @@ void Hy3TabBar::setSize(Vector2D size) { this->size = size; } -Hy3TabGroup::Hy3TabGroup() { +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); this->pos.registerVar(); this->size.registerVar(); -} -std::shared_ptr Hy3TabGroup::new_(Hy3Node& node) { - auto ptr = std::shared_ptr(new Hy3TabGroup()); - ptr->self = ptr; - ptr->bar.group = ptr; - - ptr->updateWithGroup(node); - ptr->bar.updateAnimations(true); - ptr->pos.warp(); - ptr->size.warp(); - - return ptr; + this->updateWithGroup(node); + this->bar.updateAnimations(true); + this->pos.warp(); + this->size.warp(); } void Hy3TabGroup::updateWithGroup(Hy3Node& node) { + Debug::log(LOG, "updated tab bar for %p", &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; @@ -340,8 +325,6 @@ void Hy3TabGroup::renderTabBar() { Vector2D entry_size = { (entry.width.fl() * size.x) - *padding, size.y }; if (entry_size.x < 0 || entry_size.y < 0) return; - entry.prepareTexture(scale, entry_size); - wlr_box box = { (pos.x + (entry.offset.fl() * size.x) + (*padding * 0.5)) * scale, scaled_pos.y, @@ -349,6 +332,7 @@ void Hy3TabGroup::renderTabBar() { scaled_size.y, }; + entry.prepareTexture(scale, box); g_pHyprOpenGL->renderTexture(entry.texture, &box, this->bar.fade_opacity.fl()); }; diff --git a/src/TabGroup.hpp b/src/TabGroup.hpp index 7fa4ebd..e52667d 100644 --- a/src/TabGroup.hpp +++ b/src/TabGroup.hpp @@ -16,31 +16,31 @@ struct Hy3TabBarEntry { std::string window_title; bool focused = false; bool urgent = false; - bool needs_redraw = false; CTexture texture; CAnimatedVariable offset; // offset 0, 0.0-1.0 of total bar CAnimatedVariable width; // 0.0-1.0 of total bar - std::shared_ptr tab_group; + Hy3TabBar& tab_bar; Hy3Node& node; // only used for comparioson. do not deref. - Vector2D last_render_size; - float last_render_scale = 0.0; + wlr_box last_render_box; float last_render_rounding = 0.0; + bool last_render_focused = false; + bool last_render_urgent = false; - Hy3TabBarEntry(std::shared_ptr, Hy3Node&); + Hy3TabBarEntry(Hy3TabBar&, Hy3Node&); bool operator==(const Hy3Node&) const; bool operator==(const Hy3TabBarEntry&) const; - void prepareTexture(float, Vector2D); - - void animateRemoval(); + void prepareTexture(float, wlr_box&); }; class Hy3TabBar { public: + bool destroy = false; CAnimatedVariable vertical_pos; CAnimatedVariable fade_opacity; Hy3TabBar(); + void beginDestroy(); void focusNode(Hy3Node*); void updateNodeList(std::list& nodes); @@ -48,7 +48,6 @@ public: void setSize(Vector2D); std::list entries; - std::weak_ptr group; private: Hy3Node* focused_node = nullptr; CAnimatedVariable focus_opacity; @@ -56,6 +55,10 @@ private: CAnimatedVariable focus_end; Vector2D size; + + // Tab bar entries take a reference to `this`. + Hy3TabBar(Hy3TabBar&&) = delete; + Hy3TabBar(const Hy3TabBar&) = delete; }; class Hy3TabGroup { @@ -65,7 +68,7 @@ public: CAnimatedVariable size; // initialize a group with the given node. UB if node is not a group. - static std::shared_ptr new_(Hy3Node&); + Hy3TabGroup(Hy3Node&); // update tab bar with node position and data. UB if node is not a group. void updateWithGroup(Hy3Node&); @@ -73,7 +76,6 @@ public: void renderTabBar(); private: - std::weak_ptr self; std::vector stencil_windows; Hy3TabGroup();