diff --git a/src/Compositor.cpp b/src/Compositor.cpp index d9de51959..92f81fc6e 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(); + Log::logger->log(Log::DEBUG, "Creating the Error Overlay!"); + ErrorOverlay::overlay(); Log::logger->log(Log::DEBUG, "Creating the LayoutManager!"); g_layoutManager = makeUnique(); diff --git a/src/config/legacy/ConfigManager.cpp b/src/config/legacy/ConfigManager.cpp index c91959c86..bfe8fef37 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(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(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 2db73ae8a..536b0433a 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&& 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 3f239cef0..fd9cad75f 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 fde28324b..678141f32 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 #include #include @@ -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 000000000..928d78003 --- /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 +#include + +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(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& ErrorOverlay::overlay() { + static UP p = makeUnique(); + 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(10.f * ((PMONITOR->m_pixelSize.x * SCALE) / 1920.f)), 8, 40); + + static auto LINELIMIT = CConfigValue("debug:error_limit"); + static auto BAR_POSITION = CConfigValue("debug:error_position"); + static auto FONT_FAMILY = CConfigValue("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(1.F, sc(PMONITOR->m_pixelSize.x) - m_outerPad * 2.F); + const float textMaxWidth = std::max(1.F, barWidth - 2.F * (1.F + m_outerPad)); + + m_textTexture = g_pHyprRenderer->renderText(Hyprgraphics::CTextResource::STextResourceData{ + .text = visibleText, + .font = *FONT_FAMILY, + .fontSize = sc(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(3.F, sc(m_textSize.y) + 3.F); + m_radius = std::min(m_outerPad, std::max(0.F, m_lastHeight / 2.F - 1.F)); + m_textOffsetX = 1.F + m_radius; + m_textOffsetY = 1.F; + + m_damageBox = { + sc(PMONITOR->m_position.x), + sc(PMONITOR->m_position.y + (TOPBAR ? 0 : PMONITOR->m_pixelSize.y - (m_lastHeight + m_outerPad * 2.F))), + sc(PMONITOR->m_pixelSize.x), + sc(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("debug:error_position"); + const bool TOPBAR = *BAR_POSITION == 0; + + const float barWidth = std::max(1.F, sc(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(PMONITOR->m_position.x); + m_damageBox.width = sc(PMONITOR->m_pixelSize.x); + m_damageBox.height = sc(m_lastHeight + m_outerPad * 2.F); + m_damageBox.y = sc(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(std::round(m_radius)); + g_pHyprRenderer->m_renderPass.add(makeUnique(std::move(bgData))); + + CBorderPassElement::SBorderData borderData; + borderData.box = barBox; + borderData.grad1 = m_borderGradient; + borderData.round = sc(std::round(m_radius)); + borderData.outerRound = sc(std::round(m_radius)); + borderData.borderSize = 2; + borderData.a = opacity; + g_pHyprRenderer->m_renderPass.add(makeUnique(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(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 000000000..68f0e5dcc --- /dev/null +++ b/src/errorOverlay/Overlay.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include + +#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{*configStringToInt("0xffff6666"), *configStringToInt("0xff800000")}, ANGLE_30}; + static const Config::CGradientValueData WARNING = + Config::CGradientValueData{std::vector{*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 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 m_fadeOpacity; + CBox m_damageBox = {0, 0, 0, 0}; + float m_lastHeight = 0.F; + + bool m_monitorChanged = false; + }; + + UP& overlay(); +} diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 5fb6cf31b..b65cb5753 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 634a13519..000000000 --- a/src/hyprerror/HyprError.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include -#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 -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(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("debug:error_limit"); - static auto BAR_POSITION = CConfigValue("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(PMONITOR->m_position.x), sc(PMONITOR->m_position.y + (TOPBAR ? 0 : PMONITOR->m_pixelSize.y - (HEIGHT + PAD * 2))), sc(PMONITOR->m_pixelSize.x), - sc(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("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("debug:error_position"); - m_damageBox.x = sc(PMONITOR->m_position.x); - m_damageBox.y = sc(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(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 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 f9c522836..000000000 --- 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 - -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 texture(); - - private: - void createQueued(); - std::string m_queued = ""; - CHyprColor m_queuedColor; - bool m_queuedDestroy = false; - bool m_isCreated = false; - SP m_texture; - PHLANIMVAR m_fadeOpacity; - CBox m_damageBox = {0, 0, 0, 0}; - float m_lastHeight = 0.F; - - bool m_monitorChanged = false; -}; - -inline UP 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 d7c57baa0..e7f616f8a 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 9883d8fcd..590330a33 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 acd83f8f2..a77e855d1 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 dfc9045ae..14601560e 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) {