mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-22 20:49:49 +01:00
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.
This commit is contained in:
parent
2b520571e8
commit
0e86808e59
4 changed files with 585 additions and 408 deletions
|
@ -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);
|
||||
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<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 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<CCursorBuffer>((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot));
|
||||
|
||||
icon = c.second;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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;
|
447
src/managers/XCursorManager.cpp
Normal file
447
src/managers/XCursorManager.cpp
Normal file
|
@ -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;
|
||||
}
|
46
src/managers/XCursorManager.hpp
Normal file
46
src/managers/XCursorManager.hpp
Normal file
|
@ -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;
|
||||
};
|
Loading…
Reference in a new issue