aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTom Englund <[email protected]>2024-08-05 19:58:21 +0200
committerGitHub <[email protected]>2024-08-05 19:58:21 +0200
commit0e86808e5912823f1c6bea1b6d5fcae297fc9f57 (patch)
tree261ff4c9a108ef9d2de1c151685d52d85405497d
parent2b520571e897be2a0e88c8692da607b062000038 (diff)
downloadHyprland-0e86808e5912823f1c6bea1b6d5fcae297fc9f57.tar.gz
Hyprland-0e86808e5912823f1c6bea1b6d5fcae297fc9f57.zip
cursor: Better xcursor implementation (#7178)
* xcursor: bootleg xcursors into its own manager implent XCursorManager and load themes based on librarypath and its dir, now we catch all supplied theme files. and also implent animated cursors. also refactor a bit of spaghetti regarding xcursors in CursorManager. * hyprcursor: fix buffer leak animated cursors are creating a new buffer for each image, ensure we drop the buffers so it continously doesnt build up in infinity. * cursormgr: use eventloopmgr for animation use EvenloopManager for timers instead of adding it directly to m_sWLEventLoop and using its related wl_* functions.
-rw-r--r--src/managers/CursorManager.cpp472
-rw-r--r--src/managers/CursorManager.hpp26
-rw-r--r--src/managers/XCursorManager.cpp447
-rw-r--r--src/managers/XCursorManager.hpp46
4 files changed, 584 insertions, 407 deletions
diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp
index e0d3a62c..9b574901 100644
--- a/src/managers/CursorManager.cpp
+++ b/src/managers/CursorManager.cpp
@@ -3,15 +3,10 @@
#include "../config/ConfigValue.hpp"
#include "PointerManager.hpp"
#include "../xwayland/XWayland.hpp"
-#include <cstring>
-#include "../helpers/CursorShapes.hpp"
-extern "C" {
-#include <X11/Xcursor/Xcursor.h>
-}
-
-static int cursorAnimTimer(void* data) {
- g_pCursorManager->tickAnimatedCursor();
+static int cursorAnimTimer(SP<CEventLoopTimer> self, void* data) {
+ const auto cursorMgr = reinterpret_cast<CCursorManager*>(data);
+ cursorMgr->tickAnimatedCursor();
return 1;
}
@@ -24,31 +19,41 @@ static void hcLogger(enum eHyprcursorLogLevel level, char* message) {
CCursorManager::CCursorManager() {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger);
+ m_pXcursor = std::make_unique<CXCursorManager>();
- if (!m_pHyprcursor->valid())
- Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme);
-
- // 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 (...) { ; }
- }
+ if (m_pHyprcursor->valid()) {
+ // find default size. First, HYPRCURSOR_SIZE then default to 24
+ auto const* 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) {
+ Debug::log(WARN, "HYPRCURSOR_SIZE size not set, defaulting to size 24");
+ m_iSize = 24;
+ }
+ } else {
+ Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to Xcursor.", m_szTheme);
- if (m_iSize == 0)
- m_iSize = 24;
+ auto const* SIZE = getenv("XCURSOR_SIZE");
+ if (SIZE) {
+ try {
+ m_iSize = std::stoi(SIZE);
+ } catch (...) { ; }
+ }
- xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale));
+ if (m_iSize <= 0) {
+ Debug::log(WARN, "XCURSOR_SIZE size not set, defaulting to size 24");
+ m_iSize = 24;
+ }
+
+ m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale));
+ }
- m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
+ m_pAnimationTimer = makeShared<CEventLoopTimer>(std::nullopt, cursorAnimTimer, this);
+ g_pEventLoopManager->addTimer(m_pAnimationTimer);
updateTheme();
@@ -56,8 +61,10 @@ CCursorManager::CCursorManager() {
}
CCursorManager::~CCursorManager() {
- if (m_pAnimationTimer)
- wl_event_source_remove(m_pAnimationTimer);
+ if (m_pAnimationTimer && g_pEventLoopManager) {
+ g_pEventLoopManager->removeTimer(m_pAnimationTimer);
+ m_pAnimationTimer.reset();
+ }
}
void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
@@ -133,30 +140,26 @@ void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotsp
void CCursorManager::setXCursor(const std::string& name) {
float scale = std::ceil(m_fCursorScale);
- if (!xcursor.themeLoaded) {
- Debug::log(ERR, "XCursor failed to find theme in setXCursor");
- if (!xcursor.defaultCursor) {
- g_pPointerManager->resetCursorImage();
- return;
- }
- }
-
- auto& icon = xcursor.defaultCursor;
- // try to get an icon we know if we have one
- for (auto const& c : xcursor.cursors) {
- if (c.first != name)
- continue;
-
- icon = c.second;
- }
+ auto xcursor = m_pXcursor->getShape(name, m_iSize * scale);
+ auto& icon = xcursor->images.front();
- m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot));
+ m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot));
- g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon->hotspot / scale, scale);
+ g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale);
if (m_vCursorBuffers.size() > 1)
dropBufferRef(m_vCursorBuffers.at(0).get());
+ m_currentXcursor = xcursor;
m_bOurBufferConnected = true;
+
+ if (m_currentXcursor->images.size() > 1) {
+ // animated
+ m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[0].delay));
+ m_iCurrentAnimationFrame = 0;
+ } else {
+ // disarm
+ m_pAnimationTimer->updateTimeout(std::nullopt);
+ }
}
void CCursorManager::setCursorFromName(const std::string& name) {
@@ -209,15 +212,35 @@ void CCursorManager::setCursorFromName(const std::string& name) {
if (m_sCurrentCursorShapeData.images.size() > 1) {
// animated
- wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[0].delay);
+ m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[0].delay));
m_iCurrentAnimationFrame = 0;
} else {
// disarm
- wl_event_source_timer_update(m_pAnimationTimer, 0);
+ m_pAnimationTimer->updateTimeout(std::nullopt);
}
}
void CCursorManager::tickAnimatedCursor() {
+ if (!m_pHyprcursor->valid() && m_currentXcursor->images.size() > 1 && m_bOurBufferConnected) {
+ m_iCurrentAnimationFrame++;
+
+ if ((size_t)m_iCurrentAnimationFrame >= m_currentXcursor->images.size())
+ m_iCurrentAnimationFrame = 0;
+
+ float scale = std::ceil(m_fCursorScale);
+ auto& icon = m_currentXcursor->images.at(m_iCurrentAnimationFrame);
+ m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot));
+
+ g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale);
+
+ if (m_vCursorBuffers.size() > 1)
+ dropBufferRef(m_vCursorBuffers.at(0).get());
+
+ m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[m_iCurrentAnimationFrame].delay));
+
+ return;
+ }
+
if (m_sCurrentCursorShapeData.images.size() < 2 || !m_bOurBufferConnected)
return;
@@ -235,7 +258,10 @@ void CCursorManager::tickAnimatedCursor() {
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale,
m_fCursorScale);
- wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay);
+ if (m_vCursorBuffers.size() > 1)
+ dropBufferRef(m_vCursorBuffers.at(0).get());
+
+ m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay));
}
SCursorImageData CCursorManager::dataFor(const std::string& name) {
@@ -256,10 +282,12 @@ void CCursorManager::setXWaylandCursor() {
if (CURSOR.surface) {
g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size},
{CURSOR.hotspotX, CURSOR.hotspotY});
- } else if (xcursor.themeLoaded)
- g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot);
- else
- Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
+ } else {
+ auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale));
+ auto& icon = xcursor->images.front();
+
+ g_pXWayland->setCursor((uint8_t*)icon.pixels.data(), icon.size.x * 4, icon.size, icon.hotspot);
+ }
}
void CCursorManager::updateTheme() {
@@ -300,340 +328,12 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) {
return true;
}
- Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name);
+ Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", name);
- xcursor.loadTheme(name, size);
+ m_pXcursor->loadTheme(name, size);
m_szTheme = name;
m_iSize = size;
updateTheme();
return true;
-}
-
-// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
-// _ -> -
-// clang-format off
-static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
- "X_cursor",
- "arrow",
- "based_arrow_down",
- "based_arrow_up",
- "boat",
- "bogosity",
- "bottom_left_corner",
- "bottom_right_corner",
- "bottom_side",
- "bottom_tee",
- "box_spiral",
- "center_ptr",
- "circle",
- "clock",
- "coffee_mug",
- "cross",
- "cross_reverse",
- "crosshair",
- "diamond_cross",
- "dot",
- "dotbox",
- "double_arrow",
- "draft_large",
- "draft_small",
- "draped_box",
- "exchange",
- "fleur",
- "gobbler",
- "gumby",
- "hand1",
- "hand2",
- "heart",
- "icon",
- "iron_cross",
- "left_ptr",
- "left_side",
- "left_tee",
- "leftbutton",
- "ll_angle",
- "lr_angle",
- "man",
- "middlebutton",
- "mouse",
- "pencil",
- "pirate",
- "plus",
- "question_arrow",
- "right_ptr",
- "right_side",
- "right_tee",
- "rightbutton",
- "rtl_logo",
- "sailboat",
- "sb_down_arrow",
- "sb_h_double_arrow",
- "sb_left_arrow",
- "sb_right_arrow",
- "sb_up_arrow",
- "sb_v_double_arrow",
- "shuttle",
- "sizing",
- "spider",
- "spraycan",
- "star",
- "target",
- "tcross",
- "top_left_arrow",
- "top_left_corner",
- "top_right_corner",
- "top_side",
- "top_tee",
- "trek",
- "ul_angle",
- "umbrella",
- "ur_angle",
- "watch",
- "xterm",
-};
-// clang-format on
-
-void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) {
- if (lastLoadSize == size && themeName == name)
- return;
-
- lastLoadSize = size;
- themeLoaded = false;
- themeName = name.empty() ? "default" : name;
-
- std::vector<std::pair<std::string, SP<SXCursor>>> newCursors;
-
- // load the default xcursor shapes that exist in the theme
- for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
- auto shape = XCURSOR_STANDARD_NAMES.at(i);
- auto xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), size);
-
- if (!xImage) {
- Debug::log(LOG, "XCursor failed to find a shape with name {}, trying size 24.", shape);
- xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), 24);
-
- if (!xImage) {
- Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape);
- continue;
- }
- }
-
- auto xcursor = makeShared<SXCursor>();
- xcursor->size = {(int)xImage->width, (int)xImage->height};
- xcursor->hotspot = {(int)xImage->xhot, (int)xImage->yhot};
-
- xcursor->pixels.resize(xImage->width * xImage->height);
- std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
-
- newCursors.emplace_back(std::string{shape}, xcursor);
-
- XcursorImageDestroy(xImage);
- }
-
- if (newCursors.empty()) {
- Debug::log(ERR, "XCursor failed finding any shapes in theme \"{}\".", themeName);
- if (!defaultCursor) {
- defaultCursor = createDefaultCursor();
- }
- return;
- }
-
- cursors.clear();
- cursors = std::move(newCursors);
- defaultCursor.reset();
- themeLoaded = true;
-
- for (auto const& shape : CURSOR_SHAPE_NAMES) {
- auto legacyName = getLegacyShapeName(shape);
- if (legacyName.empty())
- continue;
-
- auto it = std::find_if(cursors.begin(), cursors.end(), [&legacyName](auto const& c) { return c.first == legacyName; });
-
- if (it == cursors.end()) {
- Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName);
- continue;
- }
-
- cursors.emplace_back(shape, it->second);
- }
-
- // set default cursor
- for (auto const& c : cursors) {
- if (c.first == "left_ptr" || c.first == "arrow") {
- defaultCursor = c.second;
- break;
- }
- }
-
- // just assign the first one then.
- if (!defaultCursor)
- defaultCursor = cursors.at(0).second;
-}
-
-std::string CCursorManager::SXCursorManager::getLegacyShapeName(std::string const& shape) {
- if (shape == "invalid")
- return std::string();
- else if (shape == "default")
- return "left_ptr";
- else if (shape == "context-menu")
- return "left_ptr";
- else if (shape == "help")
- return "left_ptr";
- else if (shape == "pointer")
- return "hand2";
- else if (shape == "progress")
- return "watch";
- else if (shape == "wait")
- return "watch";
- else if (shape == "cell")
- return "plus";
- else if (shape == "crosshair")
- return "cross";
- else if (shape == "text")
- return "xterm";
- else if (shape == "vertical-text")
- return "xterm";
- else if (shape == "alias")
- return "dnd-link";
- else if (shape == "copy")
- return "dnd-copy";
- else if (shape == "move")
- return "dnd-move";
- else if (shape == "no-drop")
- return "dnd-none";
- else if (shape == "not-allowed")
- return "crossed_circle";
- else if (shape == "grab")
- return "hand1";
- else if (shape == "grabbing")
- return "hand1";
- else if (shape == "e-resize")
- return "right_side";
- else if (shape == "n-resize")
- return "top_side";
- else if (shape == "ne-resize")
- return "top_right_corner";
- else if (shape == "nw-resize")
- return "top_left_corner";
- else if (shape == "s-resize")
- return "bottom_side";
- else if (shape == "se-resize")
- return "bottom_right_corner";
- else if (shape == "sw-resize")
- return "bottom_left_corner";
- else if (shape == "w-resize")
- return "left_side";
- else if (shape == "ew-resize")
- return "sb_h_double_arrow";
- else if (shape == "ns-resize")
- return "sb_v_double_arrow";
- else if (shape == "nesw-resize")
- return "fd_double_arrow";
- else if (shape == "nwse-resize")
- return "bd_double_arrow";
- else if (shape == "col-resize")
- return "sb_h_double_arrow";
- else if (shape == "row-resize")
- return "sb_v_double_arrow";
- else if (shape == "all-scroll")
- return "fleur";
- else if (shape == "zoom-in")
- return "left_ptr";
- else if (shape == "zoom-out")
- return "left_ptr";
-
- return std::string();
-}
-
-SP<CCursorManager::SXCursor> CCursorManager::SXCursorManager::createDefaultCursor() {
- int cursorWidth = 32;
- int cursorHeight = 32;
- int cursorHotspotX = 3;
- int cursorHotspotY = 2;
-
- static const uint32_t pixels[] = {
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1b001816, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8e008173, 0x5f00564d, 0x16001412, 0x09000807, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b002624, 0x05000404, 0x00000000, 0x35002f2b, 0xd400bead,
- 0xc300b09e, 0x90008275, 0x44003e37, 0x04000403, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x67005a56,
- 0x6f00615c, 0x00000000, 0x00000000, 0x8b007c72, 0xf200d7c6, 0xfa00e0cc, 0xe800d0bd, 0xa0009181, 0x44003e37, 0x1a001815, 0x06000505, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x8d007976, 0xd600b8b3, 0x2500201f, 0x00000000, 0x17001413, 0xbd00a79c, 0xf600dacb, 0xff00e3d1, 0xfc00e1ce, 0xe800d0bc, 0xbf00ac9b,
- 0x95008778, 0x51004a41, 0x0f000e0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92007b7b, 0xf500d0cf, 0x9e008685, 0x00000000, 0x00000000, 0x23001f1d, 0x64005853,
- 0x9b008980, 0xd900bfb3, 0xfb00dfce, 0xff00e4d0, 0xfb00e1cd, 0xec00d5c0, 0xa7009788, 0x47004139, 0x1e001b18, 0x05000504, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa200878a, 0xff00d6d9, 0xd600b4b5,
- 0x0e000c0c, 0x00000000, 0x00000000, 0x02000202, 0x0c000b0a, 0x30002a28, 0x8e007d75, 0xd600bdb0, 0xef00d4c4, 0xfb00e0ce, 0xff00e4d0, 0xe600cfbb, 0xb800a695, 0x5f00564d,
- 0x06000505, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x02000202, 0xc600a3aa, 0xff00d3da, 0xea00c3c8, 0x08000707, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x2a002523, 0x61005550, 0x9500837b,
- 0xd800bfb1, 0xfd00e1cf, 0xff00e5d0, 0xf500dcc7, 0x7c007065, 0x2a002622, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000505, 0xd600aeb9, 0xff00d0dc, 0xcc00a7af, 0x04000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x01000101, 0x01000101, 0x2c002724, 0xa1008e85, 0xe600ccbd, 0xf800ddcb, 0xef00d6c3, 0xc300af9f, 0x2c002824, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, 0xd800adbc, 0xff00cdde, 0xb90095a0, 0x02000202, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000e0d, 0x4b00423e, 0xa4009088, 0xfd00dfd0, 0xff00e3d1,
- 0xae009c8f, 0x42003b36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x14001012, 0xf400c0d6,
- 0xff00cadf, 0xb2008e9c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x02000202, 0x1200100f, 0xa2008e86, 0xec00cfc3, 0xfc00ded0, 0xc300ada0, 0x15001311, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x2e002429, 0xfd00c4e0, 0xff00c7e2, 0x8f00707e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1e001a19, 0x75006662, 0xfb00dbd1, 0xf700d9cc, 0x9600847c, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e002f37, 0xfc00c1e1, 0xff00c5e3, 0x60004b55, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x15001212, 0xa6008f8b, 0xff00ddd5,
- 0xf800d8ce, 0x36002f2d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x51003d49, 0xfe00bfe5, 0xfe00c1e4, 0x4c003a44,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x01000101, 0x1d001918, 0xf400d1cd, 0xfe00dad5, 0xb3009a96, 0x03000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x66004b5d, 0xff00bee7, 0xfd00bee5, 0x4500343f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000202, 0x82006e6e, 0xff00d8d7, 0xd800b9b6, 0x33002c2b, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70005267, 0xff00bbe9, 0xfa00b8e3, 0x29001e25, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f003536, 0xea00c3c7, 0xf800d1d3,
- 0x4a003e3f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5f004458, 0xff00b8eb, 0xf400b1e0, 0x29001e26, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x1b001617, 0xe100bac0, 0xff00d4da, 0x82006c6f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5a004054, 0xfe00b4eb,
- 0xfb00b3e8, 0x3b002a36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0a000809, 0xc900a4ad, 0xff00d1dc, 0x88007075, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x44002f3f, 0xf300aae3, 0xfc00b1ea, 0x48003343, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000404, 0xdf00b3c2, 0xff00cedd, 0x8f00747c, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x25001a23, 0xf200a6e4, 0xff00b1ef, 0x84005c7c, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708,
- 0xe400b5c8, 0xff00cbdf, 0x78006068, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x12000c11, 0xc00082b6, 0xff00aef1, 0xaa0075a0,
- 0x11000c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x1e00171b, 0xf700c1db, 0xff00c8e1, 0x4b003b42, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x05000305, 0x8d005f86, 0xfc00aaef, 0xed00a0e1, 0x26001a24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6f005463, 0xff00c4e3, 0xf500beda, 0x0c00090b, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e00293b, 0xed009de2, 0xff00aaf3, 0x8b005d84, 0x04000304, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x07000506, 0xeb00b1d4, 0xff00c1e6, 0xba008ea7,
- 0x02000202, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb20075ab, 0xff00a7f4, 0xf300a1e9, 0x35002333,
- 0x06000406, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x8900647d, 0xff00bde8, 0xfb00bce2, 0x26001d22, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x2b001c29, 0xf1009ce8, 0xfe00a5f4, 0xc60082be, 0x3b002738, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x01000101, 0x54003c4d, 0xfd00b8e8, 0xff00baea, 0x96006f89, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x78004d74, 0xe20091da, 0xff00a5f6, 0xb60077af, 0x42002b3f, 0x0c00080c, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9400688a, 0xff00b5ed, 0xff00b6ec, 0xcc0093bc, 0x02000102, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x8100527d, 0xeb0096e4, 0xf900a0f1, 0xdc008dd4,
- 0x9b006595, 0x32002130, 0x0a00070a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2100161f, 0x5300394e, 0xe2009cd4, 0xff00b1ef, 0xff00b2ee, 0xc8008cba, 0x17001015,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x19001018, 0x5e003b5b, 0xcb0081c5, 0xff00a2f8, 0xfc00a1f4, 0xde0090d6, 0xa9006da3, 0x8300567e, 0x6f00496a, 0x76004e71, 0xbb007db2, 0xeb009edf, 0xfb00a9ee, 0xff00adf1,
- 0xfd00adee, 0x9e006d95, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x34002133, 0xa60069a1, 0xd70089d1, 0xf2009bea, 0xff00a3f7, 0xfb00a1f2, 0xfb00a2f2, 0xff00a6f5,
- 0xff00a8f4, 0xfd00a7f2, 0xed009ee2, 0xcf008bc5, 0x14000e13, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000b11, 0x35002134, 0x5b003959,
- 0x8b005887, 0xb30072ae, 0xc90080c3, 0xd10086ca, 0xa6006ba0, 0x65004261, 0x3c002839, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x06000406, 0x0d00080d, 0x0f000a0f, 0x0a00060a, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000};
-
- auto hackcursor = makeShared<SXCursor>();
- hackcursor->size = {cursorWidth, cursorHeight};
- hackcursor->hotspot = {cursorHotspotX, cursorHotspotY};
- hackcursor->pixels.resize(cursorWidth * cursorHeight);
- std::memcpy(hackcursor->pixels.data(), pixels, cursorWidth * cursorHeight * sizeof(uint32_t));
-
- return hackcursor;
-}
+} \ No newline at end of file
diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp
index 44ab2e7b..a114b6c2 100644
--- a/src/managers/CursorManager.hpp
+++ b/src/managers/CursorManager.hpp
@@ -7,6 +7,8 @@
#include "../helpers/math/Math.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../macros.hpp"
+#include "managers/eventLoop/EventLoopManager.hpp"
+#include "managers/XCursorManager.hpp"
#include <aquamarine/buffer/Buffer.hpp>
class CWLSurface;
@@ -63,6 +65,8 @@ class CCursorManager {
std::vector<SP<CCursorBuffer>> m_vCursorBuffers;
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;
+ std::unique_ptr<CXCursorManager> m_pXcursor;
+ SP<SXCursors> m_currentXcursor;
std::string m_szTheme = "";
int m_iSize = 0;
@@ -70,29 +74,9 @@ class CCursorManager {
Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo;
- wl_event_source* m_pAnimationTimer = nullptr;
+ SP<CEventLoopTimer> m_pAnimationTimer;
int m_iCurrentAnimationFrame = 0;
Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData;
-
- // gangsta bootleg XCursor impl. Whenever Hyprland has to use
- // an xcursor, just use the pointer.
- struct SXCursor {
- Vector2D size;
- Vector2D hotspot;
- std::vector<uint32_t> pixels; // XPixel is a u32
- };
-
- struct SXCursorManager {
- void loadTheme(const std::string& name, int size);
- std::string getLegacyShapeName(std::string const& shape);
- SP<SXCursor> createDefaultCursor();
-
- int lastLoadSize = 0;
- bool themeLoaded = false;
- std::string themeName = "";
- SP<SXCursor> defaultCursor;
- std::vector<std::pair<std::string, SP<SXCursor>>> cursors;
- } xcursor;
};
inline std::unique_ptr<CCursorManager> g_pCursorManager; \ No newline at end of file
diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp
new file mode 100644
index 00000000..b3f33086
--- /dev/null
+++ b/src/managers/XCursorManager.cpp
@@ -0,0 +1,447 @@
+#include <cstring>
+#include <dirent.h>
+#include <filesystem>
+#include "helpers/CursorShapes.hpp"
+#include "debug/Log.hpp"
+#include "XCursorManager.hpp"
+
+// clang-format off
+static std::vector<uint32_t> HYPR_XCURSOR_PIXELS = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1b001816, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8e008173, 0x5f00564d, 0x16001412, 0x09000807, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b002624, 0x05000404, 0x00000000, 0x35002f2b, 0xd400bead,
+ 0xc300b09e, 0x90008275, 0x44003e37, 0x04000403, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x67005a56,
+ 0x6f00615c, 0x00000000, 0x00000000, 0x8b007c72, 0xf200d7c6, 0xfa00e0cc, 0xe800d0bd, 0xa0009181, 0x44003e37, 0x1a001815, 0x06000505, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x8d007976, 0xd600b8b3, 0x2500201f, 0x00000000, 0x17001413, 0xbd00a79c, 0xf600dacb, 0xff00e3d1, 0xfc00e1ce, 0xe800d0bc, 0xbf00ac9b,
+ 0x95008778, 0x51004a41, 0x0f000e0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92007b7b, 0xf500d0cf, 0x9e008685, 0x00000000, 0x00000000, 0x23001f1d, 0x64005853,
+ 0x9b008980, 0xd900bfb3, 0xfb00dfce, 0xff00e4d0, 0xfb00e1cd, 0xec00d5c0, 0xa7009788, 0x47004139, 0x1e001b18, 0x05000504, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa200878a, 0xff00d6d9, 0xd600b4b5,
+ 0x0e000c0c, 0x00000000, 0x00000000, 0x02000202, 0x0c000b0a, 0x30002a28, 0x8e007d75, 0xd600bdb0, 0xef00d4c4, 0xfb00e0ce, 0xff00e4d0, 0xe600cfbb, 0xb800a695, 0x5f00564d,
+ 0x06000505, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x02000202, 0xc600a3aa, 0xff00d3da, 0xea00c3c8, 0x08000707, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x2a002523, 0x61005550, 0x9500837b,
+ 0xd800bfb1, 0xfd00e1cf, 0xff00e5d0, 0xf500dcc7, 0x7c007065, 0x2a002622, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000505, 0xd600aeb9, 0xff00d0dc, 0xcc00a7af, 0x04000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x01000101, 0x01000101, 0x2c002724, 0xa1008e85, 0xe600ccbd, 0xf800ddcb, 0xef00d6c3, 0xc300af9f, 0x2c002824, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, 0xd800adbc, 0xff00cdde, 0xb90095a0, 0x02000202, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000e0d, 0x4b00423e, 0xa4009088, 0xfd00dfd0, 0xff00e3d1,
+ 0xae009c8f, 0x42003b36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x14001012, 0xf400c0d6,
+ 0xff00cadf, 0xb2008e9c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x02000202, 0x1200100f, 0xa2008e86, 0xec00cfc3, 0xfc00ded0, 0xc300ada0, 0x15001311, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x2e002429, 0xfd00c4e0, 0xff00c7e2, 0x8f00707e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1e001a19, 0x75006662, 0xfb00dbd1, 0xf700d9cc, 0x9600847c, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e002f37, 0xfc00c1e1, 0xff00c5e3, 0x60004b55, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x15001212, 0xa6008f8b, 0xff00ddd5,
+ 0xf800d8ce, 0x36002f2d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x51003d49, 0xfe00bfe5, 0xfe00c1e4, 0x4c003a44,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x01000101, 0x1d001918, 0xf400d1cd, 0xfe00dad5, 0xb3009a96, 0x03000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x66004b5d, 0xff00bee7, 0xfd00bee5, 0x4500343f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000202, 0x82006e6e, 0xff00d8d7, 0xd800b9b6, 0x33002c2b, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70005267, 0xff00bbe9, 0xfa00b8e3, 0x29001e25, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f003536, 0xea00c3c7, 0xf800d1d3,
+ 0x4a003e3f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5f004458, 0xff00b8eb, 0xf400b1e0, 0x29001e26, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x1b001617, 0xe100bac0, 0xff00d4da, 0x82006c6f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5a004054, 0xfe00b4eb,
+ 0xfb00b3e8, 0x3b002a36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0a000809, 0xc900a4ad, 0xff00d1dc, 0x88007075, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x44002f3f, 0xf300aae3, 0xfc00b1ea, 0x48003343, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000404, 0xdf00b3c2, 0xff00cedd, 0x8f00747c, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x25001a23, 0xf200a6e4, 0xff00b1ef, 0x84005c7c, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708,
+ 0xe400b5c8, 0xff00cbdf, 0x78006068, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x12000c11, 0xc00082b6, 0xff00aef1, 0xaa0075a0,
+ 0x11000c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x1e00171b, 0xf700c1db, 0xff00c8e1, 0x4b003b42, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x05000305, 0x8d005f86, 0xfc00aaef, 0xed00a0e1, 0x26001a24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6f005463, 0xff00c4e3, 0xf500beda, 0x0c00090b, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e00293b, 0xed009de2, 0xff00aaf3, 0x8b005d84, 0x04000304, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x07000506, 0xeb00b1d4, 0xff00c1e6, 0xba008ea7,
+ 0x02000202, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb20075ab, 0xff00a7f4, 0xf300a1e9, 0x35002333,
+ 0x06000406, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8900647d, 0xff00bde8, 0xfb00bce2, 0x26001d22, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x2b001c29, 0xf1009ce8, 0xfe00a5f4, 0xc60082be, 0x3b002738, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x01000101, 0x54003c4d, 0xfd00b8e8, 0xff00baea, 0x96006f89, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x78004d74, 0xe20091da, 0xff00a5f6, 0xb60077af, 0x42002b3f, 0x0c00080c, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9400688a, 0xff00b5ed, 0xff00b6ec, 0xcc0093bc, 0x02000102, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x8100527d, 0xeb0096e4, 0xf900a0f1, 0xdc008dd4,
+ 0x9b006595, 0x32002130, 0x0a00070a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2100161f, 0x5300394e, 0xe2009cd4, 0xff00b1ef, 0xff00b2ee, 0xc8008cba, 0x17001015,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x19001018, 0x5e003b5b, 0xcb0081c5, 0xff00a2f8, 0xfc00a1f4, 0xde0090d6, 0xa9006da3, 0x8300567e, 0x6f00496a, 0x76004e71, 0xbb007db2, 0xeb009edf, 0xfb00a9ee, 0xff00adf1,
+ 0xfd00adee, 0x9e006d95, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x34002133, 0xa60069a1, 0xd70089d1, 0xf2009bea, 0xff00a3f7, 0xfb00a1f2, 0xfb00a2f2, 0xff00a6f5,
+ 0xff00a8f4, 0xfd00a7f2, 0xed009ee2, 0xcf008bc5, 0x14000e13, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000b11, 0x35002134, 0x5b003959,
+ 0x8b005887, 0xb30072ae, 0xc90080c3, 0xd10086ca, 0xa6006ba0, 0x65004261, 0x3c002839, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x06000406, 0x0d00080d, 0x0f000a0f, 0x0a00060a, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000};
+// clang-format on
+
+CXCursorManager::CXCursorManager() {
+ hyprCursor = makeShared<SXCursors>();
+ SXCursorImage image;
+ image.size = {32, 32};
+ image.hotspot = {3, 2};
+ image.pixels = HYPR_XCURSOR_PIXELS;
+ image.delay = 0;
+
+ hyprCursor->images.push_back(image);
+ hyprCursor->shape = "left_ptr";
+ defaultCursor = hyprCursor;
+}
+
+void CXCursorManager::loadTheme(std::string const& name, int size) {
+ if (lastLoadSize == size && themeName == name)
+ return;
+
+ lastLoadSize = size;
+ themeName = name.empty() ? "default" : name;
+ defaultCursor.reset();
+ cursors.clear();
+
+ auto paths = themePaths(themeName);
+ if (paths.empty()) {
+ Debug::log(ERR, "XCursor librarypath is empty loading standard XCursors");
+ cursors = loadStandardCursors(themeName, lastLoadSize);
+ } else {
+ for (auto const& p : paths) {
+ auto dirCursors = loadAllFromDir(p, lastLoadSize);
+ std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(cursors),
+ [this](auto const& p) { return std::none_of(cursors.begin(), cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); });
+ }
+ }
+
+ if (cursors.empty()) {
+ Debug::log(ERR, "XCursor failed finding any shapes in theme \"{}\".", themeName);
+ defaultCursor = hyprCursor;
+ return;
+ }
+
+ for (auto const& shape : CURSOR_SHAPE_NAMES) {
+ auto legacyName = getLegacyShapeName(shape);
+ if (legacyName.empty())
+ continue;
+
+ auto it = std::find_if(cursors.begin(), cursors.end(), [&legacyName](auto const& c) { return c->shape == legacyName; });
+
+ if (it == cursors.end()) {
+ Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName);
+ continue;
+ }
+
+ auto cursor = makeShared<SXCursors>();
+ cursor->images = it->get()->images;
+ cursor->shape = shape;
+
+ cursors.emplace_back(cursor);
+ }
+}
+
+SP<SXCursors> CXCursorManager::getShape(std::string const& shape, int size) {
+ // monitor scaling changed etc, so reload theme with new size.
+ if (size != lastLoadSize)
+ loadTheme(themeName, size);
+
+ // try to get an icon we know if we have one
+ for (auto const& c : cursors) {
+ if (c->shape != shape)
+ continue;
+
+ return c;
+ }
+
+ Debug::log(WARN, "XCursor couldn't find shape {} , using default cursor instead", shape);
+ return defaultCursor;
+}
+
+SP<SXCursors> CXCursorManager::createCursor(std::string const& shape, XcursorImages* xImages) {
+ auto xcursor = makeShared<SXCursors>();
+
+ for (int i = 0; i < xImages->nimage; i++) {
+ auto xImage = xImages->images[i];
+ SXCursorImage image;
+ image.size = {(int)xImage->width, (int)xImage->height};
+ image.hotspot = {(int)xImage->xhot, (int)xImage->yhot};
+ image.pixels.resize(xImage->width * xImage->height);
+ std::memcpy(image.pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
+ image.delay = xImage->delay;
+
+ xcursor->images.emplace_back(image);
+ }
+
+ xcursor->shape = shape;
+
+ return xcursor;
+}
+
+std::vector<std::string> CXCursorManager::themePaths(std::string const& theme) {
+ auto const* path = XcursorLibraryPath();
+ std::vector<std::string> paths;
+
+ auto expandTilde = [](std::string const& path) {
+ if (!path.empty() && path[0] == '~') {
+ const char* home = std::getenv("HOME");
+ if (home)
+ return std::string(home) + path.substr(1);
+ }
+ return path;
+ };
+
+ if (path) {
+ std::stringstream ss(path);
+ std::string item;
+
+ while (std::getline(ss, item, ':')) {
+ auto p = expandTilde(item + "/" + theme + "/cursors");
+
+ if (std::filesystem::exists(p) && std::filesystem::is_directory(p))
+ paths.push_back(p);
+ }
+ }
+
+ return paths;
+}
+
+std::string CXCursorManager::getLegacyShapeName(std::string const& shape) {
+ if (shape == "invalid")
+ return std::string();
+ else if (shape == "default")
+ return "left_ptr";
+ else if (shape == "context-menu")
+ return "left_ptr";
+ else if (shape == "help")
+ return "left_ptr";
+ else if (shape == "pointer")
+ return "hand2";
+ else if (shape == "progress")
+ return "watch";
+ else if (shape == "wait")
+ return "watch";
+ else if (shape == "cell")
+ return "plus";
+ else if (shape == "crosshair")
+ return "cross";
+ else if (shape == "text")
+ return "xterm";
+ else if (shape == "vertical-text")
+ return "xterm";
+ else if (shape == "alias")
+ return "dnd-link";
+ else if (shape == "copy")
+ return "dnd-copy";
+ else if (shape == "move")
+ return "dnd-move";
+ else if (shape == "no-drop")
+ return "dnd-none";
+ else if (shape == "not-allowed")
+ return "crossed_circle";
+ else if (shape == "grab")
+ return "hand1";
+ else if (shape == "grabbing")
+ return "hand1";
+ else if (shape == "e-resize")
+ return "right_side";
+ else if (shape == "n-resize")
+ return "top_side";
+ else if (shape == "ne-resize")
+ return "top_right_corner";
+ else if (shape == "nw-resize")
+ return "top_left_corner";
+ else if (shape == "s-resize")
+ return "bottom_side";
+ else if (shape == "se-resize")
+ return "bottom_right_corner";
+ else if (shape == "sw-resize")
+ return "bottom_left_corner";
+ else if (shape == "w-resize")
+ return "left_side";
+ else if (shape == "ew-resize")
+ return "sb_h_double_arrow";
+ else if (shape == "ns-resize")
+ return "sb_v_double_arrow";
+ else if (shape == "nesw-resize")
+ return "fd_double_arrow";
+ else if (shape == "nwse-resize")
+ return "bd_double_arrow";
+ else if (shape == "col-resize")
+ return "sb_h_double_arrow";
+ else if (shape == "row-resize")
+ return "sb_v_double_arrow";
+ else if (shape == "all-scroll")
+ return "fleur";
+ else if (shape == "zoom-in")
+ return "left_ptr";
+ else if (shape == "zoom-out")
+ return "left_ptr";
+
+ return std::string();
+};
+
+// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
+// clang-format off
+static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
+ "X_cursor",
+ "arrow",
+ "based_arrow_down",
+ "based_arrow_up",
+ "boat",
+ "bogosity",
+ "bottom_left_corner",
+ "bottom_right_corner",
+ "bottom_side",
+ "bottom_tee",
+ "box_spiral",
+ "center_ptr",
+ "circle",
+ "clock",
+ "coffee_mug",
+ "cross",
+ "cross_reverse",
+ "crosshair",
+ "diamond_cross",
+ "dot",
+ "dotbox",
+ "double_arrow",
+ "draft_large",
+ "draft_small",
+ "draped_box",
+ "exchange",
+ "fleur",
+ "gobbler",
+ "gumby",
+ "hand1",
+ "hand2",
+ "heart",
+ "icon",
+ "iron_cross",
+ "left_ptr",
+ "left_side",
+ "left_tee",
+ "leftbutton",
+ "ll_angle",
+ "lr_angle",
+ "man",
+ "middlebutton",
+ "mouse",
+ "pencil",
+ "pirate",
+ "plus",
+ "question_arrow",
+ "right_ptr",
+ "right_side",
+ "right_tee",
+ "rightbutton",
+ "rtl_logo",
+ "sailboat",
+ "sb_down_arrow",
+ "sb_h_double_arrow",
+ "sb_left_arrow",
+ "sb_right_arrow",
+ "sb_up_arrow",
+ "sb_v_double_arrow",
+ "shuttle",
+ "sizing",
+ "spider",
+ "spraycan",
+ "star",
+ "target",
+ "tcross",
+ "top_left_arrow",
+ "top_left_corner",
+ "top_right_corner",
+ "top_side",
+ "top_tee",
+ "trek",
+ "ul_angle",
+ "umbrella",
+ "ur_angle",
+ "watch",
+ "xterm",
+};
+// clang-format on
+
+std::vector<SP<SXCursors>> CXCursorManager::loadStandardCursors(std::string const& name, int size) {
+ std::vector<SP<SXCursors>> newCursors;
+
+ // load the default xcursor shapes that exist in the theme
+ for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
+ std::string shape{XCURSOR_STANDARD_NAMES.at(i)};
+ auto xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), size);
+
+ if (!xImages) {
+ Debug::log(WARN, "XCursor failed to find a shape with name {}, trying size 24.", shape);
+ xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), 24);
+
+ if (!xImages) {
+ Debug::log(WARN, "XCursor failed to find a shape with name {}, skipping", shape);
+ continue;
+ }
+ }
+
+ auto cursor = createCursor(shape, xImages);
+ newCursors.emplace_back(cursor);
+
+ if (!defaultCursor && (shape == "left_ptr" || shape == "arrow"))
+ defaultCursor = cursor;
+
+ XcursorImagesDestroy(xImages);
+ }
+
+ // broken theme.. just set it.
+ if (!newCursors.empty() && !defaultCursor)
+ defaultCursor = newCursors.front();
+
+ return newCursors;
+}
+
+std::vector<SP<SXCursors>> CXCursorManager::loadAllFromDir(std::string const& path, int size) {
+ std::vector<SP<SXCursors>> newCursors;
+ std::string full;
+
+ if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) {
+ for (const auto& entry : std::filesystem::directory_iterator(path)) {
+ if (!entry.is_regular_file() && !entry.is_symlink())
+ continue;
+
+ std::string full = entry.path().string();
+ using PcloseType = int (*)(FILE*);
+ const std::unique_ptr<FILE, PcloseType> f(fopen(full.c_str(), "r"), static_cast<PcloseType>(fclose));
+
+ if (!f)
+ continue;
+
+ auto xImages = XcursorFileLoadImages(f.get(), size);
+
+ if (!xImages) {
+ Debug::log(WARN, "XCursor failed to load image {}, trying size 24.", full);
+ xImages = XcursorFileLoadImages(f.get(), 24);
+
+ if (!xImages) {
+ Debug::log(WARN, "XCursor failed to load image {}, skipping", full);
+ continue;
+ }
+ }
+
+ std::string shape = entry.path().filename().string();
+ auto cursor = createCursor(shape, xImages);
+ newCursors.emplace_back(cursor);
+
+ if (!defaultCursor && (shape == "left_ptr" || shape == "arrow"))
+ defaultCursor = cursor;
+
+ XcursorImagesDestroy(xImages);
+ }
+ }
+
+ // broken theme.. just set it.
+ if (!newCursors.empty() && !defaultCursor)
+ defaultCursor = newCursors.front();
+
+ return newCursors;
+}
diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp
new file mode 100644
index 00000000..9ced076f
--- /dev/null
+++ b/src/managers/XCursorManager.hpp
@@ -0,0 +1,46 @@
+#pragma once
+#include <string>
+#include <vector>
+#include <array>
+#include <cstdint>
+#include <hyprutils/math/Vector2D.hpp>
+#include "helpers/memory/Memory.hpp"
+
+extern "C" {
+#include <X11/Xcursor/Xcursor.h>
+}
+
+// gangsta bootleg XCursor impl. adidas balkanized
+struct SXCursorImage {
+ Vector2D size;
+ Vector2D hotspot;
+ std::vector<uint32_t> pixels; // XPixel is a u32
+ uint32_t delay; // animation delay to next frame (ms)
+};
+
+struct SXCursors {
+ std::vector<SXCursorImage> images;
+ std::string shape;
+};
+
+class CXCursorManager {
+ public:
+ CXCursorManager();
+ ~CXCursorManager() = default;
+
+ void loadTheme(const std::string& name, int size);
+ SP<SXCursors> getShape(std::string const& shape, int size);
+
+ private:
+ SP<SXCursors> createCursor(std::string const& shape, XcursorImages* xImages);
+ std::vector<std::string> themePaths(std::string const& theme);
+ std::string getLegacyShapeName(std::string const& shape);
+ std::vector<SP<SXCursors>> loadStandardCursors(std::string const& name, int size);
+ std::vector<SP<SXCursors>> loadAllFromDir(std::string const& path, int size);
+
+ int lastLoadSize = 0;
+ std::string themeName = "";
+ SP<SXCursors> defaultCursor;
+ SP<SXCursors> hyprCursor;
+ std::vector<SP<SXCursors>> cursors;
+}; \ No newline at end of file