mirror of
https://github.com/hyprwm/hyprcursor.git
synced 2024-12-22 10:19:48 +01:00
lib: Added a raw data API (#23)
* raw data API * add missing type arg * tests: better stuff
This commit is contained in:
parent
981b661782
commit
7561459770
12 changed files with 337 additions and 47 deletions
|
@ -65,12 +65,17 @@ target_link_libraries(hyprcursor-util PkgConfig::deps hyprcursor)
|
||||||
# tests
|
# tests
|
||||||
add_custom_target(tests)
|
add_custom_target(tests)
|
||||||
|
|
||||||
add_executable(hyprcursor_test "tests/test.cpp")
|
add_executable(hyprcursor_test1 "tests/full_rendering.cpp")
|
||||||
target_link_libraries(hyprcursor_test PRIVATE hyprcursor)
|
target_link_libraries(hyprcursor_test1 PRIVATE hyprcursor)
|
||||||
add_test(NAME "Test libhyprcursor in C++" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprcursor_test)
|
add_test(NAME "Test libhyprcursor in C++ (full rendering)" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprcursor_test1)
|
||||||
add_dependencies(tests hyprcursor_test)
|
add_dependencies(tests hyprcursor_test1)
|
||||||
|
|
||||||
add_executable(hyprcursor_test_c "tests/test.c")
|
add_executable(hyprcursor_test2 "tests/only_metadata.cpp")
|
||||||
|
target_link_libraries(hyprcursor_test2 PRIVATE hyprcursor)
|
||||||
|
add_test(NAME "Test libhyprcursor in C++ (only metadata)" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprcursor_test2)
|
||||||
|
add_dependencies(tests hyprcursor_test2)
|
||||||
|
|
||||||
|
add_executable(hyprcursor_test_c "tests/c_test.c")
|
||||||
target_link_libraries(hyprcursor_test_c PRIVATE hyprcursor)
|
target_link_libraries(hyprcursor_test_c PRIVATE hyprcursor)
|
||||||
add_test(NAME "Test libhyprcursor in C" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprcursor_test_c)
|
add_test(NAME "Test libhyprcursor in C" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprcursor_test_c)
|
||||||
add_dependencies(tests hyprcursor_test_c)
|
add_dependencies(tests hyprcursor_test_c)
|
||||||
|
|
|
@ -15,7 +15,7 @@ enum eOperation {
|
||||||
OPERATION_EXTRACT = 1,
|
OPERATION_EXTRACT = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
eResizeAlgo explicitResizeAlgo = RESIZE_INVALID;
|
eHyprcursorResizeAlgo explicitResizeAlgo = HC_RESIZE_INVALID;
|
||||||
|
|
||||||
struct XCursorConfigEntry {
|
struct XCursorConfigEntry {
|
||||||
int size = 0, hotspotX = 0, hotspotY = 0, delay = 0;
|
int size = 0, hotspotX = 0, hotspotY = 0, delay = 0;
|
||||||
|
@ -329,7 +329,7 @@ static std::optional<std::string> extractXTheme(const std::string& xpath_, const
|
||||||
}
|
}
|
||||||
|
|
||||||
// write a meta.hl
|
// write a meta.hl
|
||||||
std::string metaString = std::format("resize_algorithm = {}\n", explicitResizeAlgo == RESIZE_INVALID ? "none" : algoToString(explicitResizeAlgo));
|
std::string metaString = std::format("resize_algorithm = {}\n", explicitResizeAlgo == HC_RESIZE_INVALID ? "none" : algoToString(explicitResizeAlgo));
|
||||||
|
|
||||||
// find hotspot from first entry
|
// find hotspot from first entry
|
||||||
metaString +=
|
metaString +=
|
||||||
|
|
|
@ -102,4 +102,21 @@ CAPI void hyprcursor_style_done(struct hyprcursor_manager_t* manager, struct hyp
|
||||||
*/
|
*/
|
||||||
CAPI void hyprcursor_register_logging_function(struct hyprcursor_manager_t* manager, PHYPRCURSORLOGFUNC fn);
|
CAPI void hyprcursor_register_logging_function(struct hyprcursor_manager_t* manager, PHYPRCURSORLOGFUNC fn);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 0.1.6
|
||||||
|
|
||||||
|
Returns the raw image data of a cursor shape, not rendered at all, alongside the metadata.
|
||||||
|
|
||||||
|
The object needs to be freed instantly after using, see hyprcursor_raw_shape_data_free()
|
||||||
|
*/
|
||||||
|
CAPI hyprcursor_cursor_raw_shape_data* hyprcursor_get_raw_shape_data(struct hyprcursor_manager_t* manager, char* shape);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 0.1.6
|
||||||
|
|
||||||
|
See hyprcursor_get_raw_shape_data.
|
||||||
|
Frees the returned object.
|
||||||
|
*/
|
||||||
|
CAPI void hyprcursor_raw_shape_data_free(hyprcursor_cursor_raw_shape_data* data);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
|
|
||||||
|
@ -28,6 +29,24 @@ namespace Hyprcursor {
|
||||||
std::vector<SCursorImageData> images;
|
std::vector<SCursorImageData> images;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
C++ structs for hyprcursor_cursor_raw_shape_image and hyprcursor_cursor_raw_shape_data
|
||||||
|
*/
|
||||||
|
struct SCursorRawShapeImage {
|
||||||
|
std::vector<unsigned char> data;
|
||||||
|
int size = 0;
|
||||||
|
int delay = 200;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SCursorRawShapeData {
|
||||||
|
std::vector<SCursorRawShapeImage> images;
|
||||||
|
float hotspotX = 0;
|
||||||
|
float hotspotY = 0;
|
||||||
|
std::string overridenBy = "";
|
||||||
|
eHyprcursorResizeAlgo resizeAlgo = HC_RESIZE_NONE;
|
||||||
|
eHyprcursorDataType type = HC_DATA_PNG;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Basic Hyprcursor manager.
|
Basic Hyprcursor manager.
|
||||||
|
|
||||||
|
@ -93,11 +112,47 @@ namespace Hyprcursor {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 0.1.6
|
||||||
|
|
||||||
|
Returns the raw image data of a cursor shape, not rendered at all, alongside the metadata.
|
||||||
|
*/
|
||||||
|
SCursorRawShapeData getRawShapeData(const char* shape_) {
|
||||||
|
auto CDATA = getRawShapeDataC(shape_);
|
||||||
|
|
||||||
|
if (CDATA->overridenBy) {
|
||||||
|
SCursorRawShapeData d{.overridenBy = CDATA->overridenBy};
|
||||||
|
free(CDATA->overridenBy);
|
||||||
|
delete CDATA;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCursorRawShapeData data{.hotspotX = CDATA->hotspotX, .hotspotY = CDATA->hotspotY, .overridenBy = "", .resizeAlgo = CDATA->resizeAlgo, .type = CDATA->type};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < CDATA->len; ++i) {
|
||||||
|
SCursorRawShapeImageC* cimage = &CDATA->images[i];
|
||||||
|
SCursorRawShapeImage& img = data.images.emplace_back();
|
||||||
|
img.size = cimage->size;
|
||||||
|
img.delay = cimage->delay;
|
||||||
|
img.data = std::vector<unsigned char>{(unsigned char*)cimage->data, (unsigned char*)cimage->data + (std::size_t)cimage->len};
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] CDATA->images;
|
||||||
|
delete CDATA;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Prefer getShape, this is for C compat.
|
Prefer getShape, this is for C compat.
|
||||||
*/
|
*/
|
||||||
SCursorImageData** getShapesC(int& outSize, const char* shape_, const SCursorStyleInfo& info);
|
SCursorImageData** getShapesC(int& outSize, const char* shape_, const SCursorStyleInfo& info);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Prefer getShapeData, this is for C compat.
|
||||||
|
*/
|
||||||
|
SCursorRawShapeDataC* getRawShapeDataC(const char* shape_);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Marks a certain style as done, allowing it to be potentially freed
|
Marks a certain style as done, allowing it to be potentially freed
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,6 +25,39 @@ enum eHyprcursorLogLevel {
|
||||||
HC_LOG_CRITICAL,
|
HC_LOG_CRITICAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum eHyprcursorDataType {
|
||||||
|
HC_DATA_PNG = 0,
|
||||||
|
HC_DATA_SVG,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eHyprcursorResizeAlgo {
|
||||||
|
HC_RESIZE_INVALID = 0,
|
||||||
|
HC_RESIZE_NONE,
|
||||||
|
HC_RESIZE_BILINEAR,
|
||||||
|
HC_RESIZE_NEAREST,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SCursorRawShapeImageC {
|
||||||
|
void* data;
|
||||||
|
unsigned long int len;
|
||||||
|
int size;
|
||||||
|
int delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SCursorRawShapeImageC hyprcursor_cursor_raw_shape_image;
|
||||||
|
|
||||||
|
struct SCursorRawShapeDataC {
|
||||||
|
struct SCursorRawShapeImageC* images;
|
||||||
|
unsigned long int len;
|
||||||
|
float hotspotX;
|
||||||
|
float hotspotY;
|
||||||
|
char* overridenBy;
|
||||||
|
enum eHyprcursorResizeAlgo resizeAlgo;
|
||||||
|
enum eHyprcursorDataType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SCursorRawShapeDataC hyprcursor_cursor_raw_shape_data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
msg is owned by the caller and will be freed afterwards.
|
msg is owned by the caller and will be freed afterwards.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -294,7 +294,7 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
||||||
break;
|
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 != HC_RESIZE_NONE) {
|
||||||
Debug::log(HC_LOG_ERR, logFn, "getSurfaceFor didn't match a size?");
|
Debug::log(HC_LOG_ERR, logFn, "getSurfaceFor didn't match a size?");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -348,11 +348,59 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
|
||||||
|
if (!shape_) {
|
||||||
|
Debug::log(HC_LOG_ERR, logFn, "getShapeDataC: shape of nullptr is invalid");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string SHAPE = shape_;
|
||||||
|
|
||||||
|
SCursorRawShapeDataC* data = new SCursorRawShapeDataC;
|
||||||
|
std::vector<SLoadedCursorImage*> resultingImages;
|
||||||
|
|
||||||
|
for (auto& shape : impl->theme.shapes) {
|
||||||
|
// if it's overridden just return the override
|
||||||
|
if (const auto IT = std::find(shape->overrides.begin(), shape->overrides.end(), SHAPE); IT != shape->overrides.end()) {
|
||||||
|
data->overridenBy = strdup(IT->c_str());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shape->directory != SHAPE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!impl->loadedShapes.contains(shape.get()))
|
||||||
|
continue; // ??
|
||||||
|
|
||||||
|
// found it
|
||||||
|
for (auto& i : impl->loadedShapes[shape.get()].images) {
|
||||||
|
resultingImages.push_back(i.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
data->hotspotX = shape->hotspotX;
|
||||||
|
data->hotspotY = shape->hotspotY;
|
||||||
|
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->len = resultingImages.size();
|
||||||
|
data->images = new SCursorRawShapeImageC[data->len];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data->len; ++i) {
|
||||||
|
data->images[i].data = resultingImages[i]->data;
|
||||||
|
data->images[i].len = resultingImages[i]->dataLen;
|
||||||
|
data->images[i].size = resultingImages[i]->side;
|
||||||
|
data->images[i].delay = resultingImages[i]->delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
Debug::log(HC_LOG_INFO, logFn, "loadThemeStyle: loading for size {}", info.size);
|
Debug::log(HC_LOG_INFO, logFn, "loadThemeStyle: loading for size {}", info.size);
|
||||||
|
|
||||||
for (auto& shape : impl->theme.shapes) {
|
for (auto& shape : impl->theme.shapes) {
|
||||||
if (shape->resizeAlgo == RESIZE_NONE && shape->shapeType != SHAPE_SVG) {
|
if (shape->resizeAlgo == HC_RESIZE_NONE && shape->shapeType != SHAPE_SVG) {
|
||||||
// don't resample NONE style cursors
|
// don't resample NONE style cursors
|
||||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: ignoring {}", shape->directory);
|
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: ignoring {}", shape->directory);
|
||||||
continue;
|
continue;
|
||||||
|
@ -415,7 +463,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
|
|
||||||
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
||||||
|
|
||||||
cairo_set_antialias(PCAIRO, shape->resizeAlgo == RESIZE_BILINEAR ? CAIRO_ANTIALIAS_GOOD : CAIRO_ANTIALIAS_NONE);
|
cairo_set_antialias(PCAIRO, shape->resizeAlgo == HC_RESIZE_BILINEAR ? CAIRO_ANTIALIAS_GOOD : CAIRO_ANTIALIAS_NONE);
|
||||||
|
|
||||||
cairo_save(PCAIRO);
|
cairo_save(PCAIRO);
|
||||||
cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR);
|
cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR);
|
||||||
|
@ -426,7 +474,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
cairo_pattern_set_extend(PTN, CAIRO_EXTEND_NONE);
|
cairo_pattern_set_extend(PTN, CAIRO_EXTEND_NONE);
|
||||||
const float scale = info.size / (float)f->side;
|
const float scale = info.size / (float)f->side;
|
||||||
cairo_scale(PCAIRO, scale, scale);
|
cairo_scale(PCAIRO, scale, scale);
|
||||||
cairo_pattern_set_filter(PTN, shape->resizeAlgo == RESIZE_BILINEAR ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST);
|
cairo_pattern_set_filter(PTN, shape->resizeAlgo == HC_RESIZE_BILINEAR ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST);
|
||||||
cairo_set_source(PCAIRO, PTN);
|
cairo_set_source(PCAIRO, PTN);
|
||||||
|
|
||||||
cairo_rectangle(PCAIRO, 0, 0, info.size, info.size);
|
cairo_rectangle(PCAIRO, 0, 0, info.size, info.size);
|
||||||
|
@ -487,7 +535,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
|
|
||||||
void CHyprcursorManager::cursorSurfaceStyleDone(const SCursorStyleInfo& info) {
|
void CHyprcursorManager::cursorSurfaceStyleDone(const SCursorStyleInfo& info) {
|
||||||
for (auto& shape : impl->theme.shapes) {
|
for (auto& shape : impl->theme.shapes) {
|
||||||
if (shape->resizeAlgo == RESIZE_NONE && shape->shapeType != SHAPE_SVG)
|
if (shape->resizeAlgo == HC_RESIZE_NONE && shape->shapeType != SHAPE_SVG)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::erase_if(impl->loadedShapes[shape.get()].images, [info, &shape](const auto& e) {
|
std::erase_if(impl->loadedShapes[shape.get()].images, [info, &shape](const auto& e) {
|
||||||
|
@ -520,6 +568,9 @@ PNG reading
|
||||||
static cairo_status_t readPNG(void* data, unsigned char* output, unsigned int len) {
|
static cairo_status_t readPNG(void* data, unsigned char* output, unsigned int len) {
|
||||||
const auto DATA = (SLoadedCursorImage*)data;
|
const auto DATA = (SLoadedCursorImage*)data;
|
||||||
|
|
||||||
|
if (DATA->readNeedle >= DATA->dataLen)
|
||||||
|
return CAIRO_STATUS_READ_ERROR;
|
||||||
|
|
||||||
if (!DATA->data)
|
if (!DATA->data)
|
||||||
return CAIRO_STATUS_READ_ERROR;
|
return CAIRO_STATUS_READ_ERROR;
|
||||||
|
|
||||||
|
@ -528,11 +579,6 @@ static cairo_status_t readPNG(void* data, unsigned char* output, unsigned int le
|
||||||
std::memcpy(output, (uint8_t*)DATA->data + DATA->readNeedle, toRead);
|
std::memcpy(output, (uint8_t*)DATA->data + DATA->readNeedle, toRead);
|
||||||
DATA->readNeedle += toRead;
|
DATA->readNeedle += toRead;
|
||||||
|
|
||||||
if (DATA->readNeedle >= DATA->dataLen) {
|
|
||||||
delete[] (char*)DATA->data;
|
|
||||||
DATA->data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,3 +56,19 @@ void hyprcursor_register_logging_function(struct hyprcursor_manager_t* manager,
|
||||||
const auto MGR = (CHyprcursorManager*)manager;
|
const auto MGR = (CHyprcursorManager*)manager;
|
||||||
MGR->registerLoggingFunction(fn);
|
MGR->registerLoggingFunction(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CAPI hyprcursor_cursor_raw_shape_data* hyprcursor_get_raw_shape_data(struct hyprcursor_manager_t* manager, char* shape) {
|
||||||
|
const auto MGR = (CHyprcursorManager*)manager;
|
||||||
|
return MGR->getRawShapeDataC(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAPI void hyprcursor_raw_shape_data_free(hyprcursor_cursor_raw_shape_data* data) {
|
||||||
|
if (data->overridenBy) {
|
||||||
|
free(data->overridenBy);
|
||||||
|
delete data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data->images;
|
||||||
|
delete data;
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ struct SLoadedCursorImage {
|
||||||
|
|
||||||
// read stuff
|
// read stuff
|
||||||
size_t readNeedle = 0;
|
size_t readNeedle = 0;
|
||||||
void* data = nullptr;
|
void* data = nullptr; // raw png / svg data, not image data
|
||||||
size_t dataLen = 0;
|
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
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <hyprcursor/shared.h>
|
||||||
enum eResizeAlgo {
|
|
||||||
RESIZE_INVALID = 0,
|
|
||||||
RESIZE_NONE,
|
|
||||||
RESIZE_BILINEAR,
|
|
||||||
RESIZE_NEAREST,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eShapeType {
|
enum eShapeType {
|
||||||
SHAPE_INVALID = 0,
|
SHAPE_INVALID = 0,
|
||||||
|
@ -16,19 +10,19 @@ enum eShapeType {
|
||||||
SHAPE_SVG,
|
SHAPE_SVG,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline eResizeAlgo stringToAlgo(const std::string& s) {
|
inline eHyprcursorResizeAlgo stringToAlgo(const std::string& s) {
|
||||||
if (s == "none")
|
if (s == "none")
|
||||||
return RESIZE_NONE;
|
return HC_RESIZE_NONE;
|
||||||
if (s == "nearest")
|
if (s == "nearest")
|
||||||
return RESIZE_NEAREST;
|
return HC_RESIZE_NEAREST;
|
||||||
return RESIZE_BILINEAR;
|
return HC_RESIZE_BILINEAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string algoToString(const eResizeAlgo a) {
|
inline std::string algoToString(const eHyprcursorResizeAlgo a) {
|
||||||
switch (a) {
|
switch (a) {
|
||||||
case RESIZE_BILINEAR: return "bilinear";
|
case HC_RESIZE_BILINEAR: return "bilinear";
|
||||||
case RESIZE_NEAREST: return "nearest";
|
case HC_RESIZE_NEAREST: return "nearest";
|
||||||
case RESIZE_NONE: return "none";
|
case HC_RESIZE_NONE: return "none";
|
||||||
default: return "none";
|
default: return "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +38,7 @@ struct SCursorImage {
|
||||||
struct SCursorShape {
|
struct SCursorShape {
|
||||||
std::string directory;
|
std::string directory;
|
||||||
float hotspotX = 0, hotspotY = 0;
|
float hotspotX = 0, hotspotY = 0;
|
||||||
eResizeAlgo resizeAlgo = RESIZE_NEAREST;
|
eHyprcursorResizeAlgo resizeAlgo = HC_RESIZE_NEAREST;
|
||||||
std::vector<SCursorImage> images;
|
std::vector<SCursorImage> images;
|
||||||
std::vector<std::string> overrides;
|
std::vector<std::string> overrides;
|
||||||
eShapeType shapeType = SHAPE_INVALID;
|
eShapeType shapeType = SHAPE_INVALID;
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
/*
|
||||||
|
hyprlang-test in C.
|
||||||
|
Renders a cursor shape to /tmp at 48px
|
||||||
|
|
||||||
|
For better explanations, see the cpp tests.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <hyprcursor/hyprcursor.h>
|
#include <hyprcursor/hyprcursor.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -6,11 +13,6 @@ void logFunction(enum eHyprcursorLogLevel level, char* message) {
|
||||||
printf("[hc] %s\n", message);
|
printf("[hc] %s\n", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
hyprlang-test in C.
|
|
||||||
Renders a cursor shape to /tmp at 48px
|
|
||||||
*/
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
struct hyprcursor_manager_t* mgr = hyprcursor_manager_create_with_logger(NULL, logFunction);
|
struct hyprcursor_manager_t* mgr = hyprcursor_manager_create_with_logger(NULL, logFunction);
|
||||||
|
|
||||||
|
@ -24,6 +26,21 @@ int main(int argc, char** argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hyprcursor_cursor_raw_shape_data* shapeData = hyprcursor_get_raw_shape_data(mgr, "left_ptr");
|
||||||
|
if (!shapeData || shapeData->len <= 0) {
|
||||||
|
printf("failed querying left_ptr\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("left_ptr images: %d\n", shapeData->len);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < shapeData->len; ++i) {
|
||||||
|
printf("left_ptr image size: %d\n", shapeData->images[i].len);
|
||||||
|
}
|
||||||
|
|
||||||
|
hyprcursor_raw_shape_data_free(shapeData);
|
||||||
|
shapeData = NULL;
|
||||||
|
|
||||||
struct hyprcursor_cursor_style_info info = {.size = 48};
|
struct hyprcursor_cursor_style_info info = {.size = 48};
|
||||||
if (!hyprcursor_load_theme_style(mgr, info)) {
|
if (!hyprcursor_load_theme_style(mgr, info)) {
|
||||||
printf("load failed\n");
|
printf("load failed\n");
|
|
@ -1,3 +1,11 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
full_rendering.cpp
|
||||||
|
|
||||||
|
This example shows probably what you want to do.
|
||||||
|
Hyprcursor will render a left_ptr shape at 48x48px to a file called /tmp/arrow.png
|
||||||
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <hyprcursor/hyprcursor.hpp>
|
#include <hyprcursor/hyprcursor.hpp>
|
||||||
|
|
||||||
|
@ -5,29 +13,43 @@ void logFunction(enum eHyprcursorLogLevel level, char* message) {
|
||||||
std::cout << "[hc] " << message << "\n";
|
std::cout << "[hc] " << message << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
hyprlang-test in C++.
|
|
||||||
Renders a cursor shape to /tmp at 48px
|
|
||||||
*/
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
/*
|
||||||
|
Create a manager. You can optionally pass a logger function.
|
||||||
|
*/
|
||||||
Hyprcursor::CHyprcursorManager mgr(nullptr, logFunction);
|
Hyprcursor::CHyprcursorManager mgr(nullptr, logFunction);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Manager could be invalid if no themes were found, or
|
||||||
|
a specified theme was invalid.
|
||||||
|
*/
|
||||||
if (!mgr.valid()) {
|
if (!mgr.valid()) {
|
||||||
std::cout << "mgr is invalid\n";
|
std::cout << "mgr is invalid\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Style describes what pixel size you want your cursor
|
||||||
|
images to be.
|
||||||
|
|
||||||
|
Remember to free styles once you're done with them
|
||||||
|
(e.g. the user requested to change the cursor size to something else)
|
||||||
|
*/
|
||||||
Hyprcursor::SCursorStyleInfo style{.size = 48};
|
Hyprcursor::SCursorStyleInfo style{.size = 48};
|
||||||
// preload size 48 for testing
|
|
||||||
if (!mgr.loadThemeStyle(style)) {
|
if (!mgr.loadThemeStyle(style)) {
|
||||||
std::cout << "failed loading style\n";
|
std::cout << "failed loading style\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get cursor for left_ptr
|
/*
|
||||||
|
Get a shape. This will return the data about available image(s),
|
||||||
|
their delay, hotspot, etc.
|
||||||
|
*/
|
||||||
const auto SHAPEDATA = mgr.getShape("left_ptr", style);
|
const auto SHAPEDATA = mgr.getShape("left_ptr", style);
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the size doesn't exist, images will be empty.
|
||||||
|
*/
|
||||||
if (SHAPEDATA.images.empty()) {
|
if (SHAPEDATA.images.empty()) {
|
||||||
std::cout << "no images\n";
|
std::cout << "no images\n";
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -35,11 +57,16 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
std::cout << "hyprcursor returned " << SHAPEDATA.images.size() << " images\n";
|
std::cout << "hyprcursor returned " << SHAPEDATA.images.size() << " images\n";
|
||||||
|
|
||||||
// save to disk
|
/*
|
||||||
|
Save to disk with cairo
|
||||||
|
*/
|
||||||
const auto RET = cairo_surface_write_to_png(SHAPEDATA.images[0].surface, "/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";
|
||||||
|
|
||||||
|
/*
|
||||||
|
As mentioned before, clean up by releasing the style.
|
||||||
|
*/
|
||||||
mgr.cursorSurfaceStyleDone(style);
|
mgr.cursorSurfaceStyleDone(style);
|
||||||
|
|
||||||
if (RET)
|
if (RET)
|
80
tests/only_metadata.cpp
Normal file
80
tests/only_metadata.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
only_metadata.cpp
|
||||||
|
|
||||||
|
This is a mode in which you probably do NOT want to operate,
|
||||||
|
but major DEs might want their own renderer for
|
||||||
|
cursor shapes.
|
||||||
|
|
||||||
|
Prefer full_rendering.cpp for consistency and simplicity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <hyprcursor/hyprcursor.hpp>
|
||||||
|
|
||||||
|
void logFunction(enum eHyprcursorLogLevel level, char* message) {
|
||||||
|
std::cout << "[hc] " << message << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
/*
|
||||||
|
Create a manager. You can optionally pass a logger function.
|
||||||
|
*/
|
||||||
|
Hyprcursor::CHyprcursorManager mgr(nullptr, logFunction);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Manager could be invalid if no themes were found, or
|
||||||
|
a specified theme was invalid.
|
||||||
|
*/
|
||||||
|
if (!mgr.valid()) {
|
||||||
|
std::cout << "mgr is invalid\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If you are planning on using your own renderer,
|
||||||
|
you do not want to load in any styles, as those
|
||||||
|
are rendered once you make your call.
|
||||||
|
|
||||||
|
Instead, let's request left_ptr's metadata
|
||||||
|
*/
|
||||||
|
auto RAWDATA = mgr.getRawShapeData("left_ptr");
|
||||||
|
|
||||||
|
/*
|
||||||
|
if images are empty, check overridenBy
|
||||||
|
*/
|
||||||
|
if (RAWDATA.images.empty()) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
if overridenBy is empty, the current theme doesn't have this shape.
|
||||||
|
*/
|
||||||
|
if (RAWDATA.overridenBy.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
load what it's overriden by.
|
||||||
|
*/
|
||||||
|
RAWDATA = mgr.getRawShapeData(RAWDATA.overridenBy.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If we still have no images, the theme seems broken.
|
||||||
|
*/
|
||||||
|
if (RAWDATA.images.empty()) {
|
||||||
|
std::cout << "failed querying left_ptr\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can query the images (animation frames)
|
||||||
|
or their properties.
|
||||||
|
|
||||||
|
Every image has .data and .type for you to handle.
|
||||||
|
*/
|
||||||
|
std::cout << "left_ptr images: " << RAWDATA.images.size() << "\n";
|
||||||
|
for (auto& i : RAWDATA.images)
|
||||||
|
std::cout << "left_ptr data size: " << i.data.size() << "\n";
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue