2022-03-17 20:22:29 +01:00
|
|
|
#include "Renderer.hpp"
|
|
|
|
#include "../Compositor.hpp"
|
|
|
|
|
|
|
|
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|
|
|
const auto TEXTURE = wlr_surface_get_texture(surface);
|
|
|
|
const auto RDATA = (SRenderData*)data;
|
|
|
|
|
|
|
|
if (!TEXTURE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
double outputX = 0, outputY = 0;
|
|
|
|
wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, RDATA->output, &outputX, &outputY);
|
|
|
|
|
2022-03-23 22:01:59 +01:00
|
|
|
wlr_box windowBox;
|
2022-03-24 19:14:09 +01:00
|
|
|
if (RDATA->surface && surface == RDATA->surface) {
|
2022-03-23 22:38:54 +01:00
|
|
|
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, RDATA->w, RDATA->h};
|
|
|
|
} else {
|
2022-03-23 22:01:59 +01:00
|
|
|
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, surface->current.width, surface->current.height};
|
2022-03-23 22:38:54 +01:00
|
|
|
}
|
2022-03-17 20:22:29 +01:00
|
|
|
scaleBox(&windowBox, RDATA->output->scale);
|
|
|
|
|
2022-04-09 16:51:08 +02:00
|
|
|
if (RDATA->surface && surface == RDATA->surface)
|
2022-05-17 13:16:37 +02:00
|
|
|
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"), RDATA->decorate);
|
2022-04-09 16:51:08 +02:00
|
|
|
else
|
2022-05-17 13:16:37 +02:00
|
|
|
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"), false, RDATA->decorate);
|
2022-03-17 20:22:29 +01:00
|
|
|
|
|
|
|
wlr_surface_send_frame_done(surface, RDATA->when);
|
|
|
|
|
|
|
|
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
|
|
|
|
}
|
|
|
|
|
2022-03-20 18:49:40 +01:00
|
|
|
bool shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) {
|
2022-04-23 14:16:02 +02:00
|
|
|
wlr_box geometry = {pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y};
|
2022-03-20 18:49:40 +01:00
|
|
|
|
|
|
|
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// now check if it has the same workspace
|
|
|
|
if (pWindow->m_iWorkspaceID == pMonitor->activeWorkspace)
|
|
|
|
return true;
|
|
|
|
|
2022-05-12 11:27:31 +02:00
|
|
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
|
|
|
// if not, check if it maybe is active on a different monitor. vvv might be animation in progress
|
2022-05-16 23:13:32 +02:00
|
|
|
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
|
2022-03-22 20:04:39 +01:00
|
|
|
return true;
|
2022-03-20 18:49:40 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-04-11 19:51:37 +02:00
|
|
|
void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) {
|
2022-03-30 20:16:23 +02:00
|
|
|
CWindow* pWorkspaceWindow = nullptr;
|
|
|
|
|
2022-03-21 19:18:33 +01:00
|
|
|
for (auto& w : g_pCompositor->m_lWindows) {
|
2022-04-11 19:51:37 +02:00
|
|
|
if (w.m_iWorkspaceID != pWorkspace->m_iID || !w.m_bIsFullscreen)
|
2022-03-21 19:18:33 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// found it!
|
|
|
|
renderWindow(&w, pMonitor, time, false);
|
2022-03-30 20:16:23 +02:00
|
|
|
|
|
|
|
pWorkspaceWindow = &w;
|
|
|
|
}
|
|
|
|
|
|
|
|
// then render windows over fullscreen
|
|
|
|
for (auto& w : g_pCompositor->m_lWindows) {
|
|
|
|
if (w.m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || !w.m_bCreatedOverFullscreen || !w.m_bIsMapped)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
renderWindow(&w, pMonitor, time, true);
|
2022-03-21 19:18:33 +01:00
|
|
|
}
|
2022-03-31 17:25:23 +02:00
|
|
|
|
2022-04-25 21:49:45 +02:00
|
|
|
// and the overlay layers
|
|
|
|
for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
|
2022-05-14 20:12:29 +02:00
|
|
|
renderLayer(ls, pMonitor, time);
|
2022-04-25 21:49:45 +02:00
|
|
|
}
|
|
|
|
|
2022-03-31 17:25:23 +02:00
|
|
|
renderDragIcon(pMonitor, time);
|
2022-04-08 21:40:41 +02:00
|
|
|
|
|
|
|
// if correct monitor draw hyprerror
|
|
|
|
if (pMonitor == &g_pCompositor->m_lMonitors.front())
|
|
|
|
g_pHyprError->draw();
|
2022-03-21 19:18:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* time, bool decorate) {
|
2022-04-12 16:44:18 +02:00
|
|
|
if (pWindow->m_bHidden)
|
|
|
|
return;
|
|
|
|
|
2022-04-05 20:49:15 +02:00
|
|
|
if (pWindow->m_bFadingOut) {
|
|
|
|
g_pHyprOpenGL->renderSnapshot(&pWindow);
|
|
|
|
return;
|
|
|
|
}
|
2022-05-12 11:27:31 +02:00
|
|
|
|
|
|
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
|
|
|
const auto REALPOS = pWindow->m_vRealPosition.vec() + PWORKSPACE->m_vRenderOffset.vec();
|
2022-03-23 22:01:59 +01:00
|
|
|
SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y};
|
|
|
|
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
|
2022-04-23 14:16:02 +02:00
|
|
|
renderdata.w = pWindow->m_vRealSize.vec().x;
|
|
|
|
renderdata.h = pWindow->m_vRealSize.vec().y;
|
2022-04-10 19:04:38 +02:00
|
|
|
renderdata.dontRound = pWindow->m_bIsFullscreen;
|
2022-05-16 23:13:32 +02:00
|
|
|
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (PWORKSPACE->m_fAlpha.fl() / 255.f);
|
2022-05-17 13:16:37 +02:00
|
|
|
renderdata.alpha = pWindow->m_bIsFullscreen ? g_pConfigManager->getFloat("decoration:fullscreen_opacity") : pWindow == g_pCompositor->m_pLastWindow ? g_pConfigManager->getFloat("decoration:active_opacity") : g_pConfigManager->getFloat("decoration:inactive_opacity");
|
|
|
|
renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders;
|
2022-03-21 19:18:33 +01:00
|
|
|
|
2022-04-22 14:37:38 +02:00
|
|
|
// apply window special data
|
|
|
|
renderdata.alpha *= pWindow->m_sSpecialRenderData.alpha;
|
|
|
|
|
2022-05-17 13:16:37 +02:00
|
|
|
g_pHyprOpenGL->m_pCurrentWindow = pWindow;
|
2022-03-21 19:18:33 +01:00
|
|
|
|
2022-05-17 13:16:37 +02:00
|
|
|
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
|
2022-04-05 17:01:44 +02:00
|
|
|
|
2022-03-21 19:18:33 +01:00
|
|
|
if (pWindow->m_bIsX11) {
|
|
|
|
if (pWindow->m_uSurface.xwayland->surface) {
|
|
|
|
wlr_surface_for_each_surface(pWindow->m_uSurface.xwayland->surface, renderSurface, &renderdata);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2022-04-10 19:04:38 +02:00
|
|
|
renderdata.dontRound = false; // restore dontround
|
2022-04-02 13:41:15 +02:00
|
|
|
renderdata.pMonitor = pMonitor;
|
2022-03-21 19:18:33 +01:00
|
|
|
wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata);
|
2022-05-17 13:16:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
g_pHyprOpenGL->m_pCurrentWindow = nullptr;
|
2022-03-21 19:18:33 +01:00
|
|
|
}
|
|
|
|
|
2022-05-14 17:23:46 +02:00
|
|
|
void CHyprRenderer::renderLayer(SLayerSurface* pLayer, SMonitor* pMonitor, timespec* time) {
|
|
|
|
if (pLayer->fadingOut) {
|
|
|
|
g_pHyprOpenGL->renderSnapshot(&pLayer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SRenderData renderdata = {pMonitor->output, time, pLayer->geometry.x, pLayer->geometry.y};
|
|
|
|
renderdata.fadeAlpha = pLayer->alpha.fl();
|
|
|
|
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
|
|
|
|
}
|
|
|
|
|
2022-03-17 20:22:29 +01:00
|
|
|
void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
|
|
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(ID);
|
|
|
|
|
|
|
|
if (!PMONITOR)
|
|
|
|
return;
|
|
|
|
|
2022-03-19 13:35:04 +01:00
|
|
|
// Render layer surfaces below windows for monitor
|
|
|
|
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) {
|
2022-05-14 17:23:46 +02:00
|
|
|
renderLayer(ls, PMONITOR, time);
|
2022-03-19 13:35:04 +01:00
|
|
|
}
|
|
|
|
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) {
|
2022-05-14 17:23:46 +02:00
|
|
|
renderLayer(ls, PMONITOR, time);
|
2022-03-19 13:35:04 +01:00
|
|
|
}
|
|
|
|
|
2022-03-21 19:18:33 +01:00
|
|
|
// if there is a fullscreen window, render it and then do not render anymore.
|
|
|
|
// fullscreen window will hide other windows and top layers
|
|
|
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
2022-03-18 20:03:39 +01:00
|
|
|
|
2022-04-11 19:51:37 +02:00
|
|
|
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
2022-03-21 19:18:33 +01:00
|
|
|
renderWorkspaceWithFullscreenWindow(PMONITOR, PWORKSPACE, time);
|
|
|
|
return;
|
2022-03-17 20:22:29 +01:00
|
|
|
}
|
2022-03-18 20:03:39 +01:00
|
|
|
|
2022-03-22 17:14:07 +01:00
|
|
|
// Non-floating
|
2022-03-18 22:35:51 +01:00
|
|
|
for (auto& w : g_pCompositor->m_lWindows) {
|
2022-04-05 20:49:15 +02:00
|
|
|
if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut)
|
2022-03-18 23:52:36 +01:00
|
|
|
continue;
|
|
|
|
|
2022-03-22 17:14:07 +01:00
|
|
|
if (w.m_bIsFloating)
|
|
|
|
continue; // floating are in second pass
|
|
|
|
|
|
|
|
if (!shouldRenderWindow(&w, PMONITOR))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// render the bad boy
|
|
|
|
renderWindow(&w, PMONITOR, time, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// floating on top
|
|
|
|
for (auto& w : g_pCompositor->m_lWindows) {
|
2022-04-05 20:49:15 +02:00
|
|
|
if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut)
|
2022-03-22 17:14:07 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!w.m_bIsFloating)
|
|
|
|
continue;
|
|
|
|
|
2022-03-20 18:49:40 +01:00
|
|
|
if (!shouldRenderWindow(&w, PMONITOR))
|
2022-03-18 20:03:39 +01:00
|
|
|
continue;
|
|
|
|
|
2022-03-18 20:42:49 +01:00
|
|
|
// render the bad boy
|
2022-03-22 17:14:07 +01:00
|
|
|
renderWindow(&w, PMONITOR, time, true);
|
2022-03-18 20:03:39 +01:00
|
|
|
}
|
2022-03-19 13:35:04 +01:00
|
|
|
|
|
|
|
// Render surfaces above windows for monitor
|
|
|
|
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
2022-05-14 17:23:46 +02:00
|
|
|
renderLayer(ls, PMONITOR, time);
|
2022-03-19 13:35:04 +01:00
|
|
|
}
|
|
|
|
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
|
2022-05-14 17:23:46 +02:00
|
|
|
renderLayer(ls, PMONITOR, time);
|
2022-03-19 13:35:04 +01:00
|
|
|
}
|
2022-03-31 17:25:23 +02:00
|
|
|
|
|
|
|
renderDragIcon(PMONITOR, time);
|
2022-04-08 21:40:41 +02:00
|
|
|
|
|
|
|
// if correct monitor draw hyprerror
|
|
|
|
if (PMONITOR == &g_pCompositor->m_lMonitors.front())
|
|
|
|
g_pHyprError->draw();
|
2022-03-17 20:22:29 +01:00
|
|
|
}
|
2022-03-19 14:07:18 +01:00
|
|
|
|
|
|
|
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
|
|
|
|
wlr_output_configuration_head_v1* head;
|
|
|
|
bool noError = true;
|
|
|
|
|
|
|
|
wl_list_for_each(head, &config->heads, link) {
|
2022-05-06 17:18:24 +02:00
|
|
|
|
|
|
|
std::string commandForCfg = "";
|
2022-03-19 14:07:18 +01:00
|
|
|
const auto OUTPUT = head->state.output;
|
|
|
|
|
2022-05-06 17:18:24 +02:00
|
|
|
commandForCfg += std::string(OUTPUT->name) + ",";
|
|
|
|
|
|
|
|
if (!head->state.enabled) {
|
|
|
|
commandForCfg += "disabled";
|
|
|
|
if (!test)
|
|
|
|
g_pConfigManager->parseKeyword("monitor", commandForCfg, true);
|
|
|
|
continue;
|
2022-03-19 14:07:18 +01:00
|
|
|
}
|
|
|
|
|
2022-05-06 17:18:24 +02:00
|
|
|
wlr_output_enable(OUTPUT, head->state.enabled);
|
|
|
|
|
|
|
|
if (head->state.mode)
|
|
|
|
commandForCfg += std::to_string(head->state.mode->width) + "x" + std::to_string(head->state.mode->height) + "@" + std::to_string(head->state.mode->refresh / 1000.f) + ",";
|
|
|
|
else
|
|
|
|
commandForCfg += std::to_string(head->state.custom_mode.width) + "x" + std::to_string(head->state.custom_mode.height) + "@" + std::to_string(head->state.custom_mode.refresh / 1000.f) + ",";
|
|
|
|
|
|
|
|
commandForCfg += std::to_string(head->state.x) + "x" + std::to_string(head->state.y) + "," + std::to_string(head->state.scale);
|
|
|
|
|
|
|
|
if (!test)
|
|
|
|
g_pConfigManager->parseKeyword("monitor", commandForCfg, true);
|
|
|
|
|
2022-03-19 14:07:18 +01:00
|
|
|
noError = wlr_output_test(OUTPUT);
|
|
|
|
|
|
|
|
if (!noError)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-06 17:18:24 +02:00
|
|
|
if (!test)
|
|
|
|
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
|
2022-03-19 14:07:18 +01:00
|
|
|
|
|
|
|
if (noError)
|
|
|
|
wlr_output_configuration_v1_send_succeeded(config);
|
|
|
|
else
|
|
|
|
wlr_output_configuration_v1_send_failed(config);
|
|
|
|
wlr_output_configuration_v1_destroy(config);
|
|
|
|
|
|
|
|
Debug::log(LOG, "OutputMgr Applied/Tested.");
|
2022-03-19 14:37:40 +01:00
|
|
|
}
|
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
// taken from Sway.
|
|
|
|
// this is just too much of a spaghetti for me to understand
|
|
|
|
void apply_exclusive(struct wlr_box* usable_area, uint32_t anchor, int32_t exclusive, int32_t margin_top, int32_t margin_right, int32_t margin_bottom, int32_t margin_left) {
|
|
|
|
if (exclusive <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
struct {
|
|
|
|
uint32_t singular_anchor;
|
|
|
|
uint32_t anchor_triplet;
|
|
|
|
int* positive_axis;
|
|
|
|
int* negative_axis;
|
|
|
|
int margin;
|
|
|
|
} edges[] = {
|
|
|
|
// Top
|
|
|
|
{
|
|
|
|
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
|
|
|
|
.anchor_triplet =
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
|
|
|
|
.positive_axis = &usable_area->y,
|
|
|
|
.negative_axis = &usable_area->height,
|
|
|
|
.margin = margin_top,
|
|
|
|
},
|
|
|
|
// Bottom
|
|
|
|
{
|
|
|
|
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
|
|
|
.anchor_triplet =
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
|
|
|
.positive_axis = NULL,
|
|
|
|
.negative_axis = &usable_area->height,
|
|
|
|
.margin = margin_bottom,
|
|
|
|
},
|
|
|
|
// Left
|
|
|
|
{
|
|
|
|
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
|
|
|
|
.anchor_triplet =
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
|
|
|
.positive_axis = &usable_area->x,
|
|
|
|
.negative_axis = &usable_area->width,
|
|
|
|
.margin = margin_left,
|
|
|
|
},
|
|
|
|
// Right
|
|
|
|
{
|
|
|
|
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
|
|
|
|
.anchor_triplet =
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
|
|
|
.positive_axis = NULL,
|
|
|
|
.negative_axis = &usable_area->width,
|
|
|
|
.margin = margin_right,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
|
|
|
|
if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) && exclusive + edges[i].margin > 0) {
|
|
|
|
if (edges[i].positive_axis) {
|
|
|
|
*edges[i].positive_axis += exclusive + edges[i].margin;
|
|
|
|
}
|
|
|
|
if (edges[i].negative_axis) {
|
|
|
|
*edges[i].negative_axis -= exclusive + edges[i].margin;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-19 14:37:40 +01:00
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
void CHyprRenderer::arrangeLayerArray(SMonitor* pMonitor, const std::list<SLayerSurface*>& layerSurfaces, bool exclusiveZone, wlr_box* usableArea) {
|
|
|
|
wlr_box full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y};
|
2022-03-19 14:37:40 +01:00
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
for (auto& ls : layerSurfaces) {
|
2022-05-15 11:25:42 +02:00
|
|
|
if (ls->fadingOut || ls->readyToDelete)
|
2022-05-14 17:23:46 +02:00
|
|
|
continue;
|
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
const auto PLAYER = ls->layerSurface;
|
|
|
|
const auto PSTATE = &PLAYER->current;
|
|
|
|
if (exclusiveZone != (PSTATE->exclusive_zone > 0)) {
|
|
|
|
continue;
|
2022-03-19 14:37:40 +01:00
|
|
|
}
|
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
wlr_box bounds;
|
|
|
|
if (PSTATE->exclusive_zone == -1) {
|
|
|
|
bounds = full_area;
|
|
|
|
} else {
|
|
|
|
bounds = *usableArea;
|
2022-03-19 14:37:40 +01:00
|
|
|
}
|
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
wlr_box box = {
|
|
|
|
.width = PSTATE->desired_width,
|
|
|
|
.height = PSTATE->desired_height};
|
|
|
|
// Horizontal axis
|
|
|
|
const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
|
|
|
if (box.width == 0) {
|
|
|
|
box.x = bounds.x;
|
|
|
|
} else if ((PSTATE->anchor & both_horiz) == both_horiz) {
|
|
|
|
box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
|
|
|
|
box.x = bounds.x;
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
|
|
|
|
box.x = bounds.x + (bounds.width - box.width);
|
|
|
|
} else {
|
|
|
|
box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
|
2022-03-19 14:37:40 +01:00
|
|
|
}
|
2022-03-21 17:00:17 +01:00
|
|
|
// Vertical axis
|
|
|
|
const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
|
|
|
if (box.height == 0) {
|
|
|
|
box.y = bounds.y;
|
|
|
|
} else if ((PSTATE->anchor & both_vert) == both_vert) {
|
|
|
|
box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
|
|
|
|
box.y = bounds.y;
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
|
|
|
|
box.y = bounds.y + (bounds.height - box.height);
|
|
|
|
} else {
|
|
|
|
box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
|
2022-03-19 14:37:40 +01:00
|
|
|
}
|
2022-03-21 17:00:17 +01:00
|
|
|
// Margin
|
|
|
|
if (box.width == 0) {
|
|
|
|
box.x += PSTATE->margin.left;
|
|
|
|
box.width = bounds.width -
|
|
|
|
(PSTATE->margin.left + PSTATE->margin.right);
|
|
|
|
} else if ((PSTATE->anchor & both_horiz) == both_horiz) {
|
|
|
|
// don't apply margins
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
|
|
|
|
box.x += PSTATE->margin.left;
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
|
|
|
|
box.x -= PSTATE->margin.right;
|
|
|
|
}
|
|
|
|
if (box.height == 0) {
|
|
|
|
box.y += PSTATE->margin.top;
|
|
|
|
box.height = bounds.height -
|
|
|
|
(PSTATE->margin.top + PSTATE->margin.bottom);
|
|
|
|
} else if ((PSTATE->anchor & both_vert) == both_vert) {
|
|
|
|
// don't apply margins
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
|
|
|
|
box.y += PSTATE->margin.top;
|
|
|
|
} else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
|
|
|
|
box.y -= PSTATE->margin.bottom;
|
|
|
|
}
|
|
|
|
if (box.width <= 0 || box.height <= 0) {
|
|
|
|
Debug::log(ERR, "LayerSurface %x has a negative/zero w/h???", ls);
|
|
|
|
continue;
|
2022-03-20 14:52:23 +01:00
|
|
|
}
|
2022-03-21 17:00:17 +01:00
|
|
|
// Apply
|
|
|
|
ls->geometry = box;
|
2022-03-20 14:52:23 +01:00
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
apply_exclusive(usableArea, PSTATE->anchor, PSTATE->exclusive_zone, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left);
|
2022-03-19 14:37:40 +01:00
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
wlr_layer_surface_v1_configure(ls->layerSurface, box.width, box.height);
|
2022-03-19 14:37:40 +01:00
|
|
|
|
2022-03-21 17:50:28 +01:00
|
|
|
Debug::log(LOG, "LayerSurface %x arranged: x: %i y: %i w: %i h: %i with margins: t: %i l: %i r: %i b: %i", &ls, box.x, box.y, box.width, box.height, PSTATE->margin.top, PSTATE->margin.left, PSTATE->margin.right, PSTATE->margin.bottom);
|
2022-03-19 14:37:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) {
|
|
|
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitor);
|
|
|
|
|
|
|
|
if (!PMONITOR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Reset the reserved
|
|
|
|
PMONITOR->vecReservedBottomRight = Vector2D();
|
|
|
|
PMONITOR->vecReservedTopLeft = Vector2D();
|
|
|
|
|
2022-03-21 17:00:17 +01:00
|
|
|
wlr_box usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
|
|
|
|
|
|
|
for (auto& la : PMONITOR->m_aLayerSurfaceLists)
|
|
|
|
arrangeLayerArray(PMONITOR, la, true, &usableArea);
|
|
|
|
|
2022-03-19 14:37:40 +01:00
|
|
|
for (auto& la : PMONITOR->m_aLayerSurfaceLists)
|
2022-03-21 17:00:17 +01:00
|
|
|
arrangeLayerArray(PMONITOR, la, false, &usableArea);
|
|
|
|
|
|
|
|
PMONITOR->vecReservedTopLeft = Vector2D(usableArea.x, usableArea.y) - PMONITOR->vecPosition;
|
|
|
|
PMONITOR->vecReservedBottomRight = PMONITOR->vecSize - Vector2D(usableArea.width, usableArea.height) - PMONITOR->vecReservedTopLeft;
|
|
|
|
|
2022-04-27 17:46:07 +02:00
|
|
|
const auto ENTRY = g_pConfigManager->m_mAdditionalReservedAreas[PMONITOR->szName];
|
|
|
|
PMONITOR->vecReservedTopLeft = PMONITOR->vecReservedTopLeft + Vector2D(ENTRY.left, ENTRY.top);
|
|
|
|
PMONITOR->vecReservedBottomRight = PMONITOR->vecReservedBottomRight + Vector2D(ENTRY.right, ENTRY.bottom);
|
|
|
|
|
2022-05-04 15:23:30 +02:00
|
|
|
// damage the monitor if can
|
|
|
|
if (PMONITOR->damage)
|
|
|
|
damageMonitor(PMONITOR);
|
|
|
|
|
2022-03-21 17:26:02 +01:00
|
|
|
Debug::log(LOG, "Monitor %s layers arranged: reserved: %f %f %f %f", PMONITOR->szName.c_str(), PMONITOR->vecReservedTopLeft.x, PMONITOR->vecReservedTopLeft.y, PMONITOR->vecReservedBottomRight.x, PMONITOR->vecReservedBottomRight.y);
|
2022-03-19 16:13:19 +01:00
|
|
|
}
|
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
|
|
|
|
if (!pSurface)
|
|
|
|
return; // wut?
|
2022-03-21 16:13:43 +01:00
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
pixman_region32_t damageBox;
|
|
|
|
pixman_region32_init(&damageBox);
|
|
|
|
wlr_surface_get_effective_damage(pSurface, &damageBox);
|
2022-03-21 16:13:43 +01:00
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
pixman_region32_translate(&damageBox, x, y);
|
2022-03-21 16:13:43 +01:00
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
for (auto& m : g_pCompositor->m_lMonitors) {
|
|
|
|
double lx = 0, ly = 0;
|
|
|
|
wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m.output, &lx, &ly);
|
|
|
|
pixman_region32_translate(&damageBox, lx, ly);
|
|
|
|
wlr_output_damage_add(m.damage, &damageBox);
|
|
|
|
pixman_region32_translate(&damageBox, -lx, -ly);
|
2022-03-21 16:13:43 +01:00
|
|
|
}
|
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
pixman_region32_fini(&damageBox);
|
2022-05-05 15:09:26 +02:00
|
|
|
|
|
|
|
if (g_pConfigManager->getInt("debug:log_damage"))
|
|
|
|
Debug::log(LOG, "Damage: Surface (extents): xy: %d, %d wh: %d, %d", damageBox.extents.x1, damageBox.extents.y1, damageBox.extents.x2 - damageBox.extents.x1, damageBox.extents.y2 - damageBox.extents.y1);
|
2022-04-14 16:43:29 +02:00
|
|
|
}
|
2022-03-21 16:13:43 +01:00
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
void CHyprRenderer::damageWindow(CWindow* pWindow) {
|
|
|
|
if (!pWindow->m_bIsFloating) {
|
|
|
|
// damage by size & pos
|
|
|
|
// TODO TEMP: revise when added shadows/etc
|
2022-03-21 16:13:43 +01:00
|
|
|
|
2022-04-24 12:04:16 +02:00
|
|
|
wlr_box damageBox = {pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y};
|
|
|
|
for (auto& m : g_pCompositor->m_lMonitors) {
|
|
|
|
wlr_box fixedDamageBox = damageBox;
|
|
|
|
fixedDamageBox.x -= m.vecPosition.x;
|
|
|
|
fixedDamageBox.y -= m.vecPosition.y;
|
|
|
|
wlr_output_damage_add_box(m.damage, &fixedDamageBox);
|
|
|
|
}
|
2022-05-05 15:09:26 +02:00
|
|
|
|
|
|
|
if (g_pConfigManager->getInt("debug:log_damage"))
|
|
|
|
Debug::log(LOG, "Damage: Window floated (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height);
|
2022-04-14 16:43:29 +02:00
|
|
|
} else {
|
2022-04-14 17:00:35 +02:00
|
|
|
// damage by real size & pos + border size * 2 (JIC)
|
2022-04-14 16:43:29 +02:00
|
|
|
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
|
2022-04-23 14:16:02 +02:00
|
|
|
wlr_box damageBox = { pWindow->m_vRealPosition.vec().x - BORDERSIZE - 1, pWindow->m_vRealPosition.vec().y - BORDERSIZE - 1, pWindow->m_vRealSize.vec().x + 2 * BORDERSIZE + 2, pWindow->m_vRealSize.vec().y + 2 * BORDERSIZE + 2};
|
2022-04-24 12:04:16 +02:00
|
|
|
for (auto& m : g_pCompositor->m_lMonitors) {
|
|
|
|
wlr_box fixedDamageBox = damageBox;
|
|
|
|
fixedDamageBox.x -= m.vecPosition.x;
|
|
|
|
fixedDamageBox.y -= m.vecPosition.y;
|
|
|
|
wlr_output_damage_add_box(m.damage, &fixedDamageBox);
|
|
|
|
}
|
2022-05-05 15:09:26 +02:00
|
|
|
|
|
|
|
if (g_pConfigManager->getInt("debug:log_damage"))
|
|
|
|
Debug::log(LOG, "Damage: Window tiled (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height);
|
2022-03-21 16:13:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
void CHyprRenderer::damageMonitor(SMonitor* pMonitor) {
|
2022-04-23 23:53:12 +02:00
|
|
|
wlr_box damageBox = {0, 0, pMonitor->vecSize.x, pMonitor->vecSize.y};
|
2022-04-17 18:47:10 +02:00
|
|
|
scaleBox(&damageBox, pMonitor->scale);
|
2022-04-14 16:43:29 +02:00
|
|
|
wlr_output_damage_add_box(pMonitor->damage, &damageBox);
|
2022-05-05 15:09:26 +02:00
|
|
|
|
|
|
|
if (g_pConfigManager->getInt("debug:log_damage"))
|
|
|
|
Debug::log(LOG, "Damage: Monitor %s", pMonitor->szName.c_str());
|
2022-04-14 16:43:29 +02:00
|
|
|
}
|
2022-03-21 16:13:43 +01:00
|
|
|
|
2022-04-14 16:43:29 +02:00
|
|
|
void CHyprRenderer::damageBox(wlr_box* pBox) {
|
2022-04-17 18:47:10 +02:00
|
|
|
for (auto& m : g_pCompositor->m_lMonitors) {
|
2022-04-24 12:04:16 +02:00
|
|
|
wlr_box damageBox = {pBox->x - m.vecPosition.x, pBox->y - m.vecPosition.y, pBox->width, pBox->height};
|
|
|
|
wlr_output_damage_add_box(m.damage, &damageBox);
|
2022-04-17 18:47:10 +02:00
|
|
|
}
|
2022-05-05 15:09:26 +02:00
|
|
|
|
|
|
|
if (g_pConfigManager->getInt("debug:log_damage"))
|
|
|
|
Debug::log(LOG, "Damage: Box: xy: %d, %d wh: %d, %d", pBox->x, pBox->y, pBox->width, pBox->height);
|
2022-03-31 17:25:23 +02:00
|
|
|
}
|
|
|
|
|
2022-05-05 14:02:30 +02:00
|
|
|
void CHyprRenderer::damageBox(const int& x, const int& y, const int& w, const int& h) {
|
|
|
|
wlr_box box = {x, y, w, h};
|
|
|
|
damageBox(&box);
|
|
|
|
}
|
|
|
|
|
2022-03-31 17:25:23 +02:00
|
|
|
void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) {
|
|
|
|
if (!(g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.iconMapped && g_pInputManager->m_sDrag.dragIcon->surface))
|
|
|
|
return;
|
|
|
|
|
|
|
|
SRenderData renderdata = {pMonitor->output, time, g_pInputManager->m_sDrag.pos.x, g_pInputManager->m_sDrag.pos.y};
|
|
|
|
renderdata.surface = g_pInputManager->m_sDrag.dragIcon->surface;
|
|
|
|
renderdata.w = g_pInputManager->m_sDrag.dragIcon->surface->current.width;
|
|
|
|
renderdata.h = g_pInputManager->m_sDrag.dragIcon->surface->current.height;
|
|
|
|
|
|
|
|
wlr_surface_for_each_surface(g_pInputManager->m_sDrag.dragIcon->surface, renderSurface, &renderdata);
|
2022-04-14 16:43:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& mode) {
|
|
|
|
if (mode == "full")
|
|
|
|
return DAMAGE_TRACKING_FULL;
|
|
|
|
if (mode == "monitor")
|
|
|
|
return DAMAGE_TRACKING_MONITOR;
|
|
|
|
if (mode == "none")
|
|
|
|
return DAMAGE_TRACKING_NONE;
|
|
|
|
|
|
|
|
return DAMAGE_TRACKING_INVALID;
|
2022-04-19 19:01:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) {
|
|
|
|
|
2022-04-21 18:11:28 +02:00
|
|
|
Debug::log(LOG, "Applying monitor rule for %s", pMonitor->szName.c_str());
|
|
|
|
|
2022-04-19 19:01:23 +02:00
|
|
|
// Check if the rule isn't already applied
|
|
|
|
if (!force && DELTALESSTHAN(pMonitor->vecSize.x, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecSize.y, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->scale == pMonitorRule->scale) {
|
|
|
|
Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wlr_output_set_scale(pMonitor->output, pMonitorRule->scale);
|
|
|
|
pMonitor->scale = pMonitorRule->scale;
|
|
|
|
|
|
|
|
// loop over modes and choose an appropriate one.
|
|
|
|
if (!wl_list_empty(&pMonitor->output->modes)) {
|
|
|
|
wlr_output_mode* mode;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
|
|
|
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
|
|
|
|
if (DELTALESSTHAN(mode->width, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(mode->height, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(mode->refresh / 1000.f, pMonitorRule->refreshRate, 1)) {
|
|
|
|
wlr_output_set_mode(pMonitor->output, mode);
|
|
|
|
|
|
|
|
if (!wlr_output_test(pMonitor->output)) {
|
|
|
|
Debug::log(LOG, "Monitor %s: REJECTED available mode: %ix%i@%2f!",
|
|
|
|
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
|
|
|
|
mode->width, mode->height, mode->refresh / 1000.f);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug::log(LOG, "Monitor %s: requested %ix%i@%2f, found available mode: %ix%i@%imHz, applying.",
|
|
|
|
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
|
|
|
|
mode->width, mode->height, mode->refresh);
|
|
|
|
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
pMonitor->refreshRate = mode->refresh / 1000.f;
|
|
|
|
pMonitor->vecSize = Vector2D(mode->width, mode->height);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
|
|
|
|
|
|
|
|
if (!PREFERREDMODE) {
|
|
|
|
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f",
|
|
|
|
(int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Preferred is valid
|
|
|
|
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
|
|
|
|
|
|
|
|
Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f",
|
|
|
|
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
|
|
|
|
PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
|
|
|
|
|
|
|
|
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
|
|
|
|
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
// update renderer
|
|
|
|
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
|
|
|
|
|
|
|
|
if (!wlr_output_commit(pMonitor->output)) {
|
|
|
|
Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name);
|
|
|
|
return;
|
|
|
|
}
|
2022-04-21 18:11:28 +02:00
|
|
|
|
|
|
|
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitorRule->offset.x, (int)pMonitorRule->offset.y);
|
|
|
|
|
|
|
|
//wlr_output_damage_add_whole(pMonitor->damage);
|
|
|
|
|
|
|
|
wlr_output_enable(pMonitor->output, true);
|
|
|
|
|
|
|
|
// updato wlroots
|
|
|
|
Events::listener_change(nullptr, nullptr);
|
|
|
|
|
|
|
|
// updato us
|
|
|
|
arrangeLayersForMonitor(pMonitor->ID);
|
|
|
|
|
|
|
|
// frame skip
|
|
|
|
pMonitor->needsFrameSkip = true;
|
|
|
|
}
|