mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-07 10:18:07 +02:00
errorOverlay: modernize, refactor, use GPU rendering (#14122)
Improves the overlay's rendering: - GPU accelerated - supports gradients - wraps - cleaner code a bit
This commit is contained in:
parent
889ee4f26d
commit
a360c31d04
14 changed files with 359 additions and 319 deletions
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
260
src/errorOverlay/Overlay.cpp
Normal file
260
src/errorOverlay/Overlay.cpp
Normal file
|
|
@ -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;
|
||||
}
|
||||
57
src/errorOverlay/Overlay.hpp
Normal file
57
src/errorOverlay/Overlay.hpp
Normal file
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue