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
39
README.md
39
README.md
|
@ -36,7 +36,7 @@ This plugin is still very early in its development. There are also multiple thin
|
||||||
- [X] stick simulation
|
- [X] stick simulation
|
||||||
- [X] air drag simulation
|
- [X] air drag simulation
|
||||||
- [ ] pendulum simulation
|
- [ ] pendulum simulation
|
||||||
- [ ] per-shape length and starting angle (if possible)
|
- [X] per-shape length and starting angle (if possible)
|
||||||
- [X] cursor shake to find
|
- [X] cursor shake to find
|
||||||
- [ ] overdue refactoring (wait for aquamarine merge)
|
- [ ] overdue refactoring (wait for aquamarine merge)
|
||||||
- [ ] ~~inverted cursor?~~ (i think out of scope here, but see the [inverted branch](https://github.com/VirtCode/hypr-dynamic-cursors/tree/inverted))
|
- [ ] ~~inverted cursor?~~ (i think out of scope here, but see the [inverted branch](https://github.com/VirtCode/hypr-dynamic-cursors/tree/inverted))
|
||||||
|
@ -112,6 +112,14 @@ plugin:dynamic-cursors {
|
||||||
# smaller values are smoother, but more expensive for hw cursors
|
# smaller values are smoother, but more expensive for hw cursors
|
||||||
threshold = 2
|
threshold = 2
|
||||||
|
|
||||||
|
# override the mode behaviour per shape
|
||||||
|
# this is a keyword and can be repeated many times
|
||||||
|
# by default, there are no rules added
|
||||||
|
# see the dedicated `shape rules` section below!
|
||||||
|
shaperule = <shape-name>, <mode> (optional), <property>: <value>, ...
|
||||||
|
shaperule = <shape-name>, <mode> (optional), <property>: <value>, ...
|
||||||
|
...
|
||||||
|
|
||||||
# for mode = rotate
|
# for mode = rotate
|
||||||
rotate {
|
rotate {
|
||||||
|
|
||||||
|
@ -153,10 +161,10 @@ plugin:dynamic-cursors {
|
||||||
}
|
}
|
||||||
|
|
||||||
# configure shake to find
|
# configure shake to find
|
||||||
|
# magnifies the cursor if its is being shaken
|
||||||
shake {
|
shake {
|
||||||
|
|
||||||
# enables shake to find
|
# enables shake to find
|
||||||
# magnifies the cursor if its is being shaken
|
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
||||||
# controls how soon a shake is detected
|
# controls how soon a shake is detected
|
||||||
|
@ -180,6 +188,33 @@ plugin:dynamic-cursors {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### shape rules
|
||||||
|
Shape Rules can be used to override the mode or its behaviour on a per-shape basis. They can be defined with the keyword `shaperule` in the config file, perferrably in the `plugin:dynamic-cursors` section.
|
||||||
|
|
||||||
|
**Note:** Shape rules only apply to server side cursor shapes. Sadly, not everyone supports server side cursors yet, which means shape rules won't work with apps using toolkits like e.g. GTK.
|
||||||
|
|
||||||
|
A shape rule usually consists of three parts:
|
||||||
|
```
|
||||||
|
shaperule = shape-name, mode (optional), property: value, property: value, ...
|
||||||
|
```
|
||||||
|
- `shape-name`: This is the name of the shape, this rule will apply to. Should be one of [those specified in the protocol](https://wayland.app/protocols/cursor-shape-v1#wp_cursor_shape_device_v1:enum:shape). You can use the special shape `clientside` to apply your rule to **ALL** client side cursors.
|
||||||
|
- `mode` (optional): Can override the mode used by this shape, see `mode` in the config. This argument is optional and can be left out.
|
||||||
|
- `property: value`: At the end of the rule follow zero or more property-value pairs. These are config values that will be overridden if this rule is active. Only config values from the sections `rotate`, `tilt`, `stretch` as seen above can be used.
|
||||||
|
|
||||||
|
Here are a few example rules to get you started:
|
||||||
|
```
|
||||||
|
plugin:dynamic-cursors {
|
||||||
|
# apply a 90° offset in rotate mode to the text shape
|
||||||
|
shaperule = text, rotate:offset: 90
|
||||||
|
|
||||||
|
# use stretch mode when grabbing, and set the limit low
|
||||||
|
shaperule = grab, stretch, stretch:limit: 2000
|
||||||
|
|
||||||
|
# do not show any effects on clientside cursors
|
||||||
|
shaperule = clientside, none
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## performance
|
## performance
|
||||||
> **TL;DR:** Hardware cursor performance is about the same as if an animated cursor shape was shown whenever you move your mouse. Sofware cursor performance is not impacted. When the cursor is magnified during a shake, the compositor will temporarily switch to software cursors.
|
> **TL;DR:** Hardware cursor performance is about the same as if an animated cursor shape was shown whenever you move your mouse. Sofware cursor performance is not impacted. When the cursor is magnified during a shake, the compositor will temporarily switch to software cursors.
|
||||||
|
|
||||||
|
|
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 "mode/Mode.hpp"
|
||||||
#include "src/debug/Log.hpp"
|
#include "src/debug/Log.hpp"
|
||||||
#include "src/managers/eventLoop/EventLoopManager.hpp"
|
#include "src/managers/eventLoop/EventLoopManager.hpp"
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
|
||||||
void tickRaw(SP<CEventLoopTimer> self, void* data) {
|
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)
|
if (**PENABLED && g_pDynamicCursors)
|
||||||
g_pDynamicCursors->onTick(g_pPointerManager.get());
|
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.
|
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) {
|
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())
|
if (!pointers->hasCursor())
|
||||||
return;
|
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.
|
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) {
|
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* PHW_DEBUG= (Hyprlang::INT* const*) getConfig(CONFIG_HW_DEBUG);
|
||||||
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);
|
||||||
|
|
||||||
auto output = state->monitor->output;
|
auto output = state->monitor->output;
|
||||||
auto zoom = resultShown.scale;
|
auto zoom = resultShown.scale;
|
||||||
|
@ -261,6 +261,14 @@ void CDynamicCursors::onCursorMoved(CPointerManager* pointers) {
|
||||||
calculate(MOVE);
|
calculate(MOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDynamicCursors::setShape(const std::string& shape) {
|
||||||
|
g_pShapeRuleHandler->activate(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDynamicCursors::unsetShape() {
|
||||||
|
g_pShapeRuleHandler->activate("clientside");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Handle cursor tick events.
|
Handle cursor tick events.
|
||||||
*/
|
*/
|
||||||
|
@ -269,18 +277,19 @@ void CDynamicCursors::onTick(CPointerManager* pointers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IMode* CDynamicCursors::currentMode() {
|
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;
|
if (mode == "rotate") return &rotate;
|
||||||
else if (!strcmp(*PMODE, "tilt")) return &tilt;
|
else if (mode == "tilt") return &tilt;
|
||||||
else if (!strcmp(*PMODE, "stretch")) return &stretch;
|
else if (mode == "stretch") return &stretch;
|
||||||
else return nullptr;
|
else return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDynamicCursors::calculate(EModeUpdate type) {
|
void CDynamicCursors::calculate(EModeUpdate type) {
|
||||||
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_THRESHOLD)->getDataStaticPtr();
|
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*) getConfig(CONFIG_THRESHOLD);
|
||||||
static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr();
|
static auto* const* PSHAKE = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE);
|
||||||
static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS)->getDataStaticPtr();
|
static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_EFFECTS);
|
||||||
|
|
||||||
IMode* mode = currentMode();
|
IMode* mode = currentMode();
|
||||||
|
|
||||||
|
@ -322,12 +331,24 @@ void CDynamicCursors::calculate(EModeUpdate type) {
|
||||||
// damage software and change hardware cursor shape
|
// damage software and change hardware cursor shape
|
||||||
g_pPointerManager->damageIfSoftware();
|
g_pPointerManager->damageIfSoftware();
|
||||||
|
|
||||||
|
bool entered = false;
|
||||||
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||||
auto state = g_pPointerManager->stateFor(m);
|
auto state = g_pPointerManager->stateFor(m);
|
||||||
|
|
||||||
|
if (state->entered) entered = true;
|
||||||
if (state->hardwareFailed || !state->entered)
|
if (state->hardwareFailed || !state->entered)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
g_pPointerManager->attemptHardwareCursor(state);
|
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 */
|
/* hook on setHWCursorBuffer */
|
||||||
bool setHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, wlr_buffer* buf);
|
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:
|
private:
|
||||||
SP<CEventLoopTimer> tick;
|
SP<CEventLoopTimer> tick;
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,4 @@
|
||||||
|
|
||||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
#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;
|
inline HANDLE PHANDLE = nullptr;
|
||||||
|
|
107
src/main.cpp
107
src/main.cpp
|
@ -8,60 +8,73 @@
|
||||||
|
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
#include "cursor.hpp"
|
#include "cursor.hpp"
|
||||||
|
#include "config/config.hpp"
|
||||||
#include "src/debug/Log.hpp"
|
#include "src/debug/Log.hpp"
|
||||||
#include "src/managers/PointerManager.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>);
|
typedef void (*origRenderSofwareCursorsFor)(void*, SP<CMonitor>, timespec*, CRegion&, std::optional<Vector2D>);
|
||||||
inline CFunctionHook* g_pRenderSoftwareCursorsForHook = nullptr;
|
inline CFunctionHook* g_pRenderSoftwareCursorsForHook = nullptr;
|
||||||
void hkRenderSoftwareCursorsFor(void* thisptr, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
|
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 (isEnabled()) g_pDynamicCursors->renderSoftware((CPointerManager*) thisptr, pMonitor, now, damage, overridePos);
|
||||||
|
|
||||||
if (**PENABLED) g_pDynamicCursors->renderSoftware((CPointerManager*) thisptr, pMonitor, now, damage, overridePos);
|
|
||||||
else (*(origRenderSofwareCursorsFor)g_pRenderSoftwareCursorsForHook->m_pOriginal)(thisptr, pMonitor, now, damage, overridePos);
|
else (*(origRenderSofwareCursorsFor)g_pRenderSoftwareCursorsForHook->m_pOriginal)(thisptr, pMonitor, now, damage, overridePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*origDamageIfSoftware)(void*);
|
typedef void (*origDamageIfSoftware)(void*);
|
||||||
inline CFunctionHook* g_pDamageIfSoftwareHook = nullptr;
|
inline CFunctionHook* g_pDamageIfSoftwareHook = nullptr;
|
||||||
void hkDamageIfSoftware(void* thisptr) {
|
void hkDamageIfSoftware(void* thisptr) {
|
||||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
if (isEnabled()) g_pDynamicCursors->damageSoftware((CPointerManager*) thisptr);
|
||||||
|
|
||||||
if (**PENABLED) g_pDynamicCursors->damageSoftware((CPointerManager*) thisptr);
|
|
||||||
else (*(origDamageIfSoftware)g_pDamageIfSoftwareHook->m_pOriginal)(thisptr);
|
else (*(origDamageIfSoftware)g_pDamageIfSoftwareHook->m_pOriginal)(thisptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef wlr_buffer* (*origRenderHWCursorBuffer)(void*, SP<CPointerManager::SMonitorPointerState>, SP<CTexture>);
|
typedef wlr_buffer* (*origRenderHWCursorBuffer)(void*, SP<CPointerManager::SMonitorPointerState>, SP<CTexture>);
|
||||||
inline CFunctionHook* g_pRenderHWCursorBufferHook = nullptr;
|
inline CFunctionHook* g_pRenderHWCursorBufferHook = nullptr;
|
||||||
wlr_buffer* hkRenderHWCursorBuffer(void* thisptr, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
|
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 (isEnabled()) return g_pDynamicCursors->renderHardware((CPointerManager*) thisptr, state, texture);
|
||||||
|
|
||||||
if (**PENABLED) return g_pDynamicCursors->renderHardware((CPointerManager*) thisptr, state, texture);
|
|
||||||
else return (*(origRenderHWCursorBuffer)g_pRenderHWCursorBufferHook->m_pOriginal)(thisptr, state, texture);
|
else return (*(origRenderHWCursorBuffer)g_pRenderHWCursorBufferHook->m_pOriginal)(thisptr, state, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef bool (*origSetHWCursorBuffer)(void*, SP<CPointerManager::SMonitorPointerState>, wlr_buffer*);
|
typedef bool (*origSetHWCursorBuffer)(void*, SP<CPointerManager::SMonitorPointerState>, wlr_buffer*);
|
||||||
inline CFunctionHook* g_pSetHWCursorBufferHook = nullptr;
|
inline CFunctionHook* g_pSetHWCursorBufferHook = nullptr;
|
||||||
bool hkSetHWCursorBuffer(void* thisptr, SP<CPointerManager::SMonitorPointerState> state, wlr_buffer* buffer) {
|
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 (isEnabled()) return g_pDynamicCursors->setHardware((CPointerManager*) thisptr, state, buffer);
|
||||||
|
|
||||||
if (**PENABLED) return g_pDynamicCursors->setHardware((CPointerManager*) thisptr, state, buffer);
|
|
||||||
else return (*(origSetHWCursorBuffer)g_pSetHWCursorBufferHook->m_pOriginal)(thisptr, state, buffer);
|
else return (*(origSetHWCursorBuffer)g_pSetHWCursorBufferHook->m_pOriginal)(thisptr, state, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*origOnCursorMoved)(void*);
|
typedef void (*origOnCursorMoved)(void*);
|
||||||
inline CFunctionHook* g_pOnCursorMovedHook = nullptr;
|
inline CFunctionHook* g_pOnCursorMovedHook = nullptr;
|
||||||
void hkOnCursorMoved(void* thisptr) {
|
void hkOnCursorMoved(void* thisptr) {
|
||||||
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
if (isEnabled()) return g_pDynamicCursors->onCursorMoved((CPointerManager*) thisptr);
|
||||||
|
|
||||||
if (**PENABLED) return g_pDynamicCursors->onCursorMoved((CPointerManager*) thisptr);
|
|
||||||
else return (*(origOnCursorMoved)g_pOnCursorMovedHook->m_pOriginal)(thisptr);
|
else return (*(origOnCursorMoved)g_pOnCursorMovedHook->m_pOriginal)(thisptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hooks a function hook */
|
typedef void (*origSetCusorFromName)(void*, const std::string& name);
|
||||||
CFunctionHook* hook(std::string name, void* function) {
|
inline CFunctionHook* g_pSetCursorFromNameHook = nullptr;
|
||||||
auto names = HyprlandAPI::findFunctionsByName(PHANDLE, name);
|
void hkSetCursorFromName(void* thisptr, const std::string& name) {
|
||||||
auto match = names.at(0);
|
if (isEnabled()) g_pDynamicCursors->setShape(name);
|
||||||
|
(*(origSetCusorFromName)g_pSetCursorFromNameHook->m_pOriginal)(thisptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
Debug::log(LOG, "[dynamic-cursors] hooking on {} for {}", match.signature, 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, std::string object, void* function) {
|
||||||
|
auto names = HyprlandAPI::findFunctionsByName(PHANDLE, name);
|
||||||
|
|
||||||
|
// we hook on member functions, so search for them
|
||||||
|
for (auto match : names) {
|
||||||
|
if (!match.demangled.starts_with(object)) continue;
|
||||||
|
|
||||||
|
Debug::log(LOG, "[dynamic-cursors] hooking on {} for {}::{}", match.demangled, object, name);
|
||||||
|
|
||||||
auto hook = HyprlandAPI::createFunctionHook(PHANDLE, match.address, function);
|
auto hook = HyprlandAPI::createFunctionHook(PHANDLE, match.address, function);
|
||||||
hook->hook();
|
hook->hook();
|
||||||
|
@ -69,6 +82,10 @@ CFunctionHook* hook(std::string name, void* function) {
|
||||||
return 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) {
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
PHANDLE = handle;
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
@ -80,40 +97,46 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup config
|
// setup config
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_ENABLED, Hyprlang::INT{1});
|
startConfig();
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MODE, Hyprlang::STRING{"tilt"});
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_THRESHOLD, Hyprlang::INT{2});
|
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE, Hyprlang::INT{1});
|
addConfig(CONFIG_ENABLED, true);
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST, Hyprlang::INT{1});
|
addConfig(CONFIG_MODE, "tilt");
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS, Hyprlang::INT{0});
|
addConfig(CONFIG_THRESHOLD, 2);
|
||||||
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});
|
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_TILT_FUNCTION, Hyprlang::STRING{"negative_quadratic"});
|
addConfig(CONFIG_SHAKE, true);
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_TILT_LIMIT, Hyprlang::INT{5000});
|
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"});
|
addShapeConfig(CONFIG_TILT_FUNCTION, "negative_quadratic");
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_STRETCH_LIMIT, Hyprlang::INT{3000});
|
addShapeConfig(CONFIG_TILT_LIMIT, 5000);
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_ROTATE_LENGTH, Hyprlang::INT{20});
|
addShapeConfig(CONFIG_STRETCH_FUNCTION, "negative_quadratic");
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_ROTATE_OFFSET, Hyprlang::FLOAT{0});
|
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
|
// init things
|
||||||
g_pDynamicCursors = std::make_unique<CDynamicCursors>();
|
g_pDynamicCursors = std::make_unique<CDynamicCursors>();
|
||||||
|
|
||||||
// try hooking
|
// try hooking
|
||||||
try {
|
try {
|
||||||
g_pRenderSoftwareCursorsForHook = hook("renderSoftwareCursorsFor", (void*) &hkRenderSoftwareCursorsFor);
|
g_pRenderSoftwareCursorsForHook = hook("renderSoftwareCursorsFor", "CPointerManager", (void*) &hkRenderSoftwareCursorsFor);
|
||||||
g_pDamageIfSoftwareHook = hook("damageIfSoftware", (void*) &hkDamageIfSoftware);
|
g_pDamageIfSoftwareHook = hook("damageIfSoftware", "CPointerManager", (void*) &hkDamageIfSoftware);
|
||||||
g_pRenderHWCursorBufferHook = hook("renderHWCursorBuffer", (void*) &hkRenderHWCursorBuffer);
|
g_pRenderHWCursorBufferHook = hook("renderHWCursorBuffer", "CPointerManager", (void*) &hkRenderHWCursorBuffer);
|
||||||
g_pSetHWCursorBufferHook = hook("setHWCursorBuffer", (void*) &hkSetHWCursorBuffer);
|
g_pSetHWCursorBufferHook = hook("setHWCursorBuffer", "CPointerManager", (void*) &hkSetHWCursorBuffer);
|
||||||
g_pOnCursorMovedHook = hook("onCursorMoved", (void*) &hkOnCursorMoved);
|
g_pOnCursorMovedHook = hook("onCursorMoved", "CPointerManager", (void*) &hkOnCursorMoved);
|
||||||
|
|
||||||
|
g_pSetCursorFromNameHook = hook("setCursorFromName", "CCursorManager", (void*) &hkSetCursorFromName);
|
||||||
|
g_pSetCursorSurfaceHook = hook("setCursorSurface", "CCursorManager", (void*) &hkSetCursorSurface);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
HyprlandAPI::addNotification(PHANDLE, "[dynamic-cursors] Failed to load, hooks could not be made!", CColor{1.0, 0.2, 0.2, 1.0}, 5000);
|
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");
|
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"
|
#include "ModeRotate.hpp"
|
||||||
|
|
||||||
EModeUpdate CModeRotate::strategy() {
|
EModeUpdate CModeRotate::strategy() {
|
||||||
|
@ -6,8 +8,10 @@ EModeUpdate CModeRotate::strategy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SModeResult CModeRotate::update(Vector2D pos) {
|
SModeResult CModeRotate::update(Vector2D pos) {
|
||||||
static auto* const* PLENGTH = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ROTATE_LENGTH)->getDataStaticPtr();
|
static auto* const* PLENGTH = (Hyprlang::INT* const*) getConfig(CONFIG_ROTATE_LENGTH);
|
||||||
static auto* const* POFFSET = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ROTATE_OFFSET)->getDataStaticPtr();
|
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
|
// translate to origin
|
||||||
end.x -= pos.x;
|
end.x -= pos.x;
|
||||||
|
@ -19,14 +23,14 @@ SModeResult CModeRotate::update(Vector2D pos) {
|
||||||
end.y /= size;
|
end.y /= size;
|
||||||
|
|
||||||
// scale to length
|
// scale to length
|
||||||
end.x *= **PLENGTH;
|
end.x *= length;
|
||||||
end.y *= **PLENGTH;
|
end.y *= length;
|
||||||
|
|
||||||
// calculate angle
|
// calculate angle
|
||||||
double angle = -std::atan(end.x / end.y);
|
double angle = -std::atan(end.x / end.y);
|
||||||
if (end.y > 0) angle += PI;
|
if (end.y > 0) angle += PI;
|
||||||
angle += PI;
|
angle += PI;
|
||||||
angle += **POFFSET * ((2 * PI) / 360); // convert to radiants
|
angle += offset * ((2 * PI) / 360); // convert to radiants
|
||||||
|
|
||||||
// translate back
|
// translate back
|
||||||
end.x += pos.x;
|
end.x += pos.x;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "ModeStretch.hpp"
|
#include "ModeStretch.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "../globals.hpp"
|
#include "../config/config.hpp"
|
||||||
#include <hyprland/src/Compositor.hpp>
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
|
||||||
EModeUpdate CModeStretch::strategy() {
|
EModeUpdate CModeStretch::strategy() {
|
||||||
|
@ -8,8 +8,10 @@ EModeUpdate CModeStretch::strategy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SModeResult CModeStretch::update(Vector2D pos) {
|
SModeResult CModeStretch::update(Vector2D pos) {
|
||||||
static auto const* PFUNCTION = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_STRETCH_FUNCTION)->getDataStaticPtr();
|
static auto const* PFUNCTION = (Hyprlang::STRING const*) getConfig(CONFIG_STRETCH_FUNCTION);
|
||||||
static auto* const* PLIMIT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_STRETCH_LIMIT)->getDataStaticPtr();
|
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
|
// create samples array
|
||||||
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate / 10; // 100ms worth of history
|
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 (speed.y > 0) angle += PI;
|
||||||
if (mag == 0) angle = 0;
|
if (mag == 0) angle = 0;
|
||||||
|
|
||||||
double scale = activation(*PFUNCTION, **PLIMIT, mag);
|
double scale = activation(function, limit, mag);
|
||||||
|
|
||||||
auto result = SModeResult();
|
auto result = SModeResult();
|
||||||
result.stretch.angle = angle;
|
result.stretch.angle = angle;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "ModeTilt.hpp"
|
#include "ModeTilt.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "../globals.hpp"
|
#include "../config/config.hpp"
|
||||||
#include <hyprland/src/Compositor.hpp>
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
|
||||||
EModeUpdate CModeTilt::strategy() {
|
EModeUpdate CModeTilt::strategy() {
|
||||||
|
@ -8,8 +8,10 @@ EModeUpdate CModeTilt::strategy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SModeResult CModeTilt::update(Vector2D pos) {
|
SModeResult CModeTilt::update(Vector2D pos) {
|
||||||
static auto const* PFUNCTION = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_TILT_FUNCTION)->getDataStaticPtr();
|
static auto const* PFUNCTION = (Hyprlang::STRING const*) getConfig(CONFIG_TILT_FUNCTION);
|
||||||
static auto* const* PMASS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_TILT_LIMIT)->getDataStaticPtr();
|
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
|
// create samples array
|
||||||
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate / 10; // 100ms worth of history
|
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;
|
double speed = (samples[current].x - samples[first].x) / 0.1;
|
||||||
|
|
||||||
auto result = SModeResult();
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#include "../globals.hpp"
|
#include "../globals.hpp"
|
||||||
|
#include "../config/config.hpp"
|
||||||
#include "src/managers/EventManager.hpp"
|
#include "src/managers/EventManager.hpp"
|
||||||
#include "Shake.hpp"
|
#include "Shake.hpp"
|
||||||
#include <hyprland/src/Compositor.hpp>
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
|
||||||
double CShake::update(Vector2D pos) {
|
double CShake::update(Vector2D pos) {
|
||||||
static auto* const* PTHRESHOLD = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_THRESHOLD)->getDataStaticPtr();
|
static auto* const* PTHRESHOLD = (Hyprlang::FLOAT* const*) getConfig(CONFIG_SHAKE_THRESHOLD);
|
||||||
static auto* const* PFACTOR = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_FACTOR)->getDataStaticPtr();
|
static auto* const* PFACTOR = (Hyprlang::FLOAT* const*) getConfig(CONFIG_SHAKE_FACTOR);
|
||||||
static auto* const* PIPC = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_IPC)->getDataStaticPtr();
|
static auto* const* PIPC = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_IPC);
|
||||||
|
|
||||||
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate; // 1s worth of history
|
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate; // 1s worth of history
|
||||||
samples.resize(max);
|
samples.resize(max);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue