mirror of
https://github.com/hyprwm/hyprcursor.git
synced 2025-12-20 20:20:02 +01:00
Compare commits
No commits in common. "main" and "v0.1.8" have entirely different histories.
23 changed files with 209 additions and 515 deletions
101
.clang-tidy
101
.clang-tidy
|
|
@ -1,101 +0,0 @@
|
|||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: '.*\.hpp'
|
||||
FormatStyle: file
|
||||
Checks: >
|
||||
-*,
|
||||
bugprone-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-forward-declararion-namespace,
|
||||
-bugprone-forward-declararion-namespace,
|
||||
-bugprone-macro-parentheses,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-assignment-in-if-condition,
|
||||
concurrency-*,
|
||||
-concurrency-mt-unsafe,
|
||||
cppcoreguidelines-*,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-avoid-goto,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||
-cppcoreguidelines-special-member-functions,
|
||||
-cppcoreguidelines-explicit-virtual-functions,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-narrowing-conversions,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-pro-type-member-init,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-macro-to-enum,
|
||||
-cppcoreguidelines-init-variables,
|
||||
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||
google-global-names-in-headers,
|
||||
-google-readability-casting,
|
||||
google-runtime-operator,
|
||||
misc-*,
|
||||
-misc-unused-parameters,
|
||||
-misc-no-recursion,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-include-cleaner,
|
||||
-misc-use-anonymous-namespace,
|
||||
-misc-const-correctness,
|
||||
modernize-*,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-using,
|
||||
-modernize-use-override,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-macro-to-enum,
|
||||
-modernize-loop-convert,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-pass-by-value,
|
||||
-modernize-use-auto,
|
||||
performance-*,
|
||||
-performance-avoid-endl,
|
||||
-performance-unnecessary-value-param,
|
||||
portability-std-allocator-const,
|
||||
readability-*,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-function-size,
|
||||
-readability-identifier-length,
|
||||
-readability-magic-numbers,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-braces-around-statements,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-else-after-return,
|
||||
-readability-container-data-pointer,
|
||||
-readability-implicit-bool-conversion,
|
||||
-readability-avoid-nested-conditional-operator,
|
||||
-readability-redundant-member-init,
|
||||
-readability-redundant-string-init,
|
||||
-readability-avoid-const-params-in-decls,
|
||||
-readability-named-parameter,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-qualified-auto,
|
||||
-readability-make-member-function-const,
|
||||
-readability-isolate-declaration,
|
||||
-readability-inconsistent-declaration-parameter-name,
|
||||
-clang-diagnostic-error,
|
||||
|
||||
CheckOptions:
|
||||
performance-for-range-copy.WarnOnAllAutoCopies: true
|
||||
performance-inefficient-string-concatenation.StrictMode: true
|
||||
readability-braces-around-statements.ShortStatementLines: 0
|
||||
readability-identifier-naming.ClassCase: CamelCase
|
||||
readability-identifier-naming.ClassIgnoredRegexp: I.*
|
||||
readability-identifier-naming.ClassPrefix: C # We can't use regex here?!?!?!?
|
||||
readability-identifier-naming.EnumCase: CamelCase
|
||||
readability-identifier-naming.EnumPrefix: e
|
||||
readability-identifier-naming.EnumConstantCase: UPPER_CASE
|
||||
readability-identifier-naming.FunctionCase: camelBack
|
||||
readability-identifier-naming.NamespaceCase: CamelCase
|
||||
readability-identifier-naming.NamespacePrefix: N
|
||||
readability-identifier-naming.StructPrefix: S
|
||||
readability-identifier-naming.StructCase: CamelCase
|
||||
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
|
|
@ -18,10 +18,6 @@ jobs:
|
|||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang cairo librsvg git libzip tomlplusplus
|
||||
|
||||
- name: Get hyprutils-git
|
||||
run: |
|
||||
git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build
|
||||
|
||||
- name: Install hyprlang
|
||||
run: |
|
||||
git clone https://github.com/hyprwm/hyprlang --recursive
|
||||
|
|
|
|||
39
.github/workflows/test.yml
vendored
39
.github/workflows/test.yml
vendored
|
|
@ -1,39 +0,0 @@
|
|||
name: Test
|
||||
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
jobs:
|
||||
nix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
|
||||
# not needed (yet)
|
||||
# - uses: cachix/cachix-action@v12
|
||||
# with:
|
||||
# name: hyprland
|
||||
# authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
||||
- name: Build
|
||||
run: nix build .#hyprcursor-with-tests --print-build-logs --keep-going
|
||||
|
||||
# keep a fixed rev in case anything changes
|
||||
- name: Install hyprcursor theme
|
||||
run: nix build github:fufexan/dotfiles/4e05e373c1c70a2ae259b2c15eec2ad6e11ce581#bibata-hyprcursor --print-build-logs --keep-going
|
||||
|
||||
- name: Set up env
|
||||
run: |
|
||||
export HYPRCURSOR_THEME=Bibata-Modern-Classic-Hyprcursor
|
||||
export HYPRCURSOR_SIZE=16
|
||||
mkdir -p $HOME/.local/share/icons
|
||||
ln -s $(realpath result/share/icons/Bibata-Modern-Classic-Hyprcursor) $HOME/.local/share/icons/
|
||||
|
||||
- name: Run test1
|
||||
run: nix shell .#hyprcursor-with-tests -c hyprcursor_test1
|
||||
- name: Run test2
|
||||
run: nix shell .#hyprcursor-with-tests -c hyprcursor_test2
|
||||
- name: Run test_c
|
||||
run: nix shell .#hyprcursor-with-tests -c hyprcursor_test_c
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,2 @@
|
|||
.vscode/
|
||||
build/
|
||||
.cache/
|
||||
|
|
|
|||
101
CMakeLists.txt
101
CMakeLists.txt
|
|
@ -1,14 +1,12 @@
|
|||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
|
||||
string(STRIP ${VER_RAW} HYPRCURSOR_VERSION)
|
||||
|
||||
set(HYPRCURSOR_VERSION "0.1.7")
|
||||
add_compile_definitions(HYPRCURSOR_VERSION="${HYPRCURSOR_VERSION}")
|
||||
|
||||
project(
|
||||
hyprcursor
|
||||
project(hyprcursor
|
||||
VERSION ${HYPRCURSOR_VERSION}
|
||||
DESCRIPTION "A library and toolkit for the Hyprland cursor format")
|
||||
DESCRIPTION "A library and toolkit for the Hyprland cursor format"
|
||||
)
|
||||
|
||||
include(CTest)
|
||||
include(GNUInstallDirs)
|
||||
|
|
@ -20,27 +18,9 @@ set(LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR})
|
|||
configure_file(hyprcursor.pc.in hyprcursor.pc @ONLY)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
-Wno-unused-parameter
|
||||
-Wno-unused-value
|
||||
-Wno-missing-field-initializers
|
||||
-Wno-narrowing
|
||||
-Wno-pointer-arith)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(
|
||||
deps
|
||||
REQUIRED
|
||||
IMPORTED_TARGET
|
||||
hyprlang>=0.4.2
|
||||
libzip
|
||||
cairo
|
||||
librsvg-2.0
|
||||
tomlplusplus)
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprlang>=0.4.2 libzip cairo librsvg-2.0 tomlplusplus)
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
message(STATUS "Configuring hyprcursor in Debug")
|
||||
|
|
@ -50,43 +30,36 @@ else()
|
|||
message(STATUS "Configuring hyprcursor in Release")
|
||||
endif()
|
||||
|
||||
file(
|
||||
GLOB_RECURSE
|
||||
SRCFILES
|
||||
CONFIGURE_DEPENDS
|
||||
"libhyprcursor/*.cpp"
|
||||
"include/hyprcursor/hyprcursor.hpp"
|
||||
"include/hyprcursor/hyprcursor.h"
|
||||
"include/hyprcursor/shared.h")
|
||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "libhyprcursor/*.cpp" "include/hyprcursor/hyprcursor.hpp" "include/hyprcursor/hyprcursor.h" "include/hyprcursor/shared.h")
|
||||
|
||||
add_library(hyprcursor SHARED ${SRCFILES})
|
||||
target_include_directories(
|
||||
hyprcursor
|
||||
target_include_directories( hyprcursor
|
||||
PUBLIC "./include"
|
||||
PRIVATE "./libhyprcursor")
|
||||
set_target_properties(
|
||||
hyprcursor
|
||||
PROPERTIES VERSION ${hyprcursor_VERSION}
|
||||
PRIVATE "./libhyprcursor"
|
||||
)
|
||||
set_target_properties(hyprcursor PROPERTIES
|
||||
VERSION ${hyprcursor_VERSION}
|
||||
SOVERSION 0
|
||||
PUBLIC_HEADER include/hyprcursor/hyprcursor.hpp
|
||||
include/hyprcursor/hyprcursor.h include/hyprcursor/shared.h)
|
||||
PUBLIC_HEADER include/hyprcursor/hyprcursor.hpp include/hyprcursor/hyprcursor.h include/hyprcursor/shared.h
|
||||
)
|
||||
|
||||
target_link_libraries(hyprcursor PkgConfig::deps)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# for std::expected.
|
||||
# probably evil. Arch's clang is very outdated tho...
|
||||
target_compile_options(hyprcursor PUBLIC
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-std=gnu++2b -D__cpp_concepts=202002L>
|
||||
-Wno-builtin-macro-redefined)
|
||||
endif()
|
||||
|
||||
# hyprcursor-util
|
||||
file(
|
||||
GLOB_RECURSE
|
||||
UTILSRCFILES
|
||||
CONFIGURE_DEPENDS
|
||||
"hyprcursor-util/src/*.cpp"
|
||||
"include/hyprcursor/hyprcursor.hpp"
|
||||
"include/hyprcursor/hyprcursor.h"
|
||||
"include/hyprcursor/shared.h")
|
||||
file(GLOB_RECURSE UTILSRCFILES CONFIGURE_DEPENDS "hyprcursor-util/src/*.cpp" "include/hyprcursor/hyprcursor.hpp" "include/hyprcursor/hyprcursor.h" "include/hyprcursor/shared.h")
|
||||
add_executable(hyprcursor-util ${UTILSRCFILES})
|
||||
target_include_directories(
|
||||
hyprcursor-util
|
||||
target_include_directories(hyprcursor-util
|
||||
PUBLIC "./include"
|
||||
PRIVATE "./libhyprcursor" "./hyprcursor-util/src")
|
||||
PRIVATE "./libhyprcursor" "./hyprcursor-util/src"
|
||||
)
|
||||
target_link_libraries(hyprcursor-util PkgConfig::deps hyprcursor)
|
||||
|
||||
# tests
|
||||
|
|
@ -94,37 +67,21 @@ add_custom_target(tests)
|
|||
|
||||
add_executable(hyprcursor_test1 "tests/full_rendering.cpp")
|
||||
target_link_libraries(hyprcursor_test1 PRIVATE hyprcursor)
|
||||
add_test(
|
||||
NAME "Test libhyprcursor in C++ (full rendering)"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
|
||||
COMMAND hyprcursor_test1)
|
||||
add_test(NAME "Test libhyprcursor in C++ (full rendering)" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprcursor_test1)
|
||||
add_dependencies(tests hyprcursor_test1)
|
||||
|
||||
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_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)
|
||||
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)
|
||||
|
||||
# Installation
|
||||
install(TARGETS hyprcursor)
|
||||
install(TARGETS hyprcursor-util)
|
||||
install(DIRECTORY "include/hyprcursor" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${CMAKE_BINARY_DIR}/hyprcursor.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
if(INSTALL_TESTS)
|
||||
install(TARGETS hyprcursor_test1)
|
||||
install(TARGETS hyprcursor_test2)
|
||||
install(TARGETS hyprcursor_test_c)
|
||||
endif()
|
||||
install(FILES ${CMAKE_BINARY_DIR}/hyprcursor.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -16,11 +16,6 @@ doesn't suck as much.
|
|||
- Support for SVG cursors
|
||||
- Way more space-efficient. As an example, Bibata-XCursor is 44.1MB, while it's 6.6MB in hyprcursor.
|
||||
|
||||
## Documentation
|
||||
See the [wiki here](https://wiki.hyprland.org/Hypr-Ecosystem/hyprcursor/)
|
||||
check out [docs/](./docs)
|
||||
and [standards](https://standards.hyprland.org/hyprcursor)
|
||||
|
||||
## Tools
|
||||
|
||||
### hyprcursor-util
|
||||
|
|
@ -37,6 +32,20 @@ It provides C and C++ bindings.
|
|||
|
||||
For both C and C++, see `tests/`.
|
||||
|
||||
## Docs
|
||||
|
||||
See `docs/`.
|
||||
|
||||
## TODO
|
||||
|
||||
Library:
|
||||
- [x] Support animated cursors
|
||||
- [x] Support SVG cursors
|
||||
|
||||
Util:
|
||||
- [ ] Support compiling a theme with X
|
||||
- [x] Support decompiling animated cursors
|
||||
|
||||
## Building
|
||||
|
||||
### Deps:
|
||||
|
|
@ -44,12 +53,11 @@ For both C and C++, see `tests/`.
|
|||
- cairo
|
||||
- libzip
|
||||
- librsvg
|
||||
- tomlplusplus
|
||||
|
||||
### 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:
|
||||
|
|
|
|||
1
VERSION
1
VERSION
|
|
@ -1 +0,0 @@
|
|||
0.1.13
|
||||
|
|
@ -49,7 +49,7 @@ Each cursor image is a separate directory. In it, multiple size variations can b
|
|||
resize_algorithm = bilinear
|
||||
|
||||
# "hotspot" is where in your cursor the actual "click point" should be.
|
||||
# this is in absolute coordinates. x+ is east, y+ is south.
|
||||
# this is in absolute coordinates. x+ is east, y+ is north.
|
||||
# the pixel coordinates of the hotspot at size are rounded to the nearest:
|
||||
# (round(size * hotspot_x), round(size * hotspot_y))
|
||||
hotspot_x = 0.0 # this goes 0 - 1
|
||||
|
|
@ -58,7 +58,6 @@ hotspot_y = 0.0 # this goes 0 - 1
|
|||
# Define what cursor images this one should override.
|
||||
# What this means is that a request for a cursor name e.g. "arrow"
|
||||
# will instead use this one, even if this one is named something else.
|
||||
# There is no unified list for all the available cursor names but this wayland list could be used as a reference https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/cursor-shape/cursor-shape-v1.xml#L71 for wayland specific cursors.
|
||||
define_override = arrow
|
||||
define_override = default
|
||||
|
||||
|
|
@ -72,7 +71,6 @@ define_size = 32, image32.png
|
|||
# define_size = 64, anim2.png, 500
|
||||
# define_size = 64, anim3.png, 500
|
||||
# define_size = 64, anim4.png, 500
|
||||
# Make sure the timeout is > 0, as otherwise the consumer might ignore your timeouts for being invalid.
|
||||
```
|
||||
|
||||
Supported cursor image types are png and svg.
|
||||
|
|
|
|||
38
flake.lock
generated
38
flake.lock
generated
|
|
@ -2,7 +2,6 @@
|
|||
"nodes": {
|
||||
"hyprlang": {
|
||||
"inputs": {
|
||||
"hyprutils": "hyprutils",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
|
|
@ -11,11 +10,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749145882,
|
||||
"narHash": "sha256-qr0KXeczF8Sma3Ae7+dR2NHhvG7YeLBJv19W4oMu6ZE=",
|
||||
"lastModified": 1713121246,
|
||||
"narHash": "sha256-502X0Q0fhN6tJK7iEUA8CghONKSatW/Mqj4Wappd++0=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "1bfb84f54d50c7ae6558c794d3cfd5f6a7e6e676",
|
||||
"rev": "78fcaa27ae9e1d782faa3ff06c8ea55ddce63706",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -24,38 +23,13 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprutils": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"hyprlang",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"hyprlang",
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749135356,
|
||||
"narHash": "sha256-Q8mAKMDsFbCEuq7zoSlcTuxgbIBVhfIYpX0RjE32PS0=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "e36db00dfb3a3d3fdcc4069cb292ff60d2699ccb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1748929857,
|
||||
"narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=",
|
||||
"lastModified": 1712963716,
|
||||
"narHash": "sha256-WKm9CvgCldeIVvRz87iOMi8CFVB1apJlkUT4GGvA0iM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4",
|
||||
"rev": "cfd6b5fc90b15709b780a5a1619695a88505a176",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
packages = eachSystem (system: {
|
||||
default = self.packages.${system}.hyprcursor;
|
||||
inherit (pkgsFor.${system}) hyprcursor hyprcursor-with-tests;
|
||||
inherit (pkgsFor.${system}) hyprcursor;
|
||||
});
|
||||
|
||||
checks = eachSystem (system: self.packages.${system});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include <zip.h>
|
||||
#include <optional>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <array>
|
||||
#include <format>
|
||||
#include <algorithm>
|
||||
|
|
@ -16,12 +15,12 @@
|
|||
#define ZIP_LENGTH_TO_END -1
|
||||
#endif
|
||||
|
||||
enum eOperation : uint8_t {
|
||||
enum eOperation {
|
||||
OPERATION_CREATE = 0,
|
||||
OPERATION_EXTRACT = 1,
|
||||
};
|
||||
|
||||
static eHyprcursorResizeAlgo explicitResizeAlgo = HC_RESIZE_INVALID;
|
||||
eHyprcursorResizeAlgo explicitResizeAlgo = HC_RESIZE_INVALID;
|
||||
|
||||
struct XCursorConfigEntry {
|
||||
int size = 0, hotspotX = 0, hotspotY = 0, delay = 0;
|
||||
|
|
@ -119,7 +118,7 @@ static std::optional<std::string> createCursorThemeFromPath(const std::string& p
|
|||
return "couldn't parse meta: " + *PARSERESULT2;
|
||||
|
||||
for (auto& i : meta.parsedData.definedSizes) {
|
||||
SHAPE->images.push_back(SCursorImage{.filename = i.file, .size = i.size, .delay = i.delayMs});
|
||||
SHAPE->images.push_back(SCursorImage{i.file, i.size, i.delayMs});
|
||||
}
|
||||
|
||||
SHAPE->overrides = meta.parsedData.overrides;
|
||||
|
|
@ -388,7 +387,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
eOperation op = OPERATION_CREATE;
|
||||
std::string path = "", out = "";
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
for (size_t i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
|
||||
if (arg == "-v" || arg == "--version") {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
#include "shared.h"
|
||||
|
|
@ -47,22 +47,6 @@ 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.
|
||||
|
||||
|
|
@ -84,7 +68,6 @@ namespace Hyprcursor {
|
|||
\since 0.1.6
|
||||
*/
|
||||
CHyprcursorManager(const char* themeName, PHYPRCURSORLOGFUNC fn);
|
||||
CHyprcursorManager(const char* themeName, SManagerOptions options);
|
||||
~CHyprcursorManager();
|
||||
|
||||
/*!
|
||||
|
|
@ -114,7 +97,7 @@ namespace Hyprcursor {
|
|||
|
||||
SCursorShapeData data;
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
SCursorImageData image;
|
||||
image.delay = images[i]->delay;
|
||||
image.size = images[i]->size;
|
||||
|
|
@ -191,7 +174,6 @@ namespace Hyprcursor {
|
|||
|
||||
CHyprcursorImplementation* impl = nullptr;
|
||||
bool finalizedAndValid = false;
|
||||
bool allowDefaultFallback = true;
|
||||
PHYPRCURSORLOGFUNC logFn = nullptr;
|
||||
|
||||
friend class CHyprcursorImplementation;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ struct SCursorRawShapeDataC {
|
|||
char* overridenBy;
|
||||
enum eHyprcursorResizeAlgo resizeAlgo;
|
||||
enum eHyprcursorDataType type;
|
||||
float nominalSize;
|
||||
};
|
||||
|
||||
typedef struct SCursorRawShapeDataC hyprcursor_cursor_raw_shape_data;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char del
|
|||
std::string args{in};
|
||||
size_t idx = 0;
|
||||
size_t pos = 0;
|
||||
std::ranges::replace_if(args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0);
|
||||
std::ranges::replace_if(
|
||||
args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0);
|
||||
|
||||
for (const auto& s : args | std::views::split(0)) {
|
||||
if (removeEmpty && s.empty())
|
||||
|
|
@ -38,7 +39,7 @@ CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char del
|
|||
break;
|
||||
}
|
||||
pos += s.size() + 1;
|
||||
m_vArgs.emplace_back(removeBeginEndSpacesTabs(s.data()));
|
||||
m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
#include "internalSharedTypes.hpp"
|
||||
#include "internalDefines.hpp"
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <zip.h>
|
||||
#include <cstring>
|
||||
|
|
@ -18,25 +15,11 @@
|
|||
|
||||
using namespace Hyprcursor;
|
||||
|
||||
static std::vector<std::string> getSystemThemeDirs() {
|
||||
const auto envXdgData = std::getenv("XDG_DATA_DIRS");
|
||||
std::vector<std::string> result;
|
||||
if (envXdgData) {
|
||||
std::stringstream envXdgStream(envXdgData);
|
||||
std::string tmpStr;
|
||||
while (getline(envXdgStream, tmpStr, ':'))
|
||||
result.push_back((tmpStr + "/icons"));
|
||||
} else
|
||||
result = {"/usr/share/icons"};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<std::string> systemThemeDirs = getSystemThemeDirs();
|
||||
// directories for lookup
|
||||
constexpr const std::array<const char*, 1> systemThemeDirs = {"/usr/share/icons"};
|
||||
constexpr const std::array<const char*, 2> userThemeDirs = {"/.local/share/icons", "/.icons"};
|
||||
|
||||
//
|
||||
|
||||
static std::string themeNameFromEnv(PHYPRCURSORLOGFUNC logfn) {
|
||||
const auto ENV = getenv("HYPRCURSOR_THEME");
|
||||
if (!ENV) {
|
||||
|
|
@ -97,7 +80,7 @@ static std::string getFirstTheme(PHYPRCURSORLOGFUNC logfn) {
|
|||
}
|
||||
|
||||
for (auto& dir : systemThemeDirs) {
|
||||
const auto& FULLPATH = dir;
|
||||
const auto FULLPATH = dir;
|
||||
if (!pathAccessible(FULLPATH)) {
|
||||
Debug::log(HC_LOG_TRACE, logfn, "Skipping path {} because it's inaccessible.", FULLPATH);
|
||||
continue;
|
||||
|
|
@ -125,7 +108,7 @@ static std::string getFirstTheme(PHYPRCURSORLOGFUNC logfn) {
|
|||
return "";
|
||||
}
|
||||
|
||||
static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORLOGFUNC logfn, bool allowDefaultFallback) {
|
||||
static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORLOGFUNC logfn) {
|
||||
const auto HOMEENV = getenv("HOME");
|
||||
if (!HOMEENV)
|
||||
return "";
|
||||
|
|
@ -151,7 +134,7 @@ static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORL
|
|||
|
||||
const auto MANIFESTPATH = themeDir.path().string() + "/manifest";
|
||||
|
||||
if (allowDefaultFallback && name.empty()) {
|
||||
if (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();
|
||||
|
|
@ -176,7 +159,7 @@ static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORL
|
|||
}
|
||||
|
||||
for (auto& dir : systemThemeDirs) {
|
||||
const auto& FULLPATH = dir;
|
||||
const auto FULLPATH = dir;
|
||||
if (!pathAccessible(FULLPATH)) {
|
||||
Debug::log(HC_LOG_TRACE, logfn, "Skipping path {} because it's inaccessible.", FULLPATH);
|
||||
continue;
|
||||
|
|
@ -210,40 +193,33 @@ static std::string getFullPathForThemeName(const std::string& name, PHYPRCURSORL
|
|||
}
|
||||
}
|
||||
|
||||
if (allowDefaultFallback && !name.empty()) { // try without name
|
||||
if (!name.empty()) { // try without name
|
||||
Debug::log(HC_LOG_INFO, logfn, "getFullPathForThemeName: failed, trying without name of {}", name);
|
||||
return getFullPathForThemeName("", logfn, allowDefaultFallback);
|
||||
return getFullPathForThemeName("", logfn);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
SManagerOptions::SManagerOptions() : logFn(nullptr), allowDefaultFallback(true) {
|
||||
;
|
||||
}
|
||||
|
||||
CHyprcursorManager::CHyprcursorManager(const char* themeName_) {
|
||||
init(themeName_);
|
||||
}
|
||||
|
||||
CHyprcursorManager::CHyprcursorManager(const char* themeName_, PHYPRCURSORLOGFUNC fn) : logFn(fn) {
|
||||
init(themeName_);
|
||||
}
|
||||
|
||||
CHyprcursorManager::CHyprcursorManager(const char* themeName_, SManagerOptions options) : allowDefaultFallback(options.allowDefaultFallback), logFn(options.logFn) {
|
||||
CHyprcursorManager::CHyprcursorManager(const char* themeName_, PHYPRCURSORLOGFUNC fn) {
|
||||
logFn = fn;
|
||||
init(themeName_);
|
||||
}
|
||||
|
||||
void CHyprcursorManager::init(const char* themeName_) {
|
||||
std::string themeName = themeName_ ? themeName_ : "";
|
||||
|
||||
if (allowDefaultFallback && themeName.empty()) {
|
||||
if (themeName.empty()) {
|
||||
// try reading from env
|
||||
Debug::log(HC_LOG_INFO, logFn, "CHyprcursorManager: attempting to find theme from env");
|
||||
themeName = themeNameFromEnv(logFn);
|
||||
}
|
||||
|
||||
if (allowDefaultFallback && themeName.empty()) {
|
||||
if (themeName.empty()) {
|
||||
// try finding first, in the hierarchy
|
||||
Debug::log(HC_LOG_INFO, logFn, "CHyprcursorManager: attempting to find any theme");
|
||||
themeName = getFirstTheme(logFn);
|
||||
|
|
@ -258,7 +234,7 @@ void CHyprcursorManager::init(const char* themeName_) {
|
|||
// initialize theme
|
||||
impl = new CHyprcursorImplementation(this, logFn);
|
||||
impl->themeName = themeName;
|
||||
impl->themeFullDir = getFullPathForThemeName(themeName, logFn, allowDefaultFallback);
|
||||
impl->themeFullDir = getFullPathForThemeName(themeName, logFn);
|
||||
|
||||
if (impl->themeFullDir.empty())
|
||||
return;
|
||||
|
|
@ -281,6 +257,7 @@ void CHyprcursorManager::init(const char* themeName_) {
|
|||
}
|
||||
|
||||
CHyprcursorManager::~CHyprcursorManager() {
|
||||
if (impl)
|
||||
delete impl;
|
||||
}
|
||||
|
||||
|
|
@ -303,15 +280,13 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
|||
if (REQUESTEDSHAPE != shape->directory && std::find(shape->overrides.begin(), shape->overrides.end(), REQUESTEDSHAPE) == shape->overrides.end())
|
||||
continue;
|
||||
|
||||
const int PIXELSIDE = std::round(info.size / shape->nominalSize);
|
||||
|
||||
hotX = shape->hotspotX;
|
||||
hotY = shape->hotspotY;
|
||||
|
||||
// matched :)
|
||||
bool foundAny = false;
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (image->side != PIXELSIDE)
|
||||
if (image->side != info.size)
|
||||
continue;
|
||||
|
||||
// found size
|
||||
|
|
@ -331,7 +306,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 - PIXELSIDE)) > std::abs((int)(leader - PIXELSIDE)))
|
||||
if (std::abs((int)(image->side - info.size)) > leader)
|
||||
continue;
|
||||
|
||||
leader = image->side;
|
||||
|
|
@ -387,25 +362,14 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
|
|||
|
||||
SCursorRawShapeDataC* data = new SCursorRawShapeDataC;
|
||||
std::vector<SLoadedCursorImage*> resultingImages;
|
||||
data->overridenBy = nullptr;
|
||||
data->images = nullptr;
|
||||
data->len = 0;
|
||||
data->hotspotX = 0.f;
|
||||
data->hotspotY = 0.F;
|
||||
data->nominalSize = 1.F;
|
||||
data->resizeAlgo = eHyprcursorResizeAlgo::HC_RESIZE_NONE;
|
||||
data->type = eHyprcursorDataType::HC_DATA_PNG;
|
||||
|
||||
for (auto& shape : impl->theme.shapes) {
|
||||
// if it's overridden just return the override
|
||||
if (const auto IT = std::find_if(shape->overrides.begin(), shape->overrides.end(), [&](const auto& e) { return e == SHAPE && SHAPE != shape->directory; });
|
||||
IT != shape->overrides.end()) {
|
||||
data->overridenBy = strdup(shape->directory.c_str());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& shape : impl->theme.shapes) {
|
||||
if (shape->directory != SHAPE)
|
||||
continue;
|
||||
|
||||
|
|
@ -419,7 +383,6 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
|
|||
|
||||
data->hotspotX = shape->hotspotX;
|
||||
data->hotspotY = shape->hotspotY;
|
||||
data->nominalSize = shape->nominalSize;
|
||||
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
|
||||
break;
|
||||
}
|
||||
|
|
@ -450,10 +413,8 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
bool sizeFound = false;
|
||||
|
||||
if (shape->shapeType == SHAPE_PNG) {
|
||||
const int IDEALSIDE = std::round(info.size / shape->nominalSize);
|
||||
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (image->side != IDEALSIDE)
|
||||
if (image->side != info.size)
|
||||
continue;
|
||||
|
||||
sizeFound = true;
|
||||
|
|
@ -467,7 +428,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
SLoadedCursorImage* leader = nullptr;
|
||||
int leaderVal = 1000000;
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (image->side < IDEALSIDE)
|
||||
if (image->side < info.size)
|
||||
continue;
|
||||
|
||||
if (image->side > leaderVal)
|
||||
|
|
@ -479,7 +440,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
if (!leader) {
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (std::abs((int)(image->side - IDEALSIDE)) > leaderVal)
|
||||
if (std::abs((int)(image->side - info.size)) > leaderVal)
|
||||
continue;
|
||||
|
||||
leaderVal = image->side;
|
||||
|
|
@ -496,16 +457,12 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape {} has {} frames", shape->directory, FRAMES.size());
|
||||
|
||||
const int PIXELSIDE = std::round(info.size / 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) {
|
||||
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
||||
newImage->artificial = true;
|
||||
newImage->side = PIXELSIDE;
|
||||
newImage->artificialData = new char[static_cast<unsigned long>(PIXELSIDE * PIXELSIDE * 4)];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
|
||||
newImage->side = info.size;
|
||||
newImage->artificialData = new char[info.size * info.size * 4];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
|
||||
newImage->delay = f->delay;
|
||||
|
||||
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
||||
|
|
@ -519,12 +476,12 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
const auto PTN = cairo_pattern_create_for_surface(f->cairoSurface);
|
||||
cairo_pattern_set_extend(PTN, CAIRO_EXTEND_NONE);
|
||||
const float scale = PIXELSIDE / (float)f->side;
|
||||
const float scale = info.size / (float)f->side;
|
||||
cairo_scale(PCAIRO, scale, scale);
|
||||
cairo_pattern_set_filter(PTN, shape->resizeAlgo == HC_RESIZE_BILINEAR ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST);
|
||||
cairo_set_source(PCAIRO, PTN);
|
||||
|
||||
cairo_rectangle(PCAIRO, 0, 0, PIXELSIDE, PIXELSIDE);
|
||||
cairo_rectangle(PCAIRO, 0, 0, info.size, info.size);
|
||||
|
||||
cairo_fill(PCAIRO);
|
||||
cairo_surface_flush(newImage->cairoSurface);
|
||||
|
|
@ -537,16 +494,12 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
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) {
|
||||
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
||||
newImage->artificial = true;
|
||||
newImage->side = PIXELSIDE;
|
||||
newImage->artificialData = new char[static_cast<unsigned long>(PIXELSIDE * PIXELSIDE * 4)];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
|
||||
newImage->side = info.size;
|
||||
newImage->artificialData = new char[info.size * info.size * 4];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
|
||||
newImage->delay = f->delay;
|
||||
|
||||
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
||||
|
|
@ -564,18 +517,16 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
return false;
|
||||
}
|
||||
|
||||
RsvgRectangle rect = {0, 0, (double)PIXELSIDE, (double)PIXELSIDE};
|
||||
RsvgRectangle rect = {0, 0, (double)info.size, (double)info.size};
|
||||
|
||||
if (!rsvg_handle_render_document(handle, PCAIRO, &rect, &error)) {
|
||||
Debug::log(HC_LOG_ERR, logFn, "Failed rendering svg: {}", error->message);
|
||||
g_object_unref(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
// done
|
||||
cairo_surface_flush(newImage->cairoSurface);
|
||||
cairo_destroy(PCAIRO);
|
||||
g_object_unref(handle);
|
||||
}
|
||||
} else {
|
||||
Debug::log(HC_LOG_ERR, logFn, "Invalid shapetype in loadThemeStyle");
|
||||
|
|
@ -596,7 +547,7 @@ void CHyprcursorManager::cursorSurfaceStyleDone(const SCursorStyleInfo& info) {
|
|||
const bool isArtificial = e->artificial;
|
||||
|
||||
// clean artificial rasters made for this
|
||||
if (isArtificial && e->side == std::round(info.size / shape->nominalSize))
|
||||
if (isArtificial && e->side == info.size)
|
||||
return true;
|
||||
|
||||
// clean invalid non-svg rasters
|
||||
|
|
@ -672,22 +623,18 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
|
|||
int errp = 0;
|
||||
zip_t* zip = zip_open(cursor.path().string().c_str(), ZIP_RDONLY, &errp);
|
||||
|
||||
zip_int64_t index = zip_name_locate(zip, "meta.hl", ZIP_FL_ENC_GUESS);
|
||||
zip_file_t* meta_file = zip_fopen(zip, "meta.hl", ZIP_FL_UNCHANGED);
|
||||
bool metaIsHL = true;
|
||||
|
||||
if (index == -1) {
|
||||
index = zip_name_locate(zip, "meta.toml", ZIP_FL_ENC_GUESS);
|
||||
if (!meta_file) {
|
||||
meta_file = zip_fopen(zip, "meta.toml", ZIP_FL_UNCHANGED);
|
||||
metaIsHL = false;
|
||||
if (!meta_file)
|
||||
return "cursor" + cursor.path().string() + "failed to load meta";
|
||||
}
|
||||
|
||||
if (index == -1)
|
||||
return "cursor" + cursor.path().string() + "failed to load meta";
|
||||
char* buffer = new char[1024 * 1024]; /* 1MB should be more than enough */
|
||||
|
||||
zip_file_t* meta_file = zip_fopen_index(zip, index, ZIP_FL_UNCHANGED);
|
||||
|
||||
char* buffer = new char[static_cast<unsigned long>(1024 * 1024)]; /* 1MB should be more than enough */
|
||||
|
||||
int readBytes = zip_fread(meta_file, buffer, (1024 * 1024) - 1);
|
||||
int readBytes = zip_fread(meta_file, buffer, 1024 * 1024 - 1);
|
||||
|
||||
zip_fclose(meta_file);
|
||||
|
||||
|
|
@ -707,14 +654,11 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
|
|||
return "cursor" + cursor.path().string() + "failed to parse meta: " + *METAPARSERESULT;
|
||||
|
||||
for (auto& i : meta.parsedData.definedSizes) {
|
||||
SHAPE->images.push_back(SCursorImage{.filename = i.file, .size = i.size, .delay = i.delayMs});
|
||||
SHAPE->images.push_back(SCursorImage{i.file, i.size, i.delayMs});
|
||||
}
|
||||
|
||||
SHAPE->overrides = meta.parsedData.overrides;
|
||||
|
||||
zip_stat_t sb;
|
||||
zip_stat_init(&sb);
|
||||
|
||||
for (auto& i : SHAPE->images) {
|
||||
if (SHAPE->shapeType == SHAPE_INVALID) {
|
||||
if (i.filename.ends_with(".svg"))
|
||||
|
|
@ -739,23 +683,14 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
|
|||
IMAGE->delay = i.delay;
|
||||
IMAGE->isSVG = SHAPE->shapeType == SHAPE_SVG;
|
||||
|
||||
index = zip_name_locate(zip, i.filename.c_str(), ZIP_FL_ENC_GUESS);
|
||||
if (index == -1)
|
||||
// read from zip
|
||||
zip_file_t* image_file = zip_fopen(zip, i.filename.c_str(), ZIP_FL_UNCHANGED);
|
||||
if (!image_file)
|
||||
return "cursor" + cursor.path().string() + "failed to load image_file";
|
||||
|
||||
// read from zip
|
||||
zip_file_t* image_file = zip_fopen_index(zip, index, ZIP_FL_UNCHANGED);
|
||||
zip_stat_index(zip, index, ZIP_FL_UNCHANGED, &sb);
|
||||
IMAGE->data = new char[1024 * 1024]; /* 1MB should be more than enough, again. This probably should be in the spec. */
|
||||
|
||||
if (sb.valid & ZIP_STAT_SIZE) {
|
||||
IMAGE->data = new char[sb.size + 1];
|
||||
IMAGE->dataLen = sb.size + 1;
|
||||
} else {
|
||||
IMAGE->data = new char[static_cast<unsigned long>(1024 * 1024)]; /* 1MB should be more than enough, again. This probably should be in the spec. */
|
||||
IMAGE->dataLen = static_cast<size_t>(1024 * 1024);
|
||||
}
|
||||
|
||||
IMAGE->dataLen = zip_fread(image_file, IMAGE->data, IMAGE->dataLen - 1);
|
||||
IMAGE->dataLen = zip_fread(image_file, IMAGE->data, 1024 * 1024 - 1);
|
||||
|
||||
zip_fclose(image_file);
|
||||
|
||||
|
|
@ -766,7 +701,7 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
|
|||
IMAGE->cairoSurface = cairo_image_surface_create_from_png_stream(::readPNG, IMAGE);
|
||||
|
||||
if (const auto STATUS = cairo_surface_status(IMAGE->cairoSurface); STATUS != CAIRO_STATUS_SUCCESS) {
|
||||
delete[] (char*)IMAGE->data;
|
||||
delete[](char*) IMAGE->data;
|
||||
IMAGE->data = nullptr;
|
||||
return "Failed reading cairoSurface, status " + std::to_string((int)STATUS);
|
||||
}
|
||||
|
|
@ -781,7 +716,6 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
|
|||
SHAPE->directory = cursor.path().stem().string();
|
||||
SHAPE->hotspotX = meta.parsedData.hotspotX;
|
||||
SHAPE->hotspotY = meta.parsedData.hotspotY;
|
||||
SHAPE->nominalSize = meta.parsedData.nominalSize;
|
||||
SHAPE->resizeAlgo = stringToAlgo(meta.parsedData.resizeAlgo);
|
||||
|
||||
zip_discard(zip);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ struct SCursorImageData** hyprcursor_get_cursor_image_data(struct hyprcursor_man
|
|||
}
|
||||
|
||||
void hyprcursor_cursor_image_data_free(hyprcursor_cursor_image_data** data, int size) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
free(data[i]);
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ void hyprcursor_style_done(hyprcursor_manager_t* manager, hyprcursor_cursor_styl
|
|||
const auto MGR = (CHyprcursorManager*)manager;
|
||||
SCursorStyleInfo info;
|
||||
info.size = info_.size;
|
||||
MGR->cursorSurfaceStyleDone(info);
|
||||
return MGR->cursorSurfaceStyleDone(info);
|
||||
}
|
||||
|
||||
void hyprcursor_register_logging_function(struct hyprcursor_manager_t* manager, PHYPRCURSORLOGFUNC fn) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ struct SCursorImage {
|
|||
|
||||
struct SCursorShape {
|
||||
std::string directory;
|
||||
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
|
||||
float hotspotX = 0, hotspotY = 0;
|
||||
eHyprcursorResizeAlgo resizeAlgo = HC_RESIZE_NEAREST;
|
||||
std::vector<SCursorImage> images;
|
||||
std::vector<std::string> overrides;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
#include <toml++/toml.hpp>
|
||||
#include <filesystem>
|
||||
#include <regex>
|
||||
#include <algorithm>
|
||||
|
||||
#include "VarList.hpp"
|
||||
|
||||
static CMeta* currentMeta = nullptr;
|
||||
CMeta* currentMeta = nullptr;
|
||||
|
||||
CMeta::CMeta(const std::string& rawdata_, bool hyprlang_ /* false for toml */, bool dataIsPath) : dataPath(dataIsPath), hyprlang(hyprlang_), rawdata(rawdata_) {
|
||||
CMeta::CMeta(const std::string& rawdata_, bool hyprlang_ /* false for toml */, bool dataIsPath) : rawdata(rawdata_), hyprlang(hyprlang_), dataPath(dataIsPath) {
|
||||
if (!dataIsPath)
|
||||
return;
|
||||
|
||||
|
|
@ -72,23 +71,20 @@ static Hyprlang::CParseResult parseDefineSize(const char* C, const char* V) {
|
|||
Hyprlang::CParseResult result;
|
||||
const std::string VALUE = V;
|
||||
|
||||
CVarList sizes(VALUE, 0, ';');
|
||||
|
||||
for (const auto& sizeStr : sizes) {
|
||||
if (!sizeStr.contains(",")) {
|
||||
if (!VALUE.contains(",")) {
|
||||
result.setError("Invalid define_size");
|
||||
return result;
|
||||
}
|
||||
|
||||
auto LHS = removeBeginEndSpacesTabs(sizeStr.substr(0, sizeStr.find_first_of(",")));
|
||||
auto RHS = removeBeginEndSpacesTabs(sizeStr.substr(sizeStr.find_first_of(",") + 1));
|
||||
auto LHS = removeBeginEndSpacesTabs(VALUE.substr(0, VALUE.find_first_of(",")));
|
||||
auto RHS = removeBeginEndSpacesTabs(VALUE.substr(VALUE.find_first_of(",") + 1));
|
||||
auto DELAY = 0;
|
||||
|
||||
CMeta::SDefinedSize size;
|
||||
|
||||
if (RHS.contains(",")) {
|
||||
const auto LL = removeBeginEndSpacesTabs(RHS.substr(0, RHS.find(',')));
|
||||
const auto RR = removeBeginEndSpacesTabs(RHS.substr(RHS.find(',') + 1));
|
||||
const auto LL = removeBeginEndSpacesTabs(RHS.substr(0, RHS.find(",")));
|
||||
const auto RR = removeBeginEndSpacesTabs(RHS.substr(RHS.find(",") + 1));
|
||||
|
||||
try {
|
||||
size.delayMs = std::stoull(RR);
|
||||
|
|
@ -118,7 +114,6 @@ static Hyprlang::CParseResult parseDefineSize(const char* C, const char* V) {
|
|||
size.size = 0;
|
||||
|
||||
currentMeta->parsedData.definedSizes.push_back(size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -127,11 +122,7 @@ static Hyprlang::CParseResult parseOverride(const char* C, const char* V) {
|
|||
Hyprlang::CParseResult result;
|
||||
const std::string VALUE = V;
|
||||
|
||||
CVarList overrides(VALUE, 0, ';');
|
||||
|
||||
for (const auto& o : overrides) {
|
||||
currentMeta->parsedData.overrides.push_back(o);
|
||||
}
|
||||
currentMeta->parsedData.overrides.push_back(VALUE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -143,7 +134,6 @@ std::optional<std::string> CMeta::parseHL() {
|
|||
meta = std::make_unique<Hyprlang::CConfig>(rawdata.c_str(), Hyprlang::SConfigOptions{.pathIsStream = !dataPath});
|
||||
meta->addConfigValue("hotspot_x", 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->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false});
|
||||
meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false});
|
||||
|
|
@ -155,7 +145,6 @@ std::optional<std::string> CMeta::parseHL() {
|
|||
|
||||
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
|
||||
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
|
||||
parsedData.nominalSize = std::clamp(std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("nominal_size")), 0.1F, 2.F);
|
||||
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
|
||||
|
||||
return {};
|
||||
|
|
@ -167,7 +156,6 @@ std::optional<std::string> CMeta::parseTOML() {
|
|||
|
||||
parsedData.hotspotX = MANIFEST["General"]["hotspot_x"].value_or(0.f);
|
||||
parsedData.hotspotY = MANIFEST["General"]["hotspot_y"].value_or(0.f);
|
||||
parsedData.nominalSize = std::clamp(MANIFEST["General"]["nominal_size"].value_or(1.F), 0.1F, 2.F);
|
||||
|
||||
const std::string OVERRIDES = MANIFEST["General"]["define_override"].value_or("");
|
||||
const std::string SIZES = MANIFEST["General"]["define_size"].value_or("");
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class CMeta {
|
|||
|
||||
struct {
|
||||
std::string resizeAlgo;
|
||||
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
|
||||
float hotspotX = 0, hotspotY = 0;
|
||||
std::vector<std::string> overrides;
|
||||
std::vector<SDefinedSize> definedSizes;
|
||||
} parsedData;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
hyprlang,
|
||||
librsvg,
|
||||
libzip,
|
||||
xcur2png,
|
||||
tomlplusplus,
|
||||
version ? "git",
|
||||
}:
|
||||
|
|
@ -16,6 +15,11 @@ stdenv.mkDerivation {
|
|||
inherit version;
|
||||
src = ../.;
|
||||
|
||||
patches = [
|
||||
# adds /run/current-system/sw/share/icons to the icon lookup directories
|
||||
./dirs.patch
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
|
|
@ -26,7 +30,6 @@ stdenv.mkDerivation {
|
|||
hyprlang
|
||||
librsvg
|
||||
libzip
|
||||
xcur2png
|
||||
tomlplusplus
|
||||
];
|
||||
|
||||
|
|
|
|||
13
nix/dirs.patch
Normal file
13
nix/dirs.patch
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/libhyprcursor/hyprcursor.cpp b/libhyprcursor/hyprcursor.cpp
|
||||
index 304ab9f..1f7e95d 100644
|
||||
--- a/libhyprcursor/hyprcursor.cpp
|
||||
+++ b/libhyprcursor/hyprcursor.cpp
|
||||
@@ -14,7 +14,7 @@
|
||||
using namespace Hyprcursor;
|
||||
|
||||
// directories for lookup
|
||||
-constexpr const std::array<const char*, 1> systemThemeDirs = {"/usr/share/icons"};
|
||||
+constexpr const std::array<const char*, 2> systemThemeDirs = {"/usr/share/icons", "/run/current-system/sw/share/icons"};
|
||||
constexpr const std::array<const char*, 2> userThemeDirs = {"/.local/share/icons", "/.icons"};
|
||||
|
||||
//
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
(builtins.substring 4 2 longDate)
|
||||
(builtins.substring 6 2 longDate)
|
||||
]);
|
||||
version = lib.removeSuffix "\n" (builtins.readFile ../VERSION);
|
||||
in {
|
||||
default = inputs.self.overlays.hyprcursor;
|
||||
|
||||
|
|
@ -15,14 +14,10 @@ in {
|
|||
inputs.hyprlang.overlays.default
|
||||
(final: prev: {
|
||||
hyprcursor = prev.callPackage ./default.nix {
|
||||
stdenv = prev.gcc15Stdenv;
|
||||
version = version + "+date=" + (mkDate (inputs.self.lastModifiedDate or "19700101")) + "_" + (inputs.self.shortRev or "dirty");
|
||||
stdenv = prev.gcc13Stdenv;
|
||||
version = "0.pre" + "+date=" + (mkDate (inputs.self.lastModifiedDate or "19700101")) + "_" + (inputs.self.shortRev or "dirty");
|
||||
inherit (final) hyprlang;
|
||||
};
|
||||
|
||||
hyprcursor-with-tests = final.hyprcursor.overrideAttrs (_: _: {
|
||||
cmakeFlags = [(lib.cmakeBool "INSTALL_TESTS" true)];
|
||||
});
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,26 +27,15 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
hyprcursor_cursor_raw_shape_data* shapeData = hyprcursor_get_raw_shape_data(mgr, "left_ptr");
|
||||
if (!shapeData) {
|
||||
if (!shapeData || shapeData->len <= 0) {
|
||||
printf("failed querying left_ptr\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (shapeData->overridenBy) {
|
||||
hyprcursor_cursor_raw_shape_data* ov = hyprcursor_get_raw_shape_data(mgr, shapeData->overridenBy);
|
||||
hyprcursor_raw_shape_data_free(shapeData);
|
||||
shapeData = ov;
|
||||
}
|
||||
|
||||
if (!shapeData || shapeData->len <= 0) {
|
||||
printf("left_ptr has no images\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("left_ptr images: %ld\n", shapeData->len);
|
||||
printf("left_ptr images: %d\n", shapeData->len);
|
||||
|
||||
for (size_t i = 0; i < shapeData->len; ++i) {
|
||||
printf("left_ptr image size: %ld\n", shapeData->images[i].len);
|
||||
printf("left_ptr image size: %d\n", shapeData->images[i].len);
|
||||
}
|
||||
|
||||
hyprcursor_raw_shape_data_free(shapeData);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue