This commit is contained in:
Zakk
2024-04-05 21:16:13 -04:00
commit b6eef56607
7 changed files with 623 additions and 0 deletions

239
main.cpp Normal file
View File

@@ -0,0 +1,239 @@
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <unistd.h>
#include <any>
#include <ranges>
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/desktop/Window.hpp>
#include <hyprland/src/config/ConfigManager.hpp>
#include "easymotionDeco.hpp"
#include "globals.hpp"
// Do NOT change this function.
APICALL EXPORT std::string PLUGIN_API_VERSION() {
return HYPRLAND_API_VERSION;
}
void easymotionExitDispatch(std::string args)
{
for (auto &ml : g_pGlobalState->motionLabels | std::ranges::views::reverse) {
ml->getOwner()->removeWindowDeco(ml);
}
HyprlandAPI::invokeHyprctlCommand("dispatch", "submap reset");
}
void easymotionActionDispatch(std::string args)
{
for (auto &ml : g_pGlobalState->motionLabels) {
if (ml->m_szLabel == args) {
g_pKeybindManager->m_mDispatchers["exec"](ml->m_szActionCmd);
easymotionExitDispatch("");
break;
}
}
}
void addEasyMotionKeybinds()
{
g_pKeybindManager->addKeybind(SKeybind{"escape", 0, 0, 0, "easymotionexit", "", 0, "__easymotionsubmap__", 0, 0, 0, 0, 0, 0});
//catchall
g_pKeybindManager->addKeybind(SKeybind{"", 0, 1, 0, "", "", 0, "__easymotionsubmap__", 0, 0, 0, 0, 0, 0});
}
void addLabelToWindow(CWindow *window, SMotionActionDesc *actionDesc, std::string &label)
{
std::unique_ptr<CHyprEasyLabel> motionlabel = std::make_unique<CHyprEasyLabel>(window, actionDesc);
motionlabel.get()->m_szLabel = label;
g_pGlobalState->motionLabels.push_back(motionlabel.get());
HyprlandAPI::addWindowDecoration(PHANDLE, window, std::move(motionlabel));
}
static bool parseBorderGradient(std::string VALUE, CGradientValueData *DATA) {
std::string V = VALUE;
CVarList varlist(V, 0, ' ');
DATA->m_vColors.clear();
std::string parseError = "";
for (auto& var : varlist) {
if (var.find("deg") != std::string::npos) {
// last arg
try {
DATA->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (PI / 180.0); // radians
} catch (...) {
Debug::log(WARN, "Error parsing gradient {}", V);
return false;
}
break;
}
if (DATA->m_vColors.size() >= 10) {
Debug::log(WARN, "Error parsing gradient {}: max colors is 10.", V);
return false;
break;
}
try {
DATA->m_vColors.push_back(CColor(configStringToInt(var)));
} catch (std::exception& e) {
Debug::log(WARN, "Error parsing gradient {}", V);
}
}
if (DATA->m_vColors.size() == 0) {
Debug::log(WARN, "Error parsing gradient {}", V);
DATA->m_vColors.push_back(0); // transparent
}
return true;
}
void easymotionDispatch(std::string args)
{
static auto *const TEXTSIZE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:textsize")->getDataStaticPtr();
static auto *const TEXTCOLOR = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:textcolor")->getDataStaticPtr();
static auto *const BGCOLOR = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:bgcolor")->getDataStaticPtr();
static auto *const TEXTFONT = (Hyprlang::STRING const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:textfont")->getDataStaticPtr();
static auto *const TEXTPADDING = (Hyprlang::STRING const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:textpadding")->getDataStaticPtr();
static auto *const BORDERSIZE = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:bordersize")->getDataStaticPtr();
static auto *const BORDERCOLOR = (Hyprlang::STRING const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:bordercolor")->getDataStaticPtr();
static auto *const ROUNDING = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:rounding")->getDataStaticPtr();
static auto *const MOTIONKEYS = (Hyprlang::STRING const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:motionkeys")->getDataStaticPtr();
CVarList emargs(args, 0, ';');
SMotionActionDesc actionDesc;
actionDesc.textSize = **TEXTSIZE;
actionDesc.textColor = **TEXTCOLOR;
actionDesc.backgroundColor = **BGCOLOR;
actionDesc.textFont = *TEXTFONT;
CVarList cpadding = CVarList(*TEXTPADDING);
actionDesc.boxPadding.parseGapData(cpadding);
actionDesc.rounding = **ROUNDING;
actionDesc.borderSize = **BORDERSIZE;
if(!parseBorderGradient(*BORDERCOLOR, &actionDesc.borderColor)) {
actionDesc.borderColor.m_vColors.clear();
actionDesc.borderColor.m_fAngle = 0;
}
actionDesc.motionKeys = *MOTIONKEYS;
for(int i = 0; i < emargs.size(); i++)
{
CVarList kv(emargs[i], 2, ':');
if (kv[0] == "action") {
actionDesc.commandString = kv[1];
} else if (kv[0] == "textsize") {
actionDesc.textSize = configStringToInt(kv[1]);
} else if (kv[0] == "textcolor") {
actionDesc.textColor = CColor(configStringToInt(kv[1]));
} else if (kv[0] == "bgcolor") {
actionDesc.backgroundColor = CColor(configStringToInt(kv[1]));
} else if (kv[0] == "textfont") {
actionDesc.textFont = kv[1];
} else if (kv[0] == "textpadding") {
CVarList padVars = CVarList(kv[1]);
actionDesc.boxPadding.parseGapData(padVars);
} else if (kv[0] == "rounding") {
actionDesc.rounding = configStringToInt(kv[1]);
} else if (kv[0] == "bordersize") {
actionDesc.borderSize = configStringToInt(kv[1]);
} else if (kv[0] == "bordercolor") {
CVarList varlist(kv[1], 0, ' ');
actionDesc.borderColor.m_vColors.clear();
actionDesc.borderColor.m_fAngle = 0;
if(!parseBorderGradient(kv[1], &actionDesc.borderColor)) {
actionDesc.borderColor.m_vColors.clear();
actionDesc.borderColor.m_fAngle = 0;
}
} else if (kv[0] == "motionkeys") {
actionDesc.motionKeys = kv[1];
}
}
int key_idx = 0;
for (auto &w : g_pCompositor->m_vWindows) {
for (auto &m : g_pCompositor->m_vMonitors) {
if (w->m_pWorkspace == m->activeWorkspace) {
std::string lstr = actionDesc.motionKeys.substr(key_idx++, 1);
addLabelToWindow(w.get(), &actionDesc, lstr);
}
}
}
HyprlandAPI::invokeHyprctlCommand("dispatch", "submap __easymotionsubmap__");
}
bool oneasymotionKeypress(void *self, std::any data) {
if (g_pGlobalState->motionLabels.empty()) return false;
auto map = std::any_cast<std::unordered_map<std::string, std::any>>(data);
std::any kany = map["keyboard"];
wlr_keyboard_key_event *ev = std::any_cast<wlr_keyboard_key_event *>(map["event"]);
SKeyboard *keyboard = std::any_cast<SKeyboard *>(kany);
const auto KEYCODE = ev->keycode + 8;
const xkb_keysym_t KEYSYM = xkb_state_key_get_one_sym(keyboard->xkbTranslationState, KEYCODE);
if (ev->state != WL_KEYBOARD_KEY_STATE_PRESSED) return false;
xkb_keysym_t actionKeysym = 0;
for (auto &ml : g_pGlobalState->motionLabels) {
if (ml->m_szLabel != "") {
actionKeysym = xkb_keysym_from_name(ml->m_szLabel.c_str(), XKB_KEYSYM_NO_FLAGS);
if (actionKeysym && (actionKeysym == KEYSYM)) {
easymotionActionDispatch(ml->m_szLabel);
return true;
}
}
}
return false;
}
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
PHANDLE = handle;
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:textsize", Hyprlang::INT{15});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:textcolor", Hyprlang::INT{configStringToInt("rgba(ffffffff)")});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:bgcolor", Hyprlang::INT{configStringToInt("rgba(000000ff)")});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:textfont", Hyprlang::STRING{"Sans"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:textpadding", Hyprlang::STRING{"0"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:bordersize", Hyprlang::INT{0});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:bordercolor", Hyprlang::STRING{"rgba(ffffffff)"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:rounding", Hyprlang::INT{0});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:motionkeys", Hyprlang::STRING{"abcdefghijklmnopqrstuvwxyz1234567890"});
g_pGlobalState = std::make_unique<SGlobalState>();
HyprlandAPI::addDispatcher(PHANDLE, "easymotion", easymotionDispatch);
HyprlandAPI::addDispatcher(PHANDLE, "easymotionaction", easymotionActionDispatch);
HyprlandAPI::addDispatcher(PHANDLE, "easymotionexit", easymotionExitDispatch);
HyprlandAPI::registerCallbackDynamic(PHANDLE, "keyPress", [&](void *self, SCallbackInfo &info, std::any data) {
info.cancelled = oneasymotionKeypress(self, data);
});
HyprlandAPI::registerCallbackDynamic(PHANDLE, "configReloaded", [&](void *self, SCallbackInfo&, std::any data) {addEasyMotionKeybinds();});
HyprlandAPI::reloadConfig();
return {"hypreasymotion", "Easymotion navigation", "Zakk", "1.0"};
}
APICALL EXPORT void PLUGIN_EXIT() {
}