2023-02-28 21:30:51 +01:00
|
|
|
#include "barDeco.hpp"
|
|
|
|
|
2023-05-01 03:57:48 +02:00
|
|
|
#include <hyprland/src/Compositor.hpp>
|
|
|
|
#include <hyprland/src/Window.hpp>
|
2023-05-01 21:02:05 +02:00
|
|
|
#include <pango/pangocairo.h>
|
2023-02-28 21:30:51 +01:00
|
|
|
|
|
|
|
#include "globals.hpp"
|
|
|
|
|
2023-09-19 12:24:57 +02:00
|
|
|
CHyprBar::CHyprBar(CWindow* pWindow) : IHyprWindowDecoration(pWindow) {
|
2023-11-11 15:39:46 +01:00
|
|
|
m_pWindow = pWindow;
|
2023-02-28 22:17:46 +01:00
|
|
|
|
|
|
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
|
|
|
PMONITOR->scheduledRecalc = true;
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-10-21 15:55:42 +02:00
|
|
|
m_pMouseButtonCallback = HyprlandAPI::registerCallbackDynamic(
|
2023-10-29 18:33:32 +01:00
|
|
|
PHANDLE, "mouseButton", [&](void* self, SCallbackInfo& info, std::any param) { onMouseDown(info, std::any_cast<wlr_pointer_button_event*>(param)); });
|
2023-02-28 23:53:49 +01:00
|
|
|
|
2023-10-21 15:55:42 +02:00
|
|
|
m_pMouseMoveCallback =
|
|
|
|
HyprlandAPI::registerCallbackDynamic(PHANDLE, "mouseMove", [&](void* self, SCallbackInfo& info, std::any param) { onMouseMove(std::any_cast<Vector2D>(param)); });
|
2023-02-28 21:30:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CHyprBar::~CHyprBar() {
|
|
|
|
damageEntire();
|
2023-02-28 22:59:58 +01:00
|
|
|
HyprlandAPI::unregisterCallback(PHANDLE, m_pMouseButtonCallback);
|
2023-04-28 16:27:39 +02:00
|
|
|
HyprlandAPI::unregisterCallback(PHANDLE, m_pMouseMoveCallback);
|
2023-10-29 23:31:11 +01:00
|
|
|
std::erase(g_pGlobalState->bars, this);
|
2023-02-28 21:30:51 +01:00
|
|
|
}
|
|
|
|
|
2023-11-11 15:39:46 +01:00
|
|
|
SDecorationPositioningInfo CHyprBar::getPositioningInfo() {
|
2023-12-13 01:51:21 +01:00
|
|
|
static auto* const PHEIGHT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->intValue;
|
|
|
|
static auto* const PPRECEDENCE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_precedence_over_border")->intValue;
|
2023-11-11 15:39:46 +01:00
|
|
|
|
|
|
|
SDecorationPositioningInfo info;
|
|
|
|
info.policy = DECORATION_POSITION_STICKY;
|
|
|
|
info.edges = DECORATION_EDGE_TOP;
|
2023-12-13 01:51:21 +01:00
|
|
|
info.priority = *PPRECEDENCE ? 10005 : 5000;
|
2023-11-11 15:39:46 +01:00
|
|
|
info.reserved = true;
|
|
|
|
info.desiredExtents = {{0, *PHEIGHT}, {0, 0}};
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprBar::onPositioningReply(const SDecorationPositioningReply& reply) {
|
|
|
|
if (reply.assignedGeometry.size() != m_bAssignedBox.size())
|
|
|
|
m_bWindowSizeChanged = true;
|
|
|
|
|
|
|
|
m_bAssignedBox = reply.assignedGeometry;
|
2023-02-28 21:30:51 +01:00
|
|
|
}
|
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
void CHyprBar::onMouseDown(SCallbackInfo& info, wlr_pointer_button_event* e) {
|
2023-02-28 22:59:58 +01:00
|
|
|
if (m_pWindow != g_pCompositor->m_pLastWindow)
|
|
|
|
return;
|
|
|
|
|
2023-03-16 17:00:59 +01:00
|
|
|
const auto COORDS = cursorRelativeToBar();
|
|
|
|
|
2023-12-13 02:29:13 +01:00
|
|
|
static auto* const PHEIGHT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->intValue;
|
|
|
|
static auto* const PBARBUTTONPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding")->intValue;
|
2023-12-13 02:35:16 +01:00
|
|
|
static auto* const PBARPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_padding")->intValue;
|
|
|
|
static auto* const PALIGNBUTTONS = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->strValue;
|
2023-03-16 17:00:59 +01:00
|
|
|
|
2023-12-13 02:35:16 +01:00
|
|
|
const bool BUTTONSRIGHT = *PALIGNBUTTONS != "left";
|
|
|
|
|
2023-12-14 14:09:12 +01:00
|
|
|
if (!VECINRECT(COORDS, 0, 0, assignedBoxGlobal().w, *PHEIGHT - 1)) {
|
2023-04-18 20:50:09 +02:00
|
|
|
|
|
|
|
if (m_bDraggingThis) {
|
|
|
|
g_pKeybindManager->m_mDispatchers["mouse"]("0movewindow");
|
2023-09-19 12:24:57 +02:00
|
|
|
Debug::log(LOG, "[hyprbars] Dragging ended on {:x}", (uintptr_t)m_pWindow);
|
2023-04-18 20:50:09 +02:00
|
|
|
}
|
|
|
|
|
2023-03-16 17:00:59 +01:00
|
|
|
m_bDraggingThis = false;
|
|
|
|
m_bDragPending = false;
|
|
|
|
return;
|
|
|
|
}
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-02-28 23:53:49 +01:00
|
|
|
if (e->state != WLR_BUTTON_PRESSED) {
|
2023-10-29 18:33:32 +01:00
|
|
|
|
|
|
|
if (m_bCancelledDown)
|
|
|
|
info.cancelled = true;
|
|
|
|
|
|
|
|
m_bCancelledDown = false;
|
|
|
|
|
2023-02-28 23:53:49 +01:00
|
|
|
if (m_bDraggingThis) {
|
|
|
|
g_pKeybindManager->m_mDispatchers["mouse"]("0movewindow");
|
|
|
|
m_bDraggingThis = false;
|
|
|
|
|
2023-09-19 12:24:57 +02:00
|
|
|
Debug::log(LOG, "[hyprbars] Dragging ended on {:x}", (uintptr_t)m_pWindow);
|
2023-02-28 23:53:49 +01:00
|
|
|
}
|
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
m_bDragPending = false;
|
|
|
|
|
2023-02-28 22:59:58 +01:00
|
|
|
return;
|
2023-02-28 23:53:49 +01:00
|
|
|
}
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
info.cancelled = true;
|
|
|
|
m_bCancelledDown = true;
|
|
|
|
|
2023-02-28 22:59:58 +01:00
|
|
|
// check if on a button
|
|
|
|
|
2023-12-13 02:35:16 +01:00
|
|
|
float offset = *PBARPADDING;
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
for (auto& b : g_pGlobalState->buttons) {
|
2023-12-13 02:35:16 +01:00
|
|
|
const auto BARBUF = Vector2D{(int)assignedBoxGlobal().w, *PHEIGHT};
|
|
|
|
Vector2D currentPos = Vector2D{(BUTTONSRIGHT ? BARBUF.x - *PBARBUTTONPADDING - b.size - offset : offset), (BARBUF.y - b.size) / 2.0}.floor();
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-12-13 02:29:13 +01:00
|
|
|
if (VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + b.size + *PBARBUTTONPADDING, currentPos.y + b.size)) {
|
2023-10-29 18:33:32 +01:00
|
|
|
// hit on close
|
|
|
|
g_pKeybindManager->m_mDispatchers["exec"](b.cmd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-13 02:29:13 +01:00
|
|
|
offset += *PBARBUTTONPADDING + b.size;
|
2023-02-28 22:59:58 +01:00
|
|
|
}
|
2023-02-28 23:53:49 +01:00
|
|
|
|
2023-03-16 17:00:59 +01:00
|
|
|
m_bDragPending = true;
|
2023-02-28 23:53:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprBar::onMouseMove(Vector2D coords) {
|
|
|
|
if (m_bDragPending) {
|
|
|
|
m_bDragPending = false;
|
|
|
|
g_pKeybindManager->m_mDispatchers["mouse"]("1movewindow");
|
|
|
|
m_bDraggingThis = true;
|
|
|
|
|
2023-09-19 12:24:57 +02:00
|
|
|
Debug::log(LOG, "[hyprbars] Dragging initiated on {:x}", (uintptr_t)m_pWindow);
|
2023-02-28 23:53:49 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2023-02-28 22:59:58 +01:00
|
|
|
}
|
|
|
|
|
2023-10-29 23:31:11 +01:00
|
|
|
void CHyprBar::renderText(CTexture& out, const std::string& text, const CColor& color, const Vector2D& bufferSize, const float scale, const int fontSize) {
|
|
|
|
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.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);
|
|
|
|
|
|
|
|
// draw title using Pango
|
|
|
|
PangoLayout* layout = pango_cairo_create_layout(CAIRO);
|
|
|
|
pango_layout_set_text(layout, text.c_str(), -1);
|
|
|
|
|
|
|
|
PangoFontDescription* fontDesc = pango_font_description_from_string("sans");
|
|
|
|
pango_font_description_set_size(fontDesc, fontSize * scale * PANGO_SCALE);
|
|
|
|
pango_layout_set_font_description(layout, fontDesc);
|
|
|
|
pango_font_description_free(fontDesc);
|
|
|
|
|
|
|
|
const int maxWidth = bufferSize.x;
|
|
|
|
|
|
|
|
pango_layout_set_width(layout, maxWidth * PANGO_SCALE);
|
|
|
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
|
|
|
|
|
|
|
cairo_set_source_rgba(CAIRO, color.r, color.g, color.b, color.a);
|
|
|
|
|
|
|
|
int layoutWidth, layoutHeight;
|
|
|
|
pango_layout_get_size(layout, &layoutWidth, &layoutHeight);
|
|
|
|
const double xOffset = (bufferSize.x / 2.0 - layoutWidth / PANGO_SCALE / 2.0);
|
|
|
|
const double yOffset = (bufferSize.y / 2.0 - layoutHeight / PANGO_SCALE / 2.0);
|
|
|
|
|
|
|
|
cairo_move_to(CAIRO, xOffset, yOffset);
|
|
|
|
pango_cairo_show_layout(CAIRO, layout);
|
|
|
|
|
|
|
|
g_object_unref(layout);
|
|
|
|
|
|
|
|
cairo_surface_flush(CAIROSURFACE);
|
|
|
|
|
|
|
|
// copy the data to an OpenGL texture we have
|
|
|
|
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
|
|
|
out.allocate();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, out.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, bufferSize.x, bufferSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
|
|
|
|
|
|
|
// delete cairo
|
|
|
|
cairo_destroy(CAIRO);
|
|
|
|
cairo_surface_destroy(CAIROSURFACE);
|
|
|
|
}
|
|
|
|
|
2023-08-17 10:10:33 +02:00
|
|
|
void CHyprBar::renderBarTitle(const Vector2D& bufferSize, const float scale) {
|
2023-12-13 02:29:13 +01:00
|
|
|
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:col.text")->intValue;
|
|
|
|
static auto* const PSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_text_size")->intValue;
|
|
|
|
static auto* const PFONT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_text_font")->strValue;
|
|
|
|
static auto* const PALIGN = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_text_align")->strValue;
|
|
|
|
static auto* const PALIGNBUTTONS = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->strValue;
|
|
|
|
static auto* const PBARPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_padding")->intValue;
|
|
|
|
static auto* const PBARBUTTONPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding")->intValue;
|
2023-12-13 02:13:32 +01:00
|
|
|
|
|
|
|
const bool BUTTONSRIGHT = *PALIGNBUTTONS != "left";
|
2023-10-29 19:20:47 +01:00
|
|
|
|
|
|
|
const auto BORDERSIZE = m_pWindow->getRealBorderSize();
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-12-13 02:29:13 +01:00
|
|
|
float buttonSizes = *PBARBUTTONPADDING;
|
2023-10-29 18:33:32 +01:00
|
|
|
for (auto& b : g_pGlobalState->buttons) {
|
2023-12-13 02:29:13 +01:00
|
|
|
buttonSizes += b.size + *PBARBUTTONPADDING;
|
2023-10-29 18:33:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const auto scaledSize = *PSIZE * scale;
|
2023-10-29 19:20:47 +01:00
|
|
|
const auto scaledBorderSize = BORDERSIZE * scale;
|
2023-10-29 18:33:32 +01:00
|
|
|
const auto scaledButtonsSize = buttonSizes * scale;
|
2023-12-13 02:29:13 +01:00
|
|
|
const auto scaledButtonsPad = *PBARBUTTONPADDING * scale;
|
|
|
|
const auto scaledBarPadding = *PBARPADDING * scale;
|
2023-08-17 10:10:33 +02:00
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
const CColor COLOR = *PCOLOR;
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
|
|
|
|
const auto CAIRO = cairo_create(CAIROSURFACE);
|
2023-02-28 21:30:51 +01:00
|
|
|
|
|
|
|
// clear the pixmap
|
|
|
|
cairo_save(CAIRO);
|
|
|
|
cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR);
|
|
|
|
cairo_paint(CAIRO);
|
|
|
|
cairo_restore(CAIRO);
|
|
|
|
|
2023-05-01 21:02:05 +02:00
|
|
|
// draw title using Pango
|
|
|
|
PangoLayout* layout = pango_cairo_create_layout(CAIRO);
|
|
|
|
pango_layout_set_text(layout, m_szLastTitle.c_str(), -1);
|
|
|
|
|
|
|
|
PangoFontDescription* fontDesc = pango_font_description_from_string(PFONT->c_str());
|
2023-08-17 10:10:33 +02:00
|
|
|
pango_font_description_set_size(fontDesc, scaledSize * PANGO_SCALE);
|
2023-05-01 21:02:05 +02:00
|
|
|
pango_layout_set_font_description(layout, fontDesc);
|
|
|
|
pango_font_description_free(fontDesc);
|
|
|
|
|
2023-12-13 02:13:32 +01:00
|
|
|
const int paddingTotal = scaledBarPadding * 2 + scaledButtonsSize + (*PALIGN != "left" ? scaledButtonsSize : 0);
|
|
|
|
const int maxWidth = std::clamp(static_cast<int>(bufferSize.x - paddingTotal), 0, INT_MAX);
|
2023-05-01 21:02:05 +02:00
|
|
|
|
|
|
|
pango_layout_set_width(layout, maxWidth * PANGO_SCALE);
|
|
|
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
|
|
|
|
2023-02-28 21:30:51 +01:00
|
|
|
cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a);
|
|
|
|
|
2023-05-01 21:02:05 +02:00
|
|
|
int layoutWidth, layoutHeight;
|
|
|
|
pango_layout_get_size(layout, &layoutWidth, &layoutHeight);
|
2023-12-13 02:13:32 +01:00
|
|
|
const int xOffset = *PALIGN == "left" ? std::round(scaledBarPadding + (BUTTONSRIGHT ? 0 : scaledButtonsSize)) :
|
|
|
|
std::round(((bufferSize.x - scaledBorderSize) / 2.0 - layoutWidth / PANGO_SCALE / 2.0));
|
2023-05-01 21:02:05 +02:00
|
|
|
const int yOffset = std::round((bufferSize.y / 2.0 - layoutHeight / PANGO_SCALE / 2.0));
|
|
|
|
|
|
|
|
cairo_move_to(CAIRO, xOffset, yOffset);
|
|
|
|
pango_cairo_show_layout(CAIRO, layout);
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-05-01 21:02:05 +02:00
|
|
|
g_object_unref(layout);
|
2023-02-28 21:30:51 +01:00
|
|
|
|
|
|
|
cairo_surface_flush(CAIROSURFACE);
|
|
|
|
|
|
|
|
// copy the data to an OpenGL texture we have
|
|
|
|
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
|
|
|
m_tTextTex.allocate();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, m_tTextTex.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, bufferSize.x, bufferSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
|
|
|
|
|
|
|
// delete cairo
|
|
|
|
cairo_destroy(CAIRO);
|
|
|
|
cairo_surface_destroy(CAIROSURFACE);
|
|
|
|
}
|
|
|
|
|
2023-08-17 10:10:33 +02:00
|
|
|
void CHyprBar::renderBarButtons(const Vector2D& bufferSize, const float scale) {
|
2023-12-13 02:29:13 +01:00
|
|
|
static auto* const PBARBUTTONPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding")->intValue;
|
|
|
|
static auto* const PBARPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_padding")->intValue;
|
|
|
|
|
|
|
|
const auto scaledButtonsPad = *PBARBUTTONPADDING * scale;
|
|
|
|
const auto scaledBarPadding = *PBARPADDING * scale;
|
2023-08-17 10:10:33 +02:00
|
|
|
|
2023-12-13 02:13:32 +01:00
|
|
|
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
|
|
|
|
const auto CAIRO = cairo_create(CAIROSURFACE);
|
|
|
|
|
|
|
|
static auto* const PALIGNBUTTONS = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->strValue;
|
|
|
|
|
|
|
|
const bool BUTTONSRIGHT = *PALIGNBUTTONS != "left";
|
2023-02-28 22:59:58 +01:00
|
|
|
|
|
|
|
// clear the pixmap
|
|
|
|
cairo_save(CAIRO);
|
|
|
|
cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR);
|
|
|
|
cairo_paint(CAIRO);
|
|
|
|
cairo_restore(CAIRO);
|
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
// draw buttons
|
2023-12-13 02:29:13 +01:00
|
|
|
int offset = scaledBarPadding;
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-10-29 23:31:11 +01:00
|
|
|
auto drawButton = [&](SHyprButton& button) -> void {
|
|
|
|
const auto scaledButtonSize = button.size * scale;
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-12-13 02:29:13 +01:00
|
|
|
Vector2D currentPos =
|
|
|
|
Vector2D{BUTTONSRIGHT ? bufferSize.x - offset - scaledButtonSize / 2.0 : offset + scaledButtonSize / 2.0, (bufferSize.y - scaledButtonSize) / 2.0}.floor();
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-12-13 02:29:13 +01:00
|
|
|
const int X = currentPos.x;
|
|
|
|
const int Y = currentPos.y;
|
|
|
|
const int RADIUS = static_cast<int>(std::ceil(scaledButtonSize / 2.0));
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-10-29 23:31:11 +01:00
|
|
|
cairo_set_source_rgba(CAIRO, button.col.r, button.col.g, button.col.b, button.col.a);
|
2023-10-29 18:33:32 +01:00
|
|
|
cairo_arc(CAIRO, X, Y + RADIUS, RADIUS, 0, 2 * M_PI);
|
|
|
|
cairo_fill(CAIRO);
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
offset += scaledButtonsPad + scaledButtonSize;
|
|
|
|
};
|
2023-02-28 22:59:58 +01:00
|
|
|
|
2023-10-29 18:33:32 +01:00
|
|
|
for (auto& b : g_pGlobalState->buttons) {
|
|
|
|
drawButton(b);
|
|
|
|
}
|
2023-02-28 22:59:58 +01:00
|
|
|
|
|
|
|
// copy the data to an OpenGL texture we have
|
|
|
|
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
|
|
|
m_tButtonsTex.allocate();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, m_tButtonsTex.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, bufferSize.x, bufferSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
|
|
|
|
|
|
|
// delete cairo
|
|
|
|
cairo_destroy(CAIRO);
|
|
|
|
cairo_surface_destroy(CAIROSURFACE);
|
|
|
|
}
|
|
|
|
|
2023-11-04 18:22:55 +01:00
|
|
|
void CHyprBar::renderBarButtonsText(CBox* barBox, const float scale, const float a) {
|
2023-12-13 02:29:13 +01:00
|
|
|
static auto* const PBARBUTTONPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding")->intValue;
|
|
|
|
static auto* const PBARPADDING = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_padding")->intValue;
|
|
|
|
|
|
|
|
const auto scaledButtonsPad = *PBARBUTTONPADDING * scale;
|
|
|
|
const auto scaledBarPad = *PBARPADDING * scale;
|
|
|
|
int offset = scaledBarPad;
|
2023-12-13 02:13:32 +01:00
|
|
|
|
|
|
|
static auto* const PALIGNBUTTONS = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->strValue;
|
2023-10-29 23:31:11 +01:00
|
|
|
|
2023-12-13 02:13:32 +01:00
|
|
|
const bool BUTTONSRIGHT = *PALIGNBUTTONS != "left";
|
|
|
|
|
|
|
|
auto drawButton = [&](SHyprButton& button) -> void {
|
2023-10-29 23:31:11 +01:00
|
|
|
const auto scaledButtonSize = button.size * scale;
|
|
|
|
|
|
|
|
if (button.iconTex.m_iTexID == 0 /* icon is not rendered */ && !button.icon.empty()) {
|
|
|
|
// render icon
|
|
|
|
const Vector2D BUFSIZE = {scaledButtonSize, scaledButtonSize};
|
|
|
|
|
|
|
|
const bool LIGHT = button.col.r + button.col.g + button.col.b < 1;
|
|
|
|
|
2023-10-30 00:22:29 +01:00
|
|
|
renderText(button.iconTex, button.icon, LIGHT ? CColor(0xFFFFFFFF) : CColor(0xFF000000), BUFSIZE, scale, button.size * 0.62);
|
2023-10-29 23:31:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (button.iconTex.m_iTexID == 0)
|
|
|
|
return;
|
|
|
|
|
2023-12-13 02:29:13 +01:00
|
|
|
CBox pos = {barBox->x + (BUTTONSRIGHT ? barBox->width - offset - scaledButtonSize : offset), barBox->y + (barBox->height - scaledButtonSize) / 2.0, scaledButtonSize,
|
|
|
|
scaledButtonSize};
|
2023-10-29 23:31:11 +01:00
|
|
|
|
2023-11-04 14:15:30 +01:00
|
|
|
g_pHyprOpenGL->renderTexture(button.iconTex, &pos, a);
|
2023-10-29 23:31:11 +01:00
|
|
|
|
|
|
|
offset += scaledButtonsPad + scaledButtonSize;
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto& b : g_pGlobalState->buttons) {
|
|
|
|
drawButton(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-28 21:30:51 +01:00
|
|
|
void CHyprBar::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
|
|
|
if (!g_pCompositor->windowValidMapped(m_pWindow))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
|
|
|
return;
|
|
|
|
|
2023-12-13 02:13:32 +01:00
|
|
|
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_color")->intValue;
|
|
|
|
static auto* const PHEIGHT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->intValue;
|
|
|
|
static auto* const PPRECEDENCE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_precedence_over_border")->intValue;
|
|
|
|
static auto* const PALIGNBUTTONS = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->strValue;
|
2023-12-15 16:46:37 +01:00
|
|
|
static auto* const PENABLETITLE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_title_enabled")->intValue;
|
2023-12-13 02:13:32 +01:00
|
|
|
|
|
|
|
const bool BUTTONSRIGHT = *PALIGNBUTTONS != "left";
|
2023-10-29 19:20:47 +01:00
|
|
|
|
2023-10-29 23:57:55 +01:00
|
|
|
if (*PHEIGHT < 1) {
|
|
|
|
m_iLastHeight = *PHEIGHT;
|
|
|
|
return;
|
|
|
|
}
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-11-12 23:45:42 +01:00
|
|
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID);
|
|
|
|
const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
|
|
|
|
2023-12-13 01:51:21 +01:00
|
|
|
const auto ROUNDING = m_pWindow->rounding() + (*PPRECEDENCE ? 0 : m_pWindow->getRealBorderSize());
|
2023-08-17 10:10:33 +02:00
|
|
|
|
2023-12-11 17:46:45 +01:00
|
|
|
const auto scaledRounding = ROUNDING > 0 ? ROUNDING * pMonitor->scale - 2 /* idk why but otherwise it looks bad due to the gaps */ : 0;
|
2023-10-29 23:57:55 +01:00
|
|
|
|
|
|
|
CColor color = *PCOLOR;
|
2023-02-28 21:30:51 +01:00
|
|
|
color.a *= a;
|
|
|
|
|
2023-11-04 14:15:30 +01:00
|
|
|
m_seExtents = {{0, *PHEIGHT}, {}};
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-11-11 15:39:46 +01:00
|
|
|
const auto DECOBOX = assignedBoxGlobal();
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-11-11 15:39:46 +01:00
|
|
|
const auto BARBUF = DECOBOX.size() * pMonitor->scale;
|
|
|
|
|
|
|
|
CBox titleBarBox = {DECOBOX.x - pMonitor->vecPosition.x, DECOBOX.y - pMonitor->vecPosition.y, DECOBOX.w,
|
2023-12-11 17:46:45 +01:00
|
|
|
DECOBOX.h + ROUNDING * 3 /* to fill the bottom cuz we can't disable rounding there */};
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-11-04 18:22:55 +01:00
|
|
|
titleBarBox.translate(offset).scale(pMonitor->scale).round();
|
2023-02-28 21:30:51 +01:00
|
|
|
|
2023-11-11 15:39:46 +01:00
|
|
|
if (titleBarBox.w < 1 || titleBarBox.h < 0)
|
|
|
|
return;
|
2023-11-06 17:49:39 +01:00
|
|
|
|
2023-02-28 21:30:51 +01:00
|
|
|
g_pHyprOpenGL->scissor(&titleBarBox);
|
|
|
|
|
2023-11-04 14:15:30 +01:00
|
|
|
if (ROUNDING) {
|
2023-02-28 21:30:51 +01:00
|
|
|
glClearStencil(0);
|
|
|
|
glClear(GL_STENCIL_BUFFER_BIT);
|
|
|
|
|
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
|
|
|
|
glStencilFunc(GL_ALWAYS, 1, -1);
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
|
|
|
|
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
2023-11-04 14:31:52 +01:00
|
|
|
// the +1 is a shit garbage temp fix until renderRect supports an alpha matte
|
2023-12-11 17:46:45 +01:00
|
|
|
CBox windowBox = {m_pWindow->m_vRealPosition.vec().x + offset.x - pMonitor->vecPosition.x + 1, m_pWindow->m_vRealPosition.vec().y + offset.y - pMonitor->vecPosition.y + 1,
|
|
|
|
m_pWindow->m_vRealSize.vec().x - 2, m_pWindow->m_vRealSize.vec().y - 2};
|
2023-11-12 23:45:42 +01:00
|
|
|
windowBox.translate(WORKSPACEOFFSET).scale(pMonitor->scale).round();
|
2023-11-04 14:31:52 +01:00
|
|
|
g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 0), scaledRounding);
|
2023-02-28 21:30:51 +01:00
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
|
2023-02-28 22:17:46 +01:00
|
|
|
glStencilFunc(GL_NOTEQUAL, 1, -1);
|
2023-02-28 21:30:51 +01:00
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
|
|
|
}
|
|
|
|
|
2023-08-17 10:10:33 +02:00
|
|
|
g_pHyprOpenGL->renderRect(&titleBarBox, color, scaledRounding);
|
2023-02-28 21:30:51 +01:00
|
|
|
|
|
|
|
// render title
|
2023-12-15 16:46:37 +01:00
|
|
|
if (*PENABLETITLE && (m_szLastTitle != m_pWindow->m_szTitle || m_bWindowSizeChanged || m_tTextTex.m_iTexID == 0)) {
|
2023-02-28 21:30:51 +01:00
|
|
|
m_szLastTitle = m_pWindow->m_szTitle;
|
2023-08-17 10:10:33 +02:00
|
|
|
renderBarTitle(BARBUF, pMonitor->scale);
|
2023-02-28 21:30:51 +01:00
|
|
|
}
|
|
|
|
|
2023-11-04 14:15:30 +01:00
|
|
|
if (ROUNDING) {
|
2023-02-28 21:30:51 +01:00
|
|
|
// cleanup stencil
|
|
|
|
glClearStencil(0);
|
|
|
|
glClear(GL_STENCIL_BUFFER_BIT);
|
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
glStencilMask(-1);
|
|
|
|
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
|
|
|
}
|
|
|
|
|
2023-11-04 18:22:55 +01:00
|
|
|
CBox textBox = {titleBarBox.x, titleBarBox.y, (int)BARBUF.x, (int)BARBUF.y};
|
2023-12-15 16:46:37 +01:00
|
|
|
if (*PENABLETITLE)
|
|
|
|
g_pHyprOpenGL->renderTexture(m_tTextTex, &textBox, a);
|
2023-02-28 22:17:46 +01:00
|
|
|
|
2023-10-29 23:31:11 +01:00
|
|
|
if (m_bButtonsDirty || m_bWindowSizeChanged) {
|
|
|
|
renderBarButtons(BARBUF, pMonitor->scale);
|
|
|
|
m_bButtonsDirty = false;
|
|
|
|
}
|
2023-02-28 22:59:58 +01:00
|
|
|
|
|
|
|
g_pHyprOpenGL->renderTexture(m_tButtonsTex, &textBox, a);
|
2023-02-28 22:17:46 +01:00
|
|
|
|
2023-11-04 18:22:55 +01:00
|
|
|
g_pHyprOpenGL->scissor((CBox*)nullptr);
|
2023-02-28 22:17:46 +01:00
|
|
|
|
2023-11-04 14:15:30 +01:00
|
|
|
renderBarButtonsText(&textBox, pMonitor->scale, a);
|
2023-10-29 23:31:11 +01:00
|
|
|
|
2023-02-28 22:17:46 +01:00
|
|
|
m_bWindowSizeChanged = false;
|
2023-10-29 23:57:55 +01:00
|
|
|
|
|
|
|
// dynamic updates change the extents
|
|
|
|
if (m_iLastHeight != *PHEIGHT) {
|
|
|
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_pWindow);
|
|
|
|
m_iLastHeight = *PHEIGHT;
|
|
|
|
}
|
2023-02-28 21:30:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
eDecorationType CHyprBar::getDecorationType() {
|
|
|
|
return DECORATION_CUSTOM;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprBar::updateWindow(CWindow* pWindow) {
|
|
|
|
damageEntire();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprBar::damageEntire() {
|
2023-11-11 15:39:46 +01:00
|
|
|
; // ignored
|
2023-02-28 22:59:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector2D CHyprBar::cursorRelativeToBar() {
|
2023-11-11 15:39:46 +01:00
|
|
|
return g_pInputManager->getMouseCoordsInternal() - assignedBoxGlobal().pos();
|
2023-05-01 21:02:05 +02:00
|
|
|
}
|
2023-11-04 14:15:30 +01:00
|
|
|
|
|
|
|
eDecorationLayer CHyprBar::getDecorationLayer() {
|
|
|
|
return DECORATION_LAYER_UNDER;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t CHyprBar::getDecorationFlags() {
|
2023-11-12 13:46:32 +01:00
|
|
|
static auto* const PPART = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_part_of_window")->intValue;
|
|
|
|
return DECORATION_ALLOWS_MOUSE_INPUT | (*PPART ? DECORATION_PART_OF_MAIN_WINDOW : 0);
|
2023-11-11 15:39:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CBox CHyprBar::assignedBoxGlobal() {
|
|
|
|
CBox box = m_bAssignedBox;
|
2023-11-12 23:45:42 +01:00
|
|
|
box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow));
|
|
|
|
|
|
|
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID);
|
|
|
|
const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
|
|
|
|
|
|
|
return box.translate(WORKSPACEOFFSET);
|
2023-11-04 14:15:30 +01:00
|
|
|
}
|