summaryrefslogtreecommitdiff
path: root/src/managers/CursorManager.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-03-09 16:52:59 +0000
committerGitHub <noreply@github.com>2024-03-09 16:52:59 +0000
commitc3882bb83240b602277f2d22f21d71690531f62e (patch)
treec5e9a1110cd5d22ef700fd8b7408a418cba7c4f0 /src/managers/CursorManager.cpp
parente7a5db4852d654596e554b9cdeaa2694b346ee03 (diff)
internal: Support libhyprcursor (#5009)
woo --------- Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
Diffstat (limited to 'src/managers/CursorManager.cpp')
-rw-r--r--src/managers/CursorManager.cpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp
new file mode 100644
index 00000000..ae765016
--- /dev/null
+++ b/src/managers/CursorManager.cpp
@@ -0,0 +1,200 @@
+#include "CursorManager.hpp"
+#include "Compositor.hpp"
+#include "../config/ConfigValue.hpp"
+
+extern "C" {
+#include <wlr/interfaces/wlr_buffer.h>
+#include <wlr/types/wlr_xcursor_manager.h>
+}
+
+static int cursorAnimTimer(void* data) {
+ g_pCursorManager->tickAnimatedCursor();
+ return 1;
+}
+
+CCursorManager::CCursorManager() {
+ m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str());
+
+ // find default size. First, HYPRCURSOR_SIZE, then XCURSOR_SIZE, then 24
+ auto SIZE = getenv("HYPRCURSOR_SIZE");
+ if (SIZE) {
+ try {
+ m_iSize = std::stoi(SIZE);
+ } catch (...) { ; }
+ }
+
+ SIZE = getenv("XCURSOR_SIZE");
+ if (SIZE && m_iSize == 0) {
+ try {
+ m_iSize = std::stoi(SIZE);
+ } catch (...) { ; }
+ }
+
+ if (m_iSize == 0)
+ m_iSize = 24;
+
+ m_pWLRXCursorMgr = wlr_xcursor_manager_create(nullptr, m_iSize);
+ wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0);
+
+ m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
+
+ updateTheme();
+
+ g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateTheme(); });
+}
+
+void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
+ std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; });
+}
+
+static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) {
+ CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
+ g_pCursorManager->dropBufferRef(buffer->parent);
+}
+
+static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t flags, void** data, uint32_t* format, size_t* stride) {
+ CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
+
+ if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE)
+ return false;
+
+ *data = cairo_image_surface_get_data(buffer->surface);
+ *stride = cairo_image_surface_get_stride(buffer->surface);
+ *format = DRM_FORMAT_ARGB8888;
+ return true;
+}
+
+static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) {
+ ;
+}
+
+//
+static const wlr_buffer_impl bufferImpl = {
+ .destroy = cursorBufferDestroy,
+ .begin_data_ptr_access = cursorBufferBeginDataPtr,
+ .end_data_ptr_access = cursorBufferEndDataPtr,
+};
+
+CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
+ wlrBuffer.surface = surf;
+ wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
+ wlrBuffer.parent = this;
+}
+
+CCursorManager::CCursorBuffer::~CCursorBuffer() {
+ ; // will be freed in .destroy
+}
+
+wlr_buffer* CCursorManager::getCursorBuffer() {
+ return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
+}
+
+void CCursorManager::setCursorSurface(wlr_surface* surf, const Vector2D& hotspot) {
+ wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspot.x, hotspot.y);
+
+ m_bOurBufferConnected = false;
+}
+
+void CCursorManager::setCursorFromName(const std::string& name) {
+
+ static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("misc:enable_hyprcursor");
+
+ if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) {
+ wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str());
+ return;
+ }
+
+ m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo);
+
+ if (m_sCurrentCursorShapeData.images.size() < 1) {
+ Debug::log(ERR, "BUG THIS: No cursor returned by getShape()");
+ return;
+ }
+
+ m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface,
+ Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
+ Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
+
+ if (g_pCompositor->m_sWLRCursor)
+ wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY,
+ m_fCursorScale);
+
+ m_bOurBufferConnected = true;
+
+ if (m_sCurrentCursorShapeData.images.size() > 1) {
+ // animated
+ wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[0].delay);
+ m_iCurrentAnimationFrame = 0;
+ } else {
+ // disarm
+ wl_event_source_timer_update(m_pAnimationTimer, 0);
+ }
+}
+
+void CCursorManager::tickAnimatedCursor() {
+ if (m_sCurrentCursorShapeData.images.size() < 2 || !m_bOurBufferConnected)
+ return;
+
+ m_iCurrentAnimationFrame++;
+ if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size())
+ m_iCurrentAnimationFrame = 0;
+
+ m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(
+ m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface,
+ Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size},
+ Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));
+
+ if (g_pCompositor->m_sWLRCursor)
+ wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX,
+ m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY, m_fCursorScale);
+
+ wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay);
+}
+
+SCursorImageData CCursorManager::dataFor(const std::string& name) {
+ const auto IMAGES = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo);
+
+ if (IMAGES.images.empty())
+ return {};
+
+ return IMAGES.images[0];
+}
+
+void CCursorManager::updateTheme() {
+ float highestScale = 1.0;
+
+ for (auto& m : g_pCompositor->m_vMonitors) {
+ if (m->scale > highestScale)
+ highestScale = m->scale;
+ }
+
+ if (highestScale * m_iSize == m_sCurrentStyleInfo.size)
+ return;
+
+ if (m_sCurrentStyleInfo.size && m_pHyprcursor->valid())
+ m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo);
+
+ m_sCurrentStyleInfo.size = m_iSize * highestScale;
+ m_fCursorScale = highestScale;
+
+ if (m_pHyprcursor->valid())
+ m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo);
+
+ setCursorFromName("left_ptr");
+
+ for (auto& m : g_pCompositor->m_vMonitors) {
+ m->forceFullFrames = 5;
+ g_pCompositor->scheduleFrameForMonitor(m.get());
+ }
+}
+
+void CCursorManager::changeTheme(const std::string& name, const int size) {
+ m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str());
+ m_szTheme = name;
+ m_iSize = size;
+
+ setenv("XCURSOR_SIZE", std::to_string(m_iSize).c_str(), true);
+ setenv("XCURSOR_THEME", name.c_str(), true);
+
+ updateTheme();
+}