Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

widgets: execute shell commands from more keywords #649

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions src/config/ConfigDataValues.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,92 @@ class CLayoutValueData : public ICustomConfigValueData {
CLayoutValueData() {};
virtual ~CLayoutValueData() {};

struct SExecuteResult {
Hyprutils::Math::Vector2D values;
struct {
bool x = false;
bool y = false;
} isRelative;
};

SExecuteResult executeCommand() {
if (!m_bIsCommand)
return {{0,0}, {false, false}};

FILE* pipe = popen(m_sCommand.c_str(), "r");
if (!pipe) {
Debug::log(ERR, "Failed to execute position command");
return {{0,0}, {false, false}};
}

char buffer[128];
std::string result = "";
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);

if (!result.empty() && result.back() == '\n')
result.pop_back();

SExecuteResult out;
const auto SPLIT = result.find(',');
if (SPLIT == std::string::npos) {
Debug::log(ERR, "Position command output must be x,y format");
return {{0,0}, {false, false}};
}

auto lhs = result.substr(0, SPLIT);
auto rhs = result.substr(SPLIT + 1);
if (rhs.starts_with(" "))
rhs = rhs.substr(1);

if (lhs.ends_with("%")) {
out.isRelative.x = true;
lhs.pop_back();
}

if (rhs.ends_with("%")) {
out.isRelative.y = true;
rhs.pop_back();
}

try {
out.values = {std::stof(lhs), std::stof(rhs)};
} catch (std::exception& e) {
Debug::log(ERR, "Failed to parse command output as coordinates");
return {{0,0}, {false, false}};
}

return out;
}

bool needsUpdate() const {
return m_bIsCommand;
}

float updateMs() const {
return m_bIsCommand ? m_iUpdateMs : 0;
}

void update() {
if (!m_bIsCommand)
return;

auto result = executeCommand();
m_vValues = result.values;
m_sIsRelative.x = result.isRelative.x;
m_sIsRelative.y = result.isRelative.y;
}

virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_LAYOUT;
}

virtual std::string toString() {
if (m_bIsCommand)
return std::format("cmd[update:{}]{}", m_iUpdateMs, m_sCommand);
return std::format("{}{},{}{}", m_vValues.x, (m_sIsRelative.x) ? "%" : "px", m_vValues.y, (m_sIsRelative.y) ? "%" : "px");
}

Expand All @@ -46,6 +127,8 @@ class CLayoutValueData : public ICustomConfigValueData {
}

Hyprutils::Math::Vector2D getAbsolute(const Hyprutils::Math::Vector2D& viewport) {
if (m_bIsCommand)
update();
return {
(m_sIsRelative.x ? (m_vValues.x / 100) * viewport.x : m_vValues.x),
(m_sIsRelative.y ? (m_vValues.y / 100) * viewport.y : m_vValues.y),
Expand All @@ -57,6 +140,10 @@ class CLayoutValueData : public ICustomConfigValueData {
bool x = false;
bool y = false;
} m_sIsRelative;

bool m_bIsCommand = false;
std::string m_sCommand = "";
int m_iUpdateMs = 0;
};

class CGradientValueData : public ICustomConfigValueData {
Expand Down
31 changes: 30 additions & 1 deletion src/config/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,36 @@ static Hyprlang::CParseResult configHandleLayoutOption(const char* v, void** dat
if (!*data)
*data = new CLayoutValueData();

const auto DATA = (CLayoutValueData*)(*data);
const auto DATA = (CLayoutValueData*)(*data);

if (VALUE.starts_with("cmd[") && VALUE.contains("]")) {
DATA->m_bIsCommand = true;

std::string options = VALUE.substr(4, VALUE.find_first_of(']') - 4);
CVarList vars(options, 0, ',', true);

for (const auto& var : vars) {
if (var.starts_with("update:")) {
try {
DATA->m_iUpdateMs = std::stoull(var.substr(7));
} catch (std::exception& e) {
Debug::log(ERR, "Error parsing {} in cmd[]", var);
}
} else {
Debug::log(ERR, "Unknown prop in layout format {}", var);
}
}

DATA->m_sCommand = VALUE.substr(VALUE.find_first_of(']') + 1);

auto cmdResult = DATA->executeCommand();
DATA->m_vValues = cmdResult.values;
DATA->m_sIsRelative.x = cmdResult.isRelative.x;
DATA->m_sIsRelative.y = cmdResult.isRelative.y;

return result;
}

const auto SPLIT = VALUE.find(',');
if (SPLIT == std::string::npos) {
result.setError(std::format("expected two comma seperated values, got {}", VALUE).c_str());
Expand Down
16 changes: 14 additions & 2 deletions src/renderer/widgets/Label.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ void CLabel::onTimerUpdate() {

label = formatString(labelPreFormat);

try {
const auto LAYOUT = CLayoutValueData::fromAnyPv(props.at("position"));
if (LAYOUT->needsUpdate()) {
const auto OLD_POS = LAYOUT->getAbsolute(viewport);
LAYOUT->update();
if (OLD_POS != LAYOUT->getAbsolute(viewport)) { // redraw:
configPos = LAYOUT->getAbsolute(viewport);
g_pHyprlock->renderOutput(outputStringPort);
}
}
} catch (...) { /* TODO */ }

if (label.formatted == oldFormatted && !label.alwaysUpdate)
return;

Expand All @@ -70,8 +82,8 @@ void CLabel::plantTimer() {
labelTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onTimer, this, true);
}

CLabel::CLabel(const Vector2D& viewport_, const std::unordered_map<std::string, std::any>& props, const std::string& output) :
outputStringPort(output), shadow(this, props, viewport_) {
CLabel::CLabel(const Vector2D& viewport_, const WidgetProps& props_, const std::string& output) :
outputStringPort(output), shadow(this, props_, viewport_), props(props_) {
try {
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
labelPreFormat = std::any_cast<Hyprlang::STRING>(props.at("text"));
Expand Down
5 changes: 4 additions & 1 deletion src/renderer/widgets/Label.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
struct SPreloadedAsset;
class CSessionLockSurface;

using WidgetProps = std::unordered_map<std::string, std::any>;

class CLabel : public IWidget {
public:
CLabel(const Vector2D& viewport, const std::unordered_map<std::string, std::any>& props, const std::string& output);
CLabel(const Vector2D& viewport_, const WidgetProps& props_, const std::string& output);
~CLabel();

virtual bool draw(const SRenderData& data);
Expand Down Expand Up @@ -46,4 +48,5 @@ class CLabel : public IWidget {

CShadowable shadow;
bool updateShadow = true;
WidgetProps props;
};