mirror of
https://github.com/virtcode/hypr-dynamic-cursors
synced 2025-09-19 16:13:21 +02:00
feat: implemented shaperules
This commit is contained in:
parent
f2793f3bd3
commit
9fd1b6a1c2
13 changed files with 448 additions and 95 deletions
118
src/config/ShapeRule.cpp
Normal file
118
src/config/ShapeRule.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include "ShapeRule.hpp"
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
void CShapeRuleHandler::clear() {
|
||||
rules.clear();
|
||||
active = nullptr;
|
||||
}
|
||||
|
||||
void CShapeRuleHandler::activate(std::string key) {
|
||||
if (rules.contains(key))
|
||||
active = &rules[key];
|
||||
else
|
||||
active = nullptr;
|
||||
}
|
||||
|
||||
void CShapeRuleHandler::addProperty(std::string key, EShapeRuleType type) {
|
||||
content[key] = type;
|
||||
}
|
||||
|
||||
std::variant<std::string, float, int> parse(std::string value, EShapeRuleType type) {
|
||||
switch (type) {
|
||||
case EShapeRuleType::STRING:
|
||||
return value;
|
||||
case EShapeRuleType::FLOAT:
|
||||
return std::stof(value);
|
||||
case EShapeRuleType::INT:
|
||||
return std::stoi(value);
|
||||
}
|
||||
|
||||
throw std::logic_error("unknown type");
|
||||
}
|
||||
|
||||
void CShapeRuleHandler::parseRule(std::string string) {
|
||||
std::optional<std::string> name;
|
||||
SShapeRule rule;
|
||||
|
||||
CVarList list = CVarList(string);
|
||||
|
||||
for (auto arg : list) {
|
||||
if (!name.has_value()) name = arg;
|
||||
else {
|
||||
auto pos = arg.rfind(':');
|
||||
|
||||
// mode value
|
||||
if (pos == std::string::npos) {
|
||||
if (rule.mode.has_value())
|
||||
throw std::logic_error("cannot specify mode twice");
|
||||
|
||||
rule.mode = arg;
|
||||
|
||||
// settings value
|
||||
} else {
|
||||
auto key = arg.substr(0, pos);
|
||||
auto value = arg.substr(pos + 1);
|
||||
|
||||
if (rule.content.contains(key))
|
||||
throw std::logic_error("cannot specify property " + key + " twice");
|
||||
|
||||
if (!content.contains(key))
|
||||
throw std::logic_error("unkown property " + key);
|
||||
|
||||
auto type = content[key];
|
||||
|
||||
try {
|
||||
rule.content[key] = parse(value, type);
|
||||
} catch (...) {
|
||||
throw std::logic_error("invalid type for property " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!name.has_value())
|
||||
throw std::logic_error("need to specify at least shape name");
|
||||
|
||||
if (rules.contains(name.value()))
|
||||
throw std::logic_error("cannot have two rules for shape " + name.value());
|
||||
|
||||
rules[name.value()] = rule;
|
||||
}
|
||||
|
||||
Hyprlang::CParseResult onShapeRuleKeyword(const char* COMMAND, const char* VALUE) {
|
||||
Hyprlang::CParseResult res;
|
||||
|
||||
try {
|
||||
g_pShapeRuleHandler->parseRule(std::string{VALUE});
|
||||
} catch (const std::exception& ex) {
|
||||
res.setError(ex.what());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string CShapeRuleHandler::getModeOr(std::string def) {
|
||||
if (active) return active->mode.value_or(def);
|
||||
else return def;
|
||||
}
|
||||
|
||||
std::string CShapeRuleHandler::getStringOr(std::string key, std::string def) {
|
||||
if (active && active->content.contains(key)) return std::get<std::string>(active->content[key]);
|
||||
else return def;
|
||||
}
|
||||
|
||||
int CShapeRuleHandler::getIntOr(std::string key, int def) {
|
||||
if (active && active->content.contains(key)) return std::get<int>(active->content[key]);
|
||||
else return def;
|
||||
}
|
||||
|
||||
float CShapeRuleHandler::getFloatOr(std::string key, float def) {
|
||||
if (active && active->content.contains(key)) return std::get<float>(active->content[key]);
|
||||
else return def;
|
||||
}
|
52
src/config/ShapeRule.hpp
Normal file
52
src/config/ShapeRule.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
#include <hyprlang.hpp>
|
||||
|
||||
/* stores possible types in a shape rule */
|
||||
enum EShapeRuleType {
|
||||
STRING,
|
||||
FLOAT,
|
||||
INT
|
||||
};
|
||||
|
||||
struct SShapeRule {
|
||||
std::optional<std::string> mode;
|
||||
std::unordered_map<std::string, std::variant<std::string, float, int>> content;
|
||||
};
|
||||
|
||||
class CShapeRuleHandler {
|
||||
/* induvidual rule content */
|
||||
std::unordered_map<std::string, EShapeRuleType> content;
|
||||
|
||||
/* possible rules */
|
||||
std::unordered_map<std::string, SShapeRule> rules;
|
||||
|
||||
/* currently active rule, nullptr if none */
|
||||
SShapeRule* active = nullptr;
|
||||
|
||||
public:
|
||||
/* adds a valid shape rule property */
|
||||
void addProperty(std::string key, EShapeRuleType type);
|
||||
|
||||
/* removes currently added shape rules */
|
||||
void clear();
|
||||
/* adds a new shape rule from string */
|
||||
void parseRule(std::string string);
|
||||
|
||||
/* activates the shape rule for the given shape */
|
||||
void activate(std::string name);
|
||||
|
||||
std::string getModeOr(std::string def);
|
||||
std::string getStringOr(std::string key, std::string def);
|
||||
int getIntOr(std::string key, int def);
|
||||
float getFloatOr(std::string key, float def);
|
||||
};
|
||||
|
||||
/* method called by hyprland api */
|
||||
Hyprlang::CParseResult onShapeRuleKeyword(const char* COMMAND, const char* VALUE);
|
||||
|
||||
inline std::unique_ptr<CShapeRuleHandler> g_pShapeRuleHandler;
|
65
src/config/config.cpp
Normal file
65
src/config/config.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include "../globals.hpp"
|
||||
#include "config.hpp"
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
#include <hyprlang.hpp>
|
||||
#include <stdexcept>
|
||||
#include <variant>
|
||||
|
||||
Hyprlang::CConfigValue toHyprlang(std::variant<std::string, float, int> value) {
|
||||
|
||||
if (std::holds_alternative<std::string>(value))
|
||||
return Hyprlang::STRING { std::get<std::string>(value).c_str() };
|
||||
|
||||
if (std::holds_alternative<float>(value))
|
||||
return Hyprlang::FLOAT { std::get<float>(value) };
|
||||
|
||||
if (std::holds_alternative<int>(value))
|
||||
return Hyprlang::INT { std::get<int>(value) };
|
||||
|
||||
throw new std::logic_error("invalid type in variant?!");
|
||||
}
|
||||
|
||||
EShapeRuleType toShapeRule(std::variant<std::string, float, int> value) {
|
||||
|
||||
if (std::holds_alternative<std::string>(value))
|
||||
return EShapeRuleType::STRING;
|
||||
|
||||
if (std::holds_alternative<float>(value))
|
||||
return EShapeRuleType::FLOAT;
|
||||
|
||||
if (std::holds_alternative<int>(value))
|
||||
return EShapeRuleType::INT;
|
||||
|
||||
throw new std::logic_error("invalid type in variant?!");
|
||||
}
|
||||
|
||||
void startConfig() {
|
||||
g_pShapeRuleHandler = std::make_unique<CShapeRuleHandler>();
|
||||
}
|
||||
|
||||
void addConfig(std::string name, std::variant<std::string, float, int> value) {
|
||||
HyprlandAPI::addConfigValue(PHANDLE, NAMESPACE + name, toHyprlang(value));
|
||||
}
|
||||
|
||||
void addShapeConfig(std::string name, std::variant<std::string, float, int> value) {
|
||||
addConfig(name, value);
|
||||
|
||||
g_pShapeRuleHandler->addProperty(name, toShapeRule(value));
|
||||
}
|
||||
|
||||
void* const* getConfig(std::string name) {
|
||||
return HyprlandAPI::getConfigValue(PHANDLE, NAMESPACE + name)->getDataStaticPtr();
|
||||
}
|
||||
|
||||
void addRulesConfig() {
|
||||
HyprlandAPI::addConfigKeyword(PHANDLE, CONFIG_SHAPERULE, onShapeRuleKeyword, Hyprlang::SHandlerOptions {});
|
||||
|
||||
// clear on reload
|
||||
static const auto PCALLBACK = HyprlandAPI::registerCallbackDynamic( PHANDLE, "preConfigReload", [&](void* self, SCallbackInfo&, std::any data) {
|
||||
g_pShapeRuleHandler->clear();
|
||||
});
|
||||
}
|
||||
|
||||
void finishConfig() {
|
||||
HyprlandAPI::reloadConfig();
|
||||
}
|
46
src/config/config.hpp
Normal file
46
src/config/config.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <hyprlang.hpp>
|
||||
#include "ShapeRule.hpp"
|
||||
|
||||
#define NAMESPACE "plugin:dynamic-cursors:"
|
||||
|
||||
#define CONFIG_ENABLED "enabled"
|
||||
#define CONFIG_MODE "mode"
|
||||
#define CONFIG_THRESHOLD "threshold"
|
||||
#define CONFIG_HW_DEBUG "hw_debug"
|
||||
|
||||
#define CONFIG_SHAKE "shake:enabled"
|
||||
#define CONFIG_SHAKE_NEAREST "shake:nearest"
|
||||
#define CONFIG_SHAKE_THRESHOLD "shake:threshold"
|
||||
#define CONFIG_SHAKE_FACTOR "shake:factor"
|
||||
#define CONFIG_SHAKE_EFFECTS "shake:effects"
|
||||
#define CONFIG_SHAKE_IPC "shake:ipc"
|
||||
|
||||
#define CONFIG_ROTATE_LENGTH "rotate:length"
|
||||
#define CONFIG_ROTATE_OFFSET "rotate:offset"
|
||||
|
||||
#define CONFIG_TILT_LIMIT "tilt:limit"
|
||||
#define CONFIG_TILT_FUNCTION "tilt:function"
|
||||
|
||||
#define CONFIG_STRETCH_LIMIT "stretch:limit"
|
||||
#define CONFIG_STRETCH_FUNCTION "stretch:function"
|
||||
|
||||
#define CONFIG_SHAPERULE "shaperule"
|
||||
|
||||
/* initializes stuff so config can be set up */
|
||||
void startConfig();
|
||||
/* finishes config setup */
|
||||
void finishConfig();
|
||||
|
||||
/* add shaperule config entry */
|
||||
void addRulesConfig();
|
||||
|
||||
/* will add an ordinary config value */
|
||||
void addConfig(std::string name, std::variant<std::string, float, int> value);
|
||||
|
||||
/* will add a config variable which is also a property for shape rules */
|
||||
void addShapeConfig(std::string name, std::variant<std::string, float, int> value);
|
||||
|
||||
/* get static pointer to config value */
|
||||
void* const* getConfig(std::string name);
|
|
@ -1,4 +1,4 @@
|
|||
#include "globals.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "mode/Mode.hpp"
|
||||
#include "src/debug/Log.hpp"
|
||||
#include "src/managers/eventLoop/EventLoopManager.hpp"
|
||||
|
@ -25,7 +25,7 @@
|
|||
#include "renderer.hpp"
|
||||
|
||||
void tickRaw(SP<CEventLoopTimer> self, void* data) {
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*) getConfig(CONFIG_ENABLED);
|
||||
|
||||
if (**PENABLED && g_pDynamicCursors)
|
||||
g_pDynamicCursors->onTick(g_pPointerManager.get());
|
||||
|
@ -56,7 +56,7 @@ Reimplements rendering of the software cursor.
|
|||
Is also largely identical to hyprlands impl, but uses our custom rendering to rotate the cursor.
|
||||
*/
|
||||
void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST);
|
||||
|
||||
if (!pointers->hasCursor())
|
||||
return;
|
||||
|
@ -125,8 +125,8 @@ This function reimplements the hardware cursor buffer drawing.
|
|||
It is largely copied from hyprland, but adjusted to allow the cursor to be rotated.
|
||||
*/
|
||||
wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
|
||||
static auto* const* PHW_DEBUG= (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_HW_DEBUG)->getDataStaticPtr();
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
|
||||
static auto* const* PHW_DEBUG= (Hyprlang::INT* const*) getConfig(CONFIG_HW_DEBUG);
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST);
|
||||
|
||||
auto output = state->monitor->output;
|
||||
auto zoom = resultShown.scale;
|
||||
|
@ -261,6 +261,14 @@ void CDynamicCursors::onCursorMoved(CPointerManager* pointers) {
|
|||
calculate(MOVE);
|
||||
}
|
||||
|
||||
void CDynamicCursors::setShape(const std::string& shape) {
|
||||
g_pShapeRuleHandler->activate(shape);
|
||||
}
|
||||
|
||||
void CDynamicCursors::unsetShape() {
|
||||
g_pShapeRuleHandler->activate("clientside");
|
||||
}
|
||||
|
||||
/*
|
||||
Handle cursor tick events.
|
||||
*/
|
||||
|
@ -269,18 +277,19 @@ void CDynamicCursors::onTick(CPointerManager* pointers) {
|
|||
}
|
||||
|
||||
IMode* CDynamicCursors::currentMode() {
|
||||
static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr();
|
||||
static auto const* PMODE = (Hyprlang::STRING const*) getConfig(CONFIG_MODE);
|
||||
auto mode = g_pShapeRuleHandler->getModeOr(*PMODE);
|
||||
|
||||
if (!strcmp(*PMODE, "rotate")) return &rotate;
|
||||
else if (!strcmp(*PMODE, "tilt")) return &tilt;
|
||||
else if (!strcmp(*PMODE, "stretch")) return &stretch;
|
||||
if (mode == "rotate") return &rotate;
|
||||
else if (mode == "tilt") return &tilt;
|
||||
else if (mode == "stretch") return &stretch;
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
void CDynamicCursors::calculate(EModeUpdate type) {
|
||||
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_THRESHOLD)->getDataStaticPtr();
|
||||
static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr();
|
||||
static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS)->getDataStaticPtr();
|
||||
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*) getConfig(CONFIG_THRESHOLD);
|
||||
static auto* const* PSHAKE = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE);
|
||||
static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_EFFECTS);
|
||||
|
||||
IMode* mode = currentMode();
|
||||
|
||||
|
@ -322,12 +331,24 @@ void CDynamicCursors::calculate(EModeUpdate type) {
|
|||
// damage software and change hardware cursor shape
|
||||
g_pPointerManager->damageIfSoftware();
|
||||
|
||||
bool entered = false;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
auto state = g_pPointerManager->stateFor(m);
|
||||
|
||||
if (state->entered) entered = true;
|
||||
if (state->hardwareFailed || !state->entered)
|
||||
continue;
|
||||
|
||||
g_pPointerManager->attemptHardwareCursor(state);
|
||||
}
|
||||
|
||||
// there should always be one monitor entered
|
||||
// this fixes an issue wheter the cursor shape would not properly update after change
|
||||
if (!entered) {
|
||||
Debug::log(LOG, "[dynamic-cursors] updating because none entered");
|
||||
g_pPointerManager->recheckEnteredOutputs();
|
||||
g_pPointerManager->updateCursorBackend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,11 @@ class CDynamicCursors {
|
|||
/* hook on setHWCursorBuffer */
|
||||
bool setHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, wlr_buffer* buf);
|
||||
|
||||
/* hook on setCursorFromName */
|
||||
void setShape(const std::string& name);
|
||||
/* hook on setCursorSoftware */
|
||||
void unsetShape();
|
||||
|
||||
private:
|
||||
SP<CEventLoopTimer> tick;
|
||||
|
||||
|
|
|
@ -2,25 +2,4 @@
|
|||
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
|
||||
#define CONFIG_ENABLED "plugin:dynamic-cursors:enabled"
|
||||
#define CONFIG_MODE "plugin:dynamic-cursors:mode"
|
||||
#define CONFIG_THRESHOLD "plugin:dynamic-cursors:threshold"
|
||||
#define CONFIG_HW_DEBUG "plugin:dynamic-cursors:hw_debug"
|
||||
|
||||
#define CONFIG_SHAKE "plugin:dynamic-cursors:shake:enabled"
|
||||
#define CONFIG_SHAKE_NEAREST "plugin:dynamic-cursors:shake:nearest"
|
||||
#define CONFIG_SHAKE_THRESHOLD "plugin:dynamic-cursors:shake:threshold"
|
||||
#define CONFIG_SHAKE_FACTOR "plugin:dynamic-cursors:shake:factor"
|
||||
#define CONFIG_SHAKE_EFFECTS "plugin:dynamic-cursors:shake:effects"
|
||||
#define CONFIG_SHAKE_IPC "plugin:dynamic-cursors:shake:ipc"
|
||||
|
||||
#define CONFIG_ROTATE_LENGTH "plugin:dynamic-cursors:rotate:length"
|
||||
#define CONFIG_ROTATE_OFFSET "plugin:dynamic-cursors:rotate:offset"
|
||||
|
||||
#define CONFIG_TILT_LIMIT "plugin:dynamic-cursors:tilt:limit"
|
||||
#define CONFIG_TILT_FUNCTION "plugin:dynamic-cursors:tilt:function"
|
||||
|
||||
#define CONFIG_STRETCH_LIMIT "plugin:dynamic-cursors:stretch:limit"
|
||||
#define CONFIG_STRETCH_FUNCTION "plugin:dynamic-cursors:stretch:function"
|
||||
|
||||
inline HANDLE PHANDLE = nullptr;
|
||||
|
|
109
src/main.cpp
109
src/main.cpp
|
@ -8,65 +8,82 @@
|
|||
|
||||
#include "globals.hpp"
|
||||
#include "cursor.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "src/debug/Log.hpp"
|
||||
#include "src/managers/PointerManager.hpp"
|
||||
|
||||
bool isEnabled() {
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*) getConfig(CONFIG_ENABLED);
|
||||
return **PENABLED;
|
||||
}
|
||||
|
||||
typedef void (*origRenderSofwareCursorsFor)(void*, SP<CMonitor>, timespec*, CRegion&, std::optional<Vector2D>);
|
||||
inline CFunctionHook* g_pRenderSoftwareCursorsForHook = nullptr;
|
||||
void hkRenderSoftwareCursorsFor(void* thisptr, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
||||
|
||||
if (**PENABLED) g_pDynamicCursors->renderSoftware((CPointerManager*) thisptr, pMonitor, now, damage, overridePos);
|
||||
if (isEnabled()) g_pDynamicCursors->renderSoftware((CPointerManager*) thisptr, pMonitor, now, damage, overridePos);
|
||||
else (*(origRenderSofwareCursorsFor)g_pRenderSoftwareCursorsForHook->m_pOriginal)(thisptr, pMonitor, now, damage, overridePos);
|
||||
}
|
||||
|
||||
typedef void (*origDamageIfSoftware)(void*);
|
||||
inline CFunctionHook* g_pDamageIfSoftwareHook = nullptr;
|
||||
void hkDamageIfSoftware(void* thisptr) {
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
||||
|
||||
if (**PENABLED) g_pDynamicCursors->damageSoftware((CPointerManager*) thisptr);
|
||||
if (isEnabled()) g_pDynamicCursors->damageSoftware((CPointerManager*) thisptr);
|
||||
else (*(origDamageIfSoftware)g_pDamageIfSoftwareHook->m_pOriginal)(thisptr);
|
||||
}
|
||||
|
||||
typedef wlr_buffer* (*origRenderHWCursorBuffer)(void*, SP<CPointerManager::SMonitorPointerState>, SP<CTexture>);
|
||||
inline CFunctionHook* g_pRenderHWCursorBufferHook = nullptr;
|
||||
wlr_buffer* hkRenderHWCursorBuffer(void* thisptr, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
||||
|
||||
if (**PENABLED) return g_pDynamicCursors->renderHardware((CPointerManager*) thisptr, state, texture);
|
||||
if (isEnabled()) return g_pDynamicCursors->renderHardware((CPointerManager*) thisptr, state, texture);
|
||||
else return (*(origRenderHWCursorBuffer)g_pRenderHWCursorBufferHook->m_pOriginal)(thisptr, state, texture);
|
||||
}
|
||||
|
||||
typedef bool (*origSetHWCursorBuffer)(void*, SP<CPointerManager::SMonitorPointerState>, wlr_buffer*);
|
||||
inline CFunctionHook* g_pSetHWCursorBufferHook = nullptr;
|
||||
bool hkSetHWCursorBuffer(void* thisptr, SP<CPointerManager::SMonitorPointerState> state, wlr_buffer* buffer) {
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
||||
|
||||
if (**PENABLED) return g_pDynamicCursors->setHardware((CPointerManager*) thisptr, state, buffer);
|
||||
if (isEnabled()) return g_pDynamicCursors->setHardware((CPointerManager*) thisptr, state, buffer);
|
||||
else return (*(origSetHWCursorBuffer)g_pSetHWCursorBufferHook->m_pOriginal)(thisptr, state, buffer);
|
||||
}
|
||||
|
||||
typedef void (*origOnCursorMoved)(void*);
|
||||
inline CFunctionHook* g_pOnCursorMovedHook = nullptr;
|
||||
void hkOnCursorMoved(void* thisptr) {
|
||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
||||
|
||||
if (**PENABLED) return g_pDynamicCursors->onCursorMoved((CPointerManager*) thisptr);
|
||||
if (isEnabled()) return g_pDynamicCursors->onCursorMoved((CPointerManager*) thisptr);
|
||||
else return (*(origOnCursorMoved)g_pOnCursorMovedHook->m_pOriginal)(thisptr);
|
||||
}
|
||||
|
||||
typedef void (*origSetCusorFromName)(void*, const std::string& name);
|
||||
inline CFunctionHook* g_pSetCursorFromNameHook = nullptr;
|
||||
void hkSetCursorFromName(void* thisptr, const std::string& name) {
|
||||
if (isEnabled()) g_pDynamicCursors->setShape(name);
|
||||
(*(origSetCusorFromName)g_pSetCursorFromNameHook->m_pOriginal)(thisptr, name);
|
||||
}
|
||||
|
||||
typedef void (*origSetCursorSurface)(void*, SP<CWLSurface>, const Vector2D&);
|
||||
inline CFunctionHook* g_pSetCursorSurfaceHook = nullptr;
|
||||
void hkSetCursorSurface(void* thisptr, SP<CWLSurface> surf, const Vector2D& hotspot) {
|
||||
if (isEnabled()) g_pDynamicCursors->unsetShape();
|
||||
(*(origSetCursorSurface)g_pSetCursorSurfaceHook->m_pOriginal)(thisptr, surf, hotspot);
|
||||
}
|
||||
|
||||
/* hooks a function hook */
|
||||
CFunctionHook* hook(std::string name, void* function) {
|
||||
CFunctionHook* hook(std::string name, std::string object, void* function) {
|
||||
auto names = HyprlandAPI::findFunctionsByName(PHANDLE, name);
|
||||
auto match = names.at(0);
|
||||
|
||||
Debug::log(LOG, "[dynamic-cursors] hooking on {} for {}", match.signature, name);
|
||||
// we hook on member functions, so search for them
|
||||
for (auto match : names) {
|
||||
if (!match.demangled.starts_with(object)) continue;
|
||||
|
||||
auto hook = HyprlandAPI::createFunctionHook(PHANDLE, match.address, function);
|
||||
hook->hook();
|
||||
Debug::log(LOG, "[dynamic-cursors] hooking on {} for {}::{}", match.demangled, object, name);
|
||||
|
||||
return hook;
|
||||
auto hook = HyprlandAPI::createFunctionHook(PHANDLE, match.address, function);
|
||||
hook->hook();
|
||||
|
||||
return hook;
|
||||
}
|
||||
|
||||
Debug::log(ERR, "Could not find hooking candidate for {}::{}", object, name);
|
||||
throw std::runtime_error("no hook candidate found");
|
||||
}
|
||||
|
||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||
|
@ -80,40 +97,46 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
}
|
||||
|
||||
// setup config
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_ENABLED, Hyprlang::INT{1});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MODE, Hyprlang::STRING{"tilt"});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_THRESHOLD, Hyprlang::INT{2});
|
||||
startConfig();
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE, Hyprlang::INT{1});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST, Hyprlang::INT{1});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS, Hyprlang::INT{0});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_IPC, Hyprlang::INT{0});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_THRESHOLD, Hyprlang::FLOAT{4});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_FACTOR, Hyprlang::FLOAT{1.5});
|
||||
addConfig(CONFIG_ENABLED, true);
|
||||
addConfig(CONFIG_MODE, "tilt");
|
||||
addConfig(CONFIG_THRESHOLD, 2);
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_TILT_FUNCTION, Hyprlang::STRING{"negative_quadratic"});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_TILT_LIMIT, Hyprlang::INT{5000});
|
||||
addConfig(CONFIG_SHAKE, true);
|
||||
addConfig(CONFIG_SHAKE_NEAREST, true);
|
||||
addConfig(CONFIG_SHAKE_EFFECTS, false);
|
||||
addConfig(CONFIG_SHAKE_IPC, false);
|
||||
addConfig(CONFIG_SHAKE_THRESHOLD, 4.0f);
|
||||
addConfig(CONFIG_SHAKE_FACTOR, 1.5f);
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_STRETCH_FUNCTION, Hyprlang::STRING{"negative_quadratic"});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_STRETCH_LIMIT, Hyprlang::INT{3000});
|
||||
addShapeConfig(CONFIG_TILT_FUNCTION, "negative_quadratic");
|
||||
addShapeConfig(CONFIG_TILT_LIMIT, 5000);
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_ROTATE_LENGTH, Hyprlang::INT{20});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_ROTATE_OFFSET, Hyprlang::FLOAT{0});
|
||||
addShapeConfig(CONFIG_STRETCH_FUNCTION, "negative_quadratic");
|
||||
addShapeConfig(CONFIG_STRETCH_LIMIT, 3000);
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_HW_DEBUG, Hyprlang::INT{0});
|
||||
addShapeConfig(CONFIG_ROTATE_LENGTH, 20);
|
||||
addShapeConfig(CONFIG_ROTATE_OFFSET, 0.0f);
|
||||
|
||||
HyprlandAPI::reloadConfig();
|
||||
addConfig(CONFIG_HW_DEBUG, false);
|
||||
|
||||
addRulesConfig();
|
||||
finishConfig();
|
||||
|
||||
// init things
|
||||
g_pDynamicCursors = std::make_unique<CDynamicCursors>();
|
||||
|
||||
// try hooking
|
||||
try {
|
||||
g_pRenderSoftwareCursorsForHook = hook("renderSoftwareCursorsFor", (void*) &hkRenderSoftwareCursorsFor);
|
||||
g_pDamageIfSoftwareHook = hook("damageIfSoftware", (void*) &hkDamageIfSoftware);
|
||||
g_pRenderHWCursorBufferHook = hook("renderHWCursorBuffer", (void*) &hkRenderHWCursorBuffer);
|
||||
g_pSetHWCursorBufferHook = hook("setHWCursorBuffer", (void*) &hkSetHWCursorBuffer);
|
||||
g_pOnCursorMovedHook = hook("onCursorMoved", (void*) &hkOnCursorMoved);
|
||||
g_pRenderSoftwareCursorsForHook = hook("renderSoftwareCursorsFor", "CPointerManager", (void*) &hkRenderSoftwareCursorsFor);
|
||||
g_pDamageIfSoftwareHook = hook("damageIfSoftware", "CPointerManager", (void*) &hkDamageIfSoftware);
|
||||
g_pRenderHWCursorBufferHook = hook("renderHWCursorBuffer", "CPointerManager", (void*) &hkRenderHWCursorBuffer);
|
||||
g_pSetHWCursorBufferHook = hook("setHWCursorBuffer", "CPointerManager", (void*) &hkSetHWCursorBuffer);
|
||||
g_pOnCursorMovedHook = hook("onCursorMoved", "CPointerManager", (void*) &hkOnCursorMoved);
|
||||
|
||||
g_pSetCursorFromNameHook = hook("setCursorFromName", "CCursorManager", (void*) &hkSetCursorFromName);
|
||||
g_pSetCursorSurfaceHook = hook("setCursorSurface", "CCursorManager", (void*) &hkSetCursorSurface);
|
||||
} catch (...) {
|
||||
HyprlandAPI::addNotification(PHANDLE, "[dynamic-cursors] Failed to load, hooks could not be made!", CColor{1.0, 0.2, 0.2, 1.0}, 5000);
|
||||
throw std::runtime_error("hooks failed");
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "../globals.hpp"
|
||||
#include "../config/config.hpp"
|
||||
#include "src/macros.hpp"
|
||||
#include <cmath>
|
||||
#include "ModeRotate.hpp"
|
||||
|
||||
EModeUpdate CModeRotate::strategy() {
|
||||
|
@ -6,8 +8,10 @@ EModeUpdate CModeRotate::strategy() {
|
|||
}
|
||||
|
||||
SModeResult CModeRotate::update(Vector2D pos) {
|
||||
static auto* const* PLENGTH = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ROTATE_LENGTH)->getDataStaticPtr();
|
||||
static auto* const* POFFSET = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ROTATE_OFFSET)->getDataStaticPtr();
|
||||
static auto* const* PLENGTH = (Hyprlang::INT* const*) getConfig(CONFIG_ROTATE_LENGTH);
|
||||
static auto* const* POFFSET = (Hyprlang::FLOAT* const*) getConfig(CONFIG_ROTATE_OFFSET);
|
||||
auto length = g_pShapeRuleHandler->getIntOr(CONFIG_ROTATE_LENGTH, **PLENGTH);
|
||||
auto offset = g_pShapeRuleHandler->getFloatOr(CONFIG_ROTATE_OFFSET, **POFFSET);
|
||||
|
||||
// translate to origin
|
||||
end.x -= pos.x;
|
||||
|
@ -19,14 +23,14 @@ SModeResult CModeRotate::update(Vector2D pos) {
|
|||
end.y /= size;
|
||||
|
||||
// scale to length
|
||||
end.x *= **PLENGTH;
|
||||
end.y *= **PLENGTH;
|
||||
end.x *= length;
|
||||
end.y *= length;
|
||||
|
||||
// calculate angle
|
||||
double angle = -std::atan(end.x / end.y);
|
||||
if (end.y > 0) angle += PI;
|
||||
angle += PI;
|
||||
angle += **POFFSET * ((2 * PI) / 360); // convert to radiants
|
||||
angle += offset * ((2 * PI) / 360); // convert to radiants
|
||||
|
||||
// translate back
|
||||
end.x += pos.x;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "ModeStretch.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "../globals.hpp"
|
||||
#include "../config/config.hpp"
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
|
||||
EModeUpdate CModeStretch::strategy() {
|
||||
|
@ -8,8 +8,10 @@ EModeUpdate CModeStretch::strategy() {
|
|||
}
|
||||
|
||||
SModeResult CModeStretch::update(Vector2D pos) {
|
||||
static auto const* PFUNCTION = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_STRETCH_FUNCTION)->getDataStaticPtr();
|
||||
static auto* const* PLIMIT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_STRETCH_LIMIT)->getDataStaticPtr();
|
||||
static auto const* PFUNCTION = (Hyprlang::STRING const*) getConfig(CONFIG_STRETCH_FUNCTION);
|
||||
static auto* const* PLIMIT = (Hyprlang::INT* const*) getConfig(CONFIG_STRETCH_LIMIT);
|
||||
auto function = g_pShapeRuleHandler->getStringOr(CONFIG_STRETCH_FUNCTION, *PFUNCTION);
|
||||
auto limit = g_pShapeRuleHandler->getIntOr(CONFIG_STRETCH_LIMIT, **PLIMIT);
|
||||
|
||||
// create samples array
|
||||
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate / 10; // 100ms worth of history
|
||||
|
@ -29,7 +31,7 @@ SModeResult CModeStretch::update(Vector2D pos) {
|
|||
if (speed.y > 0) angle += PI;
|
||||
if (mag == 0) angle = 0;
|
||||
|
||||
double scale = activation(*PFUNCTION, **PLIMIT, mag);
|
||||
double scale = activation(function, limit, mag);
|
||||
|
||||
auto result = SModeResult();
|
||||
result.stretch.angle = angle;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "ModeTilt.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "../globals.hpp"
|
||||
#include "../config/config.hpp"
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
|
||||
EModeUpdate CModeTilt::strategy() {
|
||||
|
@ -8,8 +8,10 @@ EModeUpdate CModeTilt::strategy() {
|
|||
}
|
||||
|
||||
SModeResult CModeTilt::update(Vector2D pos) {
|
||||
static auto const* PFUNCTION = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_TILT_FUNCTION)->getDataStaticPtr();
|
||||
static auto* const* PMASS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_TILT_LIMIT)->getDataStaticPtr();
|
||||
static auto const* PFUNCTION = (Hyprlang::STRING const*) getConfig(CONFIG_TILT_FUNCTION);
|
||||
static auto* const* PLIMIT = (Hyprlang::INT* const*) getConfig(CONFIG_TILT_LIMIT);
|
||||
auto function = g_pShapeRuleHandler->getStringOr(CONFIG_TILT_FUNCTION, *PFUNCTION);
|
||||
auto limit = g_pShapeRuleHandler->getIntOr(CONFIG_TILT_LIMIT, **PLIMIT);
|
||||
|
||||
// create samples array
|
||||
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate / 10; // 100ms worth of history
|
||||
|
@ -25,6 +27,6 @@ SModeResult CModeTilt::update(Vector2D pos) {
|
|||
double speed = (samples[current].x - samples[first].x) / 0.1;
|
||||
|
||||
auto result = SModeResult();
|
||||
result.rotation = activation(*PFUNCTION, **PMASS, speed) * (PI / 3); // 120° in both directions
|
||||
result.rotation = activation(function, limit, speed) * (PI / 3); // 120° in both directions
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include "../globals.hpp"
|
||||
#include "../config/config.hpp"
|
||||
#include "src/managers/EventManager.hpp"
|
||||
#include "Shake.hpp"
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
|
||||
double CShake::update(Vector2D pos) {
|
||||
static auto* const* PTHRESHOLD = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_THRESHOLD)->getDataStaticPtr();
|
||||
static auto* const* PFACTOR = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_FACTOR)->getDataStaticPtr();
|
||||
static auto* const* PIPC = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_IPC)->getDataStaticPtr();
|
||||
static auto* const* PTHRESHOLD = (Hyprlang::FLOAT* const*) getConfig(CONFIG_SHAKE_THRESHOLD);
|
||||
static auto* const* PFACTOR = (Hyprlang::FLOAT* const*) getConfig(CONFIG_SHAKE_FACTOR);
|
||||
static auto* const* PIPC = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_IPC);
|
||||
|
||||
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate; // 1s worth of history
|
||||
samples.resize(max);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue