New upstream version 0.1.9
This commit is contained in:
parent
f6be58e58e
commit
7f4eaa029d
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
set(HYPRCURSOR_VERSION "0.1.7")
|
||||
set(HYPRCURSOR_VERSION "0.1.9")
|
||||
add_compile_definitions(HYPRCURSOR_VERSION="${HYPRCURSOR_VERSION}")
|
||||
|
||||
project(hyprcursor
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ Util:
|
|||
### Build
|
||||
```sh
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf _NPROCESSORS_CONF`
|
||||
```
|
||||
|
||||
Install with:
|
||||
|
|
|
|||
33
flake.lock
33
flake.lock
|
|
@ -5,14 +5,16 @@
|
|||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": "systems"
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709914708,
|
||||
"narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=",
|
||||
"lastModified": 1713121246,
|
||||
"narHash": "sha256-502X0Q0fhN6tJK7iEUA8CghONKSatW/Mqj4Wappd++0=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2",
|
||||
"rev": "78fcaa27ae9e1d782faa3ff06c8ea55ddce63706",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -23,11 +25,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1708475490,
|
||||
"narHash": "sha256-g1v0TsWBQPX97ziznfJdWhgMyMGtoBFs102xSYO4syU=",
|
||||
"lastModified": 1712963716,
|
||||
"narHash": "sha256-WKm9CvgCldeIVvRz87iOMi8CFVB1apJlkUT4GGvA0iM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0e74ca98a74bc7270d28838369593635a5db3260",
|
||||
"rev": "cfd6b5fc90b15709b780a5a1619695a88505a176",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -41,7 +43,7 @@
|
|||
"inputs": {
|
||||
"hyprlang": "hyprlang",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems_2"
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
|
@ -58,21 +60,6 @@
|
|||
"repo": "default-linux",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1689347949,
|
||||
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default-linux",
|
||||
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default-linux",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
|
|||
|
|
@ -5,11 +5,16 @@
|
|||
#include <array>
|
||||
#include <format>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <hyprlang.hpp>
|
||||
#include "internalSharedTypes.hpp"
|
||||
#include "manifest.hpp"
|
||||
#include "meta.hpp"
|
||||
|
||||
#ifndef ZIP_LENGTH_TO_END
|
||||
#define ZIP_LENGTH_TO_END -1
|
||||
#endif
|
||||
|
||||
enum eOperation {
|
||||
OPERATION_CREATE = 0,
|
||||
OPERATION_EXTRACT = 1,
|
||||
|
|
@ -87,7 +92,7 @@ static std::optional<std::string> createCursorThemeFromPath(const std::string& p
|
|||
|
||||
const std::string THEMENAME = manifest.parsedData.name;
|
||||
|
||||
std::string out = (out_.empty() ? path.substr(0, path.find_last_of('/') + 1) : out_) + "/theme_" + THEMENAME + "/";
|
||||
std::string out = (out_.empty() ? path.substr(0, path.find_last_of('/')) : out_) + "/theme_" + THEMENAME;
|
||||
|
||||
const std::string CURSORSSUBDIR = manifest.parsedData.cursorsDirectory;
|
||||
const std::string CURSORDIR = path + "/" + CURSORSSUBDIR;
|
||||
|
|
@ -98,6 +103,9 @@ static std::optional<std::string> createCursorThemeFromPath(const std::string& p
|
|||
// iterate over the directory and record all cursors
|
||||
|
||||
for (auto& dir : std::filesystem::directory_iterator(CURSORDIR)) {
|
||||
if (!std::regex_match(dir.path().stem().string(), std::regex("^[A-Za-z0-9_\\-\\.]+$")))
|
||||
return "Invalid cursor directory name at " + dir.path().string() + " : characters must be within [A-Za-z0-9_\\-\\.]";
|
||||
|
||||
const auto METAPATH = dir.path().string() + "/meta";
|
||||
|
||||
auto& SHAPE = currentTheme.shapes.emplace_back(std::make_unique<SCursorShape>());
|
||||
|
|
@ -113,6 +121,8 @@ static std::optional<std::string> createCursorThemeFromPath(const std::string& p
|
|||
SHAPE->images.push_back(SCursorImage{i.file, i.size, i.delayMs});
|
||||
}
|
||||
|
||||
SHAPE->overrides = meta.parsedData.overrides;
|
||||
|
||||
// check if we have at least one image.
|
||||
for (auto& i : SHAPE->images) {
|
||||
|
||||
|
|
@ -178,7 +188,7 @@ static std::optional<std::string> createCursorThemeFromPath(const std::string& p
|
|||
|
||||
// add meta.hl
|
||||
const auto METADIR = std::filesystem::exists(CURRENTCURSORSDIR + "/meta.hl") ? (CURRENTCURSORSDIR + "/meta.hl") : (CURRENTCURSORSDIR + "/meta.toml");
|
||||
zip_source_t* meta = zip_source_file(zip, METADIR.c_str(), 0, 0);
|
||||
zip_source_t* meta = zip_source_file(zip, METADIR.c_str(), 0, ZIP_LENGTH_TO_END);
|
||||
if (!meta)
|
||||
return "(1) failed to add meta " + METADIR + " to hlc";
|
||||
if (zip_file_add(zip, (std::string{"meta."} + (METADIR.ends_with(".hl") ? "hl" : "toml")).c_str(), meta, ZIP_FL_ENC_UTF_8) < 0)
|
||||
|
|
@ -186,9 +196,9 @@ static std::optional<std::string> createCursorThemeFromPath(const std::string& p
|
|||
|
||||
meta = nullptr;
|
||||
|
||||
// add each cursor png
|
||||
// add each cursor image
|
||||
for (auto& i : shape->images) {
|
||||
zip_source_t* image = zip_source_file(zip, (CURRENTCURSORSDIR + "/" + i.filename).c_str(), 0, 0);
|
||||
zip_source_t* image = zip_source_file(zip, (CURRENTCURSORSDIR + "/" + i.filename).c_str(), 0, ZIP_LENGTH_TO_END);
|
||||
if (!image)
|
||||
return "(1) failed to add image " + (CURRENTCURSORSDIR + "/" + i.filename) + " to hlc";
|
||||
if (zip_file_add(zip, (i.filename).c_str(), image, ZIP_FL_ENC_UTF_8) < 0)
|
||||
|
|
@ -199,9 +209,8 @@ static std::optional<std::string> createCursorThemeFromPath(const std::string& p
|
|||
|
||||
// close zip and write
|
||||
if (zip_close(zip) < 0) {
|
||||
zip_error_t ziperror;
|
||||
zip_error_init_with_code(&ziperror, errp);
|
||||
return "Failed to write " + OUTPUTFILE + ": " + zip_error_strerror(&ziperror);
|
||||
zip_error_t* ziperror = zip_get_error(zip);
|
||||
return "Failed to write " + OUTPUTFILE + ": " + zip_error_strerror(ziperror);
|
||||
}
|
||||
|
||||
std::cout << "Written " << OUTPUTFILE << "\n";
|
||||
|
|
@ -449,4 +458,4 @@ int main(int argc, char** argv, char** envp) {
|
|||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,22 @@ namespace Hyprcursor {
|
|||
eHyprcursorDataType type = HC_DATA_PNG;
|
||||
};
|
||||
|
||||
/*!
|
||||
struct for cursor manager options
|
||||
*/
|
||||
struct SManagerOptions {
|
||||
explicit SManagerOptions();
|
||||
|
||||
/*!
|
||||
The function used for logging by the cursor manager
|
||||
*/
|
||||
PHYPRCURSORLOGFUNC logFn;
|
||||
/*!
|
||||
Allow fallback to env and first theme found
|
||||
*/
|
||||
bool allowDefaultFallback;
|
||||
};
|
||||
|
||||
/*!
|
||||
Basic Hyprcursor manager.
|
||||
|
||||
|
|
@ -58,6 +74,8 @@ namespace Hyprcursor {
|
|||
If none found, bool valid() will be false.
|
||||
|
||||
If loading fails, bool valid() will be false.
|
||||
|
||||
If theme has no valid cursor shapes, bool valid() will be false.
|
||||
*/
|
||||
class CHyprcursorManager {
|
||||
public:
|
||||
|
|
@ -66,6 +84,7 @@ namespace Hyprcursor {
|
|||
\since 0.1.6
|
||||
*/
|
||||
CHyprcursorManager(const char* themeName, PHYPRCURSORLOGFUNC fn);
|
||||
CHyprcursorManager(const char* themeName, SManagerOptions options);
|
||||
~CHyprcursorManager();
|
||||
|
||||
/*!
|
||||
|
|
@ -170,9 +189,10 @@ namespace Hyprcursor {
|
|||
private:
|
||||
void init(const char* themeName_);
|
||||
|
||||
CHyprcursorImplementation* impl = nullptr;
|
||||
bool finalizedAndValid = false;
|
||||
PHYPRCURSORLOGFUNC logFn = nullptr;
|
||||
CHyprcursorImplementation* impl = nullptr;
|
||||
bool finalizedAndValid = false;
|
||||
bool allowDefaultFallback = true;
|
||||
PHYPRCURSORLOGFUNC logFn = nullptr;
|
||||
|
||||
friend class CHyprcursorImplementation;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ static std::string getFirstTheme(PHYPRCURSORLOGFUNC logfn) {
|
|||
return "";
|
||||
}
|
||||
|
||||
static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORLOGFUNC logfn) {
|
||||
static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORLOGFUNC logfn, bool allowDefaultFallback) {
|
||||
const auto HOMEENV = getenv("HOME");
|
||||
if (!HOMEENV)
|
||||
return "";
|
||||
|
|
@ -134,7 +134,7 @@ static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORL
|
|||
|
||||
const auto MANIFESTPATH = themeDir.path().string() + "/manifest";
|
||||
|
||||
if (name.empty()) {
|
||||
if (allowDefaultFallback && name.empty()) {
|
||||
if (std::filesystem::exists(MANIFESTPATH + ".hl") || std::filesystem::exists(MANIFESTPATH + ".toml")) {
|
||||
Debug::log(HC_LOG_INFO, logfn, "getFullPathForThemeName: found {}", themeDir.path().string());
|
||||
return std::filesystem::canonical(themeDir.path()).string();
|
||||
|
|
@ -193,14 +193,19 @@ static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORL
|
|||
}
|
||||
}
|
||||
|
||||
if (!name.empty()) { // try without name
|
||||
if (allowDefaultFallback && !name.empty()) { // try without name
|
||||
Debug::log(HC_LOG_INFO, logfn, "getFullPathForThemeName: failed, trying without name of {}", name);
|
||||
return getFullPathForThemeName("", logfn);
|
||||
return getFullPathForThemeName("", logfn, allowDefaultFallback);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
SManagerOptions::SManagerOptions() {
|
||||
logFn = nullptr;
|
||||
allowDefaultFallback = true;
|
||||
}
|
||||
|
||||
CHyprcursorManager::CHyprcursorManager(const char* themeName_) {
|
||||
init(themeName_);
|
||||
}
|
||||
|
|
@ -210,16 +215,22 @@ CHyprcursorManager::CHyprcursorManager(const char* themeName_, PHYPRCURSORLOGFUN
|
|||
init(themeName_);
|
||||
}
|
||||
|
||||
CHyprcursorManager::CHyprcursorManager(const char* themeName_, SManagerOptions options) {
|
||||
logFn = options.logFn;
|
||||
allowDefaultFallback = options.allowDefaultFallback;
|
||||
init(themeName_);
|
||||
}
|
||||
|
||||
void CHyprcursorManager::init(const char* themeName_) {
|
||||
std::string themeName = themeName_ ? themeName_ : "";
|
||||
|
||||
if (themeName.empty()) {
|
||||
if (allowDefaultFallback && themeName.empty()) {
|
||||
// try reading from env
|
||||
Debug::log(HC_LOG_INFO, logFn, "CHyprcursorManager: attempting to find theme from env");
|
||||
themeName = themeNameFromEnv(logFn);
|
||||
}
|
||||
|
||||
if (themeName.empty()) {
|
||||
if (allowDefaultFallback && themeName.empty()) {
|
||||
// try finding first, in the hierarchy
|
||||
Debug::log(HC_LOG_INFO, logFn, "CHyprcursorManager: attempting to find any theme");
|
||||
themeName = getFirstTheme(logFn);
|
||||
|
|
@ -234,7 +245,7 @@ void CHyprcursorManager::init(const char* themeName_) {
|
|||
// initialize theme
|
||||
impl = new CHyprcursorImplementation(this, logFn);
|
||||
impl->themeName = themeName;
|
||||
impl->themeFullDir = getFullPathForThemeName(themeName, logFn);
|
||||
impl->themeFullDir = getFullPathForThemeName(themeName, logFn, allowDefaultFallback);
|
||||
|
||||
if (impl->themeFullDir.empty())
|
||||
return;
|
||||
|
|
@ -248,6 +259,11 @@ void CHyprcursorManager::init(const char* themeName_) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (impl->theme.shapes.empty()) {
|
||||
Debug::log(HC_LOG_ERR, logFn, "Theme {} has no valid cursor shapes\n", impl->themeName);
|
||||
return;
|
||||
}
|
||||
|
||||
finalizedAndValid = true;
|
||||
}
|
||||
|
||||
|
|
@ -301,7 +317,7 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
|||
// find nearest
|
||||
int leader = 13371337;
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (std::abs((int)(image->side - info.size)) > leader)
|
||||
if (std::abs((int)(image->side - info.size)) > std::abs((int)(leader - info.size)))
|
||||
continue;
|
||||
|
||||
leader = image->side;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <hyprlang.hpp>
|
||||
#include <toml++/toml.hpp>
|
||||
#include <filesystem>
|
||||
#include <regex>
|
||||
|
||||
#include "VarList.hpp"
|
||||
|
||||
|
|
@ -95,6 +96,11 @@ static Hyprlang::CParseResult parseDefineSize(const char* C, const char* V) {
|
|||
RHS = LL;
|
||||
}
|
||||
|
||||
if (!std::regex_match(RHS, std::regex("^[A-Za-z0-9_\\-\\.]+$"))) {
|
||||
result.setError("Invalid cursor file name, characters must be within [A-Za-z0-9_\\-\\.] (if this seems like a mistake, check for invisible characters)");
|
||||
return result;
|
||||
}
|
||||
|
||||
size.file = RHS;
|
||||
|
||||
if (!size.file.ends_with(".svg")) {
|
||||
|
|
@ -132,7 +138,9 @@ std::optional<std::string> CMeta::parseHL() {
|
|||
meta->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false});
|
||||
meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false});
|
||||
meta->commence();
|
||||
meta->parse();
|
||||
const auto RESULT = meta->parse();
|
||||
if (RESULT.error)
|
||||
return RESULT.getError();
|
||||
} catch (const char* err) { return "failed parsing meta: " + std::string{err}; }
|
||||
|
||||
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue