Hyprland/src/hyprerror/HyprError.cpp

228 lines
8 KiB
C++
Raw Normal View History

#include <pango/pangocairo.h>
#include "HyprError.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../render/pass/TexPassElement.hpp"
#include "../managers/AnimationManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/HookSystemManager.hpp"
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Animation;
2023-01-20 20:48:07 +01:00
CHyprError::CHyprError() {
g_pAnimationManager->createAnimation(0.f, m_fadeOpacity, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
2023-02-28 19:18:13 +00:00
2024-04-20 20:16:42 +01:00
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (!m_isCreated)
2023-02-28 19:18:13 +00:00
return;
g_pHyprRenderer->damageMonitor(g_pCompositor->m_lastMonitor.lock());
m_monitorChanged = true;
2023-02-28 19:18:13 +00:00
});
2024-04-20 20:16:42 +01:00
static auto P2 = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any param) {
if (!m_isCreated)
2023-02-28 19:18:13 +00:00
return;
if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
g_pHyprRenderer->damageBox(m_damageBox);
2023-02-28 19:18:13 +00:00
});
m_texture = makeShared<CTexture>();
2023-01-20 20:48:07 +01:00
}
void CHyprError::queueCreate(std::string message, const CHyprColor& color) {
m_queued = message;
m_queuedColor = color;
}
void CHyprError::createQueued() {
if (m_isCreated)
m_texture->destroyTexture();
m_fadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
2023-01-23 12:04:48 +00:00
m_fadeOpacity->setValueAndWarp(0.f);
*m_fadeOpacity = 1.f;
2023-01-20 20:48:07 +01:00
const auto PMONITOR = g_pCompositor->m_monitors.front();
const auto SCALE = PMONITOR->m_scale;
2023-01-20 20:21:09 +01:00
const auto FONTSIZE = std::clamp((int)(10.f * ((PMONITOR->m_pixelSize.x * SCALE) / 1920.f)), 8, 40);
2022-08-16 16:25:53 +02:00
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::count(m_queued.begin(), m_queued.end(), '\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;
2023-01-20 19:32:41 +01:00
const double DEGREES = M_PI / 180.0;
2023-01-20 20:21:09 +01:00
const double PAD = 10 * SCALE;
2023-01-20 19:32:41 +01:00
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;
2023-01-20 19:32:41 +01:00
m_damageBox = {0, 0, (int)PMONITOR->m_pixelSize.x, (int)HEIGHT + (int)PAD * 2};
2023-01-20 20:48:07 +01:00
2023-01-20 19:32:41 +01:00
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);
2024-08-02 18:42:05 +02:00
cairo_set_source_rgba(CAIRO, 0.06, 0.06, 0.06, 1.0);
2023-01-20 19:32:41 +01:00
cairo_fill_preserve(CAIRO);
cairo_set_source_rgba(CAIRO, m_queuedColor.r, m_queuedColor.g, m_queuedColor.b, m_queuedColor.a);
2023-01-20 19:32:41 +01:00
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);
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 = "";
2023-01-20 19:32:41 +01:00
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);
2022-08-16 16:25:53 +02:00
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_queued = "";
2022-09-25 20:07:48 +02:00
m_lastHeight = yoffset + PAD + 1 - (TOPBAR ? 0 : Y - PAD);
pango_font_description_free(pangoFD);
g_object_unref(layoutText);
cairo_surface_flush(CAIROSURFACE);
// copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
m_texture->allocate();
glBindTexture(GL_TEXTURE_2D, m_texture->m_texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2022-11-07 20:31:56 +00:00
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
2022-09-25 20:07:48 +02:00
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
// delete cairo
cairo_destroy(CAIRO);
cairo_surface_destroy(CAIROSURFACE);
m_isCreated = true;
m_queued = "";
m_queuedColor = CHyprColor();
2022-05-12 12:46:38 +02:00
g_pHyprRenderer->damageMonitor(PMONITOR);
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id);
}
void CHyprError::draw() {
if (!m_isCreated || m_queued != "") {
if (m_queued != "")
createQueued();
return;
}
if (m_queuedDestroy) {
if (!m_fadeOpacity->isBeingAnimated()) {
if (m_fadeOpacity->value() == 0.f) {
m_queuedDestroy = false;
m_texture->destroyTexture();
m_isCreated = false;
m_queued = "";
for (auto& m : g_pCompositor->m_monitors) {
g_pHyprRenderer->arrangeLayersForMonitor(m->m_id);
}
2023-01-20 20:48:07 +01:00
return;
} else {
m_fadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
*m_fadeOpacity = 0.f;
2023-01-20 20:48:07 +01:00
}
}
}
const auto PMONITOR = g_pHyprOpenGL->m_renderData.pMonitor;
CBox monbox = {0, 0, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y};
m_damageBox.x = (int)PMONITOR->m_position.x;
m_damageBox.y = (int)PMONITOR->m_position.y;
2023-01-20 20:48:07 +01:00
if (m_fadeOpacity->isBeingAnimated() || m_monitorChanged)
g_pHyprRenderer->damageBox(m_damageBox);
m_monitorChanged = false;
2023-02-28 19:18:13 +00:00
CTexPassElement::SRenderData data;
data.tex = m_texture;
data.box = monbox;
data.a = m_fadeOpacity->value();
g_pHyprRenderer->m_renderPass.add(makeShared<CTexPassElement>(data));
}
void CHyprError::destroy() {
if (m_isCreated)
m_queuedDestroy = true;
else
m_queued = "";
2022-09-25 20:07:48 +02:00
}
bool CHyprError::active() {
return m_isCreated;
}
float CHyprError::height() {
return m_lastHeight;
}