diff --git a/CMakeLists.txt b/CMakeLists.txt index fae0801..62ebb68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,8 @@ pkg_check_modules( libdrm gbm hyprutils>=0.2.3 - sdbus-c++>=2.0.0) + sdbus-c++>=2.0.0 + hyprgraphics) file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") add_executable(hyprlock ${SRCFILES}) diff --git a/README.md b/README.md index d6f26b9..d00d615 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ yay -S hyprlock-git # compiles from latest source ## Building ### Deps -You also need the following dependencies +You need the following dependencies - wayland-client - wayland-protocols - mesa @@ -37,6 +37,7 @@ And the development libraries for the following - pam - hyprlang - hyprutils +- hyprgraphics - libmagic (file-devel on Fedora) Development libraries are usually suffixed with `-devel` or `-dev` in most distro repos. diff --git a/flake.lock b/flake.lock index d29dbb2..707a698 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,31 @@ { "nodes": { + "hyprgraphics": { + "inputs": { + "hyprutils": [ + "hyprutils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1732808127, + "narHash": "sha256-jwqYmLVfvoLPu8UScEzZgdbbiNU3ioYcrsthjEEnGqI=", + "owner": "hyprwm", + "repo": "hyprgraphics", + "rev": "4d927a52be7e15e0846456f2aa1b0ad76b5bf059", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprgraphics", + "type": "github" + } + }, "hyprlang": { "inputs": { "hyprutils": [ @@ -67,6 +93,7 @@ }, "root": { "inputs": { + "hyprgraphics": "hyprgraphics", "hyprlang": "hyprlang", "hyprutils": "hyprutils", "nixpkgs": "nixpkgs", diff --git a/flake.nix b/flake.nix index 54dbbe2..17e7b8d 100644 --- a/flake.nix +++ b/flake.nix @@ -5,6 +5,13 @@ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; systems.url = "github:nix-systems/default-linux"; + hyprgraphics = { + url = "github:hyprwm/hyprgraphics"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + inputs.hyprutils.follows = "hyprutils"; + }; + hyprutils = { url = "github:hyprwm/hyprutils"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/nix/default.nix b/nix/default.nix index adb23f2..9b31c58 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -11,6 +11,7 @@ libwebp, libxkbcommon, mesa, + hyprgraphics, hyprlang, hyprutils, pam, @@ -43,6 +44,7 @@ stdenv.mkDerivation { libwebp libxkbcommon mesa + hyprgraphics hyprlang hyprutils pam diff --git a/nix/overlays.nix b/nix/overlays.nix index 40c56f2..bab4cac 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -13,6 +13,7 @@ in { default = inputs.self.overlays.hyprlock; hyprlock = lib.composeManyExtensions [ + inputs.hyprgraphics.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.self.overlays.sdbuscpp diff --git a/src/defines.hpp b/src/defines.hpp new file mode 100644 index 0000000..5043864 --- /dev/null +++ b/src/defines.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include +using namespace Hyprutils::Memory; +#define SP CSharedPointer +#define WP CWeakPointer \ No newline at end of file diff --git a/src/helpers/Jpeg.cpp b/src/helpers/Jpeg.cpp deleted file mode 100644 index d63e802..0000000 --- a/src/helpers/Jpeg.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "Jpeg.hpp" -#include "Log.hpp" -#include -#include -#include -#include -#include - -cairo_surface_t* JPEG::createSurfaceFromJPEG(const std::filesystem::path& path) { - - if (!std::filesystem::exists(path)) { - Debug::log(ERR, "createSurfaceFromJPEG: file doesn't exist??"); - return nullptr; - } - - if (__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__) { - Debug::log(CRIT, "tried to load a jpeg on a big endian system! ping vaxry he is lazy."); - return nullptr; - } - - void* imageRawData; - struct stat fileInfo = {}; - const auto FD = open(path.c_str(), O_RDONLY); - - fstat(FD, &fileInfo); - - imageRawData = malloc(fileInfo.st_size); - - read(FD, imageRawData, fileInfo.st_size); - close(FD); - - // now the JPEG is in the memory - - jpeg_decompress_struct decompressStruct = {}; - jpeg_error_mgr errorManager = {}; - - decompressStruct.err = jpeg_std_error(&errorManager); - jpeg_create_decompress(&decompressStruct); - jpeg_mem_src(&decompressStruct, (const unsigned char*)imageRawData, fileInfo.st_size); - jpeg_read_header(&decompressStruct, true); - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - decompressStruct.out_color_space = JCS_EXT_BGRA; -#else - decompressStruct.out_color_space = JCS_EXT_ARGB; -#endif - - // decompress - jpeg_start_decompress(&decompressStruct); - - auto cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, decompressStruct.output_width, decompressStruct.output_height); - - if (cairo_surface_status(cairoSurface) != CAIRO_STATUS_SUCCESS) { - Debug::log(ERR, "createSurfaceFromJPEG: Cairo Failed (?)"); - return nullptr; - } - - const auto CAIRODATA = cairo_image_surface_get_data(cairoSurface); - const auto CAIROSTRIDE = cairo_image_surface_get_stride(cairoSurface); - JSAMPROW rowRead; - - while (decompressStruct.output_scanline < decompressStruct.output_height) { - const auto PROW = CAIRODATA + (decompressStruct.output_scanline * CAIROSTRIDE); - rowRead = PROW; - jpeg_read_scanlines(&decompressStruct, &rowRead, 1); - } - - cairo_surface_flush(cairoSurface); - cairo_surface_mark_dirty(cairoSurface); - cairo_surface_set_mime_data(cairoSurface, CAIRO_MIME_TYPE_JPEG, (const unsigned char*)imageRawData, fileInfo.st_size, free, imageRawData); - jpeg_finish_decompress(&decompressStruct); - jpeg_destroy_decompress(&decompressStruct); - - return cairoSurface; -} diff --git a/src/helpers/Jpeg.hpp b/src/helpers/Jpeg.hpp deleted file mode 100644 index 58a6e8b..0000000 --- a/src/helpers/Jpeg.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include -#include - -namespace JPEG { - cairo_surface_t* createSurfaceFromJPEG(const std::filesystem::path&); -}; diff --git a/src/helpers/Webp.cpp b/src/helpers/Webp.cpp deleted file mode 100644 index 6941502..0000000 --- a/src/helpers/Webp.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "Webp.hpp" -#include "Log.hpp" - -#include -#include -#include -#include - -#include - -cairo_surface_t* WEBP::createSurfaceFromWEBP(const std::filesystem::path& path) { - - if (!std::filesystem::exists(path)) { - Debug::log(ERR, "createSurfaceFromWEBP: file doesn't exist??"); - return nullptr; - } - - void* imageRawData; - - struct stat fileInfo = {}; - - const auto FD = open(path.c_str(), O_RDONLY); - - fstat(FD, &fileInfo); - - imageRawData = malloc(fileInfo.st_size); - - read(FD, imageRawData, fileInfo.st_size); - close(FD); - - // now the WebP is in the memory - - WebPDecoderConfig config; - if (!WebPInitDecoderConfig(&config)) { - Debug::log(CRIT, "WebPInitDecoderConfig Failed"); - return nullptr; - } - - if (WebPGetFeatures((const unsigned char*)imageRawData, fileInfo.st_size, &config.input) != VP8_STATUS_OK) { - Debug::log(ERR, "createSurfaceFromWEBP: file is not webp format"); - free(imageRawData); - return nullptr; - } - - const auto HEIGHT = config.input.height; - const auto WIDTH = config.input.width; - - auto cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT); - if (cairo_surface_status(cairoSurface) != CAIRO_STATUS_SUCCESS) { - Debug::log(CRIT, "createSurfaceFromWEBP: Cairo Failed (?)"); - cairo_surface_destroy(cairoSurface); - return nullptr; - } - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - config.output.colorspace = MODE_bgrA; -#else - config.output.colorspace = MODE_Argb; -#endif - - const auto CAIRODATA = cairo_image_surface_get_data(cairoSurface); - const auto CAIROSTRIDE = cairo_image_surface_get_stride(cairoSurface); - - config.options.no_fancy_upsampling = 1; - config.output.u.RGBA.rgba = CAIRODATA; - config.output.u.RGBA.stride = CAIROSTRIDE; - config.output.u.RGBA.size = CAIROSTRIDE * HEIGHT; - config.output.is_external_memory = 1; - config.output.width = WIDTH; - config.output.height = HEIGHT; - - if (WebPDecode((const unsigned char*)imageRawData, fileInfo.st_size, &config) != VP8_STATUS_OK) { - Debug::log(CRIT, "createSurfaceFromWEBP: WebP Decode Failed (?)"); - return nullptr; - } - - cairo_surface_flush(cairoSurface); - cairo_surface_mark_dirty(cairoSurface); - cairo_surface_set_mime_data(cairoSurface, CAIRO_MIME_TYPE_PNG, (const unsigned char*)imageRawData, fileInfo.st_size, free, imageRawData); - - WebPFreeDecBuffer(&config.output); - - return cairoSurface; -} diff --git a/src/helpers/Webp.hpp b/src/helpers/Webp.hpp deleted file mode 100644 index 3fc4790..0000000 --- a/src/helpers/Webp.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include -#include - -namespace WEBP { - cairo_surface_t* createSurfaceFromWEBP(const std::filesystem::path&); -}; diff --git a/src/renderer/AsyncResourceGatherer.cpp b/src/renderer/AsyncResourceGatherer.cpp index 5c6daea..60e00a8 100644 --- a/src/renderer/AsyncResourceGatherer.cpp +++ b/src/renderer/AsyncResourceGatherer.cpp @@ -8,10 +8,10 @@ #include #include "../core/hyprlock.hpp" #include "../helpers/MiscFunctions.hpp" -#include "../helpers/Jpeg.hpp" -#include "../helpers/Webp.hpp" #include "src/helpers/Color.hpp" #include "src/helpers/Log.hpp" +#include +using namespace Hyprgraphics; CAsyncResourceGatherer::CAsyncResourceGatherer() { if (g_pHyprlock->getScreencopy()) @@ -81,56 +81,15 @@ SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) { return nullptr; } -enum class FileType { - PNG, - JPEG, - WEBP, - UNKNOWN, -}; +static SP getCairoSurfaceFromImageFile(const std::filesystem::path& path) { -FileType getFileType(const std::filesystem::path& path) { - std::string ext = path.extension().string(); - // convert the extension to lower case - std::transform(ext.begin(), ext.end(), ext.begin(), [](char c) { return c <= 'Z' && c >= 'A' ? c - ('Z' - 'z') : c; }); - - FileType ft = FileType::UNKNOWN; - Debug::log(TRACE, "Extension: {}", ext); - if (ext == ".png") - ft = FileType::PNG; - else if (ext == ".jpg" || ext == ".jpeg") - ft = FileType::JPEG; - else if (ext == ".webp") - ft = FileType::WEBP; - else { - // magic is slow, so only use it when no recognized extension is found - auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS | MAGIC_SYMLINK); - magic_load(handle, nullptr); - - const auto type_str = std::string(magic_file(handle, path.c_str())); - const auto first_word = type_str.substr(0, type_str.find(" ")); - magic_close(handle); - - if (first_word == "PNG") - ft = FileType::PNG; - else if (first_word == "JPEG") - ft = FileType::JPEG; - else if (first_word == "RIFF" && type_str.find("Web/P image") != std::string::npos) - ft = FileType::WEBP; + auto image = CImage(path); + if (!image.success()) { + Debug::log(ERR, "Image {} could not be loaded: {}", path.string(), image.getError()); + return nullptr; } - return ft; -} - -cairo_surface_t* getCairoSurfaceFromImageFile(const std::filesystem::path& path) { - cairo_surface_t* cairoSurface = nullptr; - switch (getFileType(path)) { - case FileType::PNG: cairoSurface = cairo_image_surface_create_from_png(path.c_str()); break; - case FileType::JPEG: cairoSurface = JPEG::createSurfaceFromJPEG(path); break; - case FileType::WEBP: cairoSurface = WEBP::createSurfaceFromWEBP(path); break; - default: Debug::log(ERR, "unrecognized image format of {}", path.c_str()); - } - - return cairoSurface; + return image.cairoSurface(); } void CAsyncResourceGatherer::gather() { @@ -192,13 +151,13 @@ bool CAsyncResourceGatherer::apply() { for (auto& t : currentPreloadTargets) { if (t.type == TARGET_IMAGE) { - const auto ASSET = &assets[t.id]; + const auto ASSET = &assets[t.id]; - const auto SURFACESTATUS = cairo_surface_status((cairo_surface_t*)t.cairosurface); - const auto CAIROFORMAT = cairo_image_surface_get_format((cairo_surface_t*)t.cairosurface); - const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA; - const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA; - const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; + const cairo_status_t SURFACESTATUS = (cairo_status_t)t.cairosurface->status(); + const auto CAIROFORMAT = cairo_image_surface_get_format(t.cairosurface->cairo()); + const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA; + const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA; + const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; if (SURFACESTATUS != CAIRO_STATUS_SUCCESS) { Debug::log(ERR, "Resource {} invalid ({})", t.id, cairo_status_to_string(SURFACESTATUS)); @@ -218,11 +177,9 @@ bool CAsyncResourceGatherer::apply() { glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, ASSET->texture.m_vSize.x, ASSET->texture.m_vSize.y, 0, glFormat, glType, t.data); cairo_destroy((cairo_t*)t.cairo); - cairo_surface_destroy((cairo_surface_t*)t.cairosurface); - - } else { - Debug::log(ERR, "Unsupported type in ::apply() {}", (int)t.type); - } + t.cairosurface.reset(); + } else + Debug::log(ERR, "Unsupported type in ::apply(): {}", (int)t.type); } return true; @@ -237,17 +194,17 @@ void CAsyncResourceGatherer::renderImage(const SPreloadRequest& rq) { const auto CAIROISURFACE = getCairoSurfaceFromImageFile(ABSOLUTEPATH); if (!CAIROISURFACE) { - Debug::log(ERR, "No cairo surface!"); + Debug::log(ERR, "renderImage: No cairo surface!"); return; } - const auto CAIRO = cairo_create(CAIROISURFACE); + const auto CAIRO = cairo_create(CAIROISURFACE->cairo()); cairo_scale(CAIRO, 1, 1); target.cairo = CAIRO; target.cairosurface = CAIROISURFACE; - target.data = cairo_image_surface_get_data(CAIROISURFACE); - target.size = {(double)cairo_image_surface_get_width(CAIROISURFACE), (double)cairo_image_surface_get_height(CAIROISURFACE)}; + target.data = CAIROISURFACE->data(); + target.size = CAIROISURFACE->size(); std::lock_guard lg{preloadTargetsMutex}; preloadTargets.push_back(target); @@ -271,8 +228,8 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) { TEXT.erase(TEXT.find_last_not_of(" \n\r\t") + 1); } - auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* dummy value */); - auto CAIRO = cairo_create(CAIROSURFACE); + auto CAIROSURFACE = makeShared(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* dummy value */)); + auto CAIRO = cairo_create(CAIROSURFACE->cairo()); // draw title using Pango PangoLayout* layout = pango_cairo_create_layout(CAIRO); @@ -319,9 +276,8 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) { // TODO: avoid this? cairo_destroy(CAIRO); - cairo_surface_destroy(CAIROSURFACE); - CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layoutWidth / PANGO_SCALE, layoutHeight / PANGO_SCALE); - CAIRO = cairo_create(CAIROSURFACE); + CAIROSURFACE = makeShared(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layoutWidth / PANGO_SCALE, layoutHeight / PANGO_SCALE)); + CAIRO = cairo_create(CAIROSURFACE->cairo()); // clear the pixmap cairo_save(CAIRO); @@ -337,11 +293,11 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) { g_object_unref(layout); - cairo_surface_flush(CAIROSURFACE); + cairo_surface_flush(CAIROSURFACE->cairo()); target.cairo = CAIRO; target.cairosurface = CAIROSURFACE; - target.data = cairo_image_surface_get_data(CAIROSURFACE); + target.data = CAIROSURFACE->data(); target.size = {layoutWidth / (double)PANGO_SCALE, layoutHeight / (double)PANGO_SCALE}; std::lock_guard lg{preloadTargetsMutex}; diff --git a/src/renderer/AsyncResourceGatherer.hpp b/src/renderer/AsyncResourceGatherer.hpp index 7046cec..ae82380 100644 --- a/src/renderer/AsyncResourceGatherer.hpp +++ b/src/renderer/AsyncResourceGatherer.hpp @@ -8,6 +8,7 @@ #include #include #include "Shared.hpp" +#include class CAsyncResourceGatherer { public: @@ -64,14 +65,14 @@ class CAsyncResourceGatherer { } asyncLoopState; struct SPreloadTarget { - eTargetType type = TARGET_IMAGE; - std::string id = ""; + eTargetType type = TARGET_IMAGE; + std::string id = ""; - void* data; - void* cairo; - void* cairosurface; + void* data = nullptr; + void* cairo = nullptr; + SP cairosurface; - Vector2D size; + Vector2D size; }; std::vector> dmas; diff --git a/src/renderer/Shared.hpp b/src/renderer/Shared.hpp index b333f3f..11ecf6c 100644 --- a/src/renderer/Shared.hpp +++ b/src/renderer/Shared.hpp @@ -1,5 +1,6 @@ #pragma once #include "Texture.hpp" +#include "../defines.hpp" struct SPreloadedAsset { CTexture texture;