mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-09 15:45:57 +01:00
Viewporter implementaion (#585)
Implementation of the `wp_viewporter` core protocol and some bugfixes
This commit is contained in:
parent
8b5c64c8fd
commit
52c0ba544c
7 changed files with 93 additions and 54 deletions
|
@ -99,7 +99,7 @@ CCompositor::CCompositor() {
|
|||
wlr_data_control_manager_v1_create(m_sWLDisplay);
|
||||
wlr_gamma_control_manager_v1_create(m_sWLDisplay);
|
||||
wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
|
||||
// wlr_viewporter_create(m_sWLDisplay); // TODO: support wl_viewporter
|
||||
wlr_viewporter_create(m_sWLDisplay);
|
||||
|
||||
m_sWLROutputLayout = wlr_output_layout_create();
|
||||
|
||||
|
|
|
@ -18,14 +18,20 @@
|
|||
void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
|
||||
SXDGPopup *const PPOPUP = (SXDGPopup*)pPopup;
|
||||
|
||||
auto curPopup = PPOPUP;
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
auto curPopup = PPOPUP;
|
||||
while (true) {
|
||||
px += curPopup->popup->current.geometry.x;
|
||||
py += curPopup->popup->current.geometry.y;
|
||||
|
||||
if (curPopup == PPOPUP && PPOPUP->parentWindow) {
|
||||
px -= curPopup->popup->base->current.geometry.x;
|
||||
py -= curPopup->popup->base->current.geometry.y;
|
||||
}
|
||||
|
||||
// fix oversized fucking popups
|
||||
// kill me
|
||||
if (curPopup->pSurfaceTree && curPopup->pSurfaceTree->pSurface && !curPopup->parentPopup) {
|
||||
|
|
|
@ -139,6 +139,9 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
|
|||
|
||||
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
|
||||
|
||||
if (PSUBSURFACE->mapped)
|
||||
listener_mapSubsurface(PNEWSUBSURFACE, nullptr);
|
||||
|
||||
wlr_subsurface* existingWlrSubsurface;
|
||||
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) {
|
||||
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
|
||||
|
|
|
@ -35,6 +35,10 @@ class Vector2D {
|
|||
return a.x != x || a.y != y;
|
||||
}
|
||||
|
||||
Vector2D operator*(const Vector2D& a) const {
|
||||
return Vector2D(this->x * a.x, this->y * a.y);
|
||||
}
|
||||
|
||||
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D());
|
||||
|
||||
Vector2D floor();
|
||||
|
|
|
@ -73,6 +73,9 @@ struct SRenderData {
|
|||
|
||||
// only for windows, not popups
|
||||
bool squishOversized = true;
|
||||
|
||||
// for calculating UV
|
||||
CWindow* pWindow = nullptr;
|
||||
};
|
||||
|
||||
struct SExtensionFindingData {
|
||||
|
|
|
@ -17,11 +17,6 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|||
else // here we clamp to 2, these might be some tiny specks
|
||||
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::clamp(surface->current.width, 2, 1337420), std::clamp(surface->current.height, 2, 1337420)};
|
||||
|
||||
// squish all oversized but dont in some cases, jesus christ this is a mess
|
||||
// TODO: this shouldn't be done this way. Custom UV here as well.
|
||||
// this is fucking horrible
|
||||
// Issue: will cause oversized apps with reserved area to overflow from the window box. (see chromium on ozone wayland)
|
||||
const auto PRESQUISHSIZE = Vector2D(windowBox.width, windowBox.height);
|
||||
if (RDATA->squishOversized) {
|
||||
if (x + windowBox.width > RDATA->w)
|
||||
windowBox.width = RDATA->w - x;
|
||||
|
@ -29,6 +24,9 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|||
windowBox.height = RDATA->h - y;
|
||||
}
|
||||
|
||||
if (RDATA->pWindow)
|
||||
g_pHyprRenderer->calculateUVForWindowSurface(RDATA->pWindow, surface, RDATA->squishOversized);
|
||||
|
||||
scaleBox(&windowBox, RDATA->output->scale);
|
||||
|
||||
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
|
@ -49,21 +47,7 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (RDATA->surface && wlr_surface_is_xdg_surface(RDATA->surface)) {
|
||||
wlr_box geo;
|
||||
wlr_xdg_surface_get_geometry(wlr_xdg_surface_from_wlr_surface(RDATA->surface), &geo);
|
||||
|
||||
// TODO: continuation of the above madness.
|
||||
if (geo.x != 0 || geo.y != 0) {
|
||||
windowBox.width = PRESQUISHSIZE.x;
|
||||
windowBox.height = PRESQUISHSIZE.y;
|
||||
}
|
||||
|
||||
windowBox.x -= geo.x;
|
||||
windowBox.y -= geo.y;
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false);
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
}
|
||||
|
||||
wlr_surface_send_frame_done(surface, RDATA->when);
|
||||
|
@ -213,6 +197,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true) && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL);
|
||||
renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding;
|
||||
renderdata.blur = true; // if it shouldn't, it will be ignored later
|
||||
renderdata.pWindow = pWindow;
|
||||
|
||||
// apply window special data
|
||||
if (pWindow->m_sSpecialRenderData.alphaInactive == -1)
|
||||
|
@ -232,38 +217,6 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations)
|
||||
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f);
|
||||
|
||||
if (!pWindow->m_bIsX11) {
|
||||
wlr_box geom;
|
||||
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
|
||||
|
||||
// first, check for poorly sized windows.
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height);
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
|
||||
// No special UV mods needed
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
// then, if the surface is too big, modify the pos UV
|
||||
if (geom.width > renderdata.w + 1 || geom.height > renderdata.h + 1) {
|
||||
const auto OFF = Vector2D(renderdata.w / (double)geom.width, renderdata.h / (double)geom.height);
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D(-1, -1))
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(0, 0);
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x * ((double)renderdata.w / ((double)geom.width / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x)),
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y * ((double)renderdata.h / ((double)geom.height / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
|
||||
|
||||
if (renderdata.decorate && pWindow->m_sSpecialRenderData.border) {
|
||||
|
@ -288,6 +241,12 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
|
||||
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) {
|
||||
if (!pWindow->m_bIsX11) {
|
||||
wlr_box geom;
|
||||
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
|
||||
|
||||
renderdata.x -= geom.x;
|
||||
renderdata.y -= geom.y;
|
||||
|
||||
renderdata.dontRound = true; // don't round popups
|
||||
renderdata.pMonitor = pMonitor;
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
|
@ -295,6 +254,10 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
}
|
||||
}
|
||||
|
||||
// reset uv
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
|
||||
g_pHyprOpenGL->m_pCurrentWindow = nullptr;
|
||||
}
|
||||
|
||||
|
@ -442,6 +405,65 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
|||
renderDragIcon(PMONITOR, time);
|
||||
}
|
||||
|
||||
void CHyprRenderer::calculateUVForWindowSurface(CWindow* pWindow, wlr_surface* pSurface, bool main) {
|
||||
if (!pWindow->m_bIsX11) {
|
||||
Vector2D uvTL;
|
||||
Vector2D uvBR = Vector2D(1, 1);
|
||||
|
||||
wlr_box geom;
|
||||
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
|
||||
|
||||
// wp_viewporter_v1 implementation
|
||||
if (pSurface->current.viewport.has_src) {
|
||||
wlr_fbox bufferSource;
|
||||
wlr_surface_get_buffer_source_box(pSurface, &bufferSource);
|
||||
|
||||
Vector2D surfaceSize = Vector2D(pSurface->buffer->texture->width, pSurface->buffer->texture->height);
|
||||
|
||||
uvTL = Vector2D(bufferSource.x / surfaceSize.x, bufferSource.y / surfaceSize.y);
|
||||
uvBR = Vector2D((bufferSource.x + bufferSource.width) / surfaceSize.x, (bufferSource.y + bufferSource.height) / surfaceSize.y);
|
||||
|
||||
// TODO: (example: chromium) this still has a tiny "bump" at the end.
|
||||
if (main) {
|
||||
uvTL = uvTL + (Vector2D((double)geom.x / ((double)pSurface->current.width), (double)geom.y / ((double)pSurface->current.height)) * (((uvBR.x - uvTL.x) * surfaceSize.x) / surfaceSize.x));
|
||||
uvBR = uvBR * Vector2D((double)(geom.width + geom.x) / ((double)pSurface->current.width), (double)(geom.y + geom.height) / ((double)pSurface->current.height));
|
||||
}
|
||||
} else if (main) {
|
||||
// oversized windows' UV adjusting
|
||||
uvTL = Vector2D((double)geom.x / ((double)pSurface->current.width), (double)geom.y / ((double)pSurface->current.height));
|
||||
uvBR = Vector2D((double)(geom.width + geom.x) / ((double)pSurface->current.width), (double)(geom.y + geom.height) / ((double)pSurface->current.height));
|
||||
}
|
||||
|
||||
// set UV
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
|
||||
// No special UV mods needed
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
if (!main)
|
||||
return; // ignore the rest
|
||||
|
||||
// then, if the surface is too big, modify the pos UV
|
||||
if (geom.width > pWindow->m_vRealSize.vec().x + 1 || geom.height > pWindow->m_vRealSize.vec().y + 1) {
|
||||
const auto OFF = Vector2D(pWindow->m_vRealSize.vec().x / (double)geom.width, pWindow->m_vRealSize.vec().y / (double)geom.height);
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D(-1, -1))
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(0, 0);
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x * ((double)pWindow->m_vRealSize.vec().x / ((double)geom.width / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x)),
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y * ((double)pWindow->m_vRealSize.vec().y / ((double)geom.height / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y)));
|
||||
}
|
||||
} else {
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
|
||||
wlr_output_configuration_head_v1* head;
|
||||
bool noError = true;
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
bool shouldRenderWindow(CWindow*);
|
||||
void ensureCursorRenderingMode();
|
||||
bool shouldRenderCursor();
|
||||
void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false);
|
||||
|
||||
bool m_bWindowRequestedCursorHide = false;
|
||||
|
||||
|
|
Loading…
Reference in a new issue