mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-27 09:53:47 -07:00
hyprctl: add getprop (#11394)
This commit is contained in:
@@ -49,6 +49,7 @@ commands:
|
||||
the same format as in colors in config. Will reset
|
||||
when Hyprland's config is reloaded
|
||||
setprop ... → Sets a window property
|
||||
getprop ... → Gets a window property
|
||||
splash → Get the current splash
|
||||
switchxkblayout ... → Sets the xkb layout index for a keyboard
|
||||
systeminfo → Get system info
|
||||
@@ -159,6 +160,18 @@ lock:
|
||||
flags:
|
||||
See 'hyprctl --help')#";
|
||||
|
||||
const std::string_view GETPROP_HELP = R"#(usage: hyprctl [flags] getprop <regex> <property>
|
||||
|
||||
regex:
|
||||
Regular expression by which a window will be searched
|
||||
|
||||
property:
|
||||
See https://wiki.hypr.land/Configuring/Using-hyprctl/#setprop for list
|
||||
of properties
|
||||
|
||||
flags:
|
||||
See 'hyprctl --help')#";
|
||||
|
||||
const std::string_view SWITCHXKBLAYOUT_HELP = R"#(usage: [flags] switchxkblayout <device> <cmd>
|
||||
|
||||
device:
|
||||
|
@@ -427,6 +427,8 @@ int main(int argc, char** argv) {
|
||||
std::println("{}", PLUGIN_HELP);
|
||||
} else if (cmd == "setprop") {
|
||||
std::println("{}", SETPROP_HELP);
|
||||
} else if (cmd == "getprop") {
|
||||
std::println("{}", GETPROP_HELP);
|
||||
} else if (cmd == "switchxkblayout") {
|
||||
std::println("{}", SWITCHXKBLAYOUT_HELP);
|
||||
} else {
|
||||
|
@@ -18,6 +18,131 @@ using namespace Hyprutils::Memory;
|
||||
#define UP CUniquePointer
|
||||
#define SP CSharedPointer
|
||||
|
||||
static std::string getCommandStdOut(std::string command) {
|
||||
CProcess process("bash", {"-c", command});
|
||||
process.addEnv("HYPRLAND_INSTANCE_SIGNATURE", HIS);
|
||||
process.runSync();
|
||||
|
||||
const std::string& stdOut = process.stdOut();
|
||||
|
||||
// Remove trailing new line
|
||||
return stdOut.substr(0, stdOut.length() - 1);
|
||||
}
|
||||
|
||||
static bool testGetprop() {
|
||||
NLog::log("{}Testing hyprctl getprop", Colors::GREEN);
|
||||
if (!Tests::spawnKitty()) {
|
||||
NLog::log("{}Error: kitty did not spawn", Colors::RED);
|
||||
return false;
|
||||
}
|
||||
|
||||
// animationstyle
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty animationstyle"), "(unset)");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty animationstyle -j"), R"({"animationstyle": ""})");
|
||||
getFromSocket("/dispatch setprop class:kitty animationstyle teststyle");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty animationstyle"), "teststyle");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty animationstyle -j"), R"({"animationstyle": "teststyle"})");
|
||||
|
||||
// maxsize
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty maxsize"), "inf inf");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty maxsize -j"), R"({"maxsize": [null,null]})");
|
||||
getFromSocket("/dispatch setprop class:kitty maxsize 200 150");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty maxsize"), "200 150");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty maxsize -j"), R"({"maxsize": [200,150]})");
|
||||
|
||||
// minsize
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty minsize"), "20 20");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty minsize -j"), R"({"minsize": [20,20]})");
|
||||
getFromSocket("/dispatch setprop class:kitty minsize 100 50");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty minsize"), "100 50");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty minsize -j"), R"({"minsize": [100,50]})");
|
||||
|
||||
// alpha
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alpha"), "1");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alpha -j"), R"({"alpha": 1})");
|
||||
getFromSocket("/dispatch setprop class:kitty alpha 0.3");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alpha"), "0.3");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alpha -j"), R"({"alpha": 0.3})");
|
||||
|
||||
// alphainactive
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactive"), "1");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactive -j"), R"({"alphainactive": 1})");
|
||||
getFromSocket("/dispatch setprop class:kitty alphainactive 0.5");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactive"), "0.5");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactive -j"), R"({"alphainactive": 0.5})");
|
||||
|
||||
// alphafullscreen
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreen"), "1");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreen -j"), R"({"alphafullscreen": 1})");
|
||||
getFromSocket("/dispatch setprop class:kitty alphafullscreen 0.75");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreen"), "0.75");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreen -j"), R"({"alphafullscreen": 0.75})");
|
||||
|
||||
// alphaoverride
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphaoverride"), "false");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphaoverride -j"), R"({"alphaoverride": false})");
|
||||
getFromSocket("/dispatch setprop class:kitty alphaoverride true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphaoverride"), "true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphaoverride -j"), R"({"alphaoverride": true})");
|
||||
|
||||
// alphainactiveoverride
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactiveoverride"), "false");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactiveoverride -j"), R"({"alphainactiveoverride": false})");
|
||||
getFromSocket("/dispatch setprop class:kitty alphainactiveoverride true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactiveoverride"), "true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphainactiveoverride -j"), R"({"alphainactiveoverride": true})");
|
||||
|
||||
// alphafullscreenoverride
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreenoverride"), "false");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreenoverride -j"), R"({"alphafullscreenoverride": false})");
|
||||
getFromSocket("/dispatch setprop class:kitty alphafullscreenoverride true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreenoverride"), "true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty alphafullscreenoverride -j"), R"({"alphafullscreenoverride": true})");
|
||||
|
||||
// activebordercolor
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty activebordercolor"), "ee33ccff ee00ff99 45deg");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty activebordercolor -j"), R"({"activebordercolor": "ee33ccff ee00ff99 45deg"})");
|
||||
getFromSocket("/dispatch setprop class:kitty activebordercolor rgb(abcdef)");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty activebordercolor"), "ffabcdef 0deg");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty activebordercolor -j"), R"({"activebordercolor": "ffabcdef 0deg"})");
|
||||
|
||||
// bool window properties
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty allowsinput"), "false");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty allowsinput -j"), R"({"allowsinput": false})");
|
||||
getFromSocket("/dispatch setprop class:kitty allowsinput true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty allowsinput"), "true");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty allowsinput -j"), R"({"allowsinput": true})");
|
||||
|
||||
// int window properties
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding"), "10");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding -j"), R"({"rounding": 10})");
|
||||
getFromSocket("/dispatch setprop class:kitty rounding 4");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding"), "4");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding -j"), R"({"rounding": 4})");
|
||||
|
||||
// float window properties
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty roundingpower"), "2");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty roundingpower -j"), R"({"roundingpower": 2})");
|
||||
getFromSocket("/dispatch setprop class:kitty roundingpower 1.25");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty roundingpower"), "1.25");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty roundingpower -j"), R"({"roundingpower": 1.25})");
|
||||
|
||||
// errors
|
||||
EXPECT(getCommandStdOut("hyprctl getprop"), "not enough args");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty"), "not enough args");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:nonexistantclass animationstyle"), "window not found");
|
||||
EXPECT(getCommandStdOut("hyprctl getprop class:kitty nonexistantprop"), "prop not found");
|
||||
|
||||
// kill all
|
||||
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||
Tests::killAllWindows();
|
||||
|
||||
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
|
||||
EXPECT(Tests::windowCount(), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test() {
|
||||
NLog::log("{}Testing hyprctl", Colors::GREEN);
|
||||
|
||||
@@ -29,6 +154,9 @@ static bool test() {
|
||||
EXPECT(jqProc.exitCode(), 0);
|
||||
}
|
||||
|
||||
if (!testGetprop())
|
||||
return false;
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
|
@@ -1399,6 +1399,134 @@ static std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string requ
|
||||
return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error);
|
||||
}
|
||||
|
||||
static std::string dispatchGetProp(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
if (vars.size() < 3)
|
||||
return "not enough args";
|
||||
|
||||
const auto WINREGEX = vars[1];
|
||||
const auto PROP = vars[2];
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getWindowByRegex(WINREGEX);
|
||||
|
||||
if (!PWINDOW)
|
||||
return "window not found";
|
||||
|
||||
const bool FORMNORM = format == FORMAT_NORMAL;
|
||||
|
||||
auto sizeToString = [&](bool max) -> std::string {
|
||||
auto sizeValue = PWINDOW->m_windowData.minSize.valueOr(Vector2D(MIN_WINDOW_SIZE, MIN_WINDOW_SIZE));
|
||||
if (max)
|
||||
sizeValue = PWINDOW->m_windowData.maxSize.valueOr(Vector2D(INFINITY, INFINITY));
|
||||
|
||||
if (FORMNORM)
|
||||
return std::format("{} {}", sizeValue.x, sizeValue.y);
|
||||
else {
|
||||
std::string xSizeString = (sizeValue.x != INFINITY) ? std::to_string(sizeValue.x) : "null";
|
||||
std::string ySizeString = (sizeValue.y != INFINITY) ? std::to_string(sizeValue.y) : "null";
|
||||
return std::format(R"({{"{}": [{},{}]}})", PROP, xSizeString, ySizeString);
|
||||
}
|
||||
};
|
||||
|
||||
auto alphaToString = [&](CWindowOverridableVar<SAlphaValue>& alpha, bool getAlpha) -> std::string {
|
||||
if (FORMNORM) {
|
||||
if (getAlpha)
|
||||
return std::format("{}", alpha.valueOrDefault().alpha);
|
||||
else
|
||||
return std::format("{}", alpha.valueOrDefault().overridden);
|
||||
} else {
|
||||
if (getAlpha)
|
||||
return std::format(R"({{"{}": {}}})", PROP, alpha.valueOrDefault().alpha);
|
||||
else
|
||||
return std::format(R"({{"{}": {}}})", PROP, alpha.valueOrDefault().overridden);
|
||||
}
|
||||
};
|
||||
|
||||
auto borderColorToString = [&](bool active) -> std::string {
|
||||
static auto PACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.active_border");
|
||||
static auto PINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.inactive_border");
|
||||
static auto PNOGROUPACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.nogroup_border_active");
|
||||
static auto PNOGROUPINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.nogroup_border");
|
||||
static auto PGROUPACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_active");
|
||||
static auto PGROUPINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_inactive");
|
||||
static auto PGROUPACTIVELOCKEDCOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_locked_active");
|
||||
static auto PGROUPINACTIVELOCKEDCOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_locked_inactive");
|
||||
|
||||
const bool GROUPLOCKED = PWINDOW->m_groupData.pNextWindow.lock() ? PWINDOW->getGroupHead()->m_groupData.locked : false;
|
||||
|
||||
if (active) {
|
||||
auto* const ACTIVECOL = (CGradientValueData*)(PACTIVECOL.ptr())->getData();
|
||||
auto* const NOGROUPACTIVECOL = (CGradientValueData*)(PNOGROUPACTIVECOL.ptr())->getData();
|
||||
auto* const GROUPACTIVECOL = (CGradientValueData*)(PGROUPACTIVECOL.ptr())->getData();
|
||||
auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)(PGROUPACTIVELOCKEDCOL.ptr())->getData();
|
||||
const auto* const ACTIVECOLOR =
|
||||
!PWINDOW->m_groupData.pNextWindow.lock() ? (!PWINDOW->m_groupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
|
||||
|
||||
std::string borderColorString = PWINDOW->m_windowData.activeBorderColor.valueOr(*ACTIVECOLOR).toString();
|
||||
if (FORMNORM)
|
||||
return borderColorString;
|
||||
else
|
||||
return std::format(R"({{"{}": "{}"}})", PROP, borderColorString);
|
||||
} else {
|
||||
auto* const INACTIVECOL = (CGradientValueData*)(PINACTIVECOL.ptr())->getData();
|
||||
auto* const NOGROUPINACTIVECOL = (CGradientValueData*)(PNOGROUPINACTIVECOL.ptr())->getData();
|
||||
auto* const GROUPINACTIVECOL = (CGradientValueData*)(PGROUPINACTIVECOL.ptr())->getData();
|
||||
auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)(PGROUPINACTIVELOCKEDCOL.ptr())->getData();
|
||||
const auto* const INACTIVECOLOR = !PWINDOW->m_groupData.pNextWindow.lock() ? (!PWINDOW->m_groupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) :
|
||||
(GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
|
||||
|
||||
std::string borderColorString = PWINDOW->m_windowData.inactiveBorderColor.valueOr(*INACTIVECOLOR).toString();
|
||||
if (FORMNORM)
|
||||
return borderColorString;
|
||||
else
|
||||
return std::format(R"({{"{}": "{}"}})", PROP, borderColorString);
|
||||
}
|
||||
};
|
||||
|
||||
auto windowPropToString = [&](auto& prop) -> std::string {
|
||||
if (FORMNORM)
|
||||
return std::format("{}", prop.valueOrDefault());
|
||||
else
|
||||
return std::format(R"({{"{}": {}}})", PROP, prop.valueOrDefault());
|
||||
};
|
||||
|
||||
if (PROP == "animationstyle") {
|
||||
auto& animationStyle = PWINDOW->m_windowData.animationStyle;
|
||||
if (FORMNORM)
|
||||
return animationStyle.valueOr("(unset)");
|
||||
else
|
||||
return std::format(R"({{"{}": "{}"}})", PROP, animationStyle.valueOr(""));
|
||||
} else if (PROP == "maxsize")
|
||||
return sizeToString(true);
|
||||
else if (PROP == "minsize")
|
||||
return sizeToString(false);
|
||||
else if (PROP == "alpha")
|
||||
return alphaToString(PWINDOW->m_windowData.alpha, true);
|
||||
else if (PROP == "alphainactive")
|
||||
return alphaToString(PWINDOW->m_windowData.alphaInactive, true);
|
||||
else if (PROP == "alphafullscreen")
|
||||
return alphaToString(PWINDOW->m_windowData.alphaFullscreen, true);
|
||||
else if (PROP == "alphaoverride")
|
||||
return alphaToString(PWINDOW->m_windowData.alpha, false);
|
||||
else if (PROP == "alphainactiveoverride")
|
||||
return alphaToString(PWINDOW->m_windowData.alphaInactive, false);
|
||||
else if (PROP == "alphafullscreenoverride")
|
||||
return alphaToString(PWINDOW->m_windowData.alphaFullscreen, false);
|
||||
else if (PROP == "activebordercolor")
|
||||
return borderColorToString(true);
|
||||
else if (PROP == "inactivebordercolor")
|
||||
return borderColorToString(false);
|
||||
else if (auto search = NWindowProperties::boolWindowProperties.find(PROP); search != NWindowProperties::boolWindowProperties.end())
|
||||
return windowPropToString(*search->second(PWINDOW));
|
||||
else if (auto search = NWindowProperties::intWindowProperties.find(PROP); search != NWindowProperties::intWindowProperties.end())
|
||||
return windowPropToString(*search->second(PWINDOW));
|
||||
else if (auto search = NWindowProperties::floatWindowProperties.find(PROP); search != NWindowProperties::floatWindowProperties.end())
|
||||
return windowPropToString(*search->second(PWINDOW));
|
||||
|
||||
return "prop not found";
|
||||
}
|
||||
|
||||
static std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string curitem = "";
|
||||
|
||||
@@ -1760,6 +1888,7 @@ CHyprCtl::CHyprCtl() {
|
||||
registerCommand(SHyprCtlCommand{"notify", false, dispatchNotify});
|
||||
registerCommand(SHyprCtlCommand{"dismissnotify", false, dispatchDismissNotify});
|
||||
registerCommand(SHyprCtlCommand{"setprop", false, dispatchSetProp});
|
||||
registerCommand(SHyprCtlCommand{"getprop", false, dispatchGetProp});
|
||||
registerCommand(SHyprCtlCommand{"seterror", false, dispatchSeterror});
|
||||
registerCommand(SHyprCtlCommand{"switchxkblayout", false, switchXKBLayoutRequest});
|
||||
registerCommand(SHyprCtlCommand{"output", false, dispatchOutput});
|
||||
|
Reference in New Issue
Block a user