Skip to content

Commit 84203d8

Browse files
authored
core: add nominal size support (#73)
Adds nominal size support
1 parent f388aac commit 84203d8

5 files changed

Lines changed: 48 additions & 29 deletions

File tree

include/hyprcursor/shared.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct SCursorRawShapeDataC {
5454
char* overridenBy;
5555
enum eHyprcursorResizeAlgo resizeAlgo;
5656
enum eHyprcursorDataType type;
57+
float nominalSize;
5758
};
5859

5960
typedef struct SCursorRawShapeDataC hyprcursor_cursor_raw_shape_data;

libhyprcursor/hyprcursor.cpp

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -307,13 +307,15 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
307307
if (REQUESTEDSHAPE != shape->directory && std::find(shape->overrides.begin(), shape->overrides.end(), REQUESTEDSHAPE) == shape->overrides.end())
308308
continue;
309309

310+
const int PIXELSIDE = std::round(info.size / shape->nominalSize);
311+
310312
hotX = shape->hotspotX;
311313
hotY = shape->hotspotY;
312314

313315
// matched :)
314316
bool foundAny = false;
315317
for (auto& image : impl->loadedShapes[shape.get()].images) {
316-
if (image->side != info.size)
318+
if (image->side != PIXELSIDE)
317319
continue;
318320

319321
// found size
@@ -333,7 +335,7 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
333335
// find nearest
334336
int leader = 13371337;
335337
for (auto& image : impl->loadedShapes[shape.get()].images) {
336-
if (std::abs((int)(image->side - info.size)) > std::abs((int)(leader - info.size)))
338+
if (std::abs((int)(image->side - PIXELSIDE)) > std::abs((int)(leader - PIXELSIDE)))
337339
continue;
338340

339341
leader = image->side;
@@ -392,8 +394,9 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
392394
data->overridenBy = nullptr;
393395
data->images = nullptr;
394396
data->len = 0;
395-
data->hotspotX = 0;
396-
data->hotspotY = 0;
397+
data->hotspotX = 0.f;
398+
data->hotspotY = 0.F;
399+
data->nominalSize = 1.F;
397400
data->resizeAlgo = eHyprcursorResizeAlgo::HC_RESIZE_NONE;
398401
data->type = eHyprcursorDataType::HC_DATA_PNG;
399402

@@ -418,9 +421,10 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
418421
resultingImages.push_back(i.get());
419422
}
420423

421-
data->hotspotX = shape->hotspotX;
422-
data->hotspotY = shape->hotspotY;
423-
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
424+
data->hotspotX = shape->hotspotX;
425+
data->hotspotY = shape->hotspotY;
426+
data->nominalSize = shape->nominalSize;
427+
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
424428
break;
425429
}
426430

@@ -450,8 +454,10 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
450454
bool sizeFound = false;
451455

452456
if (shape->shapeType == SHAPE_PNG) {
457+
const int IDEALSIDE = std::round(info.size / shape->nominalSize);
458+
453459
for (auto& image : impl->loadedShapes[shape.get()].images) {
454-
if (image->side != info.size)
460+
if (image->side != IDEALSIDE)
455461
continue;
456462

457463
sizeFound = true;
@@ -465,7 +471,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
465471
SLoadedCursorImage* leader = nullptr;
466472
int leaderVal = 1000000;
467473
for (auto& image : impl->loadedShapes[shape.get()].images) {
468-
if (image->side < info.size)
474+
if (image->side < IDEALSIDE)
469475
continue;
470476

471477
if (image->side > leaderVal)
@@ -477,7 +483,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
477483

478484
if (!leader) {
479485
for (auto& image : impl->loadedShapes[shape.get()].images) {
480-
if (std::abs((int)(image->side - info.size)) > leaderVal)
486+
if (std::abs((int)(image->side - IDEALSIDE)) > leaderVal)
481487
continue;
482488

483489
leaderVal = image->side;
@@ -494,12 +500,16 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
494500

495501
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape {} has {} frames", shape->directory, FRAMES.size());
496502

503+
const int PIXELSIDE = std::round(leader->side / shape->nominalSize);
504+
505+
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape has nominal {:.2f}, pixel size will be {}x", shape->nominalSize, PIXELSIDE);
506+
497507
for (auto& f : FRAMES) {
498508
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
499509
newImage->artificial = true;
500-
newImage->side = info.size;
501-
newImage->artificialData = new char[info.size * info.size * 4];
502-
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
510+
newImage->side = PIXELSIDE;
511+
newImage->artificialData = new char[PIXELSIDE * PIXELSIDE * 4];
512+
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
503513
newImage->delay = f->delay;
504514

505515
const auto PCAIRO = cairo_create(newImage->cairoSurface);
@@ -513,12 +523,12 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
513523

514524
const auto PTN = cairo_pattern_create_for_surface(f->cairoSurface);
515525
cairo_pattern_set_extend(PTN, CAIRO_EXTEND_NONE);
516-
const float scale = info.size / (float)f->side;
526+
const float scale = PIXELSIDE / (float)f->side;
517527
cairo_scale(PCAIRO, scale, scale);
518528
cairo_pattern_set_filter(PTN, shape->resizeAlgo == HC_RESIZE_BILINEAR ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST);
519529
cairo_set_source(PCAIRO, PTN);
520530

521-
cairo_rectangle(PCAIRO, 0, 0, info.size, info.size);
531+
cairo_rectangle(PCAIRO, 0, 0, PIXELSIDE, PIXELSIDE);
522532

523533
cairo_fill(PCAIRO);
524534
cairo_surface_flush(newImage->cairoSurface);
@@ -531,12 +541,16 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
531541

532542
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: svg shape {} has {} frames", shape->directory, FRAMES.size());
533543

544+
const int PIXELSIDE = std::round(info.size / shape->nominalSize);
545+
546+
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: svg shape has nominal {:.2f}, pixel size will be {}x", shape->nominalSize, PIXELSIDE);
547+
534548
for (auto& f : FRAMES) {
535549
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
536550
newImage->artificial = true;
537-
newImage->side = info.size;
538-
newImage->artificialData = new char[info.size * info.size * 4];
539-
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
551+
newImage->side = PIXELSIDE;
552+
newImage->artificialData = new char[PIXELSIDE * PIXELSIDE * 4];
553+
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
540554
newImage->delay = f->delay;
541555

542556
const auto PCAIRO = cairo_create(newImage->cairoSurface);
@@ -554,7 +568,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
554568
return false;
555569
}
556570

557-
RsvgRectangle rect = {0, 0, (double)info.size, (double)info.size};
571+
RsvgRectangle rect = {0, 0, (double)PIXELSIDE, (double)PIXELSIDE};
558572

559573
if (!rsvg_handle_render_document(handle, PCAIRO, &rect, &error)) {
560574
Debug::log(HC_LOG_ERR, logFn, "Failed rendering svg: {}", error->message);
@@ -584,7 +598,7 @@ void CHyprcursorManager::cursorSurfaceStyleDone(const SCursorStyleInfo& info) {
584598
const bool isArtificial = e->artificial;
585599

586600
// clean artificial rasters made for this
587-
if (isArtificial && e->side == info.size)
601+
if (isArtificial && e->side == std::round(info.size / shape->nominalSize))
588602
return true;
589603

590604
// clean invalid non-svg rasters
@@ -766,10 +780,11 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
766780
if (SHAPE->images.empty())
767781
return "meta invalid: no images for shape " + cursor.path().stem().string();
768782

769-
SHAPE->directory = cursor.path().stem().string();
770-
SHAPE->hotspotX = meta.parsedData.hotspotX;
771-
SHAPE->hotspotY = meta.parsedData.hotspotY;
772-
SHAPE->resizeAlgo = stringToAlgo(meta.parsedData.resizeAlgo);
783+
SHAPE->directory = cursor.path().stem().string();
784+
SHAPE->hotspotX = meta.parsedData.hotspotX;
785+
SHAPE->hotspotY = meta.parsedData.hotspotY;
786+
SHAPE->nominalSize = meta.parsedData.nominalSize;
787+
SHAPE->resizeAlgo = stringToAlgo(meta.parsedData.resizeAlgo);
773788

774789
zip_discard(zip);
775790
}

libhyprcursor/internalSharedTypes.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct SCursorImage {
3737

3838
struct SCursorShape {
3939
std::string directory;
40-
float hotspotX = 0, hotspotY = 0;
40+
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
4141
eHyprcursorResizeAlgo resizeAlgo = HC_RESIZE_NEAREST;
4242
std::vector<SCursorImage> images;
4343
std::vector<std::string> overrides;

libhyprcursor/meta.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ std::optional<std::string> CMeta::parseHL() {
142142
meta = std::make_unique<Hyprlang::CConfig>(rawdata.c_str(), Hyprlang::SConfigOptions{.pathIsStream = !dataPath});
143143
meta->addConfigValue("hotspot_x", Hyprlang::FLOAT{0.F});
144144
meta->addConfigValue("hotspot_y", Hyprlang::FLOAT{0.F});
145+
meta->addConfigValue("nominal_size", Hyprlang::FLOAT{1.F});
145146
meta->addConfigValue("resize_algorithm", Hyprlang::STRING{"nearest"});
146147
meta->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false});
147148
meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false});
@@ -151,9 +152,10 @@ std::optional<std::string> CMeta::parseHL() {
151152
return RESULT.getError();
152153
} catch (const char* err) { return "failed parsing meta: " + std::string{err}; }
153154

154-
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
155-
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
156-
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
155+
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
156+
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
157+
parsedData.nominalSize = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("nominal_size"));
158+
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
157159

158160
return {};
159161
}
@@ -164,6 +166,7 @@ std::optional<std::string> CMeta::parseTOML() {
164166

165167
parsedData.hotspotX = MANIFEST["General"]["hotspot_x"].value_or(0.f);
166168
parsedData.hotspotY = MANIFEST["General"]["hotspot_y"].value_or(0.f);
169+
parsedData.hotspotY = MANIFEST["General"]["nominal_size"].value_or(1.f);
167170

168171
const std::string OVERRIDES = MANIFEST["General"]["define_override"].value_or("");
169172
const std::string SIZES = MANIFEST["General"]["define_size"].value_or("");

libhyprcursor/meta.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class CMeta {
2020

2121
struct {
2222
std::string resizeAlgo;
23-
float hotspotX = 0, hotspotY = 0;
23+
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
2424
std::vector<std::string> overrides;
2525
std::vector<SDefinedSize> definedSizes;
2626
} parsedData;

0 commit comments

Comments
 (0)