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 -#include "../helpers/CursorShapes.hpp" -extern "C" { -#include -} - -static int cursorAnimTimer(void* data) { - g_pCursorManager->tickAnimatedCursor(); +static int cursorAnimTimer(SP self, void* data) { + const auto cursorMgr = reinterpret_cast(data); + cursorMgr->tickAnimatedCursor(); return 1; } @@ -24,31 +19,41 @@ static void hcLogger(enum eHyprcursorLogLevel level, char* message) { CCursorManager::CCursorManager() { m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); + m_pXcursor = std::make_unique(); - if (!m_pHyprcursor->valid()) - Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme); + 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 (...) { ; } + } - // 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_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); + + auto const* SIZE = getenv("XCURSOR_SIZE"); + if (SIZE) { + try { + m_iSize = std::stoi(SIZE); + } catch (...) { ; } + } + + 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)); } - SIZE = getenv("XCURSOR_SIZE"); - if (SIZE && m_iSize == 0) { - try { - m_iSize = std::stoi(SIZE); - } catch (...) { ; } - } - - if (m_iSize == 0) - m_iSize = 24; - - xcursor.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(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 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 xcursor = m_pXcursor->getShape(name, m_iSize * scale); + auto& icon = xcursor->images.front(); - 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; + m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot)); - icon = c.second; - } - - m_vCursorBuffers.emplace_back(makeShared((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((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 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>> 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(); - 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::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(); - 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 class CWLSurface; @@ -63,6 +65,8 @@ class CCursorManager { std::vector> m_vCursorBuffers; std::unique_ptr m_pHyprcursor; + std::unique_ptr m_pXcursor; + SP 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 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 pixels; // XPixel is a u32 - }; - - struct SXCursorManager { - void loadTheme(const std::string& name, int size); - std::string getLegacyShapeName(std::string const& shape); - SP createDefaultCursor(); - - int lastLoadSize = 0; - bool themeLoaded = false; - std::string themeName = ""; - SP defaultCursor; - std::vector>> cursors; - } xcursor; }; inline std::unique_ptr 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 +#include +#include +#include "helpers/CursorShapes.hpp" +#include "debug/Log.hpp" +#include "XCursorManager.hpp" + +// clang-format off +static std::vector 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(); + 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(); + cursor->images = it->get()->images; + cursor->shape = shape; + + cursors.emplace_back(cursor); + } +} + +SP 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 CXCursorManager::createCursor(std::string const& shape, XcursorImages* xImages) { + auto xcursor = makeShared(); + + 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 CXCursorManager::themePaths(std::string const& theme) { + auto const* path = XcursorLibraryPath(); + std::vector 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 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> CXCursorManager::loadStandardCursors(std::string const& name, int size) { + std::vector> 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> CXCursorManager::loadAllFromDir(std::string const& path, int size) { + std::vector> 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 f(fopen(full.c_str(), "r"), static_cast(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 +#include +#include +#include +#include +#include "helpers/memory/Memory.hpp" + +extern "C" { +#include +} + +// gangsta bootleg XCursor impl. adidas balkanized +struct SXCursorImage { + Vector2D size; + Vector2D hotspot; + std::vector pixels; // XPixel is a u32 + uint32_t delay; // animation delay to next frame (ms) +}; + +struct SXCursors { + std::vector images; + std::string shape; +}; + +class CXCursorManager { + public: + CXCursorManager(); + ~CXCursorManager() = default; + + void loadTheme(const std::string& name, int size); + SP getShape(std::string const& shape, int size); + + private: + SP createCursor(std::string const& shape, XcursorImages* xImages); + std::vector themePaths(std::string const& theme); + std::string getLegacyShapeName(std::string const& shape); + std::vector> loadStandardCursors(std::string const& name, int size); + std::vector> loadAllFromDir(std::string const& path, int size); + + int lastLoadSize = 0; + std::string themeName = ""; + SP defaultCursor; + SP hyprCursor; + std::vector> cursors; +}; \ No newline at end of file