mirror of
https://github.com/hyprwm/hyprcursor.git
synced 2024-12-22 18:29:48 +01:00
parent
f388aacd22
commit
84203d8126
5 changed files with 48 additions and 29 deletions
|
@ -54,6 +54,7 @@ struct SCursorRawShapeDataC {
|
||||||
char* overridenBy;
|
char* overridenBy;
|
||||||
enum eHyprcursorResizeAlgo resizeAlgo;
|
enum eHyprcursorResizeAlgo resizeAlgo;
|
||||||
enum eHyprcursorDataType type;
|
enum eHyprcursorDataType type;
|
||||||
|
float nominalSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct SCursorRawShapeDataC hyprcursor_cursor_raw_shape_data;
|
typedef struct SCursorRawShapeDataC hyprcursor_cursor_raw_shape_data;
|
||||||
|
|
|
@ -307,13 +307,15 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
||||||
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;
|
||||||
|
|
||||||
|
const int PIXELSIDE = std::round(info.size / shape->nominalSize);
|
||||||
|
|
||||||
hotX = shape->hotspotX;
|
hotX = shape->hotspotX;
|
||||||
hotY = shape->hotspotY;
|
hotY = shape->hotspotY;
|
||||||
|
|
||||||
// matched :)
|
// matched :)
|
||||||
bool foundAny = false;
|
bool foundAny = false;
|
||||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||||
if (image->side != info.size)
|
if (image->side != PIXELSIDE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// found size
|
// found size
|
||||||
|
@ -333,7 +335,7 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
||||||
// find nearest
|
// find nearest
|
||||||
int leader = 13371337;
|
int leader = 13371337;
|
||||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||||
if (std::abs((int)(image->side - info.size)) > std::abs((int)(leader - info.size)))
|
if (std::abs((int)(image->side - PIXELSIDE)) > std::abs((int)(leader - PIXELSIDE)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
leader = image->side;
|
leader = image->side;
|
||||||
|
@ -392,8 +394,9 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
|
||||||
data->overridenBy = nullptr;
|
data->overridenBy = nullptr;
|
||||||
data->images = nullptr;
|
data->images = nullptr;
|
||||||
data->len = 0;
|
data->len = 0;
|
||||||
data->hotspotX = 0;
|
data->hotspotX = 0.f;
|
||||||
data->hotspotY = 0;
|
data->hotspotY = 0.F;
|
||||||
|
data->nominalSize = 1.F;
|
||||||
data->resizeAlgo = eHyprcursorResizeAlgo::HC_RESIZE_NONE;
|
data->resizeAlgo = eHyprcursorResizeAlgo::HC_RESIZE_NONE;
|
||||||
data->type = eHyprcursorDataType::HC_DATA_PNG;
|
data->type = eHyprcursorDataType::HC_DATA_PNG;
|
||||||
|
|
||||||
|
@ -418,9 +421,10 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
|
||||||
resultingImages.push_back(i.get());
|
resultingImages.push_back(i.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
data->hotspotX = shape->hotspotX;
|
data->hotspotX = shape->hotspotX;
|
||||||
data->hotspotY = shape->hotspotY;
|
data->hotspotY = shape->hotspotY;
|
||||||
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
|
data->nominalSize = shape->nominalSize;
|
||||||
|
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,8 +454,10 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
bool sizeFound = false;
|
bool sizeFound = false;
|
||||||
|
|
||||||
if (shape->shapeType == SHAPE_PNG) {
|
if (shape->shapeType == SHAPE_PNG) {
|
||||||
|
const int IDEALSIDE = std::round(info.size / shape->nominalSize);
|
||||||
|
|
||||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||||
if (image->side != info.size)
|
if (image->side != IDEALSIDE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sizeFound = true;
|
sizeFound = true;
|
||||||
|
@ -465,7 +471,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
SLoadedCursorImage* leader = nullptr;
|
SLoadedCursorImage* leader = nullptr;
|
||||||
int leaderVal = 1000000;
|
int leaderVal = 1000000;
|
||||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||||
if (image->side < info.size)
|
if (image->side < IDEALSIDE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (image->side > leaderVal)
|
if (image->side > leaderVal)
|
||||||
|
@ -477,7 +483,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
|
|
||||||
if (!leader) {
|
if (!leader) {
|
||||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||||
if (std::abs((int)(image->side - info.size)) > leaderVal)
|
if (std::abs((int)(image->side - IDEALSIDE)) > leaderVal)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
leaderVal = image->side;
|
leaderVal = image->side;
|
||||||
|
@ -494,12 +500,16 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
|
|
||||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape {} has {} frames", shape->directory, FRAMES.size());
|
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape {} has {} frames", shape->directory, FRAMES.size());
|
||||||
|
|
||||||
|
const int PIXELSIDE = std::round(leader->side / shape->nominalSize);
|
||||||
|
|
||||||
|
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape has nominal {:.2f}, pixel size will be {}x", shape->nominalSize, PIXELSIDE);
|
||||||
|
|
||||||
for (auto& f : FRAMES) {
|
for (auto& f : FRAMES) {
|
||||||
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
||||||
newImage->artificial = true;
|
newImage->artificial = true;
|
||||||
newImage->side = info.size;
|
newImage->side = PIXELSIDE;
|
||||||
newImage->artificialData = new char[info.size * info.size * 4];
|
newImage->artificialData = new char[PIXELSIDE * PIXELSIDE * 4];
|
||||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
|
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
|
||||||
newImage->delay = f->delay;
|
newImage->delay = f->delay;
|
||||||
|
|
||||||
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
||||||
|
@ -513,12 +523,12 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
|
|
||||||
const auto PTN = cairo_pattern_create_for_surface(f->cairoSurface);
|
const auto PTN = cairo_pattern_create_for_surface(f->cairoSurface);
|
||||||
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 = PIXELSIDE / (float)f->side;
|
||||||
cairo_scale(PCAIRO, scale, scale);
|
cairo_scale(PCAIRO, scale, scale);
|
||||||
cairo_pattern_set_filter(PTN, shape->resizeAlgo == HC_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, PIXELSIDE, PIXELSIDE);
|
||||||
|
|
||||||
cairo_fill(PCAIRO);
|
cairo_fill(PCAIRO);
|
||||||
cairo_surface_flush(newImage->cairoSurface);
|
cairo_surface_flush(newImage->cairoSurface);
|
||||||
|
@ -531,12 +541,16 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
|
|
||||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: svg shape {} has {} frames", shape->directory, FRAMES.size());
|
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: svg shape {} has {} frames", shape->directory, FRAMES.size());
|
||||||
|
|
||||||
|
const int PIXELSIDE = std::round(info.size / shape->nominalSize);
|
||||||
|
|
||||||
|
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: svg shape has nominal {:.2f}, pixel size will be {}x", shape->nominalSize, PIXELSIDE);
|
||||||
|
|
||||||
for (auto& f : FRAMES) {
|
for (auto& f : FRAMES) {
|
||||||
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
||||||
newImage->artificial = true;
|
newImage->artificial = true;
|
||||||
newImage->side = info.size;
|
newImage->side = PIXELSIDE;
|
||||||
newImage->artificialData = new char[info.size * info.size * 4];
|
newImage->artificialData = new char[PIXELSIDE * PIXELSIDE * 4];
|
||||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
|
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
|
||||||
newImage->delay = f->delay;
|
newImage->delay = f->delay;
|
||||||
|
|
||||||
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
||||||
|
@ -554,7 +568,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RsvgRectangle rect = {0, 0, (double)info.size, (double)info.size};
|
RsvgRectangle rect = {0, 0, (double)PIXELSIDE, (double)PIXELSIDE};
|
||||||
|
|
||||||
if (!rsvg_handle_render_document(handle, PCAIRO, &rect, &error)) {
|
if (!rsvg_handle_render_document(handle, PCAIRO, &rect, &error)) {
|
||||||
Debug::log(HC_LOG_ERR, logFn, "Failed rendering svg: {}", error->message);
|
Debug::log(HC_LOG_ERR, logFn, "Failed rendering svg: {}", error->message);
|
||||||
|
@ -584,7 +598,7 @@ void CHyprcursorManager::cursorSurfaceStyleDone(const SCursorStyleInfo& info) {
|
||||||
const bool isArtificial = e->artificial;
|
const bool isArtificial = e->artificial;
|
||||||
|
|
||||||
// clean artificial rasters made for this
|
// clean artificial rasters made for this
|
||||||
if (isArtificial && e->side == info.size)
|
if (isArtificial && e->side == std::round(info.size / shape->nominalSize))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// clean invalid non-svg rasters
|
// clean invalid non-svg rasters
|
||||||
|
@ -766,10 +780,11 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
|
||||||
if (SHAPE->images.empty())
|
if (SHAPE->images.empty())
|
||||||
return "meta invalid: no images for shape " + cursor.path().stem().string();
|
return "meta invalid: no images for shape " + cursor.path().stem().string();
|
||||||
|
|
||||||
SHAPE->directory = cursor.path().stem().string();
|
SHAPE->directory = cursor.path().stem().string();
|
||||||
SHAPE->hotspotX = meta.parsedData.hotspotX;
|
SHAPE->hotspotX = meta.parsedData.hotspotX;
|
||||||
SHAPE->hotspotY = meta.parsedData.hotspotY;
|
SHAPE->hotspotY = meta.parsedData.hotspotY;
|
||||||
SHAPE->resizeAlgo = stringToAlgo(meta.parsedData.resizeAlgo);
|
SHAPE->nominalSize = meta.parsedData.nominalSize;
|
||||||
|
SHAPE->resizeAlgo = stringToAlgo(meta.parsedData.resizeAlgo);
|
||||||
|
|
||||||
zip_discard(zip);
|
zip_discard(zip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ struct SCursorImage {
|
||||||
|
|
||||||
struct SCursorShape {
|
struct SCursorShape {
|
||||||
std::string directory;
|
std::string directory;
|
||||||
float hotspotX = 0, hotspotY = 0;
|
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
|
||||||
eHyprcursorResizeAlgo resizeAlgo = HC_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;
|
||||||
|
|
|
@ -142,6 +142,7 @@ std::optional<std::string> CMeta::parseHL() {
|
||||||
meta = std::make_unique<Hyprlang::CConfig>(rawdata.c_str(), Hyprlang::SConfigOptions{.pathIsStream = !dataPath});
|
meta = std::make_unique<Hyprlang::CConfig>(rawdata.c_str(), Hyprlang::SConfigOptions{.pathIsStream = !dataPath});
|
||||||
meta->addConfigValue("hotspot_x", Hyprlang::FLOAT{0.F});
|
meta->addConfigValue("hotspot_x", Hyprlang::FLOAT{0.F});
|
||||||
meta->addConfigValue("hotspot_y", Hyprlang::FLOAT{0.F});
|
meta->addConfigValue("hotspot_y", Hyprlang::FLOAT{0.F});
|
||||||
|
meta->addConfigValue("nominal_size", Hyprlang::FLOAT{1.F});
|
||||||
meta->addConfigValue("resize_algorithm", Hyprlang::STRING{"nearest"});
|
meta->addConfigValue("resize_algorithm", Hyprlang::STRING{"nearest"});
|
||||||
meta->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false});
|
meta->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false});
|
||||||
meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false});
|
meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false});
|
||||||
|
@ -151,9 +152,10 @@ std::optional<std::string> CMeta::parseHL() {
|
||||||
return RESULT.getError();
|
return RESULT.getError();
|
||||||
} catch (const char* err) { return "failed parsing meta: " + std::string{err}; }
|
} catch (const char* err) { return "failed parsing meta: " + std::string{err}; }
|
||||||
|
|
||||||
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
|
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
|
||||||
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
|
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
|
||||||
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
|
parsedData.nominalSize = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("nominal_size"));
|
||||||
|
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -164,6 +166,7 @@ std::optional<std::string> CMeta::parseTOML() {
|
||||||
|
|
||||||
parsedData.hotspotX = MANIFEST["General"]["hotspot_x"].value_or(0.f);
|
parsedData.hotspotX = MANIFEST["General"]["hotspot_x"].value_or(0.f);
|
||||||
parsedData.hotspotY = MANIFEST["General"]["hotspot_y"].value_or(0.f);
|
parsedData.hotspotY = MANIFEST["General"]["hotspot_y"].value_or(0.f);
|
||||||
|
parsedData.hotspotY = MANIFEST["General"]["nominal_size"].value_or(1.f);
|
||||||
|
|
||||||
const std::string OVERRIDES = MANIFEST["General"]["define_override"].value_or("");
|
const std::string OVERRIDES = MANIFEST["General"]["define_override"].value_or("");
|
||||||
const std::string SIZES = MANIFEST["General"]["define_size"].value_or("");
|
const std::string SIZES = MANIFEST["General"]["define_size"].value_or("");
|
||||||
|
|
|
@ -20,7 +20,7 @@ class CMeta {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
std::string resizeAlgo;
|
std::string resizeAlgo;
|
||||||
float hotspotX = 0, hotspotY = 0;
|
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
|
||||||
std::vector<std::string> overrides;
|
std::vector<std::string> overrides;
|
||||||
std::vector<SDefinedSize> definedSizes;
|
std::vector<SDefinedSize> definedSizes;
|
||||||
} parsedData;
|
} parsedData;
|
||||||
|
|
Loading…
Reference in a new issue