2022-05-28 20:46:20 +02:00
|
|
|
#include "CHyprGroupBarDecoration.hpp"
|
|
|
|
#include "../../Compositor.hpp"
|
2023-05-22 21:40:32 +02:00
|
|
|
#include <ranges>
|
|
|
|
#include <pango/pangocairo.h>
|
2022-05-28 20:46:20 +02:00
|
|
|
|
2023-05-22 22:06:40 +02:00
|
|
|
// shared things to conserve VRAM
|
2023-07-11 20:57:33 +02:00
|
|
|
static CTexture m_tGradientActive;
|
|
|
|
static CTexture m_tGradientInactive;
|
2023-11-26 18:59:49 +01:00
|
|
|
static CTexture m_tGradientLockedActive;
|
|
|
|
static CTexture m_tGradientLockedInactive;
|
|
|
|
|
2023-11-11 15:37:17 +01:00
|
|
|
constexpr int BAR_INDICATOR_HEIGHT = 3;
|
|
|
|
constexpr int BAR_PADDING_OUTER_VERT = 2;
|
|
|
|
constexpr int BAR_TEXT_PAD = 2;
|
|
|
|
constexpr int BAR_HORIZONTAL_PADDING = 2;
|
2023-05-22 22:06:40 +02:00
|
|
|
|
2023-08-30 17:39:22 +02:00
|
|
|
CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindowDecoration(pWindow) {
|
2023-12-30 15:18:53 +01:00
|
|
|
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
|
|
|
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
|
|
|
m_pWindow = pWindow;
|
|
|
|
|
|
|
|
if (m_tGradientActive.m_iTexID == 0 && *PENABLED && *PGRADIENTS)
|
2023-11-26 18:59:49 +01:00
|
|
|
refreshGroupBarGradients();
|
2022-05-28 20:46:20 +02:00
|
|
|
}
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {}
|
2022-05-28 20:46:20 +02:00
|
|
|
|
2023-11-11 15:37:17 +01:00
|
|
|
SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
|
2024-01-15 16:17:42 +01:00
|
|
|
static auto* const PHEIGHT = &g_pConfigManager->getConfigValuePtr("group:groupbar:height")->intValue;
|
|
|
|
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
|
|
|
static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue;
|
|
|
|
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
2023-11-11 15:37:17 +01:00
|
|
|
|
|
|
|
SDecorationPositioningInfo info;
|
2023-12-30 15:18:53 +01:00
|
|
|
info.policy = DECORATION_POSITION_STICKY;
|
|
|
|
info.edges = DECORATION_EDGE_TOP;
|
|
|
|
info.priority = g_pConfigManager->getConfigValuePtr("group:groupbar:priority")->intValue;
|
|
|
|
info.reserved = true;
|
|
|
|
|
|
|
|
if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate)
|
2024-01-15 16:17:42 +01:00
|
|
|
info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}};
|
2023-12-30 15:18:53 +01:00
|
|
|
else
|
|
|
|
info.desiredExtents = {{0, 0}, {0, 0}};
|
|
|
|
|
2023-11-11 15:37:17 +01:00
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprGroupBarDecoration::onPositioningReply(const SDecorationPositioningReply& reply) {
|
|
|
|
m_bAssignedBox = reply.assignedGeometry;
|
2022-05-28 20:46:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
eDecorationType CHyprGroupBarDecoration::getDecorationType() {
|
|
|
|
return DECORATION_GROUPBAR;
|
|
|
|
}
|
|
|
|
|
2023-05-22 20:52:41 +02:00
|
|
|
//
|
|
|
|
|
2022-05-28 20:46:20 +02:00
|
|
|
void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) {
|
2023-02-19 22:07:32 +01:00
|
|
|
if (!m_pWindow->m_sGroupData.pNextWindow) {
|
2023-11-11 15:37:17 +01:00
|
|
|
m_pWindow->removeWindowDeco(this);
|
2022-07-05 17:31:47 +02:00
|
|
|
return;
|
2022-05-28 20:46:20 +02:00
|
|
|
}
|
|
|
|
|
2023-02-19 22:07:32 +01:00
|
|
|
m_dwGroupMembers.clear();
|
2023-09-04 15:13:39 +02:00
|
|
|
CWindow* head = pWindow->getGroupHead();
|
|
|
|
m_dwGroupMembers.push_back(head);
|
2022-05-28 20:46:20 +02:00
|
|
|
|
2023-09-04 15:13:39 +02:00
|
|
|
CWindow* curr = head->m_sGroupData.pNextWindow;
|
2023-02-19 22:07:32 +01:00
|
|
|
while (curr != head) {
|
|
|
|
m_dwGroupMembers.push_back(curr);
|
|
|
|
curr = curr->m_sGroupData.pNextWindow;
|
|
|
|
}
|
2022-05-28 20:46:20 +02:00
|
|
|
|
|
|
|
damageEntire();
|
|
|
|
|
|
|
|
if (m_dwGroupMembers.size() == 0) {
|
2023-11-11 15:37:17 +01:00
|
|
|
m_pWindow->removeWindowDeco(this);
|
2022-07-05 17:31:47 +02:00
|
|
|
return;
|
2022-05-28 20:46:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprGroupBarDecoration::damageEntire() {
|
2023-11-11 15:37:17 +01:00
|
|
|
auto box = assignedBoxGlobal();
|
|
|
|
g_pHyprRenderer->damageBox(&box);
|
2022-05-28 20:46:20 +02:00
|
|
|
}
|
|
|
|
|
2022-10-07 13:34:54 +02:00
|
|
|
void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
2022-05-28 20:46:20 +02:00
|
|
|
// get how many bars we will draw
|
2023-05-22 21:40:32 +02:00
|
|
|
int barsToDraw = m_dwGroupMembers.size();
|
|
|
|
|
2023-12-30 15:18:53 +01:00
|
|
|
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
2023-10-10 18:42:45 +02:00
|
|
|
static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue;
|
|
|
|
static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue;
|
2024-01-15 16:17:42 +01:00
|
|
|
static auto* const PHEIGHT = &g_pConfigManager->getConfigValuePtr("group:groupbar:height")->intValue;
|
2023-10-10 18:42:45 +02:00
|
|
|
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
2022-05-28 20:46:20 +02:00
|
|
|
|
2023-12-30 15:18:53 +01:00
|
|
|
if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate)
|
2022-09-23 17:47:58 +02:00
|
|
|
return;
|
|
|
|
|
2023-11-11 15:37:17 +01:00
|
|
|
const auto ASSIGNEDBOX = assignedBoxGlobal();
|
|
|
|
|
|
|
|
m_fBarWidth = (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw;
|
|
|
|
|
2024-01-15 16:17:42 +01:00
|
|
|
const auto DESIREDHEIGHT = BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2;
|
2023-11-11 15:37:17 +01:00
|
|
|
if (DESIREDHEIGHT != ASSIGNEDBOX.h)
|
|
|
|
g_pDecorationPositioner->repositionDeco(this);
|
2022-05-28 20:46:20 +02:00
|
|
|
|
2023-10-29 21:14:47 +01:00
|
|
|
int xoff = 0;
|
2022-05-28 20:46:20 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < barsToDraw; ++i) {
|
2023-11-11 15:37:17 +01:00
|
|
|
CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x,
|
|
|
|
ASSIGNEDBOX.y + ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + offset.y, m_fBarWidth, BAR_INDICATOR_HEIGHT};
|
2022-05-28 20:46:20 +02:00
|
|
|
|
|
|
|
if (rect.width <= 0 || rect.height <= 0)
|
|
|
|
break;
|
|
|
|
|
2023-11-04 18:03:05 +01:00
|
|
|
rect.scale(pMonitor->scale);
|
2022-09-18 13:13:16 +02:00
|
|
|
|
2023-10-10 18:42:45 +02:00
|
|
|
static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data;
|
|
|
|
static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data;
|
|
|
|
static auto* const PGROUPCOLACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data;
|
|
|
|
static auto* const PGROUPCOLINACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data;
|
2022-09-03 22:49:45 +02:00
|
|
|
|
2023-06-13 12:04:54 +02:00
|
|
|
const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked;
|
|
|
|
const auto* const PCOLACTIVE = GROUPLOCKED ? PGROUPCOLACTIVELOCKED : PGROUPCOLACTIVE;
|
|
|
|
const auto* const PCOLINACTIVE = GROUPLOCKED ? PGROUPCOLINACTIVELOCKED : PGROUPCOLINACTIVE;
|
|
|
|
|
|
|
|
CColor color =
|
|
|
|
m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? ((CGradientValueData*)PCOLACTIVE->get())->m_vColors[0] : ((CGradientValueData*)PCOLINACTIVE->get())->m_vColors[0];
|
2022-06-25 20:31:54 +02:00
|
|
|
color.a *= a;
|
2022-05-28 20:46:20 +02:00
|
|
|
g_pHyprOpenGL->renderRect(&rect, color);
|
|
|
|
|
2024-01-15 16:17:42 +01:00
|
|
|
rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth,
|
|
|
|
ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2};
|
|
|
|
rect.scale(pMonitor->scale);
|
|
|
|
|
|
|
|
if (*PGRADIENTS) {
|
|
|
|
const auto& GRADIENTTEX = (m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
|
|
|
|
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
|
|
|
|
if (GRADIENTTEX.m_iTexID != 0)
|
|
|
|
g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
|
|
|
|
}
|
2023-11-11 15:37:17 +01:00
|
|
|
|
2024-01-15 16:17:42 +01:00
|
|
|
if (*PRENDERTITLES) {
|
2023-05-22 21:40:32 +02:00
|
|
|
CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle);
|
|
|
|
|
|
|
|
if (!pTitleTex)
|
2023-10-29 21:14:47 +01:00
|
|
|
pTitleTex = m_sTitleTexs.titleTexs
|
|
|
|
.emplace_back(std::make_unique<CTitleTex>(m_dwGroupMembers[i],
|
|
|
|
Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}))
|
|
|
|
.get();
|
2023-05-22 21:40:32 +02:00
|
|
|
|
2023-11-19 13:29:26 +01:00
|
|
|
rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale;
|
2023-05-22 21:40:32 +02:00
|
|
|
rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale;
|
|
|
|
|
|
|
|
g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f);
|
|
|
|
}
|
|
|
|
|
2023-10-29 21:14:47 +01:00
|
|
|
xoff += BAR_HORIZONTAL_PADDING + m_fBarWidth;
|
2022-05-28 20:46:20 +02:00
|
|
|
}
|
2023-05-22 21:40:32 +02:00
|
|
|
|
|
|
|
if (*PRENDERTITLES)
|
2023-07-11 20:57:33 +02:00
|
|
|
invalidateTextures();
|
2023-05-22 20:52:41 +02:00
|
|
|
}
|
|
|
|
|
2023-05-22 21:40:32 +02:00
|
|
|
CTitleTex* CHyprGroupBarDecoration::textureFromTitle(const std::string& title) {
|
2023-07-11 20:57:33 +02:00
|
|
|
for (auto& tex : m_sTitleTexs.titleTexs) {
|
2023-05-22 21:40:32 +02:00
|
|
|
if (tex->szContent == title)
|
|
|
|
return tex.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprGroupBarDecoration::invalidateTextures() {
|
2023-07-11 20:57:33 +02:00
|
|
|
m_sTitleTexs.titleTexs.clear();
|
2023-05-22 21:40:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CTitleTex::CTitleTex(CWindow* pWindow, const Vector2D& bufferSize) {
|
|
|
|
szContent = pWindow->m_szTitle;
|
|
|
|
pWindowOwner = pWindow;
|
|
|
|
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
|
|
|
|
const auto CAIRO = cairo_create(CAIROSURFACE);
|
2024-02-08 23:29:10 +01:00
|
|
|
const auto MONITORSCALE = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)->scale;
|
2023-05-22 21:40:32 +02:00
|
|
|
|
2023-11-05 20:25:50 +01:00
|
|
|
static auto* const PTITLEFONTFAMILY = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_family")->strValue;
|
|
|
|
static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue;
|
|
|
|
static auto* const PTEXTCOLOR = &g_pConfigManager->getConfigValuePtr("group:groupbar:text_color")->intValue;
|
2023-05-27 17:45:56 +02:00
|
|
|
|
|
|
|
const CColor COLOR = CColor(*PTEXTCOLOR);
|
2023-05-22 21:40:32 +02:00
|
|
|
|
|
|
|
// 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, szContent.c_str(), -1);
|
|
|
|
|
2023-11-05 20:25:50 +01:00
|
|
|
PangoFontDescription* fontDesc = pango_font_description_from_string(PTITLEFONTFAMILY->c_str());
|
2024-02-08 23:29:10 +01:00
|
|
|
pango_font_description_set_size(fontDesc, *PTITLEFONTSIZE * MONITORSCALE * PANGO_SCALE);
|
2023-05-22 21:40:32 +02:00
|
|
|
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_END);
|
|
|
|
|
2023-05-27 17:45:56 +02:00
|
|
|
cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a);
|
2023-05-22 21:40:32 +02:00
|
|
|
|
|
|
|
int layoutWidth, layoutHeight;
|
|
|
|
pango_layout_get_size(layout, &layoutWidth, &layoutHeight);
|
|
|
|
const int xOffset = std::round((bufferSize.x / 2.0 - layoutWidth / PANGO_SCALE / 2.0));
|
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
tex.allocate();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex.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);
|
|
|
|
}
|
|
|
|
|
|
|
|
CTitleTex::~CTitleTex() {
|
|
|
|
tex.destroyTexture();
|
|
|
|
}
|
|
|
|
|
2024-01-08 19:38:22 +01:00
|
|
|
void renderGradientTo(CTexture& tex, CGradientValueData* grad) {
|
2023-05-22 21:40:32 +02:00
|
|
|
|
2023-11-29 14:36:37 +01:00
|
|
|
if (!g_pCompositor->m_pLastMonitor)
|
|
|
|
return;
|
|
|
|
|
2023-05-22 21:40:32 +02:00
|
|
|
const Vector2D& bufferSize = g_pCompositor->m_pLastMonitor->vecPixelSize;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
cairo_pattern_t* pattern;
|
|
|
|
pattern = cairo_pattern_create_linear(0, 0, 0, bufferSize.y);
|
2024-01-08 19:38:22 +01:00
|
|
|
|
|
|
|
for (unsigned long i = 0; i < grad->m_vColors.size(); i++) {
|
|
|
|
cairo_pattern_add_color_stop_rgba(pattern, 1 - (double)(i + 1) / (grad->m_vColors.size() + 1), grad->m_vColors[i].r, grad->m_vColors[i].g, grad->m_vColors[i].b,
|
|
|
|
grad->m_vColors[i].a);
|
|
|
|
}
|
|
|
|
|
2023-05-22 21:40:32 +02:00
|
|
|
cairo_rectangle(CAIRO, 0, 0, bufferSize.x, bufferSize.y);
|
|
|
|
cairo_set_source(CAIRO, pattern);
|
|
|
|
cairo_fill(CAIRO);
|
|
|
|
cairo_pattern_destroy(pattern);
|
|
|
|
|
|
|
|
cairo_surface_flush(CAIROSURFACE);
|
|
|
|
|
|
|
|
// copy the data to an OpenGL texture we have
|
|
|
|
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
|
|
|
tex.allocate();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex.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-26 18:59:49 +01:00
|
|
|
void refreshGroupBarGradients() {
|
2024-01-08 19:38:22 +01:00
|
|
|
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
|
|
|
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
2023-12-30 15:18:53 +01:00
|
|
|
|
2024-01-08 19:38:22 +01:00
|
|
|
CGradientValueData* PGROUPCOLACTIVE = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data.get();
|
|
|
|
CGradientValueData* PGROUPCOLINACTIVE = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data.get();
|
|
|
|
CGradientValueData* PGROUPCOLACTIVELOCKED = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data.get();
|
|
|
|
CGradientValueData* PGROUPCOLINACTIVELOCKED = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data.get();
|
2023-06-13 12:04:54 +02:00
|
|
|
|
2023-12-24 19:29:04 +01:00
|
|
|
g_pHyprRenderer->makeEGLCurrent();
|
|
|
|
|
2023-11-26 18:59:49 +01:00
|
|
|
if (m_tGradientActive.m_iTexID != 0) {
|
|
|
|
m_tGradientActive.destroyTexture();
|
|
|
|
m_tGradientInactive.destroyTexture();
|
|
|
|
m_tGradientLockedActive.destroyTexture();
|
|
|
|
m_tGradientLockedInactive.destroyTexture();
|
|
|
|
}
|
2023-06-13 12:04:54 +02:00
|
|
|
|
2023-12-30 15:18:53 +01:00
|
|
|
if (!*PENABLED || !*PGRADIENTS)
|
|
|
|
return;
|
|
|
|
|
2024-01-08 19:38:22 +01:00
|
|
|
renderGradientTo(m_tGradientActive, PGROUPCOLACTIVE);
|
|
|
|
renderGradientTo(m_tGradientInactive, PGROUPCOLINACTIVE);
|
|
|
|
renderGradientTo(m_tGradientLockedActive, PGROUPCOLACTIVELOCKED);
|
|
|
|
renderGradientTo(m_tGradientLockedInactive, PGROUPCOLINACTIVELOCKED);
|
2023-07-23 15:49:49 +02:00
|
|
|
}
|
2023-08-30 17:39:22 +02:00
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {
|
2024-01-02 13:37:03 +01:00
|
|
|
if (m_pWindow == m_pWindow->m_sGroupData.pNextWindow)
|
|
|
|
return false;
|
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x;
|
|
|
|
const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
|
|
|
|
|
|
|
if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
CWindow* pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX);
|
|
|
|
|
|
|
|
// hack
|
|
|
|
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow);
|
|
|
|
if (!pWindow->m_bIsFloating) {
|
|
|
|
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
|
|
|
|
g_pKeybindManager->m_bGroupsLocked = true;
|
|
|
|
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow);
|
|
|
|
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_pInputManager->currentlyDraggedWindow = pWindow;
|
|
|
|
|
|
|
|
if (!g_pCompositor->isWindowActive(pWindow))
|
|
|
|
g_pCompositor->focusWindow(pWindow);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, CWindow* pDraggedWindow) {
|
2023-10-30 15:54:12 +01:00
|
|
|
if (!pDraggedWindow->canBeGroupedInto(m_pWindow))
|
2023-12-28 23:54:41 +01:00
|
|
|
return false;
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-11-11 15:37:17 +01:00
|
|
|
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x - m_fBarWidth / 2;
|
2023-10-29 21:14:47 +01:00
|
|
|
const int WINDOWINDEX = BARRELATIVEX < 0 ? -1 : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
|
|
|
|
|
|
|
CWindow* pWindowInsertAfter = m_pWindow->getGroupWindowByIndex(WINDOWINDEX);
|
2023-11-01 20:13:39 +01:00
|
|
|
CWindow* pWindowInsertEnd = pWindowInsertAfter->m_sGroupData.pNextWindow;
|
|
|
|
CWindow* pDraggedHead = pDraggedWindow->m_sGroupData.pNextWindow ? pDraggedWindow->getGroupHead() : pDraggedWindow;
|
|
|
|
|
|
|
|
if (pDraggedWindow->m_sGroupData.pNextWindow) {
|
|
|
|
|
|
|
|
// stores group data
|
|
|
|
std::vector<CWindow*> members;
|
|
|
|
CWindow* curr = pDraggedHead;
|
|
|
|
const bool WASLOCKED = pDraggedHead->m_sGroupData.locked;
|
|
|
|
do {
|
|
|
|
members.push_back(curr);
|
|
|
|
curr = curr->m_sGroupData.pNextWindow;
|
|
|
|
} while (curr != members[0]);
|
|
|
|
|
|
|
|
// removes all windows
|
|
|
|
for (CWindow* w : members) {
|
|
|
|
w->m_sGroupData.pNextWindow = nullptr;
|
|
|
|
w->m_sGroupData.head = false;
|
|
|
|
w->m_sGroupData.locked = false;
|
|
|
|
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(w);
|
|
|
|
}
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-11-01 20:13:39 +01:00
|
|
|
// restores the group
|
|
|
|
for (auto it = members.begin(); it != members.end(); ++it) {
|
|
|
|
if (std::next(it) != members.end())
|
|
|
|
(*it)->m_sGroupData.pNextWindow = *std::next(it);
|
|
|
|
else
|
|
|
|
(*it)->m_sGroupData.pNextWindow = members[0];
|
|
|
|
}
|
|
|
|
members[0]->m_sGroupData.head = true;
|
|
|
|
members[0]->m_sGroupData.locked = WASLOCKED;
|
|
|
|
} else {
|
|
|
|
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pDraggedWindow);
|
|
|
|
}
|
2023-10-29 21:14:47 +01:00
|
|
|
|
|
|
|
pWindowInsertAfter->insertWindowToGroup(pDraggedWindow);
|
|
|
|
|
|
|
|
if (WINDOWINDEX == -1)
|
2023-11-01 20:13:39 +01:00
|
|
|
std::swap(pDraggedHead->m_sGroupData.head, pWindowInsertEnd->m_sGroupData.head);
|
2023-10-29 21:14:47 +01:00
|
|
|
|
|
|
|
m_pWindow->setGroupCurrent(pDraggedWindow);
|
|
|
|
pDraggedWindow->applyGroupRules();
|
|
|
|
pDraggedWindow->updateWindowDecos();
|
|
|
|
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow);
|
|
|
|
|
2023-11-19 13:29:01 +01:00
|
|
|
if (!pDraggedWindow->getDecorationByType(DECORATION_GROUPBAR))
|
|
|
|
pDraggedWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pDraggedWindow));
|
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
return true;
|
2023-10-29 21:14:47 +01:00
|
|
|
}
|
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_pointer_button_event* e) {
|
2023-12-30 00:38:12 +01:00
|
|
|
if (m_pWindow->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_FULL)
|
|
|
|
return true;
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-11-11 15:37:17 +01:00
|
|
|
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x;
|
2023-10-29 21:14:47 +01:00
|
|
|
const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
|
|
|
|
2023-12-30 00:38:12 +01:00
|
|
|
// close window on middle click
|
|
|
|
if (e->button == 274) {
|
|
|
|
static Vector2D pressedCursorPos;
|
|
|
|
|
|
|
|
if (e->state == WLR_BUTTON_PRESSED)
|
|
|
|
pressedCursorPos = pos;
|
|
|
|
else if (e->state == WLR_BUTTON_RELEASED && pressedCursorPos == pos)
|
|
|
|
g_pXWaylandManager->sendCloseWindow(m_pWindow->getGroupWindowByIndex(WINDOWINDEX));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->state != WLR_BUTTON_PRESSED)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// click on padding
|
2023-10-29 21:14:47 +01:00
|
|
|
if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) {
|
|
|
|
if (!g_pCompositor->isWindowActive(m_pWindow))
|
|
|
|
g_pCompositor->focusWindow(m_pWindow);
|
2023-12-28 23:54:41 +01:00
|
|
|
return true;
|
2023-10-29 21:14:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CWindow* pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX);
|
|
|
|
|
|
|
|
if (pWindow != m_pWindow)
|
|
|
|
pWindow->setGroupCurrent(pWindow);
|
|
|
|
|
2023-12-30 00:38:12 +01:00
|
|
|
if (pWindow->m_bIsFloating)
|
|
|
|
g_pCompositor->changeWindowZOrder(pWindow, 1);
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
return true;
|
|
|
|
}
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
bool CHyprGroupBarDecoration::onScrollOnDeco(const Vector2D& pos, wlr_pointer_axis_event* e) {
|
|
|
|
static auto* const PGROUPBARSCROLLING = &g_pConfigManager->getConfigValuePtr("group:groupbar:scrolling")->intValue;
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
if (!*PGROUPBARSCROLLING || !m_pWindow->m_sGroupData.pNextWindow) {
|
|
|
|
return false;
|
2023-10-29 21:14:47 +01:00
|
|
|
}
|
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
if (e->delta > 0)
|
|
|
|
m_pWindow->setGroupCurrent(m_pWindow->m_sGroupData.pNextWindow);
|
|
|
|
else
|
|
|
|
m_pWindow->setGroupCurrent(m_pWindow->getGroupPrevious());
|
2023-10-29 21:14:47 +01:00
|
|
|
|
2023-12-28 23:54:41 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CHyprGroupBarDecoration::onInputOnDeco(const eInputType type, const Vector2D& mouseCoords, std::any data) {
|
|
|
|
switch (type) {
|
|
|
|
case INPUT_TYPE_AXIS: return onScrollOnDeco(mouseCoords, std::any_cast<wlr_pointer_axis_event*>(data));
|
|
|
|
case INPUT_TYPE_BUTTON: return onMouseButtonOnDeco(mouseCoords, std::any_cast<wlr_pointer_button_event*>(data));
|
|
|
|
case INPUT_TYPE_DRAG_START: return onBeginWindowDragOnDeco(mouseCoords);
|
|
|
|
case INPUT_TYPE_DRAG_END: return onEndWindowDragOnDeco(mouseCoords, std::any_cast<CWindow*>(data));
|
|
|
|
default: return false;
|
|
|
|
}
|
2023-10-29 21:14:47 +01:00
|
|
|
}
|
2023-11-04 14:10:52 +01:00
|
|
|
|
|
|
|
eDecorationLayer CHyprGroupBarDecoration::getDecorationLayer() {
|
|
|
|
return DECORATION_LAYER_OVER;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t CHyprGroupBarDecoration::getDecorationFlags() {
|
|
|
|
return DECORATION_ALLOWS_MOUSE_INPUT;
|
2023-11-11 15:37:17 +01:00
|
|
|
}
|
|
|
|
|
2023-12-28 16:38:16 +01:00
|
|
|
std::string CHyprGroupBarDecoration::getDisplayName() {
|
|
|
|
return "GroupBar";
|
|
|
|
}
|
|
|
|
|
2023-11-11 15:37:17 +01:00
|
|
|
CBox CHyprGroupBarDecoration::assignedBoxGlobal() {
|
|
|
|
CBox box = m_bAssignedBox;
|
2023-11-12 23:40:21 +01:00
|
|
|
box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow));
|
|
|
|
|
|
|
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID);
|
|
|
|
|
|
|
|
if (!PWORKSPACE)
|
|
|
|
return box;
|
|
|
|
|
|
|
|
const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
|
|
|
return box.translate(WORKSPACEOFFSET);
|
2023-11-15 21:32:44 +01:00
|
|
|
}
|