mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-11-16 23:05:58 +01:00
label: add executing commands
This commit is contained in:
parent
3d27060688
commit
06b07c53e5
8 changed files with 220 additions and 4 deletions
|
@ -539,3 +539,73 @@ std::shared_ptr<CTimer> CHyprlock::addTimer(const std::chrono::system_clock::dur
|
||||||
m_sLoopState.timerCV.notify_all();
|
m_sLoopState.timerCV.notify_all();
|
||||||
return T;
|
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<char, 128> buffer;
|
||||||
|
std::string result;
|
||||||
|
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||||
|
if (!pipe)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||||
|
result += buffer.data();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,9 @@ class CHyprlock {
|
||||||
void lockSession();
|
void lockSession();
|
||||||
void unlockSession();
|
void unlockSession();
|
||||||
|
|
||||||
|
void spawnAsync(const std::string& cmd);
|
||||||
|
std::string spawnSync(const std::string& cmd);
|
||||||
|
|
||||||
void onKey(uint32_t key);
|
void onKey(uint32_t key);
|
||||||
void onPasswordCheckTimer();
|
void onPasswordCheckTimer();
|
||||||
bool passwordCheckWaiting();
|
bool passwordCheckWaiting();
|
||||||
|
|
55
src/helpers/VarList.cpp
Normal file
55
src/helpers/VarList.cpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "VarList.hpp"
|
||||||
|
#include <ranges>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
static std::string removeBeginEndSpacesTabs(std::string str) {
|
||||||
|
if (str.empty())
|
||||||
|
return str;
|
||||||
|
|
||||||
|
int countBefore = 0;
|
||||||
|
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||||
|
countBefore++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int countAfter = 0;
|
||||||
|
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
||||||
|
countAfter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) {
|
||||||
|
if (in.empty())
|
||||||
|
m_vArgs.emplace_back("");
|
||||||
|
|
||||||
|
std::string args{in};
|
||||||
|
size_t idx = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
std::ranges::replace_if(
|
||||||
|
args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0);
|
||||||
|
|
||||||
|
for (const auto& s : args | std::views::split(0)) {
|
||||||
|
if (removeEmpty && s.empty())
|
||||||
|
continue;
|
||||||
|
if (++idx == lastArgNo) {
|
||||||
|
m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += s.size() + 1;
|
||||||
|
m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CVarList::join(const std::string& joiner, size_t from, size_t to) const {
|
||||||
|
size_t last = to == 0 ? size() : to;
|
||||||
|
|
||||||
|
std::string rolling;
|
||||||
|
for (size_t i = from; i < last; ++i) {
|
||||||
|
rolling += m_vArgs[i] + (i + 1 < last ? joiner : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rolling;
|
||||||
|
}
|
63
src/helpers/VarList.hpp
Normal file
63
src/helpers/VarList.hpp
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CVarList {
|
||||||
|
public:
|
||||||
|
/** Split string into arg list
|
||||||
|
@param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args
|
||||||
|
@param delim if delimiter is 's', use std::isspace
|
||||||
|
@param removeEmpty remove empty args from argv
|
||||||
|
*/
|
||||||
|
CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false);
|
||||||
|
|
||||||
|
~CVarList() = default;
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return m_vArgs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const;
|
||||||
|
|
||||||
|
void map(std::function<void(std::string&)> func) {
|
||||||
|
for (auto& s : m_vArgs)
|
||||||
|
func(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const std::string arg) {
|
||||||
|
m_vArgs.emplace_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string operator[](const size_t& idx) const {
|
||||||
|
if (idx >= m_vArgs.size())
|
||||||
|
return "";
|
||||||
|
return m_vArgs[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
// for range-based loops
|
||||||
|
std::vector<std::string>::iterator begin() {
|
||||||
|
return m_vArgs.begin();
|
||||||
|
}
|
||||||
|
std::vector<std::string>::const_iterator begin() const {
|
||||||
|
return m_vArgs.begin();
|
||||||
|
}
|
||||||
|
std::vector<std::string>::iterator end() {
|
||||||
|
return m_vArgs.end();
|
||||||
|
}
|
||||||
|
std::vector<std::string>::const_iterator end() const {
|
||||||
|
return m_vArgs.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const std::string& el) {
|
||||||
|
for (auto& a : m_vArgs) {
|
||||||
|
if (a == el)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_vArgs;
|
||||||
|
};
|
|
@ -129,6 +129,8 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) {
|
||||||
const int FONTSIZE = rq.props.contains("font_size") ? std::any_cast<int>(rq.props.at("font_size")) : 16;
|
const int FONTSIZE = rq.props.contains("font_size") ? std::any_cast<int>(rq.props.at("font_size")) : 16;
|
||||||
const CColor FONTCOLOR = rq.props.contains("color") ? std::any_cast<CColor>(rq.props.at("color")) : CColor(1.0, 1.0, 1.0, 1.0);
|
const CColor FONTCOLOR = rq.props.contains("color") ? std::any_cast<CColor>(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<std::string>(rq.props.at("font_family")) : "Sans";
|
const std::string FONTFAMILY = rq.props.contains("font_family") ? std::any_cast<std::string>(rq.props.at("font_family")) : "Sans";
|
||||||
|
const bool ISCMD = rq.props.contains("cmd") ? std::any_cast<bool>(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 CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* dummy value */);
|
||||||
auto CAIRO = cairo_create(CAIROSURFACE);
|
auto CAIRO = cairo_create(CAIROSURFACE);
|
||||||
|
@ -144,12 +146,12 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) {
|
||||||
PangoAttrList* attrList = nullptr;
|
PangoAttrList* attrList = nullptr;
|
||||||
GError* gError = nullptr;
|
GError* gError = nullptr;
|
||||||
char* buf = 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);
|
pango_layout_set_text(layout, buf, -1);
|
||||||
else {
|
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);
|
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)
|
if (!attrList)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "IWidget.hpp"
|
#include "IWidget.hpp"
|
||||||
#include "../../helpers/Log.hpp"
|
#include "../../helpers/Log.hpp"
|
||||||
|
#include "../../helpers/VarList.hpp"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
Vector2D IWidget::posFromHVAlign(const Vector2D& viewport, const Vector2D& size, const Vector2D& offset, const std::string& halign, const std::string& valign) {
|
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;
|
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;
|
result.formatted = in;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
|
@ -16,6 +16,8 @@ class IWidget {
|
||||||
struct SFormatResult {
|
struct SFormatResult {
|
||||||
std::string formatted;
|
std::string formatted;
|
||||||
float updateEveryMs = 0; // 0 means don't (static)
|
float updateEveryMs = 0; // 0 means don't (static)
|
||||||
|
bool alwaysUpdate = false;
|
||||||
|
bool cmd = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual SFormatResult formatString(std::string in);
|
virtual SFormatResult formatString(std::string in);
|
||||||
|
|
|
@ -26,7 +26,7 @@ void CLabel::onTimerUpdate() {
|
||||||
|
|
||||||
label = formatString(labelPreFormat);
|
label = formatString(labelPreFormat);
|
||||||
|
|
||||||
if (label.formatted == oldFormatted)
|
if (label.formatted == oldFormatted && !label.alwaysUpdate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!pendingResourceID.empty())
|
if (!pendingResourceID.empty())
|
||||||
|
@ -60,6 +60,7 @@ CLabel::CLabel(const Vector2D& viewport_, const std::unordered_map<std::string,
|
||||||
request.props["font_family"] = fontFamily;
|
request.props["font_family"] = fontFamily;
|
||||||
request.props["color"] = labelColor;
|
request.props["color"] = labelColor;
|
||||||
request.props["font_size"] = fontSize;
|
request.props["font_size"] = fontSize;
|
||||||
|
request.props["cmd"] = label.cmd;
|
||||||
|
|
||||||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue