summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVaxry <vaxry@vaxry.net>2023-10-20 20:15:41 +0100
committerVaxry <vaxry@vaxry.net>2023-10-20 20:15:57 +0100
commit7f35f33b4ca16509e127976772db6abd9abf100b (patch)
tree557326d4214617c3459d983001d969fbe6510448 /src
parentbab2f6a664a67dfd0c2f442dbc0134ef7c6e07e2 (diff)
surface/wayland: conform to small surface requirements
do not stretch small surfaces, instead center them if they fit.
Diffstat (limited to 'src')
-rw-r--r--src/Window.cpp6
-rw-r--r--src/Window.hpp1
-rw-r--r--src/events/Windows.cpp2
-rw-r--r--src/helpers/WLSurface.cpp17
-rw-r--r--src/helpers/WLSurface.hpp31
-rw-r--r--src/managers/XWaylandManager.cpp4
-rw-r--r--src/render/Renderer.cpp25
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
+
+ // allow stretching. Useful for plugins.
+ bool m_bFillIgnoreSmall = false;
- CWLSurface& operator=(wlr_surface* pSurface) {
- destroy();
- m_pWLRSurface = pSurface;
- init();
+ // if present, means this is a base surface of a window. Cleaned on unassign()
+ CWindow* m_pOwner = nullptr;
- return *this;
+ 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)