diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 36d6e6cc..55d8afe7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -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(); diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp index f48f71be..5f5dbdab 100644 --- a/src/events/Popups.cpp +++ b/src/events/Popups.cpp @@ -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) { diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp index f2542486..e0e1f3c9 100644 --- a/src/helpers/SubsurfaceTree.cpp +++ b/src/helpers/SubsurfaceTree.cpp @@ -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); diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp index 7ca52a68..557cdb53 100644 --- a/src/helpers/Vector2D.hpp +++ b/src/helpers/Vector2D.hpp @@ -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(); diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 57e01099..96295b39 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -73,6 +73,9 @@ struct SRenderData { // only for windows, not popups bool squishOversized = true; + + // for calculating UV + CWindow* pWindow = nullptr; }; struct SExtensionFindingData { diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index eacd8730..c960b89b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -17,17 +17,15 @@ 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; if (y + windowBox.height > RDATA->h) windowBox.height = RDATA->h - y; } + + if (RDATA->pWindow) + g_pHyprRenderer->calculateUVForWindowSurface(RDATA->pWindow, surface, RDATA->squishOversized); scaleBox(&windowBox, RDATA->output->scale); @@ -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; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 8ed296d5..04b2bb45 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -40,6 +40,7 @@ public: bool shouldRenderWindow(CWindow*); void ensureCursorRenderingMode(); bool shouldRenderCursor(); + void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false); bool m_bWindowRequestedCursorHide = false;