mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-12-22 21:39:47 +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;
|
const auto POUTPUT = (COutput*)data;
|
||||||
Debug::log(LOG, "output {} done", POUTPUT->name);
|
Debug::log(LOG, "output {} done", POUTPUT->name);
|
||||||
if (g_pHyprlock->m_bLocked && !POUTPUT->sessionLockSurface) {
|
if (g_pHyprlock->m_bLocked && !POUTPUT->sessionLockSurface) {
|
||||||
// if we are already locked, create a surface dynamically after a small timeout
|
// if we are already locked, create a surface dynamically
|
||||||
// we also need to request a dma frame for screenshots
|
|
||||||
Debug::log(LOG, "Creating a surface dynamically for output as we are already locked");
|
Debug::log(LOG, "Creating a surface dynamically for output as we are already locked");
|
||||||
POUTPUT->sessionLockSurface = std::make_unique<CSessionLockSurface>(POUTPUT);
|
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) {
|
void CHyprlock::onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name) {
|
||||||
Debug::log(LOG, " | removed iface {}", 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
|
// end wl_registry
|
||||||
|
@ -570,9 +574,7 @@ void CHyprlock::unlock() {
|
||||||
m_tFadeEnds = std::chrono::system_clock::now() + std::chrono::milliseconds(500);
|
m_tFadeEnds = std::chrono::system_clock::now() + std::chrono::milliseconds(500);
|
||||||
m_bFadeStarted = true;
|
m_bFadeStarted = true;
|
||||||
|
|
||||||
for (auto& o : m_vOutputs) {
|
renderAllOutputs();
|
||||||
o->sessionLockSurface->render();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wl_seat
|
// wl_seat
|
||||||
|
@ -758,9 +760,7 @@ static const ext_session_lock_v1_listener sessionLockListener = {
|
||||||
static void displayFailTextTimerCallback(std::shared_ptr<CTimer> self, void* data) {
|
static void displayFailTextTimerCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||||
g_pAuth->m_bDisplayFailText = false;
|
g_pAuth->m_bDisplayFailText = false;
|
||||||
|
|
||||||
for (auto& o : g_pHyprlock->m_vOutputs) {
|
g_pHyprlock->renderAllOutputs();
|
||||||
o->sessionLockSurface->render();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprlock::onPasswordCheckTimer() {
|
void CHyprlock::onPasswordCheckTimer() {
|
||||||
|
@ -779,9 +779,7 @@ void CHyprlock::onPasswordCheckTimer() {
|
||||||
|
|
||||||
g_pAuth->start();
|
g_pAuth->start();
|
||||||
|
|
||||||
for (auto& o : m_vOutputs) {
|
renderAllOutputs();
|
||||||
o->sessionLockSurface->render();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,9 +788,8 @@ void CHyprlock::clearPasswordBuffer() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_sPasswordState.passBuffer = "";
|
m_sPasswordState.passBuffer = "";
|
||||||
for (auto& o : m_vOutputs) {
|
|
||||||
o->sessionLockSurface->render();
|
renderAllOutputs();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprlock::renderOutput(const std::string& stringPort) {
|
void CHyprlock::renderOutput(const std::string& stringPort) {
|
||||||
|
@ -803,9 +800,21 @@ void CHyprlock::renderOutput(const std::string& stringPort) {
|
||||||
|
|
||||||
const auto PMONITOR = MON->get();
|
const auto PMONITOR = MON->get();
|
||||||
|
|
||||||
|
if (!PMONITOR->sessionLockSurface)
|
||||||
|
return;
|
||||||
|
|
||||||
PMONITOR->sessionLockSurface->render();
|
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) {
|
void CHyprlock::startKeyRepeat(xkb_keysym_t sym) {
|
||||||
if (m_pKeyRepeatTimer) {
|
if (m_pKeyRepeatTimer) {
|
||||||
m_pKeyRepeatTimer->cancel();
|
m_pKeyRepeatTimer->cancel();
|
||||||
|
@ -830,9 +839,7 @@ void CHyprlock::repeatKey(xkb_keysym_t sym) {
|
||||||
m_pKeyRepeatTimer = addTimer(
|
m_pKeyRepeatTimer = addTimer(
|
||||||
std::chrono::milliseconds(m_iKeebRepeatRate), [sym](std::shared_ptr<CTimer> self, void* data) { g_pHyprlock->repeatKey(sym); }, nullptr);
|
std::chrono::milliseconds(m_iKeebRepeatRate), [sym](std::shared_ptr<CTimer> self, void* data) { g_pHyprlock->repeatKey(sym); }, nullptr);
|
||||||
|
|
||||||
for (auto& o : m_vOutputs) {
|
renderAllOutputs();
|
||||||
o->sessionLockSurface->render();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprlock::onKey(uint32_t key, bool down) {
|
void CHyprlock::onKey(uint32_t key, bool down) {
|
||||||
|
@ -863,9 +870,7 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_pAuth->checkWaiting()) {
|
if (g_pAuth->checkWaiting()) {
|
||||||
for (auto& o : m_vOutputs) {
|
renderAllOutputs();
|
||||||
o->sessionLockSurface->render();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,9 +886,7 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
||||||
startKeyRepeat(SYM);
|
startKeyRepeat(SYM);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& o : m_vOutputs) {
|
renderAllOutputs();
|
||||||
o->sessionLockSurface->render();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprlock::handleKeySym(xkb_keysym_t sym) {
|
void CHyprlock::handleKeySym(xkb_keysym_t sym) {
|
||||||
|
|
|
@ -64,6 +64,7 @@ class CHyprlock {
|
||||||
std::optional<std::string> passwordLastFailReason();
|
std::optional<std::string> passwordLastFailReason();
|
||||||
|
|
||||||
void renderOutput(const std::string& stringPort);
|
void renderOutput(const std::string& stringPort);
|
||||||
|
void renderAllOutputs();
|
||||||
|
|
||||||
size_t getPasswordBufferLen();
|
size_t getPasswordBufferLen();
|
||||||
size_t getPasswordBufferDisplayLen();
|
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) {
|
SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
||||||
for (auto& a : assets) {
|
for (auto& a : assets) {
|
||||||
if (a.first == id)
|
if (a.first == id)
|
||||||
|
@ -94,7 +70,7 @@ SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& dma : dmas) {
|
for (auto& dma : dmas) {
|
||||||
if (id == "dma:" + dma->name)
|
if (id == dma->resourceID)
|
||||||
return dma->asset.ready ? &dma->asset : nullptr;
|
return dma->asset.ready ? &dma->asset : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ class CAsyncResourceGatherer {
|
||||||
void unloadAsset(SPreloadedAsset* asset);
|
void unloadAsset(SPreloadedAsset* asset);
|
||||||
void notify();
|
void notify();
|
||||||
void await();
|
void await();
|
||||||
void recheckDMAFramesFor(COutput* output);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::thread asyncLoopThread;
|
std::thread asyncLoopThread;
|
||||||
|
|
|
@ -86,7 +86,12 @@ static const zwlr_screencopy_frame_v1_listener wlrFrameListener = {
|
||||||
.buffer_done = wlrOnBufferDone,
|
.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) {
|
if (!glEGLImageTargetTexture2DOES) {
|
||||||
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||||
|
@ -100,13 +105,11 @@ CDMAFrame::CDMAFrame(COutput* output_) : output(output_) {
|
||||||
eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC)eglGetProcAddress("eglQueryDmaBufModifiersEXT");
|
eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC)eglGetProcAddress("eglQueryDmaBufModifiersEXT");
|
||||||
|
|
||||||
// firstly, plant a listener for the frame
|
// 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;
|
scdata.frame = this;
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_add_listener(frameCb, &wlrFrameListener, &scdata);
|
zwlr_screencopy_frame_v1_add_listener(frameCb, &wlrFrameListener, &scdata);
|
||||||
|
|
||||||
name = output->stringPort;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CDMAFrame::~CDMAFrame() {
|
CDMAFrame::~CDMAFrame() {
|
||||||
|
|
|
@ -19,6 +19,8 @@ struct SScreencopyData {
|
||||||
|
|
||||||
class CDMAFrame {
|
class CDMAFrame {
|
||||||
public:
|
public:
|
||||||
|
static std::string getResourceId(COutput* output);
|
||||||
|
|
||||||
CDMAFrame(COutput* mon);
|
CDMAFrame(COutput* mon);
|
||||||
~CDMAFrame();
|
~CDMAFrame();
|
||||||
|
|
||||||
|
@ -27,7 +29,7 @@ class CDMAFrame {
|
||||||
|
|
||||||
wl_buffer* wlBuffer = nullptr;
|
wl_buffer* wlBuffer = nullptr;
|
||||||
|
|
||||||
std::string name;
|
std::string resourceID;
|
||||||
|
|
||||||
SPreloadedAsset asset;
|
SPreloadedAsset asset;
|
||||||
|
|
||||||
|
@ -42,7 +44,5 @@ class CDMAFrame {
|
||||||
zwlr_screencopy_frame_v1* frameCb = nullptr;
|
zwlr_screencopy_frame_v1* frameCb = nullptr;
|
||||||
SScreencopyData scdata;
|
SScreencopyData scdata;
|
||||||
|
|
||||||
COutput* output = nullptr;
|
|
||||||
|
|
||||||
EGLImage image = nullptr;
|
EGLImage image = nullptr;
|
||||||
};
|
};
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../helpers/Color.hpp"
|
#include "../helpers/Color.hpp"
|
||||||
#include "../core/Output.hpp"
|
#include "../core/Output.hpp"
|
||||||
#include "../core/hyprlock.hpp"
|
#include "../core/hyprlock.hpp"
|
||||||
|
#include "../renderer/DMAFrame.hpp"
|
||||||
#include "mtx.hpp"
|
#include "mtx.hpp"
|
||||||
|
|
||||||
#include <GLES3/gl32.h>
|
#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"));
|
const std::string PATH = std::any_cast<Hyprlang::STRING>(c.values.at("path"));
|
||||||
|
|
||||||
std::string resourceID = "";
|
std::string resourceID = "";
|
||||||
if (PATH == "screenshot")
|
if (PATH == "screenshot") {
|
||||||
resourceID = "dma:" + surf->output->stringPort;
|
resourceID = CDMAFrame::getResourceId(surf->output);
|
||||||
else if (!PATH.empty())
|
// 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;
|
resourceID = "background:" + PATH;
|
||||||
|
|
||||||
widgets[surf].emplace_back(std::make_unique<CBackground>(surf->size, surf->output, resourceID, c.values, PATH == "screenshot"));
|
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();
|
boundFBs.pop_back();
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundFBs.empty() ? 0 : boundFBs.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 pushFb(GLint fb);
|
||||||
void popFb();
|
void popFb();
|
||||||
|
|
||||||
|
void removeWidgetsFor(const CSessionLockSurface* surf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
widgetMap_t widgets;
|
widgetMap_t widgets;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue