renderer: render fonts with pango, add global font_family config option (#6138)
This commit is contained in:
parent
e419ef1873
commit
93fea89043
7 changed files with 157 additions and 136 deletions
|
|
@ -1,4 +1,6 @@
|
|||
#include <pango/pangocairo.h>
|
||||
#include "HyprDebugOverlay.hpp"
|
||||
#include "config/ConfigValue.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
|
||||
|
|
@ -47,11 +49,6 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
|||
if (!m_pMonitor)
|
||||
return 0;
|
||||
|
||||
int yOffset = offset;
|
||||
cairo_text_extents_t cairoExtents;
|
||||
float maxX = 0;
|
||||
std::string text = "";
|
||||
|
||||
// get avg fps
|
||||
float avgFrametime = 0;
|
||||
float maxFrametime = 0;
|
||||
|
|
@ -105,23 +102,49 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
|||
float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick;
|
||||
avgAnimMgrTick /= m_dLastAnimationTicks.size() == 0 ? 1 : m_dLastAnimationTicks.size();
|
||||
|
||||
const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms
|
||||
const float idealFPS = m_dLastFrametimes.size();
|
||||
const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms
|
||||
const float idealFPS = m_dLastFrametimes.size();
|
||||
|
||||
cairo_select_font_face(g_pDebugOverlay->m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
static auto fontFamily = CConfigValue<std::string>("misc:font_family");
|
||||
PangoLayout* layoutText = pango_cairo_create_layout(g_pDebugOverlay->m_pCairo);
|
||||
PangoFontDescription* pangoFD = pango_font_description_new();
|
||||
|
||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
||||
pango_font_description_set_family(pangoFD, (*fontFamily).c_str());
|
||||
pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL);
|
||||
pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL);
|
||||
|
||||
float maxTextW = 0;
|
||||
int fontSize = 0;
|
||||
auto cr = g_pDebugOverlay->m_pCairo;
|
||||
|
||||
auto showText = [cr, layoutText, pangoFD, &maxTextW, &fontSize](const char* text, int size) {
|
||||
if (fontSize != size) {
|
||||
pango_font_description_set_absolute_size(pangoFD, size * PANGO_SCALE);
|
||||
pango_layout_set_font_description(layoutText, pangoFD);
|
||||
fontSize = size;
|
||||
}
|
||||
|
||||
pango_layout_set_text(layoutText, text, -1);
|
||||
pango_cairo_show_layout(cr, layoutText);
|
||||
|
||||
int textW = 0, textH = 0;
|
||||
pango_layout_get_size(layoutText, &textW, &textH);
|
||||
textW /= PANGO_SCALE;
|
||||
textH /= PANGO_SCALE;
|
||||
if (textW > maxTextW)
|
||||
maxTextW = textW;
|
||||
|
||||
// move to next line
|
||||
cairo_rel_move_to(cr, 0, fontSize + 1);
|
||||
};
|
||||
|
||||
const int MARGIN_TOP = 8;
|
||||
const int MARGIN_LEFT = 4;
|
||||
cairo_move_to(cr, MARGIN_LEFT, MARGIN_TOP + offset);
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
yOffset += 10;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = m_pMonitor->szName;
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX)
|
||||
maxX = cairoExtents.width;
|
||||
|
||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 16);
|
||||
std::string text;
|
||||
showText(m_pMonitor->szName.c_str(), 10);
|
||||
|
||||
if (FPS > idealFPS * 0.95f)
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 0.2f, 1.f, 0.2f, 1.f);
|
||||
|
|
@ -130,57 +153,35 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
|
|||
else
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 0.2f, 0.2f, 1.f);
|
||||
|
||||
yOffset += 17;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::format("{} FPS", (int)FPS);
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX)
|
||||
maxX = cairoExtents.width;
|
||||
showText(text.c_str(), 16);
|
||||
|
||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime);
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX)
|
||||
maxX = cairoExtents.width;
|
||||
showText(text.c_str(), 10);
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::format("Avg Rendertime: {:.2f}ms (var {:.2f}ms)", avgRenderTime, varRenderTime);
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX)
|
||||
maxX = cairoExtents.width;
|
||||
showText(text.c_str(), 10);
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::format("Avg Rendertime (No Overlay): {:.2f}ms (var {:.2f}ms)", avgRenderTimeNoOverlay, varRenderTimeNoOverlay);
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX)
|
||||
maxX = cairoExtents.width;
|
||||
showText(text.c_str(), 10);
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::format("Avg Anim Tick: {:.2f}ms (var {:.2f}ms) ({:.2f} TPS)", avgAnimMgrTick, varAnimMgrTick, 1.0 / (avgAnimMgrTick / 1000.0));
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX)
|
||||
maxX = cairoExtents.width;
|
||||
showText(text.c_str(), 10);
|
||||
|
||||
yOffset += 11;
|
||||
pango_font_description_free(pangoFD);
|
||||
g_object_unref(layoutText);
|
||||
|
||||
double posX = 0, posY = 0;
|
||||
cairo_get_current_point(cr, &posX, &posY);
|
||||
|
||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||
m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset - 1, (int)maxX + 2,
|
||||
yOffset - offset + 2};
|
||||
m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1,
|
||||
(int)maxTextW + 2, posY - offset - MARGIN_TOP + 2};
|
||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||
|
||||
return yOffset - offset;
|
||||
return posY - offset;
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,20 @@
|
|||
#include <numeric>
|
||||
#include <pango/pangocairo.h>
|
||||
#include "HyprNotificationOverlay.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include <pango/pangocairo.h>
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
inline auto iconBackendFromLayout(PangoLayout* layout) {
|
||||
// preference: Nerd > FontAwesome > text
|
||||
auto eIconBackendChecks = std::array<eIconBackend, 2>{ICONS_BACKEND_NF, ICONS_BACKEND_FA};
|
||||
for (auto iconID : eIconBackendChecks) {
|
||||
auto iconsText = std::accumulate(ICONS_ARRAY[iconID].begin(), ICONS_ARRAY[iconID].end(), std::string());
|
||||
pango_layout_set_text(layout, iconsText.c_str(), -1);
|
||||
if (pango_layout_get_unknown_glyphs_count(layout) == 0)
|
||||
return iconID;
|
||||
}
|
||||
return ICONS_BACKEND_NONE;
|
||||
}
|
||||
|
||||
CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
||||
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
|
||||
|
|
@ -9,31 +23,6 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
|
|||
|
||||
g_pHyprRenderer->damageBox(&m_bLastDamage);
|
||||
});
|
||||
|
||||
// check for the icon backend
|
||||
std::string fonts = execAndGet("fc-list");
|
||||
std::string fontsLower = fonts;
|
||||
std::transform(fontsLower.begin(), fontsLower.end(), fontsLower.begin(), [&](char& i) { return std::tolower(i); });
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
if (index = fontsLower.find("nerd"); index != std::string::npos) {
|
||||
m_eIconBackend = ICONS_BACKEND_NF;
|
||||
} else if (index = fontsLower.find("font awesome"); index != std::string::npos) {
|
||||
m_eIconBackend = ICONS_BACKEND_FA;
|
||||
} else if (index = fontsLower.find("fontawesome"); index != std::string::npos) {
|
||||
m_eIconBackend = ICONS_BACKEND_FA;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto LASTNEWLINE = fonts.find_last_of('\n', index);
|
||||
const auto COLON = fonts.find(':', LASTNEWLINE);
|
||||
const auto COMMA = fonts.find(',', COLON);
|
||||
const auto NEWLINE = fonts.find('\n', COLON);
|
||||
const auto LASTCHAR = COMMA < NEWLINE ? COMMA : NEWLINE;
|
||||
|
||||
m_szIconFontName = fonts.substr(COLON + 2, LASTCHAR - (COLON + 2));
|
||||
}
|
||||
|
||||
CHyprNotificationOverlay::~CHyprNotificationOverlay() {
|
||||
|
|
@ -81,25 +70,24 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
|||
float offsetY = 10;
|
||||
float maxWidth = 0;
|
||||
|
||||
const auto SCALE = pMonitor->scale;
|
||||
|
||||
const auto SCALE = pMonitor->scale;
|
||||
const auto MONSIZE = pMonitor->vecTransformedSize;
|
||||
|
||||
cairo_text_extents_t cairoExtents;
|
||||
int iconW = 0, iconH = 0;
|
||||
static auto fontFamily = CConfigValue<std::string>("misc:font_family");
|
||||
|
||||
cairo_select_font_face(m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
PangoLayout* layout = pango_cairo_create_layout(m_pCairo);
|
||||
PangoFontDescription* pangoFD = pango_font_description_new();
|
||||
|
||||
const auto PBEZIER = g_pAnimationManager->getBezier("default");
|
||||
pango_font_description_set_family(pangoFD, (*fontFamily).c_str());
|
||||
pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL);
|
||||
pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL);
|
||||
|
||||
const auto iconBackendID = iconBackendFromLayout(layout);
|
||||
const auto PBEZIER = g_pAnimationManager->getBezier("default");
|
||||
|
||||
for (auto& notif : m_dNotifications) {
|
||||
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
|
||||
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
|
||||
|
||||
PangoLayout* pangoLayout = pango_cairo_create_layout(m_pCairo);
|
||||
PangoFontDescription* pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str());
|
||||
pango_layout_set_font_description(pangoLayout, pangoFD);
|
||||
cairo_set_font_size(m_pCairo, FONTSIZE);
|
||||
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
|
||||
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
|
||||
|
||||
// first rect (bg, col)
|
||||
const float FIRSTRECTANIMP =
|
||||
|
|
@ -122,31 +110,37 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
|||
const float THIRDRECTPERC = notif->started.getMillis() / notif->timeMs;
|
||||
|
||||
// get text size
|
||||
cairo_text_extents(m_pCairo, notif->text.c_str(), &cairoExtents);
|
||||
const auto ICON = ICONS_ARRAY[m_eIconBackend][notif->icon];
|
||||
const auto ICON = ICONS_ARRAY[iconBackendID][notif->icon];
|
||||
const auto ICONCOLOR = ICONS_COLORS[notif->icon];
|
||||
pango_layout_set_text(pangoLayout, ICON.c_str(), -1);
|
||||
pango_layout_set_font_description(pangoLayout, pangoFD);
|
||||
pango_cairo_update_layout(m_pCairo, pangoLayout);
|
||||
pango_layout_get_size(pangoLayout, &iconW, &iconH);
|
||||
|
||||
int iconW = 0, iconH = 0;
|
||||
pango_font_description_set_absolute_size(pangoFD, PANGO_SCALE * FONTSIZE * ICON_SCALE);
|
||||
pango_layout_set_font_description(layout, pangoFD);
|
||||
pango_layout_set_text(layout, ICON.c_str(), -1);
|
||||
pango_layout_get_size(layout, &iconW, &iconH);
|
||||
iconW /= PANGO_SCALE;
|
||||
iconH /= PANGO_SCALE;
|
||||
|
||||
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
|
||||
int textW = 0, textH = 0;
|
||||
pango_font_description_set_absolute_size(pangoFD, PANGO_SCALE * FONTSIZE);
|
||||
pango_layout_set_font_description(layout, pangoFD);
|
||||
pango_layout_set_text(layout, notif->text.c_str(), -1);
|
||||
pango_layout_get_size(layout, &textW, &textH);
|
||||
textW /= PANGO_SCALE;
|
||||
textH /= PANGO_SCALE;
|
||||
|
||||
const auto NOTIFSIZE = Vector2D{cairoExtents.width + 20 + iconW + 2 * ICONPADFORNOTIF, cairoExtents.height + 10};
|
||||
const auto NOTIFSIZE = Vector2D{textW + 20 + iconW + 2 * ICONPADFORNOTIF, textH + 10};
|
||||
|
||||
// draw rects
|
||||
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
|
||||
cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y);
|
||||
cairo_fill(m_pCairo);
|
||||
|
||||
cairo_set_source_rgb(m_pCairo, 0.f, 0.f, 0.f);
|
||||
|
||||
cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y);
|
||||
cairo_fill(m_pCairo);
|
||||
|
||||
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
|
||||
|
||||
cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2);
|
||||
cairo_fill(m_pCairo);
|
||||
|
||||
|
|
@ -164,26 +158,27 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
|
|||
|
||||
// draw icon
|
||||
cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
|
||||
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY + std::round((NOTIFSIZE.y - iconH - 4) / 2.0));
|
||||
pango_cairo_show_layout(m_pCairo, pangoLayout);
|
||||
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY - 2 + std::round((NOTIFSIZE.y - iconH) / 2.0));
|
||||
pango_layout_set_text(layout, ICON.c_str(), -1);
|
||||
pango_cairo_show_layout(m_pCairo, layout);
|
||||
}
|
||||
|
||||
// draw text
|
||||
cairo_set_font_size(m_pCairo, FONTSIZE);
|
||||
cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
|
||||
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY + FONTSIZE + (FONTSIZE / 10.0));
|
||||
cairo_show_text(m_pCairo, notif->text.c_str());
|
||||
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY - 2 + std::round((NOTIFSIZE.y - textH) / 2.0));
|
||||
pango_layout_set_text(layout, notif->text.c_str(), -1);
|
||||
pango_cairo_show_layout(m_pCairo, layout);
|
||||
|
||||
// adjust offset and move on
|
||||
offsetY += NOTIFSIZE.y + 10;
|
||||
|
||||
if (maxWidth < NOTIFSIZE.x)
|
||||
maxWidth = NOTIFSIZE.x;
|
||||
|
||||
pango_font_description_free(pangoFD);
|
||||
g_object_unref(pangoLayout);
|
||||
}
|
||||
|
||||
pango_font_description_free(pangoFD);
|
||||
g_object_unref(layout);
|
||||
|
||||
// cleanup notifs
|
||||
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
|
||||
|
||||
|
|
|
|||
|
|
@ -59,9 +59,6 @@ class CHyprNotificationOverlay {
|
|||
Vector2D m_vecLastSize = Vector2D(-1, -1);
|
||||
|
||||
CTexture m_tTexture;
|
||||
|
||||
eIconBackend m_eIconBackend = ICONS_BACKEND_NONE;
|
||||
std::string m_szIconFontName = "Sans";
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue