aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/hyprerror/HyprError.cpp
blob: 169d938a0fb34727a4d9e6e0370101d67cf0b5ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "HyprError.hpp"
#include "../Compositor.hpp"

void CHyprError::queueCreate(std::string message, const CColor& color) {
    m_szQueued = message;
    m_cQueued  = color;
}

void CHyprError::createQueued() {
    if (m_bIsCreated) {
        m_bQueuedDestroy = false;
        m_tTexture.destroyTexture();
    }

    const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();

    const auto FONTSIZE = std::clamp((int)(10.f * (PMONITOR->vecPixelSize.x / 1920.f)), 8, 40);

    const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.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 = 1 + std::count(m_szQueued.begin(), m_szQueued.end(), '\n');

    cairo_set_source_rgba(CAIRO, m_cQueued.r / 255.f, m_cQueued.g / 255.f, m_cQueued.b / 255.f, m_cQueued.a / 255.f);
    cairo_rectangle(CAIRO, 0, 0, PMONITOR->vecPixelSize.x, (FONTSIZE + 2 * (FONTSIZE / 10.f)) * LINECOUNT);

    // outline
    cairo_rectangle(CAIRO, 0, 0, 1, PMONITOR->vecPixelSize.y);                                                   // left
    cairo_rectangle(CAIRO, PMONITOR->vecPixelSize.x - 1, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); // right
    cairo_rectangle(CAIRO, 0, PMONITOR->vecPixelSize.y - 1, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); // bottom

    cairo_fill(CAIRO);

    // draw the text with a common font
    const CColor textColor = m_cQueued.r * m_cQueued.g * m_cQueued.b < 0.5f ? CColor(255, 255, 255, 255) : CColor(0, 0, 0, 255);

    cairo_select_font_face(CAIRO, "Noto Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size(CAIRO, FONTSIZE);
    cairo_set_source_rgba(CAIRO, textColor.r / 255.f, textColor.g / 255.f, textColor.b / 255.f, textColor.a / 255.f);

    float yoffset = FONTSIZE;
    while (m_szQueued != "") {
        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 = "";
        cairo_move_to(CAIRO, 0, yoffset);
        cairo_show_text(CAIRO, current.c_str());
        yoffset += FONTSIZE + (FONTSIZE / 10.f);
    }

    cairo_surface_flush(CAIROSURFACE);

    // copy the data to an OpenGL texture we have
    const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
    m_tTexture.allocate();
    glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

#ifndef GLES2
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
#endif

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);

    // delete cairo
    cairo_destroy(CAIRO);
    cairo_surface_destroy(CAIROSURFACE);

    m_bIsCreated = true;
    m_szQueued   = "";
    m_cQueued    = CColor();

    g_pHyprRenderer->damageMonitor(PMONITOR);
}

void CHyprError::draw() {
    if (!m_bIsCreated || m_szQueued != "") {
        if (m_szQueued != "")
            createQueued();
        return;
    }

    if (m_bQueuedDestroy) {
        m_bQueuedDestroy = false;
        m_tTexture.destroyTexture();
        m_bIsCreated = false;
        m_szQueued   = "";
        g_pHyprRenderer->damageMonitor(g_pCompositor->m_vMonitors.front().get());
        return;
    }

    const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();

    if (g_pHyprOpenGL->m_RenderData.pMonitor != PMONITOR)
        return; // wrong mon

    wlr_box windowBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};

    g_pHyprOpenGL->renderTexture(m_tTexture, &windowBox, 255.f, 0);
}

void CHyprError::destroy() {
    if (m_bIsCreated)
        m_bQueuedDestroy = true;
}