API: improve in prep for animated

This commit is contained in:
Vaxry 2024-03-07 16:01:45 +00:00
parent 953f2fb118
commit 6760e68a1b
9 changed files with 138 additions and 26 deletions

View file

@ -12,7 +12,7 @@
#endif #endif
#include <cairo/cairo.h> #include "shared.h"
struct hyprcursor_manager_t; 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); 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. 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() 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 Marks a certain style as done, allowing it to be potentially freed

View file

@ -1,6 +1,9 @@
#pragma once #pragma once
#include <cairo/cairo.h> #include <vector>
#include <stdlib.h>
#include "shared.h"
class CHyprcursorImplementation; class CHyprcursorImplementation;
@ -17,6 +20,14 @@ namespace Hyprcursor {
*/ */
unsigned int size = 0; unsigned int size = 0;
}; };
/*!
struct for cursor shape data
*/
struct SCursorShapeData {
std::vector<SCursorImageData> images;
};
/*! /*!
Basic Hyprcursor manager. Basic Hyprcursor manager.
@ -49,12 +60,38 @@ namespace Hyprcursor {
bool loadThemeStyle(const SCursorStyleInfo& info); bool loadThemeStyle(const SCursorStyleInfo& info);
/*! /*!
Returns a cairo_surface_t for a given cursor Returns the shape data struct for a given
shape and size. 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 Marks a certain style as done, allowing it to be potentially freed

17
include/shared.h Normal file
View file

@ -0,0 +1,17 @@
#include <cairo/cairo.h>
#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

View file

@ -162,22 +162,29 @@ bool CHyprcursorManager::valid() {
return finalizedAndValid; return finalizedAndValid;
} }
cairo_surface_t* CHyprcursorManager::getSurfaceFor(const char* shape_, const SCursorStyleInfo& info) { SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shape_, const SCursorStyleInfo& info) {
std::string REQUESTEDSHAPE = shape_; std::string REQUESTEDSHAPE = shape_;
std::vector<SLoadedCursorImage*> resultingImages;
for (auto& shape : impl->theme.shapes) { for (auto& shape : impl->theme.shapes) {
if (REQUESTEDSHAPE != shape.directory && std::find(shape.overrides.begin(), shape.overrides.end(), REQUESTEDSHAPE) == shape.overrides.end()) if (REQUESTEDSHAPE != shape.directory && std::find(shape.overrides.begin(), shape.overrides.end(), REQUESTEDSHAPE) == shape.overrides.end())
continue; continue;
// matched :) // matched :)
bool foundAny = false;
for (auto& image : impl->loadedShapes[&shape].images) { for (auto& image : impl->loadedShapes[&shape].images) {
if (image->side != info.size) if (image->side != info.size)
continue; continue;
// found size // 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 we get here, means loadThemeStyle wasn't called most likely. If resize algo is specified, this is an error.
if (shape.resizeAlgo != RESIZE_NONE) { if (shape.resizeAlgo != RESIZE_NONE) {
Debug::log(ERR, "getSurfaceFor didn't match a size?"); 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 // find nearest
int leader = 1337; int leader = 13371337;
SLoadedCursorImage* leaderImg = nullptr;
for (auto& image : impl->loadedShapes[&shape].images) { for (auto& image : impl->loadedShapes[&shape].images) {
if (std::abs((int)(image->side - info.size)) > leader) if (std::abs((int)(image->side - info.size)) > leader)
continue; 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?"); Debug::log(ERR, "getSurfaceFor didn't match any nearest size?");
return nullptr; 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) { bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {

View file

@ -23,11 +23,22 @@ int hyprcursor_load_theme_style(hyprcursor_manager_t* manager, hyprcursor_cursor
return MGR->loadThemeStyle(info); 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; const auto MGR = (CHyprcursorManager*)manager;
SCursorStyleInfo info; SCursorStyleInfo info;
info.size = info_.size; 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_) { void hyprcursor_style_done(hyprcursor_manager_t* manager, hyprcursor_cursor_style_info info_) {

View file

@ -23,6 +23,7 @@ struct SLoadedCursorImage {
cairo_surface_t* cairoSurface = nullptr; cairo_surface_t* cairoSurface = nullptr;
int side = 0; int side = 0;
int delay = 0;
// means this was created by resampling // means this was created by resampling
void* artificialData = nullptr; void* artificialData = nullptr;

View file

@ -19,6 +19,7 @@ inline eResizeAlgo stringToAlgo(const std::string& s) {
struct SCursorImage { struct SCursorImage {
std::string filename; std::string filename;
int size = 0; int size = 0;
int delay = 0;
}; };
struct SCursorShape { struct SCursorShape {

View file

@ -16,13 +16,16 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
cairo_surface_t* surf = hyprcursor_get_surface_for(mgr, "left_ptr", info); int dataSize = 0;
if (surf == NULL) { hyprcursor_cursor_image_data** data = hyprcursor_get_cursor_image_data(mgr, "left_ptr", info, &dataSize);
printf("surf failed\n"); if (data == NULL) {
printf("data failed\n");
return 1; 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) { if (ret) {
printf("cairo failed\n"); printf("cairo failed\n");

View file

@ -11,10 +11,13 @@ int main(int argc, char** argv) {
} }
// get cursor for left_ptr // 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 // 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"; std::cout << "Cairo returned for write: " << RET << "\n";