From 6760e68a1b812711970563202130b5c641be7e1e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 7 Mar 2024 16:01:45 +0000 Subject: [PATCH] API: improve in prep for animated --- include/hyprcursor.h | 15 ++++++-- include/hyprcursor.hpp | 47 ++++++++++++++++++++++--- include/shared.h | 17 +++++++++ libhyprcursor/hyprcursor.cpp | 50 +++++++++++++++++++++------ libhyprcursor/hyprcursor_c.cpp | 15 ++++++-- libhyprcursor/internalDefines.hpp | 1 + libhyprcursor/internalSharedTypes.hpp | 1 + tests/test.c | 11 +++--- tests/test.cpp | 7 ++-- 9 files changed, 138 insertions(+), 26 deletions(-) create mode 100644 include/shared.h diff --git a/include/hyprcursor.h b/include/hyprcursor.h index 7c9e5b7..7110375 100644 --- a/include/hyprcursor.h +++ b/include/hyprcursor.h @@ -12,7 +12,7 @@ #endif -#include +#include "shared.h" struct hyprcursor_manager_t; @@ -62,12 +62,21 @@ CAPI int hyprcursor_manager_valid(struct hyprcursor_manager_t* manager); CAPI int hyprcursor_load_theme_style(struct hyprcursor_manager_t* manager, struct hyprcursor_cursor_style_info info); /*! - Returns a cairo_surface_t for a given cursor + Returns a hyprcursor_cursor_image_data*[] for a given cursor shape and size. + The entire array needs to be freed instantly after using, see hyprcursor_cursor_image_data_free() + + Surfaces stay valid. + Once done with a size, call hyprcursor_style_done() */ -CAPI cairo_surface_t* hyprcursor_get_surface_for(struct hyprcursor_manager_t* manager, const char* shape, struct hyprcursor_cursor_style_info info); +CAPI hyprcursor_cursor_image_data** hyprcursor_get_cursor_image_data(struct hyprcursor_manager_t* manager, const char* shape, struct hyprcursor_cursor_style_info info, int* out_size); + +/*! + Free a returned hyprcursor_cursor_image_data. +*/ +CAPI void hyprcursor_cursor_image_data_free(hyprcursor_cursor_image_data** data, int size); /*! Marks a certain style as done, allowing it to be potentially freed diff --git a/include/hyprcursor.hpp b/include/hyprcursor.hpp index 87d6525..31fbfdb 100644 --- a/include/hyprcursor.hpp +++ b/include/hyprcursor.hpp @@ -1,6 +1,9 @@ #pragma once -#include +#include +#include + +#include "shared.h" class CHyprcursorImplementation; @@ -17,6 +20,14 @@ namespace Hyprcursor { */ unsigned int size = 0; }; + + + /*! + struct for cursor shape data + */ + struct SCursorShapeData { + std::vector images; + }; /*! Basic Hyprcursor manager. @@ -49,12 +60,38 @@ namespace Hyprcursor { bool loadThemeStyle(const SCursorStyleInfo& info); /*! - Returns a cairo_surface_t for a given cursor - shape and size. + Returns the shape data struct for a given + style. - Once done with a size, call cursorSurfaceDone() + Once done with a style, call cursorSurfaceDone() + + The surfaces references stay valid until cursorSurfaceStyleDone() is called on the owning style. */ - cairo_surface_t* getSurfaceFor(const char* shape, const SCursorStyleInfo& info); + SCursorShapeData getShape(const char* shape, const SCursorStyleInfo& info) { + int size = 0; + SCursorImageData** images = getShapesC(size, shape, info); + + SCursorShapeData data; + + for (size_t i = 0; i < size; ++i) { + SCursorImageData image; + image.delay = images[i]->delay; + image.size = images[i]->size; + image.surface = images[i]->surface; + data.images.push_back(image); + + free(images[i]); + } + + free(images); + + return data; + } + + /*! + Prefer getShape, this is for C compat. + */ + SCursorImageData** getShapesC(int& outSize, const char* shape_, const SCursorStyleInfo& info); /*! Marks a certain style as done, allowing it to be potentially freed diff --git a/include/shared.h b/include/shared.h new file mode 100644 index 0000000..e010fe4 --- /dev/null +++ b/include/shared.h @@ -0,0 +1,17 @@ +#include + +#ifndef HYPRCURSOR_SHARED_H +#define HYPRCURSOR_SHARED_H + +/*! + struct for a single cursor image +*/ +struct SCursorImageData { + cairo_surface_t* surface; + int size; + int delay; +}; + +typedef struct SCursorImageData hyprcursor_cursor_image_data; + +#endif diff --git a/libhyprcursor/hyprcursor.cpp b/libhyprcursor/hyprcursor.cpp index 9d9db53..cdc4495 100644 --- a/libhyprcursor/hyprcursor.cpp +++ b/libhyprcursor/hyprcursor.cpp @@ -162,22 +162,29 @@ bool CHyprcursorManager::valid() { return finalizedAndValid; } -cairo_surface_t* CHyprcursorManager::getSurfaceFor(const char* shape_, const SCursorStyleInfo& info) { - std::string REQUESTEDSHAPE = shape_; +SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shape_, const SCursorStyleInfo& info) { + std::string REQUESTEDSHAPE = shape_; + + std::vector resultingImages; for (auto& shape : impl->theme.shapes) { if (REQUESTEDSHAPE != shape.directory && std::find(shape.overrides.begin(), shape.overrides.end(), REQUESTEDSHAPE) == shape.overrides.end()) continue; // matched :) + bool foundAny = false; for (auto& image : impl->loadedShapes[&shape].images) { if (image->side != info.size) continue; // found size - return image->cairoSurface; + resultingImages.push_back(image.get()); + foundAny = true; } + if (foundAny) + break; + // if we get here, means loadThemeStyle wasn't called most likely. If resize algo is specified, this is an error. if (shape.resizeAlgo != RESIZE_NONE) { Debug::log(ERR, "getSurfaceFor didn't match a size?"); @@ -185,25 +192,48 @@ cairo_surface_t* CHyprcursorManager::getSurfaceFor(const char* shape_, const SCu } // find nearest - int leader = 1337; - SLoadedCursorImage* leaderImg = nullptr; + int leader = 13371337; for (auto& image : impl->loadedShapes[&shape].images) { if (std::abs((int)(image->side - info.size)) > leader) continue; - leaderImg = image.get(); - leader = image->side; + leader = image->side; } - if (!leaderImg) { // ??? + if (leader == 13371337) { // ??? Debug::log(ERR, "getSurfaceFor didn't match any nearest size?"); return nullptr; } - return leaderImg->cairoSurface; + // we found nearest size + for (auto& image : impl->loadedShapes[&shape].images) { + if (image->side != leader) + continue; + + // found size + resultingImages.push_back(image.get()); + foundAny = true; + } + + if (foundAny) + break; + + Debug::log(ERR, "getSurfaceFor didn't match any nearest size (2)?"); + return nullptr; } - return nullptr; + // alloc and return what we need + SCursorImageData** data = (SCursorImageData**)malloc(sizeof(SCursorImageData*) * resultingImages.size()); + for (size_t i = 0; i < resultingImages.size(); ++i) { + data[i] = (SCursorImageData*)malloc(sizeof(SCursorImageData)); + data[i]->delay = resultingImages[i]->delay; + data[i]->size = resultingImages[i]->side; + data[i]->surface = resultingImages[i]->cairoSurface; + } + + outSize = resultingImages.size(); + + return data; } bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) { diff --git a/libhyprcursor/hyprcursor_c.cpp b/libhyprcursor/hyprcursor_c.cpp index 9b00348..1831362 100644 --- a/libhyprcursor/hyprcursor_c.cpp +++ b/libhyprcursor/hyprcursor_c.cpp @@ -23,11 +23,22 @@ int hyprcursor_load_theme_style(hyprcursor_manager_t* manager, hyprcursor_cursor return MGR->loadThemeStyle(info); } -cairo_surface_t* hyprcursor_get_surface_for(hyprcursor_manager_t* manager, const char* shape, hyprcursor_cursor_style_info info_) { +struct SCursorImageData** hyprcursor_get_cursor_image_data(struct hyprcursor_manager_t* manager, const char* shape, struct hyprcursor_cursor_style_info info_, int* out_size) { const auto MGR = (CHyprcursorManager*)manager; SCursorStyleInfo info; info.size = info_.size; - return MGR->getSurfaceFor(shape, info); + int size = 0; + struct SCursorImageData** data = MGR->getShapesC(size, shape, info); + *out_size = size; + return data; +} + +void hyprcursor_cursor_image_data_free(hyprcursor_cursor_image_data** data, int size) { + for (size_t i = 0; i < size; ++i) { + free(data[i]); + } + + free(data); } void hyprcursor_style_done(hyprcursor_manager_t* manager, hyprcursor_cursor_style_info info_) { diff --git a/libhyprcursor/internalDefines.hpp b/libhyprcursor/internalDefines.hpp index 1f2e747..d948dbb 100644 --- a/libhyprcursor/internalDefines.hpp +++ b/libhyprcursor/internalDefines.hpp @@ -23,6 +23,7 @@ struct SLoadedCursorImage { cairo_surface_t* cairoSurface = nullptr; int side = 0; + int delay = 0; // means this was created by resampling void* artificialData = nullptr; diff --git a/libhyprcursor/internalSharedTypes.hpp b/libhyprcursor/internalSharedTypes.hpp index 72aae28..b464ad0 100644 --- a/libhyprcursor/internalSharedTypes.hpp +++ b/libhyprcursor/internalSharedTypes.hpp @@ -19,6 +19,7 @@ inline eResizeAlgo stringToAlgo(const std::string& s) { struct SCursorImage { std::string filename; int size = 0; + int delay = 0; }; struct SCursorShape { diff --git a/tests/test.c b/tests/test.c index 3f75704..e24d62f 100644 --- a/tests/test.c +++ b/tests/test.c @@ -16,13 +16,16 @@ int main(int argc, char** argv) { return 1; } - cairo_surface_t* surf = hyprcursor_get_surface_for(mgr, "left_ptr", info); - if (surf == NULL) { - printf("surf failed\n"); + int dataSize = 0; + hyprcursor_cursor_image_data** data = hyprcursor_get_cursor_image_data(mgr, "left_ptr", info, &dataSize); + if (data == NULL) { + printf("data failed\n"); return 1; } - int ret = cairo_surface_write_to_png(surf, "/tmp/arrowC.png"); + int ret = cairo_surface_write_to_png(data[0]->surface, "/tmp/arrowC.png"); + + hyprcursor_cursor_image_data_free(data, dataSize); if (ret) { printf("cairo failed\n"); diff --git a/tests/test.cpp b/tests/test.cpp index 84cee19..e774ca3 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -11,10 +11,13 @@ int main(int argc, char** argv) { } // get cursor for left_ptr - const auto ARROW = mgr.getSurfaceFor("left_ptr", Hyprcursor::SCursorStyleInfo{.size = 48}); + const auto SHAPEDATA = mgr.getShape("left_ptr", Hyprcursor::SCursorStyleInfo{.size = 48}); + + if (SHAPEDATA.images.empty()) + return 1; // save to disk - const auto RET = cairo_surface_write_to_png(ARROW, "/tmp/arrow.png"); + const auto RET = cairo_surface_write_to_png(SHAPEDATA.images[0].surface, "/tmp/arrow.png"); std::cout << "Cairo returned for write: " << RET << "\n";