summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2026-04-19 18:47:49 +0100
committerGitHub <noreply@github.com>2026-04-19 18:47:49 +0100
commita360c31d0434898888e710f4a5f560200f50cecf (patch)
treef68746c77b416654ec059f670e2e66af62581de3 /src
parent889ee4f26d77ff0c36f5c4767ef0629371fd2c18 (diff)
errorOverlay: modernize, refactor, use GPU rendering (#14122)
Improves the overlay's rendering: - GPU accelerated - supports gradients - wraps - cleaner code a bit
Diffstat (limited to 'src')
-rw-r--r--src/Compositor.cpp8
-rw-r--r--src/config/legacy/ConfigManager.cpp14
-rw-r--r--src/config/shared/complex/ComplexDataTypes.hpp3
-rw-r--r--src/debug/HyprCtl.cpp8
-rw-r--r--src/devices/IKeyboard.cpp6
-rw-r--r--src/errorOverlay/Overlay.cpp260
-rw-r--r--src/errorOverlay/Overlay.hpp57
-rw-r--r--src/helpers/Monitor.cpp10
-rw-r--r--src/hyprerror/HyprError.cpp242
-rw-r--r--src/hyprerror/HyprError.hpp38
-rw-r--r--src/managers/KeybindManager.cpp8
-rw-r--r--src/render/OpenGL.cpp14
-rw-r--r--src/render/Renderer.cpp6
-rw-r--r--src/render/Shader.cpp4
14 files changed, 359 insertions, 319 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index d9de5195..92f81fc6 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -72,7 +72,7 @@
#include "managers/WelcomeManager.hpp"
#include "render/AsyncResourceGatherer.hpp"
#include "plugins/PluginSystem.hpp"
-#include "hyprerror/HyprError.hpp"
+#include "errorOverlay/Overlay.hpp"
#include "notification/NotificationOverlay.hpp"
#include "debug/Overlay.hpp"
#include "helpers/MonitorFrameScheduler.hpp"
@@ -600,7 +600,7 @@ void CCompositor::cleanup() {
Render::g_pShaderLoader.reset();
Config::mgr().reset();
g_layoutManager.reset();
- g_pHyprError.reset();
+ ErrorOverlay::overlay().reset();
g_pKeybindManager.reset();
g_pXWaylandManager.reset();
g_pPointerManager.reset();
@@ -643,8 +643,8 @@ void CCompositor::initManagers(eManagersInitStage stage) {
if (!Config::initConfigManager())
exit(1);
- Log::logger->log(Log::DEBUG, "Creating the CHyprError!");
- g_pHyprError = makeUnique<CHyprError>();
+ Log::logger->log(Log::DEBUG, "Creating the Error Overlay!");
+ ErrorOverlay::overlay();
Log::logger->log(Log::DEBUG, "Creating the LayoutManager!");
g_layoutManager = makeUnique<Layout::CLayoutManager>();
diff --git a/src/config/legacy/ConfigManager.cpp b/src/config/legacy/ConfigManager.cpp
index c91959c8..bfe8fef3 100644
--- a/src/config/legacy/ConfigManager.cpp
+++ b/src/config/legacy/ConfigManager.cpp
@@ -29,7 +29,7 @@
#include "../defaultConfig.hpp"
#include "../../render/Renderer.hpp"
-#include "../../hyprerror/HyprError.hpp"
+#include "../../errorOverlay/Overlay.hpp"
#include "../../managers/input/InputManager.hpp"
#include "../../managers/eventLoop/EventLoopManager.hpp"
#include "../../managers/EventManager.hpp"
@@ -957,7 +957,7 @@ CConfigManager::CConfigManager() {
}
if (g_pEventLoopManager && ERR.has_value())
- g_pEventLoopManager->doLater([ERR] { g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0}); });
+ g_pEventLoopManager->doLater([ERR] { ErrorOverlay::overlay()->queueCreate(ERR.value(), ErrorOverlay::Colors::ERROR); });
}
eConfigManagerType CConfigManager::type() {
@@ -1311,14 +1311,14 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
m_configErrors = "";
if (result.error && !std::any_cast<Hyprlang::INT>(m_config->getConfigValue("debug:suppress_errors")))
- g_pHyprError->queueCreate(result.getError(), CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ ErrorOverlay::overlay()->queueCreate(result.getError(), ErrorOverlay::Colors::ERROR);
else if (std::any_cast<Hyprlang::INT>(m_config->getConfigValue("autogenerated")) == 1)
- g_pHyprError->queueCreate(
+ ErrorOverlay::overlay()->queueCreate(
"Warning: You're using an autogenerated config! Edit the config file to get rid of this message. (config file: " + getMainConfigPath() +
" )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland",
- CHyprColor(1.0, 1.0, 70.0 / 255.0, 1.0));
+ ErrorOverlay::Colors::ERROR);
else
- g_pHyprError->destroy();
+ ErrorOverlay::overlay()->destroy();
// Set the modes for all monitors as we configured them
// not on first launch because monitors might not exist yet
@@ -1509,7 +1509,7 @@ void CConfigManager::handlePluginLoads() {
g_pPluginSystem->updateConfigPlugins(m_declaredPlugins, pluginsChanged);
if (pluginsChanged) {
- g_pHyprError->destroy();
+ ErrorOverlay::overlay()->destroy();
reload();
}
}
diff --git a/src/config/shared/complex/ComplexDataTypes.hpp b/src/config/shared/complex/ComplexDataTypes.hpp
index 2db73ae8..536b0433 100644
--- a/src/config/shared/complex/ComplexDataTypes.hpp
+++ b/src/config/shared/complex/ComplexDataTypes.hpp
@@ -18,6 +18,9 @@ namespace Config {
m_colors.push_back(col);
updateColorsOk();
};
+ CGradientValueData(std::vector<CHyprColor>&& cols, float ang) : m_colors(std::move(cols)), m_angle(ang) {
+ updateColorsOk();
+ };
virtual ~CGradientValueData() = default;
virtual eConfigValueDataTypes getDataType() {
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index 3f239cef..fd9cad75 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -42,7 +42,7 @@ using namespace Hyprutils::OS;
#include "../config/shared/animation/AnimationTree.hpp"
#include "../config/supplementary/ConfigDescriptions.hpp"
#include "../managers/CursorManager.hpp"
-#include "../hyprerror/HyprError.hpp"
+#include "../errorOverlay/Overlay.hpp"
#include "../devices/IPointer.hpp"
#include "../devices/IKeyboard.hpp"
#include "../devices/ITouch.hpp"
@@ -1531,7 +1531,7 @@ static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string req
std::string errorMessage = "";
if (vars.size() < 3) {
- g_pHyprError->destroy();
+ ErrorOverlay::overlay()->destroy();
if (vars.size() == 2 && !vars[1].contains("dis"))
return "var 1 not color or disable";
@@ -1545,10 +1545,10 @@ static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string req
errorMessage += vars[i] + ' ';
if (errorMessage.empty()) {
- g_pHyprError->destroy();
+ ErrorOverlay::overlay()->destroy();
} else {
errorMessage.pop_back(); // pop last space
- g_pHyprError->queueCreate(errorMessage, COLOR);
+ ErrorOverlay::overlay()->queueCreate(errorMessage, COLOR);
}
return "ok";
diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp
index fde28324..678141f3 100644
--- a/src/devices/IKeyboard.cpp
+++ b/src/devices/IKeyboard.cpp
@@ -4,7 +4,7 @@
#include "../managers/input/InputManager.hpp"
#include "../managers/SeatManager.hpp"
#include "../helpers/MiscFunctions.hpp"
-#include "../hyprerror/HyprError.hpp"
+#include "../errorOverlay/Overlay.hpp"
#include <sys/mman.h>
#include <aquamarine/input/Input.hpp>
#include <hyprutils/string/VarList.hpp>
@@ -99,8 +99,8 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
m_xkbKeymap = xkb_keymap_new_from_names2(CONTEXT, &XKBRULES, XKB_KEYMAP_FORMAT_TEXT_V2, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!m_xkbKeymap) {
- g_pHyprError->queueError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant +
- ", options: " + rules.options + ", layout: " + rules.layout + " )");
+ ErrorOverlay::overlay()->queueError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant +
+ ", options: " + rules.options + ", layout: " + rules.layout + " )");
Log::logger->log(Log::ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules,
rules.model, rules.options);
diff --git a/src/errorOverlay/Overlay.cpp b/src/errorOverlay/Overlay.cpp
new file mode 100644
index 00000000..928d7800
--- /dev/null
+++ b/src/errorOverlay/Overlay.cpp
@@ -0,0 +1,260 @@
+#include "Overlay.hpp"
+#include "../Compositor.hpp"
+#include "../config/ConfigValue.hpp"
+#include "../config/shared/animation/AnimationTree.hpp"
+#include "../desktop/state/FocusState.hpp"
+#include "../event/EventBus.hpp"
+#include "../managers/animation/AnimationManager.hpp"
+#include "../render/Renderer.hpp"
+#include "../render/pass/BorderPassElement.hpp"
+#include "../render/pass/RectPassElement.hpp"
+#include "../render/pass/TexPassElement.hpp"
+
+#include <algorithm>
+#include <format>
+
+using namespace Hyprutils::Animation;
+using namespace ErrorOverlay;
+
+static std::string takeFirstNLines(const std::string& text, size_t lines) {
+ if (lines <= 0)
+ return "";
+
+ size_t begin = 0;
+ size_t count = 1;
+ while (count < lines) {
+ const auto nlPos = text.find('\n', begin);
+ if (nlPos == std::string::npos)
+ return text;
+
+ begin = nlPos + 1;
+ ++count;
+ }
+
+ const auto cutPos = text.find('\n', begin);
+ return cutPos == std::string::npos ? text : text.substr(0, cutPos);
+}
+
+static std::string buildVisibleText(const std::string& text, size_t lineLimit) {
+ const size_t lineCount = 1 + std::ranges::count(text, '\n');
+ const size_t visibleLines = std::max<size_t>(0, std::min(lineCount, lineLimit));
+
+ std::string visibleText = takeFirstNLines(text, visibleLines);
+ if (visibleLines < lineCount) {
+ if (!visibleText.empty())
+ visibleText += '\n';
+
+ visibleText += std::format("({} more...)", lineCount - visibleLines);
+ }
+
+ return visibleText;
+}
+
+UP<COverlay>& ErrorOverlay::overlay() {
+ static UP<COverlay> p = makeUnique<COverlay>();
+ return p;
+}
+
+COverlay::COverlay() {
+ g_pAnimationManager->createAnimation(0.f, m_fadeOpacity, Config::animationTree()->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
+
+ static auto P = Event::bus()->m_events.monitor.focused.listen([&](PHLMONITOR mon) {
+ if (!m_isCreated)
+ return;
+
+ g_pHyprRenderer->damageMonitor(Desktop::focusState()->monitor());
+ m_monitorChanged = true;
+ });
+
+ static auto P2 = Event::bus()->m_events.render.pre.listen([&](PHLMONITOR mon) {
+ if (!m_isCreated)
+ return;
+
+ if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
+ g_pHyprRenderer->damageBox(m_damageBox);
+ });
+}
+
+void COverlay::queueCreate(std::string message, const CHyprColor& color) {
+ queueCreate(std::move(message), Config::CGradientValueData{color});
+}
+
+void COverlay::queueCreate(std::string message, const Config::CGradientValueData& gradient) {
+ m_queued = std::move(message);
+ m_queuedBorderGradient = gradient;
+
+ if (m_queuedBorderGradient.m_colors.empty())
+ m_queuedBorderGradient.reset(CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ else
+ m_queuedBorderGradient.updateColorsOk();
+}
+
+void COverlay::queueError(std::string err) {
+ queueCreate(err + "\nHyprland may not work correctly.", CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+}
+
+void COverlay::createQueued() {
+ if (m_isCreated && m_textTexture)
+ m_textTexture.reset();
+
+ m_fadeOpacity->setConfig(Config::animationTree()->getAnimationPropertyConfig("fadeIn"));
+ m_fadeOpacity->setValueAndWarp(0.f);
+ *m_fadeOpacity = 1.f;
+
+ const auto PMONITOR = g_pCompositor->m_monitors.front();
+ if (!PMONITOR)
+ return;
+
+ const float SCALE = PMONITOR->m_scale;
+ const int FONTSIZE = std::clamp(sc<int>(10.f * ((PMONITOR->m_pixelSize.x * SCALE) / 1920.f)), 8, 40);
+
+ static auto LINELIMIT = CConfigValue<Hyprlang::INT>("debug:error_limit");
+ static auto BAR_POSITION = CConfigValue<Hyprlang::INT>("debug:error_position");
+ static auto FONT_FAMILY = CConfigValue<std::string>("misc:font_family");
+
+ const bool TOPBAR = *BAR_POSITION == 0;
+ const std::string visibleText = buildVisibleText(m_queued, *LINELIMIT);
+
+ m_outerPad = 10.F * SCALE;
+
+ const float barWidth = std::max<float>(1.F, sc<float>(PMONITOR->m_pixelSize.x) - m_outerPad * 2.F);
+ const float textMaxWidth = std::max<float>(1.F, barWidth - 2.F * (1.F + m_outerPad));
+
+ m_textTexture = g_pHyprRenderer->renderText(Hyprgraphics::CTextResource::STextResourceData{
+ .text = visibleText,
+ .font = *FONT_FAMILY,
+ .fontSize = sc<size_t>(FONTSIZE),
+ .color = CHyprColor(0.9, 0.9, 0.9, 1.0).asRGB(),
+ .maxSize = Vector2D{textMaxWidth, -1.F},
+ .ellipsize = false,
+ .wrap = true,
+ });
+
+ m_textSize = m_textTexture ? m_textTexture->m_size : Vector2D{};
+
+ m_lastHeight = std::max<float>(3.F, sc<float>(m_textSize.y) + 3.F);
+ m_radius = std::min<float>(m_outerPad, std::max<float>(0.F, m_lastHeight / 2.F - 1.F));
+ m_textOffsetX = 1.F + m_radius;
+ m_textOffsetY = 1.F;
+
+ m_damageBox = {
+ sc<int>(PMONITOR->m_position.x),
+ sc<int>(PMONITOR->m_position.y + (TOPBAR ? 0 : PMONITOR->m_pixelSize.y - (m_lastHeight + m_outerPad * 2.F))),
+ sc<int>(PMONITOR->m_pixelSize.x),
+ sc<int>(m_lastHeight + m_outerPad * 2.F),
+ };
+
+ m_borderGradient = m_queuedBorderGradient;
+
+ m_isCreated = true;
+ m_queued = "";
+ m_queuedDestroy = false;
+
+ g_pHyprRenderer->damageMonitor(PMONITOR);
+
+ for (const auto& m : g_pCompositor->m_monitors) {
+ m->m_reservedArea.resetType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR);
+ }
+
+ const auto RESERVED = (m_lastHeight + m_outerPad) / SCALE;
+ PMONITOR->m_reservedArea.addType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR, Vector2D{0.0, TOPBAR ? RESERVED : 0.0}, Vector2D{0.0, !TOPBAR ? RESERVED : 0.0});
+
+ for (const auto& m : g_pCompositor->m_monitors) {
+ g_pHyprRenderer->arrangeLayersForMonitor(m->m_id);
+ }
+}
+
+void COverlay::draw() {
+ if (!m_isCreated || !m_queued.empty()) {
+ if (!m_queued.empty())
+ createQueued();
+ return;
+ }
+
+ if (m_queuedDestroy) {
+ if (!m_fadeOpacity->isBeingAnimated()) {
+ if (m_fadeOpacity->value() == 0.f) {
+ m_queuedDestroy = false;
+ m_textTexture.reset();
+ m_textSize = {};
+ m_outerPad = 0.F;
+ m_radius = 0.F;
+ m_isCreated = false;
+ m_queued = "";
+
+ for (auto& m : g_pCompositor->m_monitors) {
+ g_pHyprRenderer->arrangeLayersForMonitor(m->m_id);
+ m->m_reservedArea.resetType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR);
+ }
+
+ return;
+ } else {
+ m_fadeOpacity->setConfig(Config::animationTree()->getAnimationPropertyConfig("fadeOut"));
+ *m_fadeOpacity = 0.f;
+ }
+ }
+ }
+
+ const auto PMONITOR = g_pHyprRenderer->m_renderData.pMonitor;
+ if (!PMONITOR)
+ return;
+
+ static auto BAR_POSITION = CConfigValue<Hyprlang::INT>("debug:error_position");
+ const bool TOPBAR = *BAR_POSITION == 0;
+
+ const float barWidth = std::max<float>(1.F, sc<float>(PMONITOR->m_pixelSize.x) - m_outerPad * 2.F);
+ const float barY = TOPBAR ? m_outerPad : PMONITOR->m_pixelSize.y - m_lastHeight - m_outerPad;
+ const CBox barBox = {m_outerPad, barY, barWidth, m_lastHeight};
+
+ m_damageBox.x = sc<int>(PMONITOR->m_position.x);
+ m_damageBox.width = sc<int>(PMONITOR->m_pixelSize.x);
+ m_damageBox.height = sc<int>(m_lastHeight + m_outerPad * 2.F);
+ m_damageBox.y = sc<int>(PMONITOR->m_position.y + (TOPBAR ? 0 : PMONITOR->m_pixelSize.y - m_damageBox.height));
+
+ if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
+ g_pHyprRenderer->damageBox(m_damageBox);
+
+ m_monitorChanged = false;
+
+ const float opacity = m_fadeOpacity->value();
+
+ CRectPassElement::SRectData bgData;
+ bgData.box = barBox;
+ bgData.color = CHyprColor(0.06, 0.06, 0.06, opacity);
+ bgData.round = sc<int>(std::round(m_radius));
+ g_pHyprRenderer->m_renderPass.add(makeUnique<CRectPassElement>(std::move(bgData)));
+
+ CBorderPassElement::SBorderData borderData;
+ borderData.box = barBox;
+ borderData.grad1 = m_borderGradient;
+ borderData.round = sc<int>(std::round(m_radius));
+ borderData.outerRound = sc<int>(std::round(m_radius));
+ borderData.borderSize = 2;
+ borderData.a = opacity;
+ g_pHyprRenderer->m_renderPass.add(makeUnique<CBorderPassElement>(std::move(borderData)));
+
+ if (m_textTexture) {
+ CTexPassElement::SRenderData textData;
+ textData.tex = m_textTexture;
+ textData.box = {Vector2D{barBox.x + m_textOffsetX, barBox.y + m_textOffsetY}.round(), m_textSize};
+ textData.a = opacity;
+ textData.clipRegion = CRegion(barBox.copy().expand(-1));
+
+ g_pHyprRenderer->m_renderPass.add(makeUnique<CTexPassElement>(std::move(textData)));
+ }
+}
+
+void COverlay::destroy() {
+ if (m_isCreated)
+ m_queuedDestroy = true;
+ else
+ m_queued = "";
+}
+
+bool COverlay::active() {
+ return m_isCreated;
+}
+
+float COverlay::height() {
+ return m_lastHeight;
+}
diff --git a/src/errorOverlay/Overlay.hpp b/src/errorOverlay/Overlay.hpp
new file mode 100644
index 00000000..68f0e5dc
--- /dev/null
+++ b/src/errorOverlay/Overlay.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <vector>
+
+#include "../defines.hpp"
+#include "../render/Texture.hpp"
+#include "../helpers/AnimatedVariable.hpp"
+#include "../helpers/MiscFunctions.hpp"
+#include "../config/shared/complex/ComplexDataTypes.hpp"
+
+namespace ErrorOverlay {
+
+ namespace Colors {
+ constexpr const float ANGLE_30 = 0.52359877;
+
+ static const Config::CGradientValueData ERROR =
+ Config::CGradientValueData{std::vector<CHyprColor>{*configStringToInt("0xffff6666"), *configStringToInt("0xff800000")}, ANGLE_30};
+ static const Config::CGradientValueData WARNING =
+ Config::CGradientValueData{std::vector<CHyprColor>{*configStringToInt("0xffffdb4d"), *configStringToInt("0xff665200")}, ANGLE_30};
+ };
+
+ class COverlay {
+ public:
+ COverlay();
+ ~COverlay() = default;
+
+ void queueCreate(std::string message, const CHyprColor& color);
+ void queueCreate(std::string message, const Config::CGradientValueData& gradient);
+ void queueError(std::string err);
+ void draw();
+ void destroy();
+
+ bool active();
+ float height(); // logical
+
+ private:
+ void createQueued();
+ std::string m_queued = "";
+ Config::CGradientValueData m_queuedBorderGradient;
+ Config::CGradientValueData m_borderGradient;
+ bool m_queuedDestroy = false;
+ bool m_isCreated = false;
+ SP<Render::ITexture> m_textTexture;
+ Vector2D m_textSize = {};
+ float m_outerPad = 0.F;
+ float m_radius = 0.F;
+ float m_textOffsetX = 0.F;
+ float m_textOffsetY = 0.F;
+ PHLANIMVAR<float> m_fadeOpacity;
+ CBox m_damageBox = {0, 0, 0, 0};
+ float m_lastHeight = 0.F;
+
+ bool m_monitorChanged = false;
+ };
+
+ UP<COverlay>& overlay();
+}
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 5fb6cf31..b65cb575 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -30,7 +30,7 @@
#include "../managers/animation/AnimationManager.hpp"
#include "../managers/animation/DesktopAnimationManager.hpp"
#include "../managers/input/InputManager.hpp"
-#include "../hyprerror/HyprError.hpp"
+#include "../errorOverlay/Overlay.hpp"
#include "../layout/LayoutManager.hpp"
#include "../i18n/Engine.hpp"
#include "../helpers/cm/ColorManagement.hpp"
@@ -981,12 +981,12 @@ bool CMonitor::applyMonitorRule(Config::CMonitorRule&& pMonitorRule, bool force)
auto image = NColorManagement::SImageDescription::fromICC(RULE->m_iccFile);
if (!image) {
Log::logger->log(Log::ERR, "icc for {} ({}) failed: {}", m_name, RULE->m_iccFile, image.error());
- g_pHyprError->queueError(std::format("failed to apply icc {} to {}: {}", RULE->m_iccFile, m_name, image.error()));
+ ErrorOverlay::overlay()->queueError(std::format("failed to apply icc {} to {}: {}", RULE->m_iccFile, m_name, image.error()));
} else {
m_imageDescription = CImageDescription::from(*image);
if (!m_imageDescription) {
Log::logger->log(Log::ERR, "icc for {} ({}) failed 2: {}", m_name, RULE->m_iccFile, image.error());
- g_pHyprError->queueError(std::format("failed to apply icc {} to {}: {}", RULE->m_iccFile, m_name, image.error()));
+ ErrorOverlay::overlay()->queueError(std::format("failed to apply icc {} to {}: {}", RULE->m_iccFile, m_name, image.error()));
m_imageDescription = CImageDescription::from(SImageDescription{});
}
}
@@ -1030,7 +1030,7 @@ bool CMonitor::applyMonitorRule(Config::CMonitorRule&& pMonitorRule, bool force)
m_scale = std::round(scaleZero);
else {
Log::logger->log(Log::ERR, "Invalid scale passed to monitor, {} failed to find a clean divisor", m_scale);
- g_pHyprError->queueError("Invalid scale passed to monitor " + m_name + ", failed to find a clean divisor");
+ ErrorOverlay::overlay()->queueError("Invalid scale passed to monitor " + m_name + ", failed to find a clean divisor");
m_scale = getDefaultScale();
}
} else {
@@ -1690,7 +1690,7 @@ uint32_t CMonitor::isSolitaryBlocked(bool full) {
return reasons;
}
- if (g_pHyprError->active() && Desktop::focusState()->monitor() == m_self) {
+ if (ErrorOverlay::overlay()->active() && Desktop::focusState()->monitor() == m_self) {
reasons |= SC_ERRORBAR;
if (!full)
return reasons;
diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp
deleted file mode 100644
index 634a1351..00000000
--- a/src/hyprerror/HyprError.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-#include <pango/pangocairo.h>
-#include "HyprError.hpp"
-#include "../Compositor.hpp"
-#include "../config/ConfigValue.hpp"
-#include "../config/shared/animation/AnimationTree.hpp"
-#include "../render/pass/TexPassElement.hpp"
-#include "../managers/animation/AnimationManager.hpp"
-#include "../render/Renderer.hpp"
-#include "../desktop/state/FocusState.hpp"
-#include "../event/EventBus.hpp"
-
-#include <hyprutils/utils/ScopeGuard.hpp>
-using namespace Hyprutils::Animation;
-
-CHyprError::CHyprError() {
- g_pAnimationManager->createAnimation(0.f, m_fadeOpacity, Config::animationTree()->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
-
- static auto P = Event::bus()->m_events.monitor.focused.listen([&](PHLMONITOR mon) {
- if (!m_isCreated)
- return;
-
- g_pHyprRenderer->damageMonitor(Desktop::focusState()->monitor());
- m_monitorChanged = true;
- });
-
- static auto P2 = Event::bus()->m_events.render.pre.listen([&](PHLMONITOR mon) {
- if (!m_isCreated)
- return;
-
- if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
- g_pHyprRenderer->damageBox(m_damageBox);
- });
-}
-
-void CHyprError::queueCreate(std::string message, const CHyprColor& color) {
- m_queued = message;
- m_queuedColor = color;
-}
-
-void CHyprError::queueError(std::string err) {
- queueCreate(err + "\nHyprland may not work correctly.", CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
-}
-
-void CHyprError::createQueued() {
- if (m_isCreated && m_texture)
- m_texture.reset();
-
- m_fadeOpacity->setConfig(Config::animationTree()->getAnimationPropertyConfig("fadeIn"));
-
- m_fadeOpacity->setValueAndWarp(0.f);
- *m_fadeOpacity = 1.f;
-
- const auto PMONITOR = g_pCompositor->m_monitors.front();
-
- const auto SCALE = PMONITOR->m_scale;
-
- const auto FONTSIZE = std::clamp(sc<int>(10.f * ((PMONITOR->m_pixelSize.x * SCALE) / 1920.f)), 8, 40);
-
- const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y);
-
- const auto CAIRO = cairo_create(CAIROSURFACE);
-
- // clear the pixmap
- cairo_save(CAIRO);
- cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR);
- cairo_paint(CAIRO);
- cairo_restore(CAIRO);
-
- const auto LINECOUNT = Hyprlang::INT{1} + std::ranges::count(m_queued, '\n');
- static auto LINELIMIT = CConfigValue<Hyprlang::INT>("debug:error_limit");
- static auto BAR_POSITION = CConfigValue<Hyprlang::INT>("debug:error_position");
-
- const bool TOPBAR = *BAR_POSITION == 0;
-
- const auto VISLINECOUNT = std::min(LINECOUNT, *LINELIMIT);
- const auto EXTRALINES = (VISLINECOUNT < LINECOUNT) ? 1 : 0;
-
- const double DEGREES = M_PI / 180.0;
-
- const double PAD = 10 * SCALE;
-
- const double WIDTH = PMONITOR->m_pixelSize.x - PAD * 2;
- const double HEIGHT = (FONTSIZE + 2 * (FONTSIZE / 10.0)) * (VISLINECOUNT + EXTRALINES) + 3;
- const double RADIUS = PAD > HEIGHT / 2 ? HEIGHT / 2 - 1 : PAD;
- const double X = PAD;
- const double Y = TOPBAR ? PAD : PMONITOR->m_pixelSize.y - HEIGHT - PAD;
-
- m_damageBox = {sc<int>(PMONITOR->m_position.x), sc<int>(PMONITOR->m_position.y + (TOPBAR ? 0 : PMONITOR->m_pixelSize.y - (HEIGHT + PAD * 2))), sc<int>(PMONITOR->m_pixelSize.x),
- sc<int>(HEIGHT + PAD * 2)};
-
- cairo_new_sub_path(CAIRO);
- cairo_arc(CAIRO, X + WIDTH - RADIUS, Y + RADIUS, RADIUS, -90 * DEGREES, 0 * DEGREES);
- cairo_arc(CAIRO, X + WIDTH - RADIUS, Y + HEIGHT - RADIUS, RADIUS, 0 * DEGREES, 90 * DEGREES);
- cairo_arc(CAIRO, X + RADIUS, Y + HEIGHT - RADIUS, RADIUS, 90 * DEGREES, 180 * DEGREES);
- cairo_arc(CAIRO, X + RADIUS, Y + RADIUS, RADIUS, 180 * DEGREES, 270 * DEGREES);
- cairo_close_path(CAIRO);
-
- cairo_set_source_rgba(CAIRO, 0.06, 0.06, 0.06, 1.0);
- cairo_fill_preserve(CAIRO);
- cairo_set_source_rgba(CAIRO, m_queuedColor.r, m_queuedColor.g, m_queuedColor.b, m_queuedColor.a);
- cairo_set_line_width(CAIRO, 2);
- cairo_stroke(CAIRO);
-
- // draw the text with a common font
- const CHyprColor textColor = CHyprColor(0.9, 0.9, 0.9, 1.0);
- cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a);
-
- static auto fontFamily = CConfigValue<std::string>("misc:font_family");
- PangoLayout* layoutText = pango_cairo_create_layout(CAIRO);
- PangoFontDescription* pangoFD = pango_font_description_new();
-
- pango_font_description_set_family(pangoFD, (*fontFamily).c_str());
- pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE);
- pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL);
- pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL);
- pango_layout_set_font_description(layoutText, pangoFD);
- pango_layout_set_width(layoutText, (WIDTH - 2 * (1 + RADIUS)) * PANGO_SCALE);
- pango_layout_set_ellipsize(layoutText, PANGO_ELLIPSIZE_END);
-
- float yoffset = TOPBAR ? 0 : Y - PAD;
- int renderedcnt = 0;
- while (!m_queued.empty() && renderedcnt < VISLINECOUNT) {
- std::string current = m_queued.substr(0, m_queued.find('\n'));
- if (const auto NEWLPOS = m_queued.find('\n'); NEWLPOS != std::string::npos)
- m_queued = m_queued.substr(NEWLPOS + 1);
- else
- m_queued = "";
- cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1);
- pango_layout_set_text(layoutText, current.c_str(), -1);
- pango_cairo_show_layout(CAIRO, layoutText);
- yoffset += FONTSIZE + (FONTSIZE / 10.f);
- renderedcnt++;
- }
- if (VISLINECOUNT < LINECOUNT) {
- std::string moreString = std::format("({} more...)", LINECOUNT - VISLINECOUNT);
- cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1);
- pango_layout_set_text(layoutText, moreString.c_str(), -1);
- pango_cairo_show_layout(CAIRO, layoutText);
- }
-
- m_lastHeight = HEIGHT;
-
- pango_font_description_free(pangoFD);
- g_object_unref(layoutText);
-
- cairo_surface_flush(CAIROSURFACE);
-
- // copy the data to an OpenGL texture we have
- m_texture = g_pHyprRenderer->createTexture(CAIROSURFACE);
-
- // delete cairo
- cairo_destroy(CAIRO);
- cairo_surface_destroy(CAIROSURFACE);
-
- m_isCreated = true;
- m_queued = "";
- m_queuedColor = CHyprColor();
-
- g_pHyprRenderer->damageMonitor(PMONITOR);
-
- for (const auto& m : g_pCompositor->m_monitors) {
- m->m_reservedArea.resetType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR);
- }
-
- const auto RESERVED = (HEIGHT + PAD) / SCALE;
- PMONITOR->m_reservedArea.addType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR, Vector2D{0.0, TOPBAR ? RESERVED : 0.0}, Vector2D{0.0, !TOPBAR ? RESERVED : 0.0});
-
- for (const auto& m : g_pCompositor->m_monitors) {
- g_pHyprRenderer->arrangeLayersForMonitor(m->m_id);
- }
-}
-
-void CHyprError::draw() {
- if (!m_isCreated || !m_queued.empty()) {
- if (!m_queued.empty())
- createQueued();
- return;
- }
-
- if (m_queuedDestroy) {
- if (!m_fadeOpacity->isBeingAnimated()) {
- if (m_fadeOpacity->value() == 0.f) {
- m_queuedDestroy = false;
- if (m_texture)
- m_texture.reset();
- m_isCreated = false;
- m_queued = "";
-
- for (auto& m : g_pCompositor->m_monitors) {
- g_pHyprRenderer->arrangeLayersForMonitor(m->m_id);
- m->m_reservedArea.resetType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR);
- }
-
- return;
- } else {
- m_fadeOpacity->setConfig(Config::animationTree()->getAnimationPropertyConfig("fadeOut"));
- *m_fadeOpacity = 0.f;
- }
- }
- }
-
- const auto PMONITOR = g_pHyprRenderer->m_renderData.pMonitor;
-
- CBox monbox = {0, 0, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y};
-
- static auto BAR_POSITION = CConfigValue<Hyprlang::INT>("debug:error_position");
- m_damageBox.x = sc<int>(PMONITOR->m_position.x);
- m_damageBox.y = sc<int>(PMONITOR->m_position.y + (*BAR_POSITION == 0 ? 0 : PMONITOR->m_pixelSize.y - m_damageBox.height));
-
- if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
- g_pHyprRenderer->damageBox(m_damageBox);
-
- m_monitorChanged = false;
-
- CTexPassElement::SRenderData data;
- data.tex = texture();
- data.box = monbox;
- data.a = m_fadeOpacity->value();
-
- g_pHyprRenderer->m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
-}
-
-void CHyprError::destroy() {
- if (m_isCreated)
- m_queuedDestroy = true;
- else
- m_queued = "";
-}
-
-bool CHyprError::active() {
- return m_isCreated;
-}
-
-float CHyprError::height() {
- return m_lastHeight;
-}
-
-SP<Render::ITexture> CHyprError::texture() {
- if (!m_texture)
- m_texture = g_pHyprRenderer->createTexture();
- return m_texture;
-} \ No newline at end of file
diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp
deleted file mode 100644
index f9c52283..00000000
--- a/src/hyprerror/HyprError.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include "../defines.hpp"
-#include "../render/Texture.hpp"
-#include "../helpers/AnimatedVariable.hpp"
-
-#include <cairo/cairo.h>
-
-class CHyprError {
- public:
- CHyprError();
- ~CHyprError() = default;
-
- void queueCreate(std::string message, const CHyprColor& color);
- void queueError(std::string err);
- void draw();
- void destroy();
-
- bool active();
- float height(); // logical
-
- SP<Render::ITexture> texture();
-
- private:
- void createQueued();
- std::string m_queued = "";
- CHyprColor m_queuedColor;
- bool m_queuedDestroy = false;
- bool m_isCreated = false;
- SP<Render::ITexture> m_texture;
- PHLANIMVAR<float> m_fadeOpacity;
- CBox m_damageBox = {0, 0, 0, 0};
- float m_lastHeight = 0.F;
-
- bool m_monitorChanged = false;
-};
-
-inline UP<CHyprError> g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time.
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index d7c57baa..e7f616f8 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -22,7 +22,7 @@
#include "../managers/animation/DesktopAnimationManager.hpp"
#include "../managers/EventManager.hpp"
#include "../render/Renderer.hpp"
-#include "../hyprerror/HyprError.hpp"
+#include "../errorOverlay/Overlay.hpp"
#include "../config/ConfigManager.hpp"
#include "../desktop/rule/windowRule/WindowRule.hpp"
#include "../desktop/rule/Engine.hpp"
@@ -288,9 +288,9 @@ void CKeybindManager::updateXKBTranslationState() {
fclose(KEYMAPFILE);
if (!PKEYMAP) {
- g_pHyprError->queueCreate("[Runtime Error] Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS +
- ", layout: " + LAYOUT + " )",
- CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ ErrorOverlay::overlay()->queueCreate("[Runtime Error] Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT +
+ ", options: " + OPTIONS + ", layout: " + LAYOUT + " )",
+ ErrorOverlay::Colors::ERROR);
Log::logger->log(Log::ERR, "[XKBTranslationState] Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout,
rules.variant, rules.rules, rules.model, rules.options);
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 9883d8fc..590330a3 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -33,7 +33,7 @@
#include "../event/EventBus.hpp"
#include "../managers/screenshare/ScreenshareManager.hpp"
#include "../notification/NotificationOverlay.hpp"
-#include "hyprerror/HyprError.hpp"
+#include "errorOverlay/Overlay.hpp"
#include "macros.hpp"
#include "pass/TexPassElement.hpp"
#include "pass/RectPassElement.hpp"
@@ -916,16 +916,16 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
std::error_code ec;
if (!std::filesystem::is_regular_file(absPath, ec)) {
if (ec)
- g_pHyprError->queueError("Screen shader parser: Failed to check screen shader path: " + ec.message());
+ ErrorOverlay::overlay()->queueError("Screen shader parser: Failed to check screen shader path: " + ec.message());
else
- g_pHyprError->queueError("Screen shader parser: Screen shader path is not a regular file");
+ ErrorOverlay::overlay()->queueError("Screen shader parser: Screen shader path is not a regular file");
return;
}
std::ifstream infile(absPath);
if (!infile.good()) {
- g_pHyprError->queueError("Screen shader parser: Failed to open screen shader");
+ ErrorOverlay::overlay()->queueError("Screen shader parser: Failed to open screen shader");
return;
}
@@ -952,9 +952,9 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
// The screen shader uses the uniform
// Since the screen shader could change every frame, damage tracking *needs* to be disabled
- g_pHyprError->queueError(std::format("Screen shader: Screen shader uses uniform '{}', which requires debug:damage_tracking to be switched off.\n"
- "WARNING:(Disabling damage tracking will *massively* increase GPU utilization!",
- name));
+ ErrorOverlay::overlay()->queueError(std::format("Screen shader: Screen shader uses uniform '{}', which requires debug:damage_tracking to be switched off.\n"
+ "WARNING:(Disabling damage tracking will *massively* increase GPU utilization!",
+ name));
};
// Allow glitch shader to use time uniform whighout damage tracking
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index acd83f8f..a77e855d 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -24,7 +24,7 @@
#include "../protocols/DRMSyncobj.hpp"
#include "../protocols/LinuxDMABUF.hpp"
#include "../helpers/sync/SyncTimeline.hpp"
-#include "../hyprerror/HyprError.hpp"
+#include "../errorOverlay/Overlay.hpp"
#include "../debug/Overlay.hpp"
#include "../notification/NotificationOverlay.hpp"
#include "../layout/LayoutManager.hpp"
@@ -159,7 +159,7 @@ IHyprRenderer::IHyprRenderer() {
static auto P3 = Event::bus()->m_events.monitor.focused.listen([&](PHLMONITOR mon) {
g_pEventLoopManager->doLater([this]() {
- if (!g_pHyprError->active())
+ if (!ErrorOverlay::overlay()->active())
return;
for (auto& m : g_pCompositor->m_monitors) {
arrangeLayersForMonitor(m->m_id);
@@ -2067,7 +2067,7 @@ void IHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
if (pMonitor == Desktop::focusState()->monitor()) {
Notification::overlay()->draw(pMonitor);
- g_pHyprError->draw();
+ ErrorOverlay::overlay()->draw();
}
// for drawing the debug overlay
diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp
index dfc9045a..14601560 100644
--- a/src/render/Shader.cpp
+++ b/src/render/Shader.cpp
@@ -1,5 +1,5 @@
#include "Shader.hpp"
-#include "../hyprerror/HyprError.hpp"
+#include "../errorOverlay/Overlay.hpp"
#include "../config/ConfigValue.hpp"
#include "OpenGL.hpp"
@@ -45,7 +45,7 @@ void CShader::logShaderError(const GLuint& shader, bool program, bool silent) {
Log::logger->log(Log::ERR, "Failed to link shader: {}", FULLERROR);
if (!silent)
- g_pHyprError->queueError(FULLERROR);
+ ErrorOverlay::overlay()->queueError(FULLERROR);
}
GLuint CShader::compileShader(const GLuint& type, std::string src, bool dynamic, bool silent) {