diff --git a/libhyprcursor/hyprcursor.cpp b/libhyprcursor/hyprcursor.cpp index eb33f28..a4a3cca 100644 --- a/libhyprcursor/hyprcursor.cpp +++ b/libhyprcursor/hyprcursor.cpp @@ -31,10 +31,6 @@ static bool themeAccessible(const std::string& path) { if (!std::filesystem::exists(path + "/manifest.hl")) return false; - const auto MANIFESTSTATUS = std::filesystem::status(path + "/manifest.hl"); - if ((MANIFESTSTATUS.permissions() & std::filesystem::perms::others_read) == std::filesystem::perms::none) - return false; - } catch (std::exception& e) { return false; } return true; @@ -205,7 +201,7 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap // matched :) bool foundAny = false; for (auto& image : impl->loadedShapes[shape.get()].images) { - if (image->side != info.size || (!image->artificial && shape->shapeType == SHAPE_SVG)) + if (image->side != info.size) continue; // found size @@ -285,13 +281,10 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) { break; } + // size wasn't found, let's resample. if (sizeFound) continue; - } - // size wasn't found, let's resample. - // if svg, render. - if (shape->shapeType == SHAPE_PNG) { SLoadedCursorImage* leader = nullptr; int leaderVal = 1000000; for (auto& image : impl->loadedShapes[shape.get()].images) { @@ -320,69 +313,77 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) { return false; } - auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique()); - newImage->artificial = true; - newImage->side = info.size; - newImage->artificialData = new char[info.size * info.size * 4]; - newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4); + const auto FRAMES = impl->getFramesFor(shape.get(), leader->side); - const auto PCAIRO = cairo_create(newImage->cairoSurface); + for (auto& f : FRAMES) { + auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique()); + newImage->artificial = true; + newImage->side = info.size; + newImage->artificialData = new char[info.size * info.size * 4]; + newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4); + newImage->delay = f->delay; - cairo_set_antialias(PCAIRO, shape->resizeAlgo == RESIZE_BILINEAR ? CAIRO_ANTIALIAS_GOOD : CAIRO_ANTIALIAS_NONE); + const auto PCAIRO = cairo_create(newImage->cairoSurface); - cairo_save(PCAIRO); - cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR); - cairo_paint(PCAIRO); - cairo_restore(PCAIRO); + cairo_set_antialias(PCAIRO, shape->resizeAlgo == RESIZE_BILINEAR ? CAIRO_ANTIALIAS_GOOD : CAIRO_ANTIALIAS_NONE); - const auto PTN = cairo_pattern_create_for_surface(leader->cairoSurface); - cairo_pattern_set_extend(PTN, CAIRO_EXTEND_NONE); - const float scale = info.size / (float)leader->side; - cairo_scale(PCAIRO, scale, scale); - cairo_pattern_set_filter(PTN, shape->resizeAlgo == RESIZE_BILINEAR ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST); - cairo_set_source(PCAIRO, PTN); + cairo_save(PCAIRO); + cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR); + cairo_paint(PCAIRO); + cairo_restore(PCAIRO); - cairo_rectangle(PCAIRO, 0, 0, info.size, info.size); + const auto PTN = cairo_pattern_create_for_surface(f->cairoSurface); + cairo_pattern_set_extend(PTN, CAIRO_EXTEND_NONE); + const float scale = info.size / (float)f->side; + cairo_scale(PCAIRO, scale, scale); + cairo_pattern_set_filter(PTN, shape->resizeAlgo == RESIZE_BILINEAR ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST); + cairo_set_source(PCAIRO, PTN); - cairo_fill(PCAIRO); - cairo_surface_flush(newImage->cairoSurface); + cairo_rectangle(PCAIRO, 0, 0, info.size, info.size); - cairo_pattern_destroy(PTN); - cairo_destroy(PCAIRO); + cairo_fill(PCAIRO); + cairo_surface_flush(newImage->cairoSurface); + + cairo_pattern_destroy(PTN); + cairo_destroy(PCAIRO); + } } else if (shape->shapeType == SHAPE_SVG) { - const auto ORIGINALSVG = impl->loadedShapes[shape.get()].images[0].get(); + const auto FRAMES = impl->getFramesFor(shape.get(), 0); - auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique()); - newImage->artificial = true; - newImage->side = info.size; - newImage->artificialData = new char[info.size * info.size * 4]; - newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4); + for (auto& f : FRAMES) { + auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique()); + newImage->artificial = true; + newImage->side = info.size; + newImage->artificialData = new char[info.size * info.size * 4]; + newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4); + newImage->delay = f->delay; - const auto PCAIRO = cairo_create(newImage->cairoSurface); + const auto PCAIRO = cairo_create(newImage->cairoSurface); - cairo_save(PCAIRO); - cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR); - cairo_paint(PCAIRO); - cairo_restore(PCAIRO); + cairo_save(PCAIRO); + cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR); + cairo_paint(PCAIRO); + cairo_restore(PCAIRO); - GError* error = nullptr; - RsvgHandle* handle = rsvg_handle_new_from_data((unsigned char*)ORIGINALSVG->data, ORIGINALSVG->dataLen, &error); + GError* error = nullptr; + RsvgHandle* handle = rsvg_handle_new_from_data((unsigned char*)f->data, f->dataLen, &error); - if (!handle) { - Debug::log(ERR, "Failed reading svg: {}", error->message); - return false; + if (!handle) { + Debug::log(ERR, "Failed reading svg: {}", error->message); + return false; + } + + RsvgRectangle rect = {0, 0, (double)info.size, (double)info.size}; + + if (!rsvg_handle_render_document(handle, PCAIRO, &rect, &error)) { + Debug::log(ERR, "Failed rendering svg: {}", error->message); + return false; + } + + // done + cairo_surface_flush(newImage->cairoSurface); + cairo_destroy(PCAIRO); } - - RsvgRectangle rect = {0, 0, (double)info.size, (double)info.size}; - - if (!rsvg_handle_render_document(handle, PCAIRO, &rect, &error)) { - Debug::log(ERR, "Failed rendering svg: {}", error->message); - return false; - } - - // done - cairo_surface_flush(newImage->cairoSurface); - cairo_destroy(PCAIRO); } else { Debug::log(ERR, "Invalid shapetype in loadThemeStyle"); return false; @@ -600,8 +601,9 @@ std::optional CHyprcursorImplementation::loadTheme() { // load image Debug::log(TRACE, "Loading {} for shape {}", i.filename, cursor.path().stem().string()); - auto* IMAGE = LOADEDSHAPE.images.emplace_back(std::make_unique()).get(); - IMAGE->side = i.size; + auto* IMAGE = LOADEDSHAPE.images.emplace_back(std::make_unique()).get(); + IMAGE->side = i.size; + IMAGE->delay = i.delay; // read from zip zip_file_t* image_file = zip_fopen(zip, i.filename.c_str(), ZIP_FL_UNCHANGED); @@ -620,8 +622,6 @@ std::optional CHyprcursorImplementation::loadTheme() { IMAGE->cairoSurface = cairo_image_surface_create_from_png_stream(::readPNG, IMAGE); - IMAGE->delay = i.delay; - if (const auto STATUS = cairo_surface_status(IMAGE->cairoSurface); STATUS != CAIRO_STATUS_SUCCESS) { delete[] (char*)IMAGE->data; IMAGE->data = nullptr; @@ -644,4 +644,20 @@ std::optional CHyprcursorImplementation::loadTheme() { } return {}; +} + +std::vector CHyprcursorImplementation::getFramesFor(SCursorShape* shape, int size) { + std::vector frames; + + for (auto& image : loadedShapes[shape].images) { + if (!image->isSVG && image->side != size) + continue; + + if (image->artificial) + continue; + + frames.push_back(image.get()); + } + + return frames; } \ No newline at end of file diff --git a/libhyprcursor/internalDefines.hpp b/libhyprcursor/internalDefines.hpp index 7a6e823..f6c1c14 100644 --- a/libhyprcursor/internalDefines.hpp +++ b/libhyprcursor/internalDefines.hpp @@ -20,7 +20,7 @@ struct SLoadedCursorImage { size_t readNeedle = 0; void* data = nullptr; size_t dataLen = 0; - bool isSVG = false; // if true, data is just a string of chars + bool isSVG = false; // if true, data is just a string of chars cairo_surface_t* cairoSurface = nullptr; int side = 0; @@ -46,5 +46,6 @@ class CHyprcursorImplementation { std::unordered_map loadedShapes; // - std::optional loadTheme(); + std::optional loadTheme(); + std::vector getFramesFor(SCursorShape* shape, int size); }; \ No newline at end of file diff --git a/tests/test.cpp b/tests/test.cpp index 9fd711a..dd94738 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -2,7 +2,7 @@ #include int main(int argc, char** argv) { - Hyprcursor::CHyprcursorManager mgr(nullptr); + Hyprcursor::CHyprcursorManager mgr("BIBATAWAIT"); // preload size 48 for testing if (!mgr.loadThemeStyle(Hyprcursor::SCursorStyleInfo{.size = 48})) {