From 7f35f33b4ca16509e127976772db6abd9abf100b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 20 Oct 2023 20:15:41 +0100 Subject: [PATCH] surface/wayland: conform to small surface requirements do not stretch small surfaces, instead center them if they fit. --- src/Window.cpp | 6 ++++++ src/Window.hpp | 1 + src/events/Windows.cpp | 2 ++ src/helpers/WLSurface.cpp | 17 +++++++++++++++++ src/helpers/WLSurface.hpp | 31 +++++++++++++++++++++++-------- src/managers/XWaylandManager.cpp | 4 ++-- src/render/Renderer.cpp | 25 +++++++++++++++++++++++-- 7 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/Window.cpp b/src/Window.cpp index 6a83c7fa..af5015d4 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -424,6 +424,7 @@ void CWindow::onUnmap() { void CWindow::onMap() { m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this)); + m_pWLSurface.m_pOwner = this; // JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped) m_vRealPosition.resetAllCallbacks(); @@ -453,6 +454,8 @@ void CWindow::onMap() { hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this, "CWindow"); + + m_vReportedSize = m_vPendingReportedSize; } void CWindow::onBorderAngleAnimEnd(void* ptr) { @@ -882,6 +885,9 @@ bool CWindow::opaque() { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); + if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall) + return false; + if (PWORKSPACE->m_fAlpha.fl() != 1.f) return false; diff --git a/src/Window.hpp b/src/Window.hpp index dd16fdcb..e9014471 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -203,6 +203,7 @@ class CWindow { // for not spamming the protocols Vector2D m_vReportedPosition; Vector2D m_vReportedSize; + Vector2D m_vPendingReportedSize; // for restoring floating statuses Vector2D m_vLastFloatingSize; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index a77c298f..df8475d2 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -789,6 +789,8 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11)) return; + PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. + PWINDOW->updateSurfaceOutputs(); g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, diff --git a/src/helpers/WLSurface.cpp b/src/helpers/WLSurface.cpp index 8524c9a5..a34c77a1 100644 --- a/src/helpers/WLSurface.cpp +++ b/src/helpers/WLSurface.cpp @@ -27,12 +27,29 @@ wlr_surface* CWLSurface::wlr() const { return m_pWLRSurface; } +bool CWLSurface::small() const { + if (!m_pOwner || !exists()) + return false; + + return m_pOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width || m_pOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height; +} + +Vector2D CWLSurface::correctSmallVec() const { + if (!m_pOwner || !exists() || !small() || m_bFillIgnoreSmall) + return {}; + + return Vector2D{(m_pOwner->m_vReportedSize.x - m_pWLRSurface->current.buffer_width) / 2, (m_pOwner->m_vReportedSize.y - m_pWLRSurface->current.buffer_height) / 2}.clamp( + {}, {INFINITY, INFINITY}) * + (m_pOwner->m_vRealSize.vec() / m_pOwner->m_vReportedSize); +} + void CWLSurface::destroy() { if (!m_pWLRSurface) return; hyprListener_destroy.removeCallback(); m_pWLRSurface->data = nullptr; + m_pOwner = nullptr; if (g_pCompositor->m_pLastFocus == m_pWLRSurface) g_pCompositor->m_pLastFocus = nullptr; diff --git a/src/helpers/WLSurface.hpp b/src/helpers/WLSurface.hpp index c5cdd37f..ee6574de 100644 --- a/src/helpers/WLSurface.hpp +++ b/src/helpers/WLSurface.hpp @@ -1,6 +1,9 @@ #pragma once #include "../defines.hpp" + +class CWindow; + class CWLSurface { public: CWLSurface() = default; @@ -10,20 +13,28 @@ class CWLSurface { void assign(wlr_surface* pSurface); void unassign(); - CWLSurface(const CWLSurface&) = delete; - CWLSurface(CWLSurface&&) = delete; + CWLSurface(const CWLSurface&) = delete; + CWLSurface(CWLSurface&&) = delete; CWLSurface& operator=(const CWLSurface&) = delete; - CWLSurface& operator=(CWLSurface&&) = delete; + CWLSurface& operator=(CWLSurface&&) = delete; wlr_surface* wlr() const; bool exists() const; + bool small() const; // means surface is smaller than the requested size + Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces - CWLSurface& operator=(wlr_surface* pSurface) { - destroy(); - m_pWLRSurface = pSurface; - init(); + // allow stretching. Useful for plugins. + bool m_bFillIgnoreSmall = false; - return *this; + // if present, means this is a base surface of a window. Cleaned on unassign() + CWindow* m_pOwner = nullptr; + + CWLSurface& operator=(wlr_surface* pSurface) { + destroy(); + m_pWLRSurface = pSurface; + init(); + + return *this; } bool operator==(const CWLSurface& other) const { @@ -38,6 +49,10 @@ class CWLSurface { return exists(); } + static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) { + return (CWLSurface*)pSurface->data; + } + private: wlr_surface* m_pWLRSurface = nullptr; diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 39331e9c..a40647fa 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -163,8 +163,8 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f if (!force && ((pWindow->m_vReportedSize == size && windowPos == pWindow->m_vReportedPosition) || (pWindow->m_vReportedSize == size && !pWindow->m_bIsX11))) return; - pWindow->m_vReportedPosition = windowPos; - pWindow->m_vReportedSize = size; + pWindow->m_vReportedPosition = windowPos; + pWindow->m_vPendingReportedSize = size; pWindow->m_fX11SurfaceScaledBy = 1.f; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c4daa416..7fe2774b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -23,9 +23,23 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, RDATA->pMonitor->output, &outputX, &outputY); wlr_box windowBox; - if (RDATA->surface && surface == RDATA->surface) + if (RDATA->surface && surface == RDATA->surface) { windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, RDATA->w, RDATA->h}; - else { // here we clamp to 2, these might be some tiny specks + + // however, if surface buffer w / h < box, we need to adjust them + auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface); + + if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees m_pOwner */) { + const auto CORRECT = PSURFACE->correctSmallVec(); + + windowBox.x += CORRECT.x; + windowBox.y += CORRECT.y; + + windowBox.width = (double)surface->current.buffer_width * (PSURFACE->m_pOwner->m_vRealSize.vec().x / PSURFACE->m_pOwner->m_vReportedSize.x); + windowBox.height = (double)surface->current.buffer_height * (PSURFACE->m_pOwner->m_vRealSize.vec().y / PSURFACE->m_pOwner->m_vReportedSize.y); + } + + } else { // here we clamp to 2, these might be some tiny specks windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max(surface->current.width, 2), std::max(surface->current.height, 2)}; if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { // adjust subsurfaces to the window @@ -1392,6 +1406,13 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, dou if (g_pCompositor->m_bUnsafeState) return; + auto* const PSURFACE = CWLSurface::surfaceFromWlr(pSurface); + if (PSURFACE && PSURFACE->m_pOwner && PSURFACE->small()) { + const auto CORRECTION = PSURFACE->correctSmallVec(); + x += CORRECTION.x; + y += CORRECTION.y; + } + CRegion damageBox; wlr_surface_get_effective_damage(pSurface, damageBox.pixman()); if (scale != 1.0)