From 5370762eb3f27ecfdb9b4d1f82a9c91c21c88730 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 21 Feb 2024 14:08:40 +0000 Subject: [PATCH] label: add executing commands --- src/core/hyprlock.cpp | 70 ++++++++++++++++++++++++++ src/core/hyprlock.hpp | 3 ++ src/renderer/AsyncResourceGatherer.cpp | 8 +-- src/renderer/widgets/IWidget.cpp | 20 ++++++++ src/renderer/widgets/IWidget.hpp | 2 + src/renderer/widgets/Label.cpp | 3 +- 6 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/core/hyprlock.cpp b/src/core/hyprlock.cpp index 9184ccc7..09cdba54 100644 --- a/src/core/hyprlock.cpp +++ b/src/core/hyprlock.cpp @@ -539,3 +539,73 @@ std::shared_ptr CHyprlock::addTimer(const std::chrono::system_clock::dur m_sLoopState.timerCV.notify_all(); return T; } + +void CHyprlock::spawnAsync(const std::string& args) { + Debug::log(LOG, "Executing (async) {}", args); + + int socket[2]; + if (pipe(socket) != 0) + Debug::log(LOG, "Unable to create pipe for fork"); + + pid_t child, grandchild; + child = fork(); + + if (child < 0) { + close(socket[0]); + close(socket[1]); + Debug::log(LOG, "Fail to create the first fork"); + return; + } + + if (child == 0) { + // run in child + + sigset_t set; + sigemptyset(&set); + sigprocmask(SIG_SETMASK, &set, NULL); + + grandchild = fork(); + + if (grandchild == 0) { + // run in grandchild + close(socket[0]); + close(socket[1]); + execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); + // exit grandchild + _exit(0); + } + + close(socket[0]); + write(socket[1], &grandchild, sizeof(grandchild)); + close(socket[1]); + // exit child + _exit(0); + } + + // run in parent + close(socket[1]); + read(socket[0], &grandchild, sizeof(grandchild)); + close(socket[0]); + // clear child and leave child to init + waitpid(child, NULL, 0); + + if (child < 0) { + Debug::log(LOG, "Failed to create the second fork"); + return; + } + + Debug::log(LOG, "Process Created with pid {}", grandchild); +} + +std::string CHyprlock::spawnSync(const std::string& cmd) { + std::array buffer; + std::string result; + const std::unique_ptr pipe(popen(cmd.c_str(), "r"), pclose); + if (!pipe) + return ""; + + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result += buffer.data(); + } + return result; +} diff --git a/src/core/hyprlock.hpp b/src/core/hyprlock.hpp index 88a53ecd..1536cc5b 100644 --- a/src/core/hyprlock.hpp +++ b/src/core/hyprlock.hpp @@ -33,6 +33,9 @@ class CHyprlock { void lockSession(); void unlockSession(); + void spawnAsync(const std::string& cmd); + std::string spawnSync(const std::string& cmd); + void onKey(uint32_t key); void onPasswordCheckTimer(); bool passwordCheckWaiting(); diff --git a/src/renderer/AsyncResourceGatherer.cpp b/src/renderer/AsyncResourceGatherer.cpp index faf63cc7..8ccf864f 100644 --- a/src/renderer/AsyncResourceGatherer.cpp +++ b/src/renderer/AsyncResourceGatherer.cpp @@ -129,6 +129,8 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) { const int FONTSIZE = rq.props.contains("font_size") ? std::any_cast(rq.props.at("font_size")) : 16; const CColor FONTCOLOR = rq.props.contains("color") ? std::any_cast(rq.props.at("color")) : CColor(1.0, 1.0, 1.0, 1.0); const std::string FONTFAMILY = rq.props.contains("font_family") ? std::any_cast(rq.props.at("font_family")) : "Sans"; + const bool ISCMD = rq.props.contains("cmd") ? std::any_cast(rq.props.at("cmd")) : false; + const std::string TEXT = ISCMD ? g_pHyprlock->spawnSync(rq.asset) : rq.asset; auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* dummy value */); auto CAIRO = cairo_create(CAIROSURFACE); @@ -144,12 +146,12 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) { PangoAttrList* attrList = nullptr; GError* gError = nullptr; char* buf = nullptr; - if (pango_parse_markup(rq.asset.c_str(), -1, 0, &attrList, &buf, nullptr, &gError)) + if (pango_parse_markup(TEXT.c_str(), -1, 0, &attrList, &buf, nullptr, &gError)) pango_layout_set_text(layout, buf, -1); else { - Debug::log(ERR, "Pango markup parsing for {} failed: {}", rq.asset, gError->message); + Debug::log(ERR, "Pango markup parsing for {} failed: {}", TEXT, gError->message); g_error_free(gError); - pango_layout_set_text(layout, rq.asset.c_str(), -1); + pango_layout_set_text(layout, TEXT.c_str(), -1); } if (!attrList) diff --git a/src/renderer/widgets/IWidget.cpp b/src/renderer/widgets/IWidget.cpp index 0b9b3661..bbfdd804 100644 --- a/src/renderer/widgets/IWidget.cpp +++ b/src/renderer/widgets/IWidget.cpp @@ -1,5 +1,6 @@ #include "IWidget.hpp" #include "../../helpers/Log.hpp" +#include "../../helpers/VarList.hpp" #include Vector2D IWidget::posFromHVAlign(const Vector2D& viewport, const Vector2D& size, const Vector2D& offset, const std::string& halign, const std::string& valign) { @@ -55,6 +56,25 @@ IWidget::SFormatResult IWidget::formatString(std::string in) { result.updateEveryMs = result.updateEveryMs != 0 && result.updateEveryMs < 1000 ? result.updateEveryMs : 1000; } + if (in.starts_with("cmd[") && in.contains("]")) { + // this is a command + CVarList vars(in.substr(4, in.find_first_of(']') - 4)); + + for (const auto& v : vars) { + if (v.starts_with("update:")) { + try { + result.updateEveryMs = std::stoull(v.substr(7)); + } catch (std::exception& e) { Debug::log(ERR, "Error parsing {} in cmd[]", v); } + } else { + Debug::log(ERR, "Unknown prop in string format {}", v); + } + } + + result.alwaysUpdate = true; + in = in.substr(in.find_first_of(']') + 1); + result.cmd = true; + } + result.formatted = in; return result; } \ No newline at end of file diff --git a/src/renderer/widgets/IWidget.hpp b/src/renderer/widgets/IWidget.hpp index 71762e58..e81b53a0 100644 --- a/src/renderer/widgets/IWidget.hpp +++ b/src/renderer/widgets/IWidget.hpp @@ -16,6 +16,8 @@ class IWidget { struct SFormatResult { std::string formatted; float updateEveryMs = 0; // 0 means don't (static) + bool alwaysUpdate = false; + bool cmd = false; }; virtual SFormatResult formatString(std::string in); diff --git a/src/renderer/widgets/Label.cpp b/src/renderer/widgets/Label.cpp index 2dd71ecc..f3e19211 100644 --- a/src/renderer/widgets/Label.cpp +++ b/src/renderer/widgets/Label.cpp @@ -26,7 +26,7 @@ void CLabel::onTimerUpdate() { label = formatString(labelPreFormat); - if (label.formatted == oldFormatted) + if (label.formatted == oldFormatted && !label.alwaysUpdate) return; if (!pendingResourceID.empty()) @@ -60,6 +60,7 @@ CLabel::CLabel(const Vector2D& viewport_, const std::unordered_mapasyncResourceGatherer->requestAsyncAssetPreload(request);