mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-12-22 05:19:48 +01:00
core: improve dynamic output handling (#386)
* core: check for sessionLockSurface before calling render
This is needed, because when a new monitor is added via `onGlobal` the
order of the events is not guaranteed. Meaning that render for a
particular monitor might get called before a `CSessionLockSurface` for
that monitor exists.
* renderer: remove widgets for destroyed lockSurfaces
* asyncResourceGatherer: don't create duplicate dma frames for a specific stringPort
* core: remove renderer widgets in ~CSessionLockSurface instead of in onGlobalRemoved
* Revert "core: remove renderer widgets in ~CSessionLockSurface instead of in onGlobalRemoved"
This reverts commit 405aa42de8
.
Because of destruction order, it is safer to do it in `onGlobalRemoved`.
* core: ditch dynamic DMAFrame generation
* core: identify DMAFrames via output size and stringPort
* core: fallback to background color for dynamic outputs with background:path=screenshot
* core: remove output pointer from DMAFrame
This commit is contained in:
parent
0f66aeac03
commit
88b9ce48ed
9 changed files with 54 additions and 61 deletions
|
@ -25,11 +25,9 @@ static void handleDone(void* data, wl_output* output) {
|
|||
const auto POUTPUT = (COutput*)data;
|
||||
Debug::log(LOG, "output {} done", POUTPUT->name);
|
||||
if (g_pHyprlock->m_bLocked && !POUTPUT->sessionLockSurface) {
|
||||
// if we are already locked, create a surface dynamically after a small timeout
|
||||
// we also need to request a dma frame for screenshots
|
||||
// if we are already locked, create a surface dynamically
|
||||
Debug::log(LOG, "Creating a surface dynamically for output as we are already locked");
|
||||
POUTPUT->sessionLockSurface = std::make_unique<CSessionLockSurface>(POUTPUT);
|
||||
g_pRenderer->asyncResourceGatherer->recheckDMAFramesFor(POUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -300,7 +300,11 @@ void CHyprlock::onGlobal(void* data, struct wl_registry* registry, uint32_t name
|
|||
|
||||
void CHyprlock::onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name) {
|
||||
Debug::log(LOG, " | removed iface {}", name);
|
||||
std::erase_if(m_vOutputs, [name](const auto& other) { return other->name == name; });
|
||||
auto outputIt = std::find_if(m_vOutputs.begin(), m_vOutputs.end(), [name](const auto& other) { return other->name == name; });
|
||||
if (outputIt != m_vOutputs.end()) {
|
||||
g_pRenderer->removeWidgetsFor(outputIt->get()->sessionLockSurface.get());
|
||||
m_vOutputs.erase(outputIt);
|
||||
}
|
||||
}
|
||||
|
||||
// end wl_registry
|
||||
|
@ -570,9 +574,7 @@ void CHyprlock::unlock() {
|
|||
m_tFadeEnds = std::chrono::system_clock::now() + std::chrono::milliseconds(500);
|
||||
m_bFadeStarted = true;
|
||||
|
||||
for (auto& o : m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
renderAllOutputs();
|
||||
}
|
||||
|
||||
// wl_seat
|
||||
|
@ -758,9 +760,7 @@ static const ext_session_lock_v1_listener sessionLockListener = {
|
|||
static void displayFailTextTimerCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
g_pAuth->m_bDisplayFailText = false;
|
||||
|
||||
for (auto& o : g_pHyprlock->m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
}
|
||||
|
||||
void CHyprlock::onPasswordCheckTimer() {
|
||||
|
@ -779,9 +779,7 @@ void CHyprlock::onPasswordCheckTimer() {
|
|||
|
||||
g_pAuth->start();
|
||||
|
||||
for (auto& o : m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
renderAllOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,9 +788,8 @@ void CHyprlock::clearPasswordBuffer() {
|
|||
return;
|
||||
|
||||
m_sPasswordState.passBuffer = "";
|
||||
for (auto& o : m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
|
||||
renderAllOutputs();
|
||||
}
|
||||
|
||||
void CHyprlock::renderOutput(const std::string& stringPort) {
|
||||
|
@ -803,9 +800,21 @@ void CHyprlock::renderOutput(const std::string& stringPort) {
|
|||
|
||||
const auto PMONITOR = MON->get();
|
||||
|
||||
if (!PMONITOR->sessionLockSurface)
|
||||
return;
|
||||
|
||||
PMONITOR->sessionLockSurface->render();
|
||||
}
|
||||
|
||||
void CHyprlock::renderAllOutputs() {
|
||||
for (auto& o : m_vOutputs) {
|
||||
if (!o->sessionLockSurface)
|
||||
continue;
|
||||
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprlock::startKeyRepeat(xkb_keysym_t sym) {
|
||||
if (m_pKeyRepeatTimer) {
|
||||
m_pKeyRepeatTimer->cancel();
|
||||
|
@ -830,9 +839,7 @@ void CHyprlock::repeatKey(xkb_keysym_t sym) {
|
|||
m_pKeyRepeatTimer = addTimer(
|
||||
std::chrono::milliseconds(m_iKeebRepeatRate), [sym](std::shared_ptr<CTimer> self, void* data) { g_pHyprlock->repeatKey(sym); }, nullptr);
|
||||
|
||||
for (auto& o : m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
renderAllOutputs();
|
||||
}
|
||||
|
||||
void CHyprlock::onKey(uint32_t key, bool down) {
|
||||
|
@ -863,9 +870,7 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
|||
}
|
||||
|
||||
if (g_pAuth->checkWaiting()) {
|
||||
for (auto& o : m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
renderAllOutputs();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -881,9 +886,7 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
|||
startKeyRepeat(SYM);
|
||||
}
|
||||
|
||||
for (auto& o : m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
}
|
||||
renderAllOutputs();
|
||||
}
|
||||
|
||||
void CHyprlock::handleKeySym(xkb_keysym_t sym) {
|
||||
|
|
|
@ -64,6 +64,7 @@ class CHyprlock {
|
|||
std::optional<std::string> passwordLastFailReason();
|
||||
|
||||
void renderOutput(const std::string& stringPort);
|
||||
void renderAllOutputs();
|
||||
|
||||
size_t getPasswordBufferLen();
|
||||
size_t getPasswordBufferDisplayLen();
|
||||
|
|
|
@ -56,30 +56,6 @@ CAsyncResourceGatherer::CAsyncResourceGatherer() {
|
|||
}
|
||||
}
|
||||
|
||||
void CAsyncResourceGatherer::recheckDMAFramesFor(COutput* output) {
|
||||
const auto CWIDGETS = g_pConfigManager->getWidgetConfigs();
|
||||
|
||||
bool shouldMake = false;
|
||||
|
||||
for (auto& c : CWIDGETS) {
|
||||
if (c.type != "background")
|
||||
continue;
|
||||
|
||||
if (std::string{std::any_cast<Hyprlang::STRING>(c.values.at("path"))} != "screenshot")
|
||||
continue;
|
||||
|
||||
if (c.monitor.empty() || c.monitor == output->stringPort || output->stringDesc.starts_with(c.monitor)) {
|
||||
shouldMake = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldMake)
|
||||
return;
|
||||
|
||||
dmas.emplace_back(std::make_unique<CDMAFrame>(output));
|
||||
}
|
||||
|
||||
SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
||||
for (auto& a : assets) {
|
||||
if (a.first == id)
|
||||
|
@ -94,7 +70,7 @@ SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
|||
};
|
||||
|
||||
for (auto& dma : dmas) {
|
||||
if (id == "dma:" + dma->name)
|
||||
if (id == dma->resourceID)
|
||||
return dma->asset.ready ? &dma->asset : nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ class CAsyncResourceGatherer {
|
|||
void unloadAsset(SPreloadedAsset* asset);
|
||||
void notify();
|
||||
void await();
|
||||
void recheckDMAFramesFor(COutput* output);
|
||||
|
||||
private:
|
||||
std::thread asyncLoopThread;
|
||||
|
|
|
@ -86,7 +86,12 @@ static const zwlr_screencopy_frame_v1_listener wlrFrameListener = {
|
|||
.buffer_done = wlrOnBufferDone,
|
||||
};
|
||||
|
||||
CDMAFrame::CDMAFrame(COutput* output_) : output(output_) {
|
||||
std::string CDMAFrame::getResourceId(COutput* output) {
|
||||
return std::format("dma:{}-{}x{}", output->stringPort, output->size.x, output->size.y);
|
||||
}
|
||||
|
||||
CDMAFrame::CDMAFrame(COutput* output_) {
|
||||
resourceID = getResourceId(output_);
|
||||
|
||||
if (!glEGLImageTargetTexture2DOES) {
|
||||
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
|
@ -100,13 +105,11 @@ CDMAFrame::CDMAFrame(COutput* output_) : output(output_) {
|
|||
eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC)eglGetProcAddress("eglQueryDmaBufModifiersEXT");
|
||||
|
||||
// firstly, plant a listener for the frame
|
||||
frameCb = zwlr_screencopy_manager_v1_capture_output(g_pHyprlock->getScreencopy(), false, output->output);
|
||||
frameCb = zwlr_screencopy_manager_v1_capture_output(g_pHyprlock->getScreencopy(), false, output_->output);
|
||||
|
||||
scdata.frame = this;
|
||||
|
||||
zwlr_screencopy_frame_v1_add_listener(frameCb, &wlrFrameListener, &scdata);
|
||||
|
||||
name = output->stringPort;
|
||||
}
|
||||
|
||||
CDMAFrame::~CDMAFrame() {
|
||||
|
|
|
@ -19,6 +19,8 @@ struct SScreencopyData {
|
|||
|
||||
class CDMAFrame {
|
||||
public:
|
||||
static std::string getResourceId(COutput* output);
|
||||
|
||||
CDMAFrame(COutput* mon);
|
||||
~CDMAFrame();
|
||||
|
||||
|
@ -27,7 +29,7 @@ class CDMAFrame {
|
|||
|
||||
wl_buffer* wlBuffer = nullptr;
|
||||
|
||||
std::string name;
|
||||
std::string resourceID;
|
||||
|
||||
SPreloadedAsset asset;
|
||||
|
||||
|
@ -42,7 +44,5 @@ class CDMAFrame {
|
|||
zwlr_screencopy_frame_v1* frameCb = nullptr;
|
||||
SScreencopyData scdata;
|
||||
|
||||
COutput* output = nullptr;
|
||||
|
||||
EGLImage image = nullptr;
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
#include "../helpers/Color.hpp"
|
||||
#include "../core/Output.hpp"
|
||||
#include "../core/hyprlock.hpp"
|
||||
#include "../renderer/DMAFrame.hpp"
|
||||
#include "mtx.hpp"
|
||||
|
||||
#include <GLES3/gl32.h>
|
||||
|
@ -320,9 +321,15 @@ std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CS
|
|||
const std::string PATH = std::any_cast<Hyprlang::STRING>(c.values.at("path"));
|
||||
|
||||
std::string resourceID = "";
|
||||
if (PATH == "screenshot")
|
||||
resourceID = "dma:" + surf->output->stringPort;
|
||||
else if (!PATH.empty())
|
||||
if (PATH == "screenshot") {
|
||||
resourceID = CDMAFrame::getResourceId(surf->output);
|
||||
// When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available.
|
||||
// Dynamic ones are tricky, because a screencopy would copy hyprlock itself.
|
||||
if (asyncResourceGatherer->ready) {
|
||||
if (!asyncResourceGatherer->getAssetByID(resourceID))
|
||||
resourceID = ""; // Fallback to solid color (background:color)
|
||||
}
|
||||
} else if (!PATH.empty())
|
||||
resourceID = "background:" + PATH;
|
||||
|
||||
widgets[surf].emplace_back(std::make_unique<CBackground>(surf->size, surf->output, resourceID, c.values, PATH == "screenshot"));
|
||||
|
@ -512,3 +519,7 @@ void CRenderer::popFb() {
|
|||
boundFBs.pop_back();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundFBs.empty() ? 0 : boundFBs.back());
|
||||
}
|
||||
|
||||
void CRenderer::removeWidgetsFor(const CSessionLockSurface* surf) {
|
||||
widgets.erase(surf);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ class CRenderer {
|
|||
void pushFb(GLint fb);
|
||||
void popFb();
|
||||
|
||||
void removeWidgetsFor(const CSessionLockSurface* surf);
|
||||
|
||||
private:
|
||||
widgetMap_t widgets;
|
||||
|
||||
|
|
Loading…
Reference in a new issue