2024-05-22 10:09:36 +02:00
|
|
|
#include <pango/pangocairo.h>
|
2022-04-08 21:40:41 +02:00
|
|
|
#include "HyprError.hpp"
|
|
|
|
#include "../Compositor.hpp"
|
2024-03-21 02:55:13 +01:00
|
|
|
#include "../config/ConfigValue.hpp"
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2023-01-20 20:48:07 +01:00
|
|
|
CHyprError::CHyprError() {
|
2024-03-29 01:23:16 +01:00
|
|
|
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
|
2023-01-20 20:48:07 +01:00
|
|
|
m_fFadeOpacity.registerVar();
|
2023-02-28 20:18:13 +01:00
|
|
|
|
2024-04-20 21:16:42 +02:00
|
|
|
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
2023-02-28 20:18:13 +01:00
|
|
|
if (!m_bIsCreated)
|
|
|
|
return;
|
|
|
|
|
2024-05-05 23:18:10 +02:00
|
|
|
g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.get());
|
2023-02-28 20:18:13 +01:00
|
|
|
m_bMonitorChanged = true;
|
|
|
|
});
|
|
|
|
|
2024-04-20 21:16:42 +02:00
|
|
|
static auto P2 = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any param) {
|
2023-02-28 20:18:13 +01:00
|
|
|
if (!m_bIsCreated)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged)
|
|
|
|
g_pHyprRenderer->damageBox(&m_bDamageBox);
|
|
|
|
});
|
2024-06-08 10:07:59 +02:00
|
|
|
|
|
|
|
m_pTexture = makeShared<CTexture>();
|
2023-01-20 20:48:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CHyprError::~CHyprError() {
|
|
|
|
m_fFadeOpacity.unregister();
|
|
|
|
}
|
|
|
|
|
2022-04-08 21:40:41 +02:00
|
|
|
void CHyprError::queueCreate(std::string message, const CColor& color) {
|
|
|
|
m_szQueued = message;
|
2022-12-16 18:17:31 +01:00
|
|
|
m_cQueued = color;
|
2022-04-08 21:40:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprError::createQueued() {
|
2024-06-08 10:07:59 +02:00
|
|
|
if (m_bIsCreated)
|
|
|
|
m_pTexture->destroyTexture();
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2023-01-23 13:04:48 +01:00
|
|
|
m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
|
|
|
|
|
2023-01-20 20:48:07 +01:00
|
|
|
m_fFadeOpacity.setValueAndWarp(0.f);
|
|
|
|
m_fFadeOpacity = 1.f;
|
|
|
|
|
2022-06-30 15:44:26 +02:00
|
|
|
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2023-01-20 20:21:09 +01:00
|
|
|
const auto SCALE = PMONITOR->scale;
|
|
|
|
|
|
|
|
const auto FONTSIZE = std::clamp((int)(10.f * ((PMONITOR->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
|
2022-08-16 16:25:53 +02:00
|
|
|
|
2022-07-07 18:45:01 +02:00
|
|
|
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
2022-04-08 21:40:41 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2024-05-17 20:06:51 +02:00
|
|
|
const auto LINECOUNT = Hyprlang::INT{1} + std::count(m_szQueued.begin(), m_szQueued.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;
|
2024-03-21 02:55:13 +01:00
|
|
|
|
|
|
|
const auto VISLINECOUNT = std::min(LINECOUNT, *LINELIMIT);
|
|
|
|
const auto EXTRALINES = (VISLINECOUNT < LINECOUNT) ? 1 : 0;
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2023-01-20 19:32:41 +01:00
|
|
|
const double DEGREES = M_PI / 180.0;
|
2022-04-08 21:40:41 +02:00
|
|
|
|
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->vecPixelSize.x - PAD * 2;
|
2024-03-21 02:55:13 +01:00
|
|
|
const double HEIGHT = (FONTSIZE + 2 * (FONTSIZE / 10.0)) * (VISLINECOUNT + EXTRALINES) + 3;
|
2023-01-22 16:48:45 +01:00
|
|
|
const double RADIUS = PAD > HEIGHT / 2 ? HEIGHT / 2 - 1 : PAD;
|
2024-05-17 20:06:51 +02:00
|
|
|
const double X = PAD;
|
|
|
|
const double Y = TOPBAR ? PAD : PMONITOR->vecPixelSize.y - HEIGHT - PAD;
|
2023-01-20 19:32:41 +01:00
|
|
|
|
2023-02-28 20:18:13 +01:00
|
|
|
m_bDamageBox = {0, 0, (int)PMONITOR->vecPixelSize.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);
|
|
|
|
|
2023-01-22 16:45:00 +01:00
|
|
|
cairo_set_source_rgba(CAIRO, m_cQueued.r, m_cQueued.g, m_cQueued.b, m_cQueued.a);
|
2023-01-20 19:32:41 +01:00
|
|
|
cairo_fill_preserve(CAIRO);
|
|
|
|
cairo_set_source_rgba(CAIRO, 0, 0, 0, 1);
|
|
|
|
cairo_set_line_width(CAIRO, 2);
|
|
|
|
cairo_stroke(CAIRO);
|
2022-04-08 21:40:41 +02:00
|
|
|
|
|
|
|
// draw the text with a common font
|
2023-01-20 19:19:07 +01:00
|
|
|
const CColor textColor = m_cQueued.r + m_cQueued.g + m_cQueued.b < 0.2f ? CColor(1.0, 1.0, 1.0, 1.0) : CColor(0, 0, 0, 1.0);
|
2023-01-05 19:25:45 +01:00
|
|
|
cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a);
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2024-05-22 10:09:36 +02:00
|
|
|
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;
|
2024-03-21 02:55:13 +01:00
|
|
|
int renderedcnt = 0;
|
2024-05-17 20:06:51 +02:00
|
|
|
while (!m_szQueued.empty() && renderedcnt < VISLINECOUNT) {
|
2022-04-08 21:40:41 +02:00
|
|
|
std::string current = m_szQueued.substr(0, m_szQueued.find('\n'));
|
|
|
|
if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos)
|
|
|
|
m_szQueued = m_szQueued.substr(NEWLPOS + 1);
|
|
|
|
else
|
|
|
|
m_szQueued = "";
|
2023-01-20 19:32:41 +01:00
|
|
|
cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1);
|
2024-05-22 10:09:36 +02:00
|
|
|
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);
|
2024-03-21 02:55:13 +01:00
|
|
|
renderedcnt++;
|
|
|
|
}
|
|
|
|
if (VISLINECOUNT < LINECOUNT) {
|
|
|
|
std::string moreString = std::format("({} more...)", LINECOUNT - VISLINECOUNT);
|
|
|
|
cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1);
|
2024-05-22 10:09:36 +02:00
|
|
|
pango_layout_set_text(layoutText, moreString.c_str(), -1);
|
|
|
|
pango_cairo_show_layout(CAIRO, layoutText);
|
2022-04-08 21:40:41 +02:00
|
|
|
}
|
2024-03-21 02:55:13 +01:00
|
|
|
m_szQueued = "";
|
2022-09-25 20:07:48 +02:00
|
|
|
|
2024-05-22 10:09:36 +02:00
|
|
|
pango_font_description_free(pangoFD);
|
|
|
|
g_object_unref(layoutText);
|
|
|
|
|
2022-04-08 21:40:41 +02:00
|
|
|
cairo_surface_flush(CAIROSURFACE);
|
|
|
|
|
|
|
|
// copy the data to an OpenGL texture we have
|
|
|
|
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
2024-06-08 10:07:59 +02:00
|
|
|
m_pTexture->allocate();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID);
|
2022-04-08 21:40:41 +02:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
2022-09-25 20:07:48 +02:00
|
|
|
|
2022-11-07 21:31:56 +01:00
|
|
|
#ifndef GLES2
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
|
|
|
#endif
|
2022-09-25 20:07:48 +02:00
|
|
|
|
2022-07-07 18:45:01 +02:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
2022-04-08 21:40:41 +02:00
|
|
|
|
|
|
|
// delete cairo
|
|
|
|
cairo_destroy(CAIRO);
|
|
|
|
cairo_surface_destroy(CAIROSURFACE);
|
|
|
|
|
|
|
|
m_bIsCreated = true;
|
2022-12-16 18:17:31 +01:00
|
|
|
m_szQueued = "";
|
|
|
|
m_cQueued = CColor();
|
2022-05-12 12:46:38 +02:00
|
|
|
|
|
|
|
g_pHyprRenderer->damageMonitor(PMONITOR);
|
2022-04-08 21:40:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprError::draw() {
|
2022-04-09 22:49:07 +02:00
|
|
|
if (!m_bIsCreated || m_szQueued != "") {
|
2022-04-08 21:40:41 +02:00
|
|
|
if (m_szQueued != "")
|
|
|
|
createQueued();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_bQueuedDestroy) {
|
2023-01-20 20:48:07 +01:00
|
|
|
if (!m_fFadeOpacity.isBeingAnimated()) {
|
2024-03-02 01:35:17 +01:00
|
|
|
if (m_fFadeOpacity.value() == 0.f) {
|
2023-01-20 20:48:07 +01:00
|
|
|
m_bQueuedDestroy = false;
|
2024-06-08 10:07:59 +02:00
|
|
|
m_pTexture->destroyTexture();
|
2023-01-20 20:48:07 +01:00
|
|
|
m_bIsCreated = false;
|
|
|
|
m_szQueued = "";
|
|
|
|
return;
|
|
|
|
} else {
|
2023-01-23 13:04:48 +01:00
|
|
|
m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
|
2023-01-20 20:48:07 +01:00
|
|
|
m_fFadeOpacity = 0.f;
|
|
|
|
}
|
|
|
|
}
|
2022-04-08 21:40:41 +02:00
|
|
|
}
|
|
|
|
|
2023-02-28 20:18:13 +01:00
|
|
|
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2023-11-04 18:03:05 +01:00
|
|
|
CBox monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2023-02-28 20:18:13 +01:00
|
|
|
m_bDamageBox.x = (int)PMONITOR->vecPosition.x;
|
|
|
|
m_bDamageBox.y = (int)PMONITOR->vecPosition.y;
|
2023-01-20 20:48:07 +01:00
|
|
|
|
2023-02-28 20:18:13 +01:00
|
|
|
if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged)
|
2023-01-20 20:48:07 +01:00
|
|
|
g_pHyprRenderer->damageBox(&m_bDamageBox);
|
2022-04-08 21:40:41 +02:00
|
|
|
|
2023-02-28 20:18:13 +01:00
|
|
|
m_bMonitorChanged = false;
|
|
|
|
|
2024-06-08 10:07:59 +02:00
|
|
|
g_pHyprOpenGL->renderTexture(m_pTexture, &monbox, m_fFadeOpacity.value(), 0);
|
2022-04-08 21:40:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprError::destroy() {
|
2022-05-12 12:46:38 +02:00
|
|
|
if (m_bIsCreated)
|
|
|
|
m_bQueuedDestroy = true;
|
2023-05-01 16:10:53 +02:00
|
|
|
else
|
|
|
|
m_szQueued = "";
|
2022-09-25 20:07:48 +02:00
|
|
|
}
|