mirror of
https://github.com/virtcode/hypr-dynamic-cursors
synced 2025-09-19 16:13:21 +02:00
feat: cursor shake to find
This commit is contained in:
parent
086c9a8c48
commit
cde5bf84fb
7 changed files with 134 additions and 50 deletions
42
README.md
42
README.md
|
@ -3,19 +3,26 @@ This plugin makes your cursor more realistic by simulating how it would behave i
|
||||||
|
|
||||||
Why did I implement this again?
|
Why did I implement this again?
|
||||||
|
|
||||||
## showcase
|
Inspired by KDE, it also supports shake to find, to enlarge the cursor when it is shaken so it is easier to find it.
|
||||||
|
|
||||||
|
## behaviour modes
|
||||||
The plugin supports two different modes, `rotate` and `tilt`. They both are customizable and have a different base behaviour.
|
The plugin supports two different modes, `rotate` and `tilt`. They both are customizable and have a different base behaviour.
|
||||||
|
|
||||||
#### rotate
|
### `rotate`
|
||||||
In this mode, the cursor is simulated as a stick which is dragged across the screen on one end. This means it will rotate towards the movement direction, and feels really realistic.
|
In this mode, the cursor is simulated as a stick which is dragged across the screen on one end. This means it will rotate towards the movement direction, and feels really realistic.
|
||||||
|
|
||||||
https://github.com/VirtCode/hypr-dynamic-cursor/assets/41426325/ccd6d742-8e2b-4073-a35e-318c7e19705c
|
https://github.com/VirtCode/hypr-dynamic-cursor/assets/41426325/ccd6d742-8e2b-4073-a35e-318c7e19705c
|
||||||
|
|
||||||
#### tilt
|
### `tilt`
|
||||||
In this mode, the cursor is tilted based on the X direction and speed it is moving at. It was intended to simulate how an object would be affected by air drag, but implemented is only a rough approximation. This mode can also be customized extensively with different activation functions.
|
In this mode, the cursor is tilted based on the X direction and speed it is moving at. It was intended to simulate how an object would be affected by air drag, but implemented is only a rough approximation. This mode can also be customized extensively with different activation functions, and is enabled by default.
|
||||||
|
|
||||||
https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/ae25415c-e77f-4c85-864c-2eedbfe432e3
|
https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/ae25415c-e77f-4c85-864c-2eedbfe432e3
|
||||||
|
|
||||||
|
## shake to find
|
||||||
|
The plugin supports shake to find, akin to how KDE Plasma, MacOS, etc. do it. It is enabled by default.
|
||||||
|
|
||||||
|
INSERT VIDEO HERE
|
||||||
|
|
||||||
## state
|
## state
|
||||||
This plugin is still very early in its development. **Currently, only the `-git` version of hyprland is supported**. There are also multiple things which may or may not be implemented in the future:
|
This plugin is still very early in its development. **Currently, only the `-git` version of hyprland is supported**. There are also multiple things which may or may not be implemented in the future:
|
||||||
|
|
||||||
|
@ -25,10 +32,12 @@ This plugin is still very early in its development. **Currently, only the `-git`
|
||||||
- [X] air drag simulation
|
- [X] air drag simulation
|
||||||
- [ ] pendulum simulation
|
- [ ] pendulum simulation
|
||||||
- [ ] per-shape length and starting angle (if possible)
|
- [ ] per-shape length and starting angle (if possible)
|
||||||
|
- [X] cursor shake to find
|
||||||
|
- [ ] overdue refactoring (wait for aquamarine merge)
|
||||||
|
|
||||||
If anything here sounds interesting to you, don't hesitate to contribute.
|
If anything here sounds interesting to you, don't hesitate to contribute.
|
||||||
|
|
||||||
Please note that this plugin was created more or less as a joke. I mainly wanted to see how using a rotating or tilted cursor was like. So I will not guarantee any future updates and bugfixes.
|
Please note that this plugin was created more or less as a joke. I mainly wanted to see how using a rotating or tilted cursor was like. So I will not guarantee any future updates and bugfixes. The only useful features, shake to find, was implemented more or less as an afterthought.
|
||||||
|
|
||||||
## installation
|
## installation
|
||||||
Installation is supported via `hyprpm`. Supported hyprland versions are `v0.42.0` (yet unreleased) and upwards. The main branch generally tries to target `-git`.
|
Installation is supported via `hyprpm`. Supported hyprland versions are `v0.42.0` (yet unreleased) and upwards. The main branch generally tries to target `-git`.
|
||||||
|
@ -51,6 +60,7 @@ plugin:dynamic-cursors {
|
||||||
# sets the cursor behaviour, supports these values:
|
# sets the cursor behaviour, supports these values:
|
||||||
# tilt - tilt the cursor based on x-velocity
|
# tilt - tilt the cursor based on x-velocity
|
||||||
# rotate - rotate the cursor based on movement direction
|
# rotate - rotate the cursor based on movement direction
|
||||||
|
# none - do not change the cursors behaviour
|
||||||
mode = tilt
|
mode = tilt
|
||||||
|
|
||||||
# minimum angle difference in degrees after which the shape is changed
|
# minimum angle difference in degrees after which the shape is changed
|
||||||
|
@ -78,6 +88,28 @@ plugin:dynamic-cursors {
|
||||||
# negative_quadratic - negative version of the quadratic one, feels more aggressive
|
# negative_quadratic - negative version of the quadratic one, feels more aggressive
|
||||||
function = negative_quadratic
|
function = negative_quadratic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# enable shake to find
|
||||||
|
# magnifies the cursor if its is being shaken
|
||||||
|
shake = true
|
||||||
|
|
||||||
|
# for when shake = true
|
||||||
|
shake {
|
||||||
|
|
||||||
|
# controls how soon a shake is detected
|
||||||
|
# lower values mean sooner
|
||||||
|
threshold = 4.0
|
||||||
|
|
||||||
|
# controls how fast the cursor gets larger
|
||||||
|
factor = 1.5
|
||||||
|
|
||||||
|
# show cursor behaviour `tilt`, `rotate`, etc. while shaking
|
||||||
|
effects = false
|
||||||
|
|
||||||
|
# use nearest-neighbour (pixelated) scaling when shaking
|
||||||
|
# may look weird when effects are enabled
|
||||||
|
nearest = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <hyprlang.hpp>
|
||||||
|
|
||||||
#define private public
|
#define private public
|
||||||
#include <hyprland/src/managers/PointerManager.hpp>
|
#include <hyprland/src/managers/PointerManager.hpp>
|
||||||
|
@ -26,6 +27,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();
|
||||||
|
|
||||||
if (!pointers->hasCursor())
|
if (!pointers->hasCursor())
|
||||||
return;
|
return;
|
||||||
|
@ -50,12 +52,14 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMo
|
||||||
return;
|
return;
|
||||||
|
|
||||||
box.scale(pMonitor->scale);
|
box.scale(pMonitor->scale);
|
||||||
|
box.w *= zoom;
|
||||||
|
box.h *= zoom;
|
||||||
|
|
||||||
// we rotate the cursor by our calculated amount
|
// we rotate the cursor by our calculated amount
|
||||||
box.rot = this->angle;
|
box.rot = this->angle;
|
||||||
|
|
||||||
// now pass the hotspot to rotate around
|
// now pass the hotspot to rotate around
|
||||||
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot);
|
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot * zoom, zoom > 1 && **PNEAREST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -65,8 +69,8 @@ It is largely identical to hyprlands implementation, but expands the damage reag
|
||||||
void CDynamicCursors::damageSoftware(CPointerManager* pointers) {
|
void CDynamicCursors::damageSoftware(CPointerManager* pointers) {
|
||||||
|
|
||||||
// we damage a 3x3 area around the cursor, to accomodate for all possible hotspots and rotations
|
// we damage a 3x3 area around the cursor, to accomodate for all possible hotspots and rotations
|
||||||
Vector2D size = pointers->currentCursorImage.size / pointers->currentCursorImage.scale;
|
Vector2D size = pointers->currentCursorImage.size / pointers->currentCursorImage.scale * zoom;
|
||||||
CBox b = CBox{pointers->pointerPos, size * 3}.translate(-(pointers->currentCursorImage.hotspot + size));
|
CBox b = CBox{pointers->pointerPos, size * 3}.translate(-(pointers->currentCursorImage.hotspot * zoom + size));
|
||||||
|
|
||||||
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
|
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
|
||||||
|
|
||||||
|
@ -87,10 +91,11 @@ It is largely copied from hyprland, but adjusted to allow the cursor to be rotat
|
||||||
*/
|
*/
|
||||||
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*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_HW_DEBUG)->getDataStaticPtr();
|
||||||
|
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
|
||||||
|
|
||||||
auto output = state->monitor->output;
|
auto output = state->monitor->output;
|
||||||
|
|
||||||
auto size = pointers->currentCursorImage.size;
|
auto size = pointers->currentCursorImage.size * zoom;
|
||||||
// we try to allocate a buffer that is thrice as big, see software rendering
|
// we try to allocate a buffer that is thrice as big, see software rendering
|
||||||
auto target = size * 3;
|
auto target = size * 3;
|
||||||
|
|
||||||
|
@ -151,11 +156,11 @@ wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPoint
|
||||||
g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
|
g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
|
||||||
|
|
||||||
// the box should start in the middle portion, rotate by our calculated amount
|
// the box should start in the middle portion, rotate by our calculated amount
|
||||||
CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale}.round()};
|
CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale * zoom}.round()};
|
||||||
xbox.rot = this->angle;
|
xbox.rot = this->angle;
|
||||||
|
|
||||||
// use our custom draw function
|
// use our custom draw function
|
||||||
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot);
|
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot * zoom, zoom > 1 && **PNEAREST);
|
||||||
|
|
||||||
g_pHyprOpenGL->end();
|
g_pHyprOpenGL->end();
|
||||||
glFlush();
|
glFlush();
|
||||||
|
@ -178,7 +183,7 @@ bool CDynamicCursors::setHardware(CPointerManager* pointers, SP<CPointerManager:
|
||||||
if (!P_MONITOR->output->cursor_swapchain) return false;
|
if (!P_MONITOR->output->cursor_swapchain) return false;
|
||||||
|
|
||||||
// we need to transform the hotspot manually as we need to indent it by the size
|
// we need to transform the hotspot manually as we need to indent it by the size
|
||||||
const auto HOTSPOT = CBox{(pointers->currentCursorImage.hotspot + pointers->currentCursorImage.size) * P_MONITOR->scale, {0, 0}}
|
const auto HOTSPOT = CBox{(pointers->currentCursorImage.hotspot + pointers->currentCursorImage.size) * P_MONITOR->scale * zoom, {0, 0}}
|
||||||
.transform(wlTransformToHyprutils(wlr_output_transform_invert(P_MONITOR->transform)), P_MONITOR->output->cursor_swapchain->width, P_MONITOR->output->cursor_swapchain->height)
|
.transform(wlTransformToHyprutils(wlr_output_transform_invert(P_MONITOR->transform)), P_MONITOR->output->cursor_swapchain->width, P_MONITOR->output->cursor_swapchain->height)
|
||||||
.pos();
|
.pos();
|
||||||
|
|
||||||
|
@ -226,25 +231,36 @@ Handle cursor tick events.
|
||||||
*/
|
*/
|
||||||
void CDynamicCursors::onTick(CPointerManager* pointers) {
|
void CDynamicCursors::onTick(CPointerManager* pointers) {
|
||||||
static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr();
|
static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr();
|
||||||
|
static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr();
|
||||||
|
|
||||||
if (!strcmp(*PMODE, "tilt")) calculate();
|
if (!strcmp(*PMODE, "tilt") || **PSHAKE) calculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDynamicCursors::calculate() {
|
void CDynamicCursors::calculate() {
|
||||||
static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr();
|
static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr();
|
||||||
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_THRESHOLD)->getDataStaticPtr();
|
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();
|
||||||
|
|
||||||
|
double zoom = 1;
|
||||||
|
if (**PSHAKE)
|
||||||
|
zoom = calculateShake();
|
||||||
|
|
||||||
double angle = 0;
|
double angle = 0;
|
||||||
if (!strcmp(*PMODE, "rotate"))
|
if (!strcmp(*PMODE, "rotate"))
|
||||||
angle = calculateStick();
|
angle = calculateStick();
|
||||||
else if (!strcmp(*PMODE, "tilt"))
|
else if (!strcmp(*PMODE, "tilt"))
|
||||||
angle = calculateAir();
|
angle = calculateAir();
|
||||||
else
|
else if (strcmp(*PMODE, "none")) // if not none, print warning
|
||||||
Debug::log(WARN, "[dynamic-cursors] unknown mode specified");
|
Debug::log(WARN, "[dynamic-cursors] unknown mode specified");
|
||||||
|
|
||||||
|
if (zoom > 1 && !**PSHAKE_EFFECTS)
|
||||||
|
angle = 0;
|
||||||
|
|
||||||
// we only consider the angle changed if it is larger than 1 degree
|
// we only consider the angle changed if it is larger than 1 degree
|
||||||
if (abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD)) {
|
if (abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD) || abs(this->zoom - zoom) > 0.1) {
|
||||||
this->angle = angle;
|
this->angle = angle;
|
||||||
|
this->zoom = zoom;
|
||||||
|
|
||||||
// damage software and change hardware cursor shape
|
// damage software and change hardware cursor shape
|
||||||
g_pPointerManager->damageIfSoftware();
|
g_pPointerManager->damageIfSoftware();
|
||||||
|
@ -301,32 +317,52 @@ double CDynamicCursors::calculateAir() {
|
||||||
samples_index = (samples_index + 1) % max; // increase for next sample
|
samples_index = (samples_index + 1) % max; // increase for next sample
|
||||||
int first = samples_index;
|
int first = samples_index;
|
||||||
|
|
||||||
/* turns out this is not relevant on my systems (should've checked before implementing lol):
|
|
||||||
// motion smooting
|
|
||||||
// fills samples in between with linear approximations
|
|
||||||
// accomodates for mice with low polling rates and monitors with high fps
|
|
||||||
int previous = current == 0 ? max - 1 : current - 1;
|
|
||||||
if (samples[previous] != samples[current]) {
|
|
||||||
int steps = std::abs(samples_last_change - previous);
|
|
||||||
Vector2D amount = (samples[current] - samples[previous]) / steps;
|
|
||||||
|
|
||||||
int factor = 1;
|
|
||||||
for (int i = (samples_last_change + 1) % max; i != current; i = (i + 1) % max) {
|
|
||||||
samples[i] += amount * factor++;
|
|
||||||
}
|
|
||||||
|
|
||||||
samples_last_change = current;
|
|
||||||
} else if (samples_last_change == current) {
|
|
||||||
samples_last_change = first; // next is the last then
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// calculate speed and tilt
|
// calculate speed and tilt
|
||||||
double speed = (samples[current].x - samples[first].x) / 0.1;
|
double speed = (samples[current].x - samples[first].x) / 0.1;
|
||||||
|
|
||||||
return airFunction(speed) * (PI / 3); // 120° in both directions
|
return airFunction(speed) * (PI / 3); // 120° in both directions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double CDynamicCursors::calculateShake() {
|
||||||
|
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();
|
||||||
|
|
||||||
|
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate; // 1s worth of history
|
||||||
|
shake_samples.resize(max);
|
||||||
|
shake_samples_distance.resize(max);
|
||||||
|
|
||||||
|
int previous = shake_samples_index == 0 ? max - 1 : shake_samples_index - 1;
|
||||||
|
shake_samples[shake_samples_index] = Vector2D{g_pPointerManager->pointerPos};
|
||||||
|
shake_samples_distance[shake_samples_index] = shake_samples[shake_samples_index].distance(shake_samples[previous]);
|
||||||
|
shake_samples_index = (shake_samples_index + 1) % max; // increase for next sample
|
||||||
|
|
||||||
|
/*
|
||||||
|
The idea for this algorith was largely inspired by KDE Plasma
|
||||||
|
https://invent.kde.org/plasma/kwin/-/blob/master/src/plugins/shakecursor/shakedetector.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
// calculate total distance travelled
|
||||||
|
double trail = 0;
|
||||||
|
for (double distance : shake_samples_distance) trail += distance;
|
||||||
|
|
||||||
|
// calculate diagonal of bounding box travelled within
|
||||||
|
double left = 1e100, right = 0, bottom = 0, top = 1e100;
|
||||||
|
for (Vector2D position : shake_samples) {
|
||||||
|
left = std::min(left, position.x);
|
||||||
|
right = std::max(right, position.x);
|
||||||
|
top = std::min(top, position.y);
|
||||||
|
bottom = std::max(bottom, position.y);
|
||||||
|
}
|
||||||
|
double diagonal = Vector2D{left, top}.distance(Vector2D(right, bottom));
|
||||||
|
|
||||||
|
// discard when the diagonal is small, so we don't have issues with inaccuracies
|
||||||
|
if (diagonal < 100) return 1.0;
|
||||||
|
|
||||||
|
std::cout << trail << " " << diagonal << " " << (trail / diagonal) << "\n";
|
||||||
|
|
||||||
|
return std::max(1.0, ((trail / diagonal) - **PTHRESHOLD) * **PFACTOR);
|
||||||
|
}
|
||||||
|
|
||||||
double CDynamicCursors::calculateStick() {
|
double CDynamicCursors::calculateStick() {
|
||||||
static auto* const* PLENGTH = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_LENGTH)->getDataStaticPtr();
|
static auto* const* PLENGTH = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_LENGTH)->getDataStaticPtr();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ class CDynamicCursors {
|
||||||
private:
|
private:
|
||||||
// current angle of the cursor in radiants
|
// current angle of the cursor in radiants
|
||||||
double angle;
|
double angle;
|
||||||
|
// current zoom value of the cursor
|
||||||
|
double zoom = 1;
|
||||||
|
|
||||||
// calculates the current angle of the cursor, and changes the cursor shape
|
// calculates the current angle of the cursor, and changes the cursor shape
|
||||||
void calculate();
|
void calculate();
|
||||||
|
@ -39,6 +41,11 @@ class CDynamicCursors {
|
||||||
// ring buffer of last position samples
|
// ring buffer of last position samples
|
||||||
std::vector<Vector2D> samples;
|
std::vector<Vector2D> samples;
|
||||||
int samples_index = 0;
|
int samples_index = 0;
|
||||||
|
|
||||||
|
double calculateShake();
|
||||||
|
std::vector<Vector2D> shake_samples;
|
||||||
|
std::vector<double> shake_samples_distance;
|
||||||
|
int shake_samples_index = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<CDynamicCursors> g_pDynamicCursors;
|
inline std::unique_ptr<CDynamicCursors> g_pDynamicCursors;
|
||||||
|
|
|
@ -2,14 +2,19 @@
|
||||||
|
|
||||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||||
|
|
||||||
#define CONFIG_ENABLED "plugin:dynamic-cursors:enabled"
|
#define CONFIG_ENABLED "plugin:dynamic-cursors:enabled"
|
||||||
#define CONFIG_MODE "plugin:dynamic-cursors:mode"
|
#define CONFIG_MODE "plugin:dynamic-cursors:mode"
|
||||||
#define CONFIG_THRESHOLD "plugin:dynamic-cursors:threshold"
|
#define CONFIG_SHAKE "plugin:dynamic-cursors:shake"
|
||||||
#define CONFIG_LENGTH "plugin:dynamic-cursors:rotate:length"
|
#define CONFIG_THRESHOLD "plugin:dynamic-cursors:threshold"
|
||||||
#define CONFIG_MASS "plugin:dynamic-cursors:tilt:limit"
|
#define CONFIG_SHAKE_NEAREST "plugin:dynamic-cursors:shake:nearest"
|
||||||
#define CONFIG_FUNCTION "plugin:dynamic-cursors:tilt:function"
|
#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_LENGTH "plugin:dynamic-cursors:rotate:length"
|
||||||
|
#define CONFIG_MASS "plugin:dynamic-cursors:tilt:limit"
|
||||||
|
#define CONFIG_FUNCTION "plugin:dynamic-cursors:tilt:function"
|
||||||
|
|
||||||
#define CONFIG_HW_DEBUG "plugin:dynamic-cursors:hw_debug"
|
#define CONFIG_HW_DEBUG "plugin:dynamic-cursors:hw_debug"
|
||||||
|
|
||||||
inline HANDLE PHANDLE = nullptr;
|
inline HANDLE PHANDLE = nullptr;
|
||||||
|
|
||||||
|
|
14
src/main.cpp
14
src/main.cpp
|
@ -55,12 +55,10 @@ void hkOnCursorMoved(void* thisptr) {
|
||||||
else return (*(origOnCursorMoved)g_pOnCursorMovedHook->m_pOriginal)(thisptr);
|
else return (*(origOnCursorMoved)g_pOnCursorMovedHook->m_pOriginal)(thisptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTick() {
|
|
||||||
g_pDynamicCursors->onTick(g_pPointerManager.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
int onTick(void* data) {
|
int onTick(void* data) {
|
||||||
g_pDynamicCursors->onTick(g_pPointerManager.get());
|
static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
|
||||||
|
|
||||||
|
if (**PENABLED) g_pDynamicCursors->onTick(g_pPointerManager.get());
|
||||||
|
|
||||||
const int TIMEOUT = g_pHyprRenderer->m_pMostHzMonitor ? 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate : 16;
|
const int TIMEOUT = g_pHyprRenderer->m_pMostHzMonitor ? 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate : 16;
|
||||||
wl_event_source_timer_update(tick, TIMEOUT);
|
wl_event_source_timer_update(tick, TIMEOUT);
|
||||||
|
@ -111,6 +109,12 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MODE, Hyprlang::STRING{"tilt"});
|
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MODE, Hyprlang::STRING{"tilt"});
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_THRESHOLD, Hyprlang::INT{2});
|
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_THRESHOLD, Hyprlang::INT{2});
|
||||||
|
|
||||||
|
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_THRESHOLD, Hyprlang::FLOAT{4});
|
||||||
|
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_FACTOR, Hyprlang::FLOAT{1.5});
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_FUNCTION, Hyprlang::STRING{"negative_quadratic"});
|
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_FUNCTION, Hyprlang::STRING{"negative_quadratic"});
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MASS, Hyprlang::INT{5000});
|
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MASS, Hyprlang::INT{5000});
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotat
|
||||||
/*
|
/*
|
||||||
This renders a texture with damage but rotates the texture around a given hotspot.
|
This renders a texture with damage but rotates the texture around a given hotspot.
|
||||||
*/
|
*/
|
||||||
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot) {
|
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest) {
|
||||||
TRACY_GPU_ZONE("RenderDynamicCursor");
|
TRACY_GPU_ZONE("RenderDynamicCursor");
|
||||||
|
|
||||||
alpha = std::clamp(alpha, 0.f, 1.f);
|
alpha = std::clamp(alpha, 0.f, 1.f);
|
||||||
|
@ -75,7 +75,7 @@ void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(tex->m_iTarget, tex->m_iTexID);
|
glBindTexture(tex->m_iTarget, tex->m_iTexID);
|
||||||
|
|
||||||
if (g_pHyprOpenGL->m_RenderData.useNearestNeighbor) {
|
if (g_pHyprOpenGL->m_RenderData.useNearestNeighbor || nearest) {
|
||||||
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <hyprland/src/render/OpenGL.hpp>
|
#include <hyprland/src/render/OpenGL.hpp>
|
||||||
#include <hyprland/src/helpers/math/Math.hpp>
|
#include <hyprland/src/helpers/math/Math.hpp>
|
||||||
|
|
||||||
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot);
|
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest);
|
||||||
void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9], Vector2D hotspot);
|
void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9], Vector2D hotspot);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue