New upstream version 0.7.4
This commit is contained in:
parent
f1708a5ac8
commit
9053826269
|
|
@ -12,6 +12,8 @@ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
|
|||
|
||||
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 @@ execute_process(
|
|||
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,6 +47,7 @@ add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value
|
|||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(hyprwayland-scanner 0.4.0 REQUIRED)
|
||||
|
||||
pkg_check_modules(
|
||||
deps
|
||||
|
|
@ -55,11 +58,9 @@ pkg_check_modules(
|
|||
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 @@ add_executable(hyprpaper ${SRCFILES})
|
|||
|
||||
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 @@ function(protocolWayland)
|
|||
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 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
|||
"${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 ${CMAKE_INSTALL_LIBDIR}/systemd/user)
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -4,7 +4,7 @@ Hyprpaper is a blazing fast wallpaper utility for Hyprland with the ability to d
|
|||
|
||||
# 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 @@ The development files of these packages need to be installed on the system for `
|
|||
- 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 @@ splash = true
|
|||
|
||||
```
|
||||
|
||||
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
|
||||
|
|
|
|||
51
flake.lock
51
flake.lock
|
|
@ -1,5 +1,31 @@
|
|||
{
|
||||
"nodes": {
|
||||
"hyprgraphics": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
"hyprutils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737634889,
|
||||
"narHash": "sha256-9JZE3KxcXOqZH9zs3UeadngDiK/yIACTiAR8HSA/TNI=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprgraphics",
|
||||
"rev": "0d77b4895ad5f1bb3b0ee43103a5246c58b65591",
|
||||
"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": 1737632363,
|
||||
"narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "962582a090bc233c4de9d9897f46794280288989",
|
||||
"rev": "006620eb29d54ea9086538891404c78563d1bae1",
|
||||
"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": 1737469691,
|
||||
"narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ad0b5eed1b6031efaed382844806550c3dcb4206",
|
||||
"rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -90,6 +116,7 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"hyprgraphics": "hyprgraphics",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||
|
|
|
|||
10
flake.nix
10
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";
|
||||
|
|
@ -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 "";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@
|
|||
expat,
|
||||
file,
|
||||
fribidi,
|
||||
hyprgraphics,
|
||||
hyprlang,
|
||||
hyprutils,
|
||||
hyprwayland-scanner,
|
||||
libdatrie,
|
||||
libGL,
|
||||
libjpeg,
|
||||
libjxl,
|
||||
libselinux,
|
||||
libsepol,
|
||||
libthai,
|
||||
|
|
@ -40,6 +42,10 @@ stdenv.mkDerivation {
|
|||
--replace GIT_COMMIT_HASH '"${commit}"'
|
||||
'';
|
||||
|
||||
depsBuildBuild = [
|
||||
pkg-config
|
||||
];
|
||||
|
||||
cmakeBuildType =
|
||||
if debug
|
||||
then "Debug"
|
||||
|
|
@ -49,6 +55,7 @@ stdenv.mkDerivation {
|
|||
cmake
|
||||
hyprwayland-scanner
|
||||
pkg-config
|
||||
wayland-scanner
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
|
|
@ -56,11 +63,13 @@ stdenv.mkDerivation {
|
|||
expat
|
||||
file
|
||||
fribidi
|
||||
hyprgraphics
|
||||
hyprlang
|
||||
hyprutils
|
||||
libdatrie
|
||||
libGL
|
||||
libjpeg
|
||||
libjxl
|
||||
libselinux
|
||||
libsepol
|
||||
libthai
|
||||
|
|
@ -70,7 +79,6 @@ stdenv.mkDerivation {
|
|||
pcre2
|
||||
wayland
|
||||
wayland-protocols
|
||||
wayland-scanner
|
||||
xorg.libXdmcp
|
||||
util-linux
|
||||
];
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ static void handleGlobal(CCWlRegistry* registry, uint32_t name, const char* inte
|
|||
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 +139,7 @@ void CHyprpaper::unloadWallpaper(const std::string& path) {
|
|||
|
||||
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 +161,7 @@ void CHyprpaper::preloadAllWallpapersFromConfig() {
|
|||
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 +201,7 @@ void CHyprpaper::createSeat(SP<CCWlSeat> pSeat) {
|
|||
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 +243,13 @@ void CHyprpaper::removeOldHyprpaperImages() {
|
|||
|
||||
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 +293,7 @@ void CHyprpaper::ensurePoolBuffersPresent() {
|
|||
|
||||
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 +307,7 @@ void CHyprpaper::ensurePoolBuffersPresent() {
|
|||
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 +397,7 @@ void CHyprpaper::ensureMonitorHasActiveWallpaper(SMonitor* pMonitor) {
|
|||
|
||||
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 +506,15 @@ SPoolBuffer* CHyprpaper::getPoolBuffer(SMonitor* pMonitor, CWallpaperTarget* pWa
|
|||
}
|
||||
|
||||
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 +564,50 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
|
|||
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 +623,8 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
|
|||
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();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
struct SWallpaperRenderData {
|
||||
bool contain = false;
|
||||
bool tile = false;
|
||||
};
|
||||
|
||||
class CHyprpaper {
|
||||
|
|
|
|||
|
|
@ -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 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
|
|||
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 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
|
|||
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 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
|
|||
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 @@ static Hyprlang::CParseResult handleReload(const char* C, const char* V) {
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
|
||||
namespace BMP {
|
||||
cairo_surface_t* createSurfaceFromBMP(const std::string&);
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <jpeglib.h>
|
||||
|
||||
namespace JPEG {
|
||||
cairo_surface_t* createSurfaceFromJPEG(const std::string&);
|
||||
};
|
||||
|
|
@ -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 @@ bool vectorDeltaLessThan(const Vector2D& a, const Vector2D& b, const Vector2D& d
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 @@ void SMonitor::registerListeners() {
|
|||
|
||||
description = desc;
|
||||
});
|
||||
}
|
||||
|
||||
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_;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ struct SMonitor {
|
|||
uint32_t wayland_name = 0;
|
||||
Vector2D size;
|
||||
int scale;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
|
||||
bool readyForLS = false;
|
||||
bool hasATarget = true;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
|
||||
namespace WEBP {
|
||||
cairo_surface_t* createSurfaceFromWEBP(const std::string&);
|
||||
};
|
||||
|
|
@ -50,7 +50,7 @@ void CIPCSocket::initialize() {
|
|||
|
||||
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 @@ void CIPCSocket::initialize() {
|
|||
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 @@ bool CIPCSocket::mainThreadParseRequest() {
|
|||
|
||||
// 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 @@ bool CIPCSocket::mainThreadParseRequest() {
|
|||
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 @@ bool CIPCSocket::mainThreadParseRequest() {
|
|||
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";
|
||||
|
|
|
|||
|
|
@ -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 @@ int main(int argc, char** argv, char** envp) {
|
|||
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 @@ int main(int argc, char** argv, char** envp) {
|
|||
g_pHyprpaper->init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
|
|||
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 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue