diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 0d06b69cb..3f73c468f 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -104,6 +104,7 @@ struct SWindowData { CWindowOverridableVar xray = false; CWindowOverridableVar renderUnfocused = false; CWindowOverridableVar noFollowMouse = false; + CWindowOverridableVar noScreenShare = false; CWindowOverridableVar borderSize = {std::string("general:border_size"), Hyprlang::INT(0), std::nullopt}; CWindowOverridableVar rounding = {std::string("decoration:rounding"), Hyprlang::INT(0), std::nullopt}; @@ -489,6 +490,7 @@ namespace NWindowProperties { {"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.tearing; }}, {"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.xray; }}, {"nofollowmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noFollowMouse; }}, + {"noscreenshare", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noScreenShare; }}, }; const std::unordered_map*(const PHLWINDOW&)>> intWindowProperties = { diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 5fa7c84e8..8002776af 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -13,6 +13,7 @@ #include "types/Buffer.hpp" #include "../helpers/Format.hpp" #include "../helpers/time/Time.hpp" +#include "XDGShell.hpp" #include #include @@ -200,6 +201,59 @@ void CScreencopyFrame::renderMon() { g_pHyprOpenGL->renderTexture(TEXTURE, monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); + + for (auto const& w : g_pCompositor->m_windows) { + if (!w->m_windowData.noScreenShare.valueOrDefault()) + continue; + + if (!g_pHyprRenderer->shouldRenderWindow(w)) + continue; + + const auto PWORKSPACE = w->m_workspace; + + if UNLIKELY (!PWORKSPACE) + continue; + + const auto REALPOS = w->m_realPosition->value() + (w->m_pinned ? Vector2D{} : PWORKSPACE->m_renderOffset->value()); + const auto noScreenShareBox = CBox{REALPOS.x, REALPOS.y, std::max(w->m_realSize->value().x, 5.0), std::max(w->m_realSize->value().y, 5.0)} + .scale(m_monitor->m_scale) + .translate({-m_monitor->m_position.x, -m_monitor->m_position.y}) + .translate({-m_box.x, -m_box.y}); + + const auto dontRound = w->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || w->m_windowData.noRounding.valueOrDefault(); + const auto rounding = dontRound ? 0 : w->rounding() * m_monitor->m_scale; + const auto roundingPower = dontRound ? 2.0f : w->roundingPower(); + + g_pHyprOpenGL->renderRect(noScreenShareBox, {0, 0, 0, 255}, rounding, roundingPower); + + if (w->m_isX11 || !w->m_popupHead) + continue; + + const auto geom = w->m_xdgSurface->m_current.geometry; + const Vector2D popupBaseOffset = REALPOS - Vector2D{geom.pos().x, geom.pos().y}; + + w->m_popupHead->breadthfirst( + [&](WP popup, void*) { + if (!popup->m_wlSurface || !popup->m_wlSurface->resource() || !popup->m_mapped) + return; + + const auto popRel = popup->coordsRelativeToParent(); + popup->m_wlSurface->resource()->breadthfirst( + [&](SP surf, const Vector2D& localOff, void*) { + const auto size = surf->m_current.size; + const auto surfBox = CBox{popupBaseOffset.x + popRel.x + localOff.x, popupBaseOffset.y + popRel.y + localOff.y, size.x, size.y} + .scale(m_monitor->m_scale) + .translate({-m_monitor->m_position.x, -m_monitor->m_position.y}) + .translate({-m_box.x, -m_box.y}); + + if LIKELY (surfBox.w > 0 && surfBox.h > 0) + g_pHyprOpenGL->renderRect(surfBox, {0, 0, 0, 255}); + }, + nullptr); + }, + nullptr); + } + if (m_overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(m_monitor.lock(), Time::steadyNow(), fakeDamage, g_pInputManager->getMouseCoordsInternal() - m_monitor->m_position - m_box.pos(), true); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index e50f1fcef..4d0ee0f83 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -257,10 +257,11 @@ bool CToplevelExportFrame::copyShm(const Time::steady_tp& now) { // render client at 0,0 if (PERM == PERMISSION_RULE_ALLOW_MODE_ALLOW) { - g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible - g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); - g_pHyprRenderer->m_bBlockSurfaceFeedback = false; - + if (!m_window->m_windowData.noScreenShare.valueOrDefault()) { + g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible + g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->m_bBlockSurfaceFeedback = false; + } if (overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->m_self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - m_window->m_realPosition->value()); } else if (PERM == PERMISSION_RULE_ALLOW_MODE_DENY) { @@ -338,9 +339,11 @@ bool CToplevelExportFrame::copyDmabuf(const Time::steady_tp& now) { g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0)); if (PERM == PERMISSION_RULE_ALLOW_MODE_ALLOW) { - g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible - g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); - g_pHyprRenderer->m_bBlockSurfaceFeedback = false; + if (!m_window->m_windowData.noScreenShare.valueOrDefault()) { + g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible + g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->m_bBlockSurfaceFeedback = false; + } if (overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->m_self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - m_window->m_realPosition->value());