Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package hyprpaper for openSUSE:Factory checked in at 2025-07-25 17:05:22 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/hyprpaper (Old) and /work/SRC/openSUSE:Factory/.hyprpaper.new.13279 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "hyprpaper" Fri Jul 25 17:05:22 2025 rev:7 rq:1295635 version:0.7.5 Changes: -------- --- /work/SRC/openSUSE:Factory/hyprpaper/hyprpaper.changes 2024-12-06 14:26:37.037082080 +0100 +++ /work/SRC/openSUSE:Factory/.hyprpaper.new.13279/hyprpaper.changes 2025-07-25 17:06:01.111013451 +0200 @@ -1,0 +2,33 @@ +Thu Jul 24 13:35:18 UTC 2025 - Bjørn Lie <bjorn....@gmail.com> + +- Update to version 0.7.5: + * Fixes: core: add mallopt to modify trim threshold + * MRs: + - Move systemd service install + - CMake: require wayland-protocols>=1.35 +- Changes from version 0.7.4: + * Fixes: core: update for hw-s 0.4.4 + * MRs: + - implement wl_output_transform + - Remove unused deps +- Changes from version 0.7.3: + * Fixes: + - core: fixup execAndGet not running correctly + - core: avoid the use of pop_back on empty string +- Changes from version 0.7.2: + * Fixes: + - cmake: drop # from commit messages + - core: move to hyprgraphics for image parsing + - core: modernize internals + * MRs: + - CMakeLists: require native hyprwayland-scanner + - CMakeLists: look for wayland.xml protocol in wayland-scanner + - add tile support + - Add systemd service + - Add support for JPEG-XL + - helpers: use C++ streams to load Jpeg and Webp + - Core: Move to hyprgraphics for image parsing + - Core: modernize internals +- Add pkgconfig(hyprgraphics) BuildRequires: New dependency. + +------------------------------------------------------------------- Old: ---- hyprpaper-0.7.1.tar.gz New: ---- hyprpaper-0.7.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ hyprpaper.spec ++++++ --- /var/tmp/diff_new_pack.UUnduh/_old 2025-07-25 17:06:03.023094047 +0200 +++ /var/tmp/diff_new_pack.UUnduh/_new 2025-07-25 17:06:03.027094215 +0200 @@ -1,7 +1,7 @@ # # spec file for package hyprpaper # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,16 +19,17 @@ %global __builder ninja Name: hyprpaper Summary: Wayland wallpaper utility with IPC controls -Version: 0.7.1 +Version: 0.7.5 Release: 0 License: BSD-3-Clause URL: https://github.com/hyprwm/hyprpaper -Source0: https://github.com/hyprwm/hyprpaper/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz +Source0: %{url}/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz BuildRequires: Mesa-libGLESv3-devel BuildRequires: cmake BuildRequires: gcc-c++ BuildRequires: ninja BuildRequires: pkgconfig(gtk-layer-shell-0) +BuildRequires: pkgconfig(hyprgraphics) BuildRequires: pkgconfig(hyprland-protocols) BuildRequires: pkgconfig(hyprlang) >= 0.2.0 BuildRequires: pkgconfig(hyprutils) >= 0.2.0 @@ -62,4 +63,5 @@ %files %_bindir/hyprpaper %license LICENSE +%_userunitdir/hyprpaper.service ++++++ hyprpaper-0.7.1.tar.gz -> hyprpaper-0.7.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/CMakeLists.txt new/hyprpaper-0.7.5/CMakeLists.txt --- old/hyprpaper-0.7.1/CMakeLists.txt 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/CMakeLists.txt 2025-05-06 21:18:13.000000000 +0200 @@ -12,6 +12,8 @@ message(STATUS "Configuring hyprpaper!") +configure_file(systemd/hyprpaper.service.in systemd/hyprpaper.service @ONLY) + # Get git info hash and branch execute_process( COMMAND git rev-parse --abbrev-ref HEAD @@ -26,7 +28,7 @@ OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process( - COMMAND bash -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1" + COMMAND bash -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -s 's/\#//g'" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_MESSAGE OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -45,21 +47,20 @@ find_package(Threads REQUIRED) find_package(PkgConfig REQUIRED) +find_package(hyprwayland-scanner 0.4.0 REQUIRED) pkg_check_modules( deps REQUIRED IMPORTED_TARGET wayland-client - wayland-protocols + wayland-protocols>=1.35 cairo pango pangocairo - libjpeg - libwebp - hyprlang>=0.2.0 - hyprutils>=0.2.0 - hyprwayland-scanner>=0.4.0) + hyprlang>=0.6.0 + hyprutils>=0.2.4 + hyprgraphics) file(GLOB_RECURSE SRCFILES "src/*.cpp") @@ -67,8 +68,9 @@ pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") -pkg_get_variable(WAYLAND_CLIENT_DIR wayland-client pkgdatadir) -message(STATUS "Found wayland-client at ${WAYLAND_CLIENT_DIR}") +pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) +message( + STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}") function(protocolnew protoPath protoName external) if(external) @@ -90,7 +92,7 @@ OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp COMMAND hyprwayland-scanner --wayland-enums --client - ${WAYLAND_CLIENT_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) target_sources(hyprpaper PRIVATE protocols/wayland.cpp protocols/wayland.hpp) endfunction() @@ -137,4 +139,7 @@ "${CMAKE_SHARED_LINKER_FLAGS} -pg -no-pie -fno-builtin") endif(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) +include(GNUInstallDirs) + install(TARGETS hyprpaper) +install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprpaper.service DESTINATION "lib/systemd/user") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/README.md new/hyprpaper-0.7.5/README.md --- old/hyprpaper-0.7.1/README.md 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/README.md 2025-05-06 21:18:13.000000000 +0200 @@ -4,7 +4,7 @@ # Features - Per-output wallpapers - - fill or contain modes + - fill, tile or contain modes - fractional scaling support - IPC for blazing fast wallpaper switches - preloading targets into memory @@ -29,18 +29,20 @@ - libglvnd-core - libjpeg-turbo - libwebp +- libjxl - hyprlang - hyprutils - hyprwayland-scanner +- hyprgraphics To install all of these in Fedora, run this command: ``` -sudo dnf install wayland-devel wayland-protocols-devel hyprlang-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel gcc-c++ hyprutils-devel hyprwayland-scanner +sudo dnf install wayland-devel wayland-protocols-devel hyprlang-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel libjxl-devel gcc-c++ hyprutils-devel hyprwayland-scanner ``` On Arch: ``` -sudo pacman -S ninja gcc wayland-protocols libjpeg-turbo libwebp pango cairo pkgconf cmake libglvnd wayland hyprutils hyprwayland-scanner hyprlang +sudo pacman -S ninja gcc wayland-protocols libjpeg-turbo libwebp libjxl pango cairo pkgconf cmake libglvnd wayland hyprutils hyprwayland-scanner hyprlang ``` On OpenSUSE: @@ -89,9 +91,9 @@ ``` -Preload will tell Hyprland to load a particular image (supported formats: png, jpg, jpeg, webp). Wallpaper will apply the wallpaper to the selected output (`monitor` is the monitor's name, easily can be retrieved with `hyprctl monitors`. You can leave it empty to set all monitors without an active wallpaper. You can also use `desc:` followed by the monitor's description without the (PORT) at the end) +Preload will tell Hyprland to load a particular image (supported formats: png, jpg, jpeg, jpeg xl, webp). Wallpaper will apply the wallpaper to the selected output (`monitor` is the monitor's name, easily can be retrieved with `hyprctl monitors`. You can leave it empty to set all monitors without an active wallpaper. You can also use `desc:` followed by the monitor's description without the (PORT) at the end) -You may add `contain:` before the file path in `wallpaper=` to set the mode to contain instead of cover: +You may add `contain:` or `tile:` before the file path in `wallpaper=` to set the mode to either contain or tile, respectively, instead of cover: ``` wallpaper = monitor,contain:/path/to/image.jpg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/VERSION new/hyprpaper-0.7.5/VERSION --- old/hyprpaper-0.7.1/VERSION 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/VERSION 2025-05-06 21:18:13.000000000 +0200 @@ -1 +1 @@ -0.7.1 +0.7.5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/flake.lock new/hyprpaper-0.7.5/flake.lock --- old/hyprpaper-0.7.1/flake.lock 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/flake.lock 2025-05-06 21:18:13.000000000 +0200 @@ -1,5 +1,31 @@ { "nodes": { + "hyprgraphics": { + "inputs": { + "hyprutils": [ + "hyprutils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1738018829, + "narHash": "sha256-5Ol5iahMlELx3lWuChyZsqqLk6sP6aqaJCJFw92OZGo=", + "owner": "hyprwm", + "repo": "hyprgraphics", + "rev": "12cd7034e441a5ebfdef1a090c0788413b4a635b", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprgraphics", + "type": "github" + } + }, "hyprlang": { "inputs": { "hyprutils": [ @@ -13,11 +39,11 @@ ] }, "locked": { - "lastModified": 1721324361, - "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=", + "lastModified": 1737634606, + "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086", + "rev": "f41271d35cc0f370d300413d756c2677f386af9d", "type": "github" }, "original": { @@ -36,11 +62,11 @@ ] }, "locked": { - "lastModified": 1721324102, - "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", + "lastModified": 1737978343, + "narHash": "sha256-TfFS0HCEJh63Kahrkp1h9hVDMdLU8a37Zz+IFucxyfA=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "962582a090bc233c4de9d9897f46794280288989", + "rev": "6a8bc9d2a4451df12f5179dc0b1d2d46518a90ab", "type": "github" }, "original": { @@ -59,11 +85,11 @@ ] }, "locked": { - "lastModified": 1721324119, - "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=", + "lastModified": 1735493474, + "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30", + "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", "type": "github" }, "original": { @@ -74,11 +100,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1721138476, - "narHash": "sha256-+W5eZOhhemLQxelojLxETfbFbc19NWawsXBlapYpqIA=", + "lastModified": 1737885589, + "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ad0b5eed1b6031efaed382844806550c3dcb4206", + "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", "type": "github" }, "original": { @@ -90,6 +116,7 @@ }, "root": { "inputs": { + "hyprgraphics": "hyprgraphics", "hyprlang": "hyprlang", "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/flake.nix new/hyprpaper-0.7.5/flake.nix --- old/hyprpaper-0.7.1/flake.nix 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/flake.nix 2025-05-06 21:18:13.000000000 +0200 @@ -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"; @@ -49,12 +56,13 @@ overlays = { default = self.overlays.hyprpaper; hyprpaper = lib.composeManyExtensions [ + inputs.hyprgraphics.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default (final: prev: rec { hyprpaper = final.callPackage ./nix/default.nix { - stdenv = final.gcc13Stdenv; + stdenv = final.gcc14Stdenv; version = version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty"); commit = self.rev or ""; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/nix/default.nix new/hyprpaper-0.7.5/nix/default.nix --- old/hyprpaper-0.7.1/nix/default.nix 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/nix/default.nix 2025-05-06 21:18:13.000000000 +0200 @@ -7,12 +7,14 @@ expat, file, fribidi, + hyprgraphics, hyprlang, hyprutils, hyprwayland-scanner, libdatrie, libGL, libjpeg, + libjxl, libselinux, libsepol, libthai, @@ -40,6 +42,10 @@ --replace GIT_COMMIT_HASH '"${commit}"' ''; + depsBuildBuild = [ + pkg-config + ]; + cmakeBuildType = if debug then "Debug" @@ -49,6 +55,7 @@ cmake hyprwayland-scanner pkg-config + wayland-scanner ]; buildInputs = [ @@ -56,11 +63,13 @@ expat file fribidi + hyprgraphics hyprlang hyprutils libdatrie libGL libjpeg + libjxl libselinux libsepol libthai @@ -70,7 +79,6 @@ pcre2 wayland wayland-protocols - wayland-scanner xorg.libXdmcp util-linux ]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/Hyprpaper.cpp new/hyprpaper-0.7.5/src/Hyprpaper.cpp --- old/hyprpaper-0.7.1/src/Hyprpaper.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/Hyprpaper.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -3,8 +3,22 @@ #include <fstream> #include <signal.h> #include <sys/types.h> +#include <malloc.h> +#include <unistd.h> -CHyprpaper::CHyprpaper() = default; +static void setMallocThreshold() { +#ifdef M_TRIM_THRESHOLD + // The default is 128 pages, + // which is very large and can lead to a lot of memory used for no reason + // because trimming hasn't happened + static const int PAGESIZE = sysconf(_SC_PAGESIZE); + mallopt(M_TRIM_THRESHOLD, 6 * PAGESIZE); +#endif +} + +CHyprpaper::CHyprpaper() { + setMallocThreshold(); +} static void handleGlobal(CCWlRegistry* registry, uint32_t name, const char* interface, uint32_t version) { if (strcmp(interface, wl_compositor_interface.name) == 0) { @@ -39,7 +53,7 @@ static void handleGlobalRemove(CCWlRegistry* registry, uint32_t name) { for (auto& m : g_pHyprpaper->m_vMonitors) { if (m->wayland_name == name) { - Debug::log(LOG, "Destroying output %s", m->name.c_str()); + Debug::log(LOG, "Destroying output {}", m->name); g_pHyprpaper->clearWallpaperFromMonitor(m->name); std::erase_if(g_pHyprpaper->m_vMonitors, [&](const auto& other) { return other->wayland_name == name; }); return; @@ -139,7 +153,7 @@ const auto PRELOADPATH = it->get()->name; - Debug::log(LOG, "Unloading target %s, preload path %s", path.c_str(), PRELOADPATH.c_str()); + Debug::log(LOG, "Unloading target {}, preload path {}", path, PRELOADPATH); std::filesystem::remove(PRELOADPATH); @@ -161,7 +175,7 @@ bool exists = false; for (auto& [ewp, cls] : m_mWallpaperTargets) { if (ewp == wp) { - Debug::log(LOG, "Ignoring request to preload %s as it already is preloaded!", ewp.c_str()); + Debug::log(LOG, "Ignoring request to preload {} as it already is preloaded!", ewp); exists = true; break; } @@ -201,7 +215,7 @@ else m_pSeatCursorShapeDevice = makeShared<CCWpCursorShapeDeviceV1>(m_pCursorShape->sendGetPointer(m_pSeatPointer->resource())); - m_pSeatPointer->setEnter([this](CCWlPointer* r, uint32_t serial, wl_resource* surface, wl_fixed_t x, wl_fixed_t y) { + m_pSeatPointer->setEnter([this](CCWlPointer* r, uint32_t serial, wl_proxy* surface, wl_fixed_t x, wl_fixed_t y) { if (!m_pCursorShape) { m_pSeatPointer->sendSetCursor(serial, nullptr, 0, 0); return; @@ -243,14 +257,13 @@ memoryFreed += entry.file_size(); if (!std::filesystem::remove(entry.path())) - Debug::log(LOG, "Couldn't remove %s", entry.path().string().c_str()); + Debug::log(LOG, "Couldn't remove {}", entry.path().string()); cleaned++; } } - if (cleaned != 0) { - Debug::log(LOG, "Cleaned old hyprpaper preloads (%i), removing %.1fMB", cleaned, ((float)memoryFreed) / 1000000.f); - } + if (cleaned != 0) + Debug::log(LOG, "Cleaned old hyprpaper preloads ({}), removing {:.1f}MB", cleaned, ((float)memoryFreed) / 1000000.f); } SMonitor* CHyprpaper::getMonitorFromName(const std::string& monname) { @@ -294,7 +307,7 @@ PBUFFER->target = wt.m_szPath; - Debug::log(LOG, "Buffer created for target %s, Shared Memory usage: %.1fMB", wt.m_szPath.c_str(), PBUFFER->size / 1000000.f); + Debug::log(LOG, "Buffer created for target {}, Shared Memory usage: {:.1f}MB", wt.m_szPath, PBUFFER->size / 1000000.f); anyNewBuffers = true; } @@ -308,7 +321,7 @@ bytesUsed += bf->size; } - Debug::log(LOG, "Total SM usage for all buffers: %.1fMB", bytesUsed / 1000000.f); + Debug::log(LOG, "Total SM usage for all buffers: {:.1f}MB", bytesUsed / 1000000.f); } } @@ -398,7 +411,7 @@ if (!it->second) { pMonitor->hasATarget = false; - Debug::log(WARN, "Monitor %s does not have a target! A wallpaper will not be created.", pMonitor->name.c_str()); + Debug::log(WARN, "Monitor {} does not have a target! A wallpaper will not be created.", pMonitor->name); return; } @@ -507,14 +520,15 @@ } void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { - static auto* const PRENDERSPLASH = reinterpret_cast<Hyprlang::INT* const*>(g_pConfigManager->config->getConfigValuePtr("splash")->getDataStaticPtr()); - static auto* const PSPLASHOFFSET = reinterpret_cast<Hyprlang::FLOAT* const*>(g_pConfigManager->config->getConfigValuePtr("splash_offset")->getDataStaticPtr()); + static auto PRENDERSPLASH = Hyprlang::CSimpleConfigValue<Hyprlang::INT>(g_pConfigManager->config.get(), "splash"); + static auto PSPLASHOFFSET = Hyprlang::CSimpleConfigValue<Hyprlang::FLOAT>(g_pConfigManager->config.get(), "splash_offset"); if (!m_mMonitorActiveWallpaperTargets[pMonitor]) recheckMonitor(pMonitor); const auto PWALLPAPERTARGET = m_mMonitorActiveWallpaperTargets[pMonitor]; const auto CONTAIN = m_mMonitorWallpaperRenderData[pMonitor->name].contain; + const auto TILE = m_mMonitorWallpaperRenderData[pMonitor->name].tile; if (!PWALLPAPERTARGET) { Debug::log(CRIT, "wallpaper target null in render??"); @@ -564,43 +578,50 @@ origin.x = -(PWALLPAPERTARGET->m_vSize.x * scale - DIMENSIONS.x) / 2.0 / scale; } - Debug::log(LOG, "Image data for %s: %s at [%.2f, %.2f], scale: %.2f (original image size: [%i, %i])", pMonitor->name.c_str(), PWALLPAPERTARGET->m_szPath.c_str(), origin.x, - origin.y, scale, (int)PWALLPAPERTARGET->m_vSize.x, (int)PWALLPAPERTARGET->m_vSize.y); + Debug::log(LOG, "Image data for {}: {} at [{:.2f}, {:.2f}], scale: {:.2f} (original image size: [{}, {}])", pMonitor->name, PWALLPAPERTARGET->m_szPath, origin.x, origin.y, + scale, (int)PWALLPAPERTARGET->m_vSize.x, (int)PWALLPAPERTARGET->m_vSize.y); - cairo_scale(PCAIRO, scale, scale); - cairo_set_source_surface(PCAIRO, PWALLPAPERTARGET->m_pCairoSurface, origin.x, origin.y); + if (TILE) { + cairo_pattern_t* pattern = cairo_pattern_create_for_surface(PWALLPAPERTARGET->m_pCairoSurface->cairo()); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source(PCAIRO, pattern); + } else { + cairo_scale(PCAIRO, scale, scale); + cairo_set_source_surface(PCAIRO, PWALLPAPERTARGET->m_pCairoSurface->cairo(), origin.x, origin.y); + } cairo_paint(PCAIRO); - if (**PRENDERSPLASH && getenv("HYPRLAND_INSTANCE_SIGNATURE")) { + if (*PRENDERSPLASH && getenv("HYPRLAND_INSTANCE_SIGNATURE")) { auto SPLASH = execAndGet("hyprctl splash"); - SPLASH.pop_back(); + if (!SPLASH.empty()) + SPLASH.pop_back(); - Debug::log(LOG, "Rendering splash: %s", SPLASH.c_str()); + Debug::log(LOG, "Rendering splash: {}", SPLASH); cairo_select_font_face(PCAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); const auto FONTSIZE = (int)(DIMENSIONS.y / 76.0 / scale); cairo_set_font_size(PCAIRO, FONTSIZE); - static auto* const PSPLASHCOLOR = reinterpret_cast<Hyprlang::INT* const*>(g_pConfigManager->config->getConfigValuePtr("splash_color")->getDataStaticPtr()); + static auto PSPLASHCOLOR = Hyprlang::CSimpleConfigValue<Hyprlang::INT>(g_pConfigManager->config.get(), "splash_color"); - Debug::log(LOG, "Splash color: %x", **PSPLASHCOLOR); + Debug::log(LOG, "Splash color: {:x}", *PSPLASHCOLOR); - cairo_set_source_rgba(PCAIRO, ((**PSPLASHCOLOR >> 16) & 0xFF) / 255.0, ((**PSPLASHCOLOR >> 8) & 0xFF) / 255.0, (**PSPLASHCOLOR & 0xFF) / 255.0, - ((**PSPLASHCOLOR >> 24) & 0xFF) / 255.0); + cairo_set_source_rgba(PCAIRO, ((*PSPLASHCOLOR >> 16) & 0xFF) / 255.0, ((*PSPLASHCOLOR >> 8) & 0xFF) / 255.0, (*PSPLASHCOLOR & 0xFF) / 255.0, + ((*PSPLASHCOLOR >> 24) & 0xFF) / 255.0); cairo_text_extents_t textExtents; cairo_text_extents(PCAIRO, SPLASH.c_str(), &textExtents); - cairo_move_to(PCAIRO, ((DIMENSIONS.x - textExtents.width * scale) / 2.0) / scale, ((DIMENSIONS.y * (100 - **PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale); + cairo_move_to(PCAIRO, ((DIMENSIONS.x - textExtents.width * scale) / 2.0) / scale, ((DIMENSIONS.y * (100 - *PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale); - Debug::log(LOG, "Splash font size: %d, pos: %.2f, %.2f", FONTSIZE, (DIMENSIONS.x - textExtents.width) / 2.0 / scale, - ((DIMENSIONS.y * (100 - **PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale); + Debug::log(LOG, "Splash font size: {}, pos: {:.2f}, {:.2f}", FONTSIZE, (DIMENSIONS.x - textExtents.width) / 2.0 / scale, + ((DIMENSIONS.y * (100 - *PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale); cairo_show_text(PCAIRO, SPLASH.c_str()); - cairo_surface_flush(PWALLPAPERTARGET->m_pCairoSurface); + cairo_surface_flush(PWALLPAPERTARGET->m_pCairoSurface->cairo()); } cairo_restore(PCAIRO); @@ -616,8 +637,8 @@ pMonitor->pCurrentLayerSurface->pSurface->sendSetOpaqueRegion(opaqueRegion.get()); if (pMonitor->pCurrentLayerSurface->pFractionalScaleInfo) { - Debug::log(LOG, "Submitting viewport dest size %ix%i for %x", static_cast<int>(std::round(pMonitor->size.x)), static_cast<int>(std::round(pMonitor->size.y)), - pMonitor->pCurrentLayerSurface); + Debug::log(LOG, "Submitting viewport dest size {}x{} for {:x}", static_cast<int>(std::round(pMonitor->size.x)), static_cast<int>(std::round(pMonitor->size.y)), + (uintptr_t)pMonitor->pCurrentLayerSurface); pMonitor->pCurrentLayerSurface->pViewport->sendSetDestination(static_cast<int>(std::round(pMonitor->size.x)), static_cast<int>(std::round(pMonitor->size.y))); } pMonitor->pCurrentLayerSurface->pSurface->sendCommit(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/Hyprpaper.hpp new/hyprpaper-0.7.5/src/Hyprpaper.hpp --- old/hyprpaper-0.7.1/src/Hyprpaper.hpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/Hyprpaper.hpp 2025-05-06 21:18:13.000000000 +0200 @@ -18,6 +18,7 @@ struct SWallpaperRenderData { bool contain = false; + bool tile = false; }; class CHyprpaper { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/config/ConfigManager.cpp new/hyprpaper-0.7.5/src/config/ConfigManager.cpp --- old/hyprpaper-0.7.1/src/config/ConfigManager.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/config/ConfigManager.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -4,8 +4,8 @@ #include <filesystem> static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) { - const std::string COMMAND = C; - const std::string VALUE = V; + const std::string COMMAND = C; + const std::string VALUE = V; Hyprlang::CParseResult result; if (VALUE.find_first_of(',') == std::string::npos) { @@ -23,6 +23,13 @@ contain = true; } + bool tile = false; + + if (WALLPAPER.find("tile:") == 0) { + WALLPAPER = WALLPAPER.substr(5); + tile = true; + } + if (WALLPAPER[0] == '~') { static const char* const ENVHOME = getenv("HOME"); WALLPAPER = std::string(ENVHOME) + WALLPAPER.substr(1); @@ -44,6 +51,7 @@ g_pHyprpaper->clearWallpaperFromMonitor(MONITOR); g_pHyprpaper->m_mMonitorActiveWallpapers[MONITOR] = WALLPAPER; g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].contain = contain; + g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].tile = tile; if (MONITOR.empty()) { for (auto& m : g_pHyprpaper->m_vMonitors) { @@ -51,6 +59,7 @@ g_pHyprpaper->clearWallpaperFromMonitor(m->name); g_pHyprpaper->m_mMonitorActiveWallpapers[m->name] = WALLPAPER; g_pHyprpaper->m_mMonitorWallpaperRenderData[m->name].contain = contain; + g_pHyprpaper->m_mMonitorWallpaperRenderData[m->name].tile = tile; } } } else { @@ -141,6 +150,9 @@ WALLPAPER = WALLPAPER.substr(8); } + if (WALLPAPER.find("tile:") == 0) + WALLPAPER = WALLPAPER.substr(5); + auto preloadResult = handlePreload(C, WALLPAPER.c_str()); if (preloadResult.error) return preloadResult; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/debug/Log.cpp new/hyprpaper-0.7.5/src/debug/Log.cpp --- old/hyprpaper-0.7.1/src/debug/Log.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/debug/Log.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,49 +0,0 @@ -#include "Log.hpp" -#include "../includes.hpp" - -#include <fstream> -#include <iostream> - -void Debug::log(LogLevel level, const char* fmt, ...) { - - std::string levelstr = ""; - - switch (level) { - case LOG: levelstr = "[LOG] "; break; - case WARN: levelstr = "[WARN] "; break; - case ERR: levelstr = "[ERR] "; break; - case CRIT: levelstr = "[CRITICAL] "; break; - case INFO: levelstr = "[INFO] "; break; - default: break; - } - - char buf[LOGMESSAGESIZE] = ""; - char* outputStr; - int logLen; - - va_list args; - va_start(args, fmt); - logLen = vsnprintf(buf, sizeof buf, fmt, args); - va_end(args); - - if ((long unsigned int)logLen < sizeof buf) { - outputStr = strdup(buf); - } else { - outputStr = (char*)malloc(logLen + 1); - - if (!outputStr) { - printf("CRITICAL: Cannot alloc size %d for log! (Out of memory?)", logLen + 1); - return; - } - - va_start(args, fmt); - vsnprintf(outputStr, logLen + 1U, fmt, args); - va_end(args); - } - - // hyprpaper only logs to stdout - std::cout << levelstr << outputStr << "\n"; - - // free the log - free(outputStr); -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/debug/Log.hpp new/hyprpaper-0.7.5/src/debug/Log.hpp --- old/hyprpaper-0.7.1/src/debug/Log.hpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/debug/Log.hpp 2025-05-06 21:18:13.000000000 +0200 @@ -1,17 +1,57 @@ #pragma once +#include <format> +#include <iostream> #include <string> -#define LOGMESSAGESIZE 1024 - -enum LogLevel { - NONE = -1, - LOG = 0, +enum eLogLevel { + TRACE = 0, + INFO, + LOG, WARN, ERR, CRIT, - INFO + NONE }; +#define RASSERT(expr, reason, ...) \ + if (!(expr)) { \ + Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n{}\n\nat: line {} in {}", \ + std::format(reason, ##__VA_ARGS__), __LINE__, \ + ([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })().c_str()); \ + std::abort(); \ + } + +#define ASSERT(expr) RASSERT(expr, "?") + namespace Debug { - void log(LogLevel level, const char* fmt, ...); -} + inline bool quiet = false; + inline bool verbose = false; + + template <typename... Args> + void log(eLogLevel level, const std::string& fmt, Args&&... args) { + + if (!verbose && level == TRACE) + return; + + if (quiet) + return; + + if (level != NONE) { + std::cout << '['; + + switch (level) { + case TRACE: std::cout << "TRACE"; break; + case INFO: std::cout << "INFO"; break; + case LOG: std::cout << "LOG"; break; + case WARN: std::cout << "WARN"; break; + case ERR: std::cout << "ERR"; break; + case CRIT: std::cout << "CRITICAL"; break; + default: break; + } + + std::cout << "] "; + } + + std::cout << std::vformat(fmt, std::make_format_args(args...)) << std::endl; + } +}; \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Bmp.cpp new/hyprpaper-0.7.5/src/helpers/Bmp.cpp --- old/hyprpaper-0.7.1/src/helpers/Bmp.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Bmp.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,127 +0,0 @@ -#include "Bmp.hpp" - -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <filesystem> - -class BmpHeader { - public: - unsigned char format[2]; - uint32_t sizeOfFile; - uint16_t reserved1; - uint16_t reserved2; - uint32_t dataOffset; - uint32_t sizeOfBitmapHeader; - uint32_t width; - uint32_t height; - uint16_t numberOfColors; - uint16_t numberOfBitPerPixel; - uint32_t compressionMethod; - uint32_t imageSize; - uint32_t horizontalResolutionPPM; - uint32_t verticalResolutionPPM; - uint32_t numberOfCollors; - uint32_t numberOfImportantCollors; - - BmpHeader(std::ifstream& file) { - file.seekg(0, std::ios::end); - uint32_t streamLength = file.tellg(); - file.seekg(0, std::ios::beg); - - file.read(reinterpret_cast<char*>(&format), sizeof(format)); - if (!(format[0] == 66 && format[1] == 77)) { - Debug::log(ERR, "Unable to parse bitmap header: wrong bmp file type"); - exit(1); - } - - file.read(reinterpret_cast<char*>(&sizeOfFile), sizeof(sizeOfFile)); - - if (sizeOfFile != streamLength) { - Debug::log(ERR, "Unable to parse bitmap header: wrong value of file size header"); - exit(1); - } - - file.read(reinterpret_cast<char*>(&reserved1), sizeof(reserved1)); - file.read(reinterpret_cast<char*>(&reserved2), sizeof(reserved2)); - file.read(reinterpret_cast<char*>(&dataOffset), sizeof(dataOffset)); - file.read(reinterpret_cast<char*>(&sizeOfBitmapHeader), sizeof(sizeOfBitmapHeader)); - file.read(reinterpret_cast<char*>(&width), sizeof(width)); - file.read(reinterpret_cast<char*>(&height), sizeof(height)); - file.read(reinterpret_cast<char*>(&numberOfColors), sizeof(numberOfColors)); - file.read(reinterpret_cast<char*>(&numberOfBitPerPixel), sizeof(numberOfBitPerPixel)); - file.read(reinterpret_cast<char*>(&compressionMethod), sizeof(compressionMethod)); - file.read(reinterpret_cast<char*>(&imageSize), sizeof(imageSize)); - file.read(reinterpret_cast<char*>(&horizontalResolutionPPM), sizeof(horizontalResolutionPPM)); - file.read(reinterpret_cast<char*>(&verticalResolutionPPM), sizeof(verticalResolutionPPM)); - file.read(reinterpret_cast<char*>(&numberOfCollors), sizeof(numberOfCollors)); - file.read(reinterpret_cast<char*>(&numberOfImportantCollors), sizeof(numberOfImportantCollors)); - - if (!imageSize) - imageSize = sizeOfFile - dataOffset; - - if (imageSize != (width * height * numberOfBitPerPixel / 8)) { - Debug::log(ERR, "Unable to parse bitmap header: wrong image size"); - exit(1); - } - - file.seekg(dataOffset); - }; -}; - -void reflectImage(unsigned char* image, uint32_t numberOfRows, int stride) { - int rowStart = 0; - int rowEnd = numberOfRows - 1; - std::vector<unsigned char> temp; - temp.resize(stride); - while (rowStart < rowEnd) { - memcpy(&temp[0], &image[rowStart * stride], stride); - memcpy(&image[rowStart * stride], &image[rowEnd * stride], stride); - memcpy(&image[rowEnd * stride], &temp[0], stride); - rowStart++; - rowEnd--; - } -}; - -void convertRgbToArgb(std::ifstream& imageStream, unsigned char* outputImage, uint32_t newImageSize) { - uint8_t forthBitCounter = 0; - unsigned long imgCursor = 0; - while (imgCursor < newImageSize) { - imageStream.read(reinterpret_cast<char*>(&outputImage[imgCursor]), 1); - imgCursor++; - forthBitCounter++; - if (forthBitCounter == 3) { - outputImage[imgCursor] = 0; - imgCursor++; - forthBitCounter = 0; - } - } -}; - -cairo_surface_t* BMP::createSurfaceFromBMP(const std::string& path) { - - if (!std::filesystem::exists(path)) { - Debug::log(ERR, "createSurfaceFromBMP: file doesn't exist??"); - exit(1); - } - - std::ifstream bitmapImageStream(path); - BmpHeader bitmapHeader(bitmapImageStream); - - cairo_format_t format = CAIRO_FORMAT_ARGB32; - int stride = cairo_format_stride_for_width(format, bitmapHeader.width); - unsigned char* imageData = (unsigned char*)malloc(bitmapHeader.height * stride); - - if (bitmapHeader.numberOfBitPerPixel == 24) - convertRgbToArgb(bitmapImageStream, imageData, bitmapHeader.height * stride); - else if (bitmapHeader.numberOfBitPerPixel == 32) - bitmapImageStream.read(reinterpret_cast<char*>(&imageData), bitmapHeader.imageSize); - else { - Debug::log(ERR, "createSurfaceFromBMP: unsupported bmp format"); - bitmapImageStream.close(); - exit(1); - } - bitmapImageStream.close(); - reflectImage(imageData, bitmapHeader.height, stride); - return cairo_image_surface_create_for_data(imageData, format, bitmapHeader.width, bitmapHeader.height, stride); -} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Bmp.hpp new/hyprpaper-0.7.5/src/helpers/Bmp.hpp --- old/hyprpaper-0.7.1/src/helpers/Bmp.hpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Bmp.hpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -#pragma once - -#include "../defines.hpp" - -namespace BMP { - cairo_surface_t* createSurfaceFromBMP(const std::string&); -}; \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Jpeg.cpp new/hyprpaper-0.7.5/src/helpers/Jpeg.cpp --- old/hyprpaper-0.7.1/src/helpers/Jpeg.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Jpeg.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,76 +0,0 @@ -#include "Jpeg.hpp" - -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <filesystem> - -cairo_surface_t* JPEG::createSurfaceFromJPEG(const std::string& path) { - - if (!std::filesystem::exists(path)) { - Debug::log(ERR, "createSurfaceFromJPEG: file doesn't exist??"); - exit(1); - } - - if (__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__) { - Debug::log(CRIT, "tried to load a jpeg on a big endian system! ping vaxry he is lazy."); - exit(1); - } - - 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 (?)"); - exit(1); - } - - 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_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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Jpeg.hpp new/hyprpaper-0.7.5/src/helpers/Jpeg.hpp --- old/hyprpaper-0.7.1/src/helpers/Jpeg.hpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Jpeg.hpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,8 +0,0 @@ -#pragma once - -#include "../defines.hpp" -#include <jpeglib.h> - -namespace JPEG { - cairo_surface_t* createSurfaceFromJPEG(const std::string&); -}; \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/MiscFunctions.cpp new/hyprpaper-0.7.5/src/helpers/MiscFunctions.cpp --- old/hyprpaper-0.7.1/src/helpers/MiscFunctions.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/MiscFunctions.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -3,6 +3,9 @@ #include "../debug/Log.hpp" #include <memory> +#include <hyprutils/os/Process.hpp> +using namespace Hyprutils::OS; + bool vectorDeltaLessThan(const Vector2D& a, const Vector2D& b, const float& delta) { return std::abs(a.x - b.x) < delta && std::abs(a.y - b.y) < delta; } @@ -12,15 +15,8 @@ } std::string execAndGet(const char* cmd) { - std::array<char, 128> buffer; - std::string result; - const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose); - if (!pipe) { - Debug::log(ERR, "execAndGet: failed in pipe"); + CProcess proc("/bin/bash", {"-c", cmd}); + if (!proc.runSync()) return ""; - } - while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { - result += buffer.data(); - } - return result; + return proc.stdOut(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Monitor.cpp new/hyprpaper-0.7.5/src/helpers/Monitor.cpp --- old/hyprpaper-0.7.1/src/helpers/Monitor.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Monitor.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -1,8 +1,15 @@ #include "Monitor.hpp" #include "../Hyprpaper.hpp" +#include "MiscFunctions.hpp" void SMonitor::registerListeners() { - output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { size = Vector2D(width, height); }); + output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + size = Vector2D(width, height); + + //ensures any transforms are also taken care of when setting the mode + if (transform & 1) + std::swap(size.x, size.y); + }); output->setDone([this](CCWlOutput* r) { readyForLS = true; @@ -21,4 +28,16 @@ description = desc; }); -} \ No newline at end of file + + output->setGeometry([this](CCWlOutput* r, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char* make, const char* model, + int32_t transform_) { // + /* + see https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output-enum-transform + If there is a difference in parity of the old vs new transforms, the size needs to be swapped. + */ + if ((transform ^ transform_) & 1) + std::swap(size.x, size.y); + + transform = (wl_output_transform)transform_; + }); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Monitor.hpp new/hyprpaper-0.7.5/src/helpers/Monitor.hpp --- old/hyprpaper-0.7.1/src/helpers/Monitor.hpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Monitor.hpp 2025-05-06 21:18:13.000000000 +0200 @@ -12,6 +12,7 @@ uint32_t wayland_name = 0; Vector2D size; int scale; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; bool readyForLS = false; bool hasATarget = true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Webp.cpp new/hyprpaper-0.7.5/src/helpers/Webp.cpp --- old/hyprpaper-0.7.1/src/helpers/Webp.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Webp.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,83 +0,0 @@ -#include "Webp.hpp" - -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <filesystem> -#include <webp/decode.h> - -cairo_surface_t* WEBP::createSurfaceFromWEBP(const std::string& path) { - - if (!std::filesystem::exists(path)) { - Debug::log(ERR, "createSurfaceFromWEBP: file doesn't exist??"); - exit(1); - } - - 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"); - exit(1); - } - - 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); - exit(1); - } - - 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); - exit(1); - } - -#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 (?)"); - exit(1); - } - - 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/helpers/Webp.hpp new/hyprpaper-0.7.5/src/helpers/Webp.hpp --- old/hyprpaper-0.7.1/src/helpers/Webp.hpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/helpers/Webp.hpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -#pragma once - -#include "../defines.hpp" - -namespace WEBP { - cairo_surface_t* createSurfaceFromWEBP(const std::string&); -}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/ipc/Socket.cpp new/hyprpaper-0.7.5/src/ipc/Socket.cpp --- old/hyprpaper-0.7.1/src/ipc/Socket.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/ipc/Socket.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -50,7 +50,7 @@ char readBuffer[1024] = {0}; - Debug::log(LOG, "hyprpaper socket started at %s (fd: %i)", socketPath.c_str(), SOCKET); + Debug::log(LOG, "hyprpaper socket started at {} (fd: {})", socketPath, SOCKET); while (1) { const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize); if (ACCEPTEDCONNECTION < 0) { @@ -58,7 +58,7 @@ break; } else { do { - Debug::log(LOG, "Accepted incoming socket connection request on fd %i", ACCEPTEDCONNECTION); + Debug::log(LOG, "Accepted incoming socket connection request on fd {}", ACCEPTEDCONNECTION); std::lock_guard<std::mutex> lg(g_pHyprpaper->m_mtTickMutex); auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024); @@ -100,7 +100,7 @@ // now we can work on the copy - Debug::log(LOG, "Received a request: %s", copy.c_str()); + Debug::log(LOG, "Received a request: {}", copy); // set default reply m_szReply = "ok"; @@ -123,7 +123,7 @@ if (copy.find("listloaded") == 0) { const auto numWallpapersLoaded = g_pHyprpaper->m_mWallpaperTargets.size(); - Debug::log(LOG, "numWallpapersLoaded: %d", numWallpapersLoaded); + Debug::log(LOG, "numWallpapersLoaded: {}", numWallpapersLoaded); if (numWallpapersLoaded == 0) { m_szReply = "no wallpapers loaded"; @@ -145,7 +145,7 @@ if (copy.find("listactive") == 0) { const auto numWallpapersActive = g_pHyprpaper->m_mMonitorActiveWallpapers.size(); - Debug::log(LOG, "numWallpapersActive: %d", numWallpapersActive); + Debug::log(LOG, "numWallpapersActive: {}", numWallpapersActive); if (numWallpapersActive == 0) { m_szReply = "no wallpapers active"; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/main.cpp new/hyprpaper-0.7.5/src/main.cpp --- old/hyprpaper-0.7.1/src/main.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/main.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -3,7 +3,7 @@ #include "Hyprpaper.hpp" int main(int argc, char** argv, char** envp) { - Debug::log(LOG, "Welcome to hyprpaper!\nbuilt from commit %s (%s)", GIT_COMMIT_HASH, GIT_COMMIT_MESSAGE); + Debug::log(LOG, "Welcome to hyprpaper!\nbuilt from commit {} ({})", GIT_COMMIT_HASH, GIT_COMMIT_MESSAGE); // parse some args std::string configPath; @@ -11,7 +11,7 @@ for (int i = 1; i < argc; ++i) { if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config")) && argc >= i + 2) { configPath = std::string(argv[++i]); - Debug::log(LOG, "Using config location %s.", configPath.c_str()); + Debug::log(LOG, "Using config location {}.", configPath); } else if (!strcmp(argv[i], "--no-fractional") || !strcmp(argv[i], "-n")) { noFractional = true; Debug::log(LOG, "Disabling fractional scaling support!"); @@ -31,4 +31,4 @@ g_pHyprpaper->init(); return 0; -} \ No newline at end of file +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/render/LayerSurface.cpp new/hyprpaper-0.7.5/src/render/LayerSurface.cpp --- old/hyprpaper-0.7.1/src/render/LayerSurface.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/render/LayerSurface.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -41,7 +41,7 @@ m_pMonitor->wantsACK = true; m_pMonitor->initialized = true; - Debug::log(LOG, "configure for %s", m_pMonitor->name.c_str()); + Debug::log(LOG, "configure for {}", m_pMonitor->name); }); pLayerSurface->setClosed([this](CCZwlrLayerSurfaceV1* r) { @@ -66,7 +66,7 @@ pFractionalScaleInfo->setPreferredScale([this](CCWpFractionalScaleV1* r, uint32_t sc120) { const double SCALE = sc120 / 120.0; - Debug::log(LOG, "handlePreferredScale: %.2lf for %lx", SCALE, this); + Debug::log(LOG, "handlePreferredScale: {:.2f} for {:x}", SCALE, (uintptr_t)this); if (fScale != SCALE) { fScale = SCALE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/render/WallpaperTarget.cpp new/hyprpaper-0.7.5/src/render/WallpaperTarget.cpp --- old/hyprpaper-0.7.1/src/render/WallpaperTarget.cpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/render/WallpaperTarget.cpp 2025-05-06 21:18:13.000000000 +0200 @@ -1,61 +1,29 @@ #include "WallpaperTarget.hpp" #include <chrono> -#include <magic.h> +#include <hyprgraphics/image/Image.hpp> +using namespace Hyprgraphics; CWallpaperTarget::~CWallpaperTarget() { - cairo_surface_destroy(m_pCairoSurface); + ; } void CWallpaperTarget::create(const std::string& path) { m_szPath = path; - const auto BEGINLOAD = std::chrono::system_clock::now(); + const auto BEGINLOAD = std::chrono::system_clock::now(); - cairo_surface_t* CAIROSURFACE = nullptr; - const auto len = path.length(); - if (path.find(".png") == len - 4 || path.find(".PNG") == len - 4) { - CAIROSURFACE = cairo_image_surface_create_from_png(path.c_str()); - } else if (path.find(".jpg") == len - 4 || path.find(".JPG") == len - 4 || path.find(".jpeg") == len - 5 || path.find(".JPEG") == len - 5) { - CAIROSURFACE = JPEG::createSurfaceFromJPEG(path); - m_bHasAlpha = false; - } else if (path.find(".bmp") == len - 4 || path.find(".BMP") == len - 4) { - CAIROSURFACE = BMP::createSurfaceFromBMP(path); - m_bHasAlpha = false; - } else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) { - CAIROSURFACE = WEBP::createSurfaceFromWEBP(path); - } else { - // magic is slow, so only use it when no recognized extension is found - auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS); - 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(" ")); - - if (first_word == "PNG") { - CAIROSURFACE = cairo_image_surface_create_from_png(path.c_str()); - } else if (first_word == "JPEG") { - CAIROSURFACE = JPEG::createSurfaceFromJPEG(path); - m_bHasAlpha = false; - } else if (first_word == "BMP") { - CAIROSURFACE = BMP::createSurfaceFromBMP(path); - m_bHasAlpha = false; - } else { - Debug::log(CRIT, "unrecognized image %s", path.c_str()); - exit(1); - } - } - - if (cairo_surface_status(CAIROSURFACE) != CAIRO_STATUS_SUCCESS) { - Debug::log(CRIT, "Failed to read image %s because of:\n%s", path.c_str(), cairo_status_to_string(cairo_surface_status(CAIROSURFACE))); + auto loadedImage = CImage(path); + if (!loadedImage.success()) { + Debug::log(CRIT, "Cannot load image {}: {}", path, loadedImage.getError()); exit(1); } - m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + m_vSize = loadedImage.cairoSurface()->size(); const auto MS = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - BEGINLOAD).count() / 1000.f; - Debug::log(LOG, "Preloaded target %s in %.2fms -> Pixel size: [%i, %i]", path.c_str(), MS, (int)m_vSize.x, (int)m_vSize.y); + Debug::log(LOG, "Preloaded target {} in {:.2f}ms -> Pixel size: [{}, {}]", path, MS, (int)m_vSize.x, (int)m_vSize.y); - m_pCairoSurface = CAIROSURFACE; + m_pCairoSurface = loadedImage.cairoSurface(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/src/render/WallpaperTarget.hpp new/hyprpaper-0.7.5/src/render/WallpaperTarget.hpp --- old/hyprpaper-0.7.1/src/render/WallpaperTarget.hpp 2024-08-16 21:26:53.000000000 +0200 +++ new/hyprpaper-0.7.5/src/render/WallpaperTarget.hpp 2025-05-06 21:18:13.000000000 +0200 @@ -1,21 +1,19 @@ #pragma once #include "../defines.hpp" -#include "../helpers/Jpeg.hpp" -#include "../helpers/Bmp.hpp" -#include "../helpers/Webp.hpp" +#include <hyprgraphics/cairo/CairoSurface.hpp> class CWallpaperTarget { public: ~CWallpaperTarget(); - void create(const std::string& path); + void create(const std::string& path); - std::string m_szPath; + std::string m_szPath; - Vector2D m_vSize; + Vector2D m_vSize; - bool m_bHasAlpha = true; + bool m_bHasAlpha = true; - cairo_surface_t* m_pCairoSurface; + SP<Hyprgraphics::CCairoSurface> m_pCairoSurface; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpaper-0.7.1/systemd/hyprpaper.service.in new/hyprpaper-0.7.5/systemd/hyprpaper.service.in --- old/hyprpaper-0.7.1/systemd/hyprpaper.service.in 1970-01-01 01:00:00.000000000 +0100 +++ new/hyprpaper-0.7.5/systemd/hyprpaper.service.in 2025-05-06 21:18:13.000000000 +0200 @@ -0,0 +1,16 @@ +[Unit] +Description=Fast, IPC-controlled wallpaper utility for Hyprland. +Documentation=https://wiki.hyprland.org/Hypr-Ecosystem/hyprpaper/ +PartOf=graphical-session.target +Requires=graphical-session.target +After=graphical-session.target +ConditionEnvironment=WAYLAND_DISPLAY + +[Service] +Type=simple +ExecStart=@CMAKE_INSTALL_PREFIX@/bin/hyprpaper +Slice=session.slice +Restart=on-failure + +[Install] +WantedBy=graphical-session.target