mirror of
https://github.com/virtcode/hypr-dynamic-cursors
synced 2025-09-20 00:23:22 +02:00
feat: inefficient support for hardware cursors
This commit is contained in:
parent
facfa7f356
commit
581a094b7b
6 changed files with 339 additions and 2 deletions
148
src/cursor.cpp
148
src/cursor.cpp
|
@ -1,18 +1,29 @@
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#define private public
|
#define private public
|
||||||
#include <hyprland/src/managers/PointerManager.hpp>
|
#include <hyprland/src/managers/PointerManager.hpp>
|
||||||
#include <hyprland/src/render/OpenGL.hpp>
|
#include <hyprland/src/render/OpenGL.hpp>
|
||||||
|
#include <hyprland/src/Compositor.hpp>
|
||||||
#undef private
|
#undef private
|
||||||
|
|
||||||
#include <hyprland/src/Compositor.hpp>
|
|
||||||
#include <hyprland/src/config/ConfigValue.hpp>
|
#include <hyprland/src/config/ConfigValue.hpp>
|
||||||
|
#include "hyprland/cursor.hpp"
|
||||||
|
|
||||||
|
#include <hyprland/wlr/interfaces/wlr_output.h>
|
||||||
|
#include <hyprland/wlr/render/interface.h>
|
||||||
|
#include <hyprland/wlr/render/wlr_renderer.h>
|
||||||
|
|
||||||
#include "cursor.hpp"
|
#include "cursor.hpp"
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
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) {
|
void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
|
||||||
|
|
||||||
if (!pointers->hasCursor())
|
if (!pointers->hasCursor())
|
||||||
|
@ -46,6 +57,10 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMo
|
||||||
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot);
|
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function implements damaging the screen such that the software cursor is drawn.
|
||||||
|
It is largely identical to hyprlands implementation, but expands the damage reagion, to accomodate various rotations.
|
||||||
|
*/
|
||||||
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
|
||||||
|
@ -65,6 +80,137 @@ void CDynamicCursors::damageSoftware(CPointerManager* pointers) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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();
|
||||||
|
|
||||||
|
auto output = state->monitor->output;
|
||||||
|
|
||||||
|
auto size = pointers->currentCursorImage.size;
|
||||||
|
// we try to allocate a buffer that is thrice as big, see software rendering
|
||||||
|
auto target = size * 3;
|
||||||
|
|
||||||
|
if (output->impl->get_cursor_size) {
|
||||||
|
int w, h;
|
||||||
|
output->impl->get_cursor_size(output, &w, &h);
|
||||||
|
|
||||||
|
if (w < target.x || h < target.y) {
|
||||||
|
Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", pointers->currentCursorImage.size, w, h);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.x = w;
|
||||||
|
target.y = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.x <= 0 || target.y <= 0) {
|
||||||
|
Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, target.x, target.y);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output->cursor_swapchain || target != Vector2D{output->cursor_swapchain->width, output->cursor_swapchain->height}) {
|
||||||
|
wlr_drm_format fmt = {0};
|
||||||
|
if (!output_pick_cursor_format(output, &fmt)) {
|
||||||
|
Debug::log(TRACE, "Failed to pick cursor format");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_swapchain_destroy(output->cursor_swapchain);
|
||||||
|
output->cursor_swapchain = wlr_swapchain_create(output->allocator, target.x, target.y, &fmt);
|
||||||
|
wlr_drm_format_finish(&fmt);
|
||||||
|
|
||||||
|
if (!output->cursor_swapchain) {
|
||||||
|
Debug::log(TRACE, "Failed to create cursor swapchain");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr);
|
||||||
|
if (!buf) {
|
||||||
|
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRegion damage = {0, 0, INT16_MAX, INT16_MAX};
|
||||||
|
|
||||||
|
g_pHyprRenderer->makeEGLCurrent();
|
||||||
|
g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); // has to be set cuz allocs
|
||||||
|
|
||||||
|
const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, DRM_FORMAT_ARGB8888);
|
||||||
|
RBO->bind();
|
||||||
|
|
||||||
|
g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO);
|
||||||
|
|
||||||
|
if (**PHW_DEBUG)
|
||||||
|
g_pHyprOpenGL->clear(CColor{rand() / float(RAND_MAX), rand() / float(RAND_MAX), rand() / float(RAND_MAX), 1.F});
|
||||||
|
else
|
||||||
|
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
|
||||||
|
CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale}.round()};
|
||||||
|
xbox.rot = this->calculate(&pointers->pointerPos);
|
||||||
|
|
||||||
|
// use our custom draw function
|
||||||
|
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot);
|
||||||
|
|
||||||
|
g_pHyprOpenGL->end();
|
||||||
|
glFlush();
|
||||||
|
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
|
||||||
|
|
||||||
|
wlr_buffer_unlock(buf);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Implements the hardware cursor setting.
|
||||||
|
It is also mostly the same as stock hyprland, but with the hotspot translated more into the middle.
|
||||||
|
*/
|
||||||
|
bool CDynamicCursors::setHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, wlr_buffer* buf) {
|
||||||
|
if (!state->monitor->output->impl->set_cursor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto HOTSPOT = pointers->transformedHotspot(state->monitor.lock());
|
||||||
|
|
||||||
|
Debug::log(TRACE, "[pointer] hw transformed hotspot for {}: {}", state->monitor->szName, HOTSPOT);
|
||||||
|
|
||||||
|
if (!state->monitor->output->impl->set_cursor(state->monitor->output, buf, HOTSPOT.x + pointers->currentCursorImage.size.x, HOTSPOT.y + pointers->currentCursorImage.size.y))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
wlr_buffer_unlock(state->cursorFrontBuffer);
|
||||||
|
state->cursorFrontBuffer = buf;
|
||||||
|
|
||||||
|
g_pCompositor->scheduleFrameForMonitor(state->monitor.get());
|
||||||
|
|
||||||
|
if (buf)
|
||||||
|
wlr_buffer_lock(buf);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Handles cursor move events.
|
||||||
|
*/
|
||||||
|
void CDynamicCursors::onCursorMoved(CPointerManager* pointers) {
|
||||||
|
if (!pointers->hasCursor())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||||
|
auto state = pointers->stateFor(m);
|
||||||
|
|
||||||
|
state->box = pointers->getCursorBoxLogicalForMonitor(state->monitor.lock());
|
||||||
|
|
||||||
|
if (state->hardwareFailed || !state->entered)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// we set a new hardware cursor on every move
|
||||||
|
pointers->attemptHardwareCursor(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double CDynamicCursors::calculate(Vector2D* pos) {
|
double CDynamicCursors::calculate(Vector2D* pos) {
|
||||||
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();
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
#define private public
|
||||||
#include <hyprland/src/managers/PointerManager.hpp>
|
#include <hyprland/src/managers/PointerManager.hpp>
|
||||||
|
#undef private
|
||||||
#include <hyprutils/math/Vector2D.hpp>
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
class CDynamicCursors;
|
class CDynamicCursors;
|
||||||
|
|
||||||
class CDynamicCursors {
|
class CDynamicCursors {
|
||||||
public:
|
public:
|
||||||
|
/* hook on onCursorMoved */
|
||||||
|
void onCursorMoved(CPointerManager* pointers);
|
||||||
|
|
||||||
/* hook on renderSoftwareCursorsFor */
|
/* hook on renderSoftwareCursorsFor */
|
||||||
void renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos);
|
void renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos);
|
||||||
/* hook on damageIfSoftware*/
|
/* hook on damageIfSoftware*/
|
||||||
void damageSoftware(CPointerManager* pointers);
|
void damageSoftware(CPointerManager* pointers);
|
||||||
|
/* hook on renderHWCursorBuffer */
|
||||||
|
wlr_buffer* renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture);
|
||||||
|
/* hook on setHWCursorBuffer */
|
||||||
|
bool setHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, wlr_buffer* buf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// calculates the current angle of the cursor
|
// calculates the current angle of the cursor
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||||
|
|
||||||
#define CONFIG_LENGTH "plugin:dynamic-cursors:length"
|
#define CONFIG_LENGTH "plugin:dynamic-cursors:length"
|
||||||
|
#define CONFIG_HW_DEBUG "plugin:dynamic-cursors:hw_debug"
|
||||||
|
|
||||||
inline HANDLE PHANDLE = nullptr;
|
inline HANDLE PHANDLE = nullptr;
|
||||||
|
|
137
src/hyprland/cursor.cpp
Normal file
137
src/hyprland/cursor.cpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
|
||||||
|
#include <hyprland/src/managers/PointerManager.hpp>
|
||||||
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
|
||||||
|
#include <hyprland/wlr/interfaces/wlr_output.h>
|
||||||
|
#include <hyprland/wlr/render/interface.h>
|
||||||
|
#include <hyprland/wlr/render/wlr_renderer.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following functions are copied 1:1 from the hyprland codebase.
|
||||||
|
This is nessecary, as these are static interop functions which wlroots which are not accessible through headers.
|
||||||
|
Will probably be obsolete anyway after https://github.com/hyprwm/Hyprland/pull/6608
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: make nicer
|
||||||
|
// this will come with the eventual rewrite of wlr_drm, etc...
|
||||||
|
bool wlr_drm_format_intersect(wlr_drm_format* dst, const wlr_drm_format* a, const wlr_drm_format* b) {
|
||||||
|
ASSERT(a->format == b->format);
|
||||||
|
|
||||||
|
size_t capacity = a->len < b->len ? a->len : b->len;
|
||||||
|
uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * capacity);
|
||||||
|
if (!modifiers)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct wlr_drm_format fmt = {
|
||||||
|
.format = a->format,
|
||||||
|
.len = 0,
|
||||||
|
.capacity = capacity,
|
||||||
|
.modifiers = modifiers,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < a->len; i++) {
|
||||||
|
for (size_t j = 0; j < b->len; j++) {
|
||||||
|
if (a->modifiers[i] == b->modifiers[j]) {
|
||||||
|
ASSERT(fmt.len < fmt.capacity);
|
||||||
|
fmt.modifiers[fmt.len++] = a->modifiers[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_drm_format_finish(dst);
|
||||||
|
*dst = fmt;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_drm_format_copy(wlr_drm_format* dst, const wlr_drm_format* src) {
|
||||||
|
ASSERT(src->len <= src->capacity);
|
||||||
|
|
||||||
|
uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * src->len);
|
||||||
|
if (!modifiers)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(modifiers, src->modifiers, sizeof(*modifiers) * src->len);
|
||||||
|
|
||||||
|
wlr_drm_format_finish(dst);
|
||||||
|
dst->capacity = src->len;
|
||||||
|
dst->len = src->len;
|
||||||
|
dst->format = src->format;
|
||||||
|
dst->modifiers = modifiers;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wlr_drm_format_set* wlr_renderer_get_render_formats(wlr_renderer* r) {
|
||||||
|
if (!r->impl->get_render_formats)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return r->impl->get_render_formats(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool output_pick_format(wlr_output* output, const wlr_drm_format_set* display_formats, wlr_drm_format* format, uint32_t fmt) {
|
||||||
|
|
||||||
|
const wlr_drm_format_set* render_formats = wlr_renderer_get_render_formats(g_pCompositor->m_sWLRRenderer);
|
||||||
|
if (render_formats == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get render formats");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wlr_drm_format* render_format = wlr_drm_format_set_get(render_formats, fmt);
|
||||||
|
if (render_format == NULL) {
|
||||||
|
wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%" PRIX32, fmt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display_formats != NULL) {
|
||||||
|
const wlr_drm_format* display_format = wlr_drm_format_set_get(display_formats, fmt);
|
||||||
|
if (display_format == NULL) {
|
||||||
|
wlr_log(WLR_DEBUG, "Output doesn't support format 0x%" PRIX32, fmt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_drm_format_intersect(format, display_format, render_format)) {
|
||||||
|
wlr_log(WLR_DEBUG,
|
||||||
|
"Failed to intersect display and render "
|
||||||
|
"modifiers for format 0x%" PRIX32 " on output %s",
|
||||||
|
fmt, output->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The output can display any format
|
||||||
|
if (!wlr_drm_format_copy(format, render_format))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format->len == 0) {
|
||||||
|
wlr_drm_format_finish(format);
|
||||||
|
wlr_log(WLR_DEBUG, "Failed to pick output format");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_format* format) {
|
||||||
|
struct wlr_allocator* allocator = output->allocator;
|
||||||
|
ASSERT(allocator != NULL);
|
||||||
|
|
||||||
|
const struct wlr_drm_format_set* display_formats = NULL;
|
||||||
|
if (output->impl->get_cursor_formats) {
|
||||||
|
display_formats = output->impl->get_cursor_formats(output, allocator->buffer_caps);
|
||||||
|
if (display_formats == NULL) {
|
||||||
|
wlr_log(WLR_DEBUG, "Failed to get cursor display formats");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: taken from https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4596/diffs#diff-content-e3ea164da86650995728d70bd118f6aa8c386797
|
||||||
|
// If this fails to find a shared modifier try to use a linear
|
||||||
|
// modifier. This avoids a scenario where the hardware cannot render to
|
||||||
|
// linear textures but only linear textures are supported for cursors,
|
||||||
|
// as is the case with Nvidia and VmWare GPUs
|
||||||
|
if (!output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888)) {
|
||||||
|
// Clear the format as output_pick_format doesn't zero it
|
||||||
|
memset(format, 0, sizeof(*format));
|
||||||
|
return output_pick_format(output, NULL, format, DRM_FORMAT_ARGB8888);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
13
src/hyprland/cursor.hpp
Normal file
13
src/hyprland/cursor.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include <hyprland/src/managers/PointerManager.hpp>
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following functions are copied 1:1 from the hyprland codebase.
|
||||||
|
This is nessecary, as these are static interop functions which wlroots which are not accessible through headers.
|
||||||
|
Will probably be obsolete anyway after https://github.com/hyprwm/Hyprland/pull/6608
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool wlr_drm_format_intersect(wlr_drm_format* dst, const wlr_drm_format* a, const wlr_drm_format* b);
|
||||||
|
bool wlr_drm_format_copy(wlr_drm_format* dst, const wlr_drm_format* src);
|
||||||
|
const wlr_drm_format_set* wlr_renderer_get_render_formats(wlr_renderer* r);
|
||||||
|
bool output_pick_format(wlr_output* output, const wlr_drm_format_set* display_formats, wlr_drm_format* format, uint32_t fmt);
|
||||||
|
bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_format* format);
|
31
src/main.cpp
31
src/main.cpp
|
@ -20,6 +20,24 @@ void hkDamageIfSoftware(void* thisptr) {
|
||||||
g_pDynamicCursors->damageSoftware((CPointerManager*) thisptr);
|
g_pDynamicCursors->damageSoftware((CPointerManager*) 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) {
|
||||||
|
return g_pDynamicCursors->renderHardware((CPointerManager*) 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) {
|
||||||
|
return g_pDynamicCursors->setHardware((CPointerManager*) thisptr, state, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*origOnCursorMoved)(void*);
|
||||||
|
inline CFunctionHook* g_pOnCursorMovedHook = nullptr;
|
||||||
|
void hkOnCursorMoved(void* thisptr) {
|
||||||
|
return g_pDynamicCursors->onCursorMoved((CPointerManager*) thisptr);
|
||||||
|
}
|
||||||
|
|
||||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
PHANDLE = handle;
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
@ -41,7 +59,20 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
g_pDamageIfSoftwareHook = HyprlandAPI::createFunctionHook(PHANDLE, DAMAGE_IF_SOFTWARE_METHODS[0].address, (void*) &hkDamageIfSoftware);
|
g_pDamageIfSoftwareHook = HyprlandAPI::createFunctionHook(PHANDLE, DAMAGE_IF_SOFTWARE_METHODS[0].address, (void*) &hkDamageIfSoftware);
|
||||||
g_pDamageIfSoftwareHook->hook();
|
g_pDamageIfSoftwareHook->hook();
|
||||||
|
|
||||||
|
static const auto RENDER_HW_CURSOR_BUFFER_METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "renderHWCursorBuffer");
|
||||||
|
g_pRenderHWCursorBufferHook = HyprlandAPI::createFunctionHook(PHANDLE, RENDER_HW_CURSOR_BUFFER_METHODS[0].address, (void*) &hkRenderHWCursorBuffer);
|
||||||
|
g_pRenderHWCursorBufferHook->hook();
|
||||||
|
|
||||||
|
static const auto SET_HW_CURSOR_BUFFER_METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "setHWCursorBuffer");
|
||||||
|
g_pSetHWCursorBufferHook = HyprlandAPI::createFunctionHook(PHANDLE, SET_HW_CURSOR_BUFFER_METHODS[0].address, (void*) &hkSetHWCursorBuffer);
|
||||||
|
g_pSetHWCursorBufferHook->hook();
|
||||||
|
|
||||||
|
static const auto ON_CURSOR_MOVED_METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "onCursorMoved");
|
||||||
|
g_pOnCursorMovedHook = HyprlandAPI::createFunctionHook(PHANDLE, ON_CURSOR_MOVED_METHODS[0].address, (void*) &hkOnCursorMoved);
|
||||||
|
g_pOnCursorMovedHook->hook();
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_LENGTH, Hyprlang::INT{20});
|
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_LENGTH, Hyprlang::INT{20});
|
||||||
|
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_HW_DEBUG, Hyprlang::INT{0});
|
||||||
|
|
||||||
return {"dynamic-cursors", "The most stupid cursor plugin.", "Virt", "1.1"};
|
return {"dynamic-cursors", "The most stupid cursor plugin.", "Virt", "1.1"};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue