diff --git a/README.md b/README.md index 80e097a..25c8d59 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,25 @@ You may add `contain:` or `tile:` before the file path in `wallpaper=` to set th wallpaper = monitor,contain:/path/to/image.jpg ``` +If you want to rotate a wallpaper, add a ```, X``` at then end of the wallpaper rule, where ```X``` corresponds to a transform number, e.g.: + +``` +wallpaper = monitor,/path/to/image.jpg, 1 +``` + +Transform list: + +``` +0 -> normal (no transforms) +1 -> 90 degrees +2 -> 180 degrees +3 -> 270 degrees +4 -> flipped +5 -> flipped + 90 degrees +6 -> flipped + 180 degrees +7 -> flipped + 270 degrees +``` + A Wallpaper ***cannot*** be applied without preloading. The config is ***not*** reloaded dynamically. ## Important note to the inner workings diff --git a/src/Hyprpaper.cpp b/src/Hyprpaper.cpp index abaa362..4e536b4 100644 --- a/src/Hyprpaper.cpp +++ b/src/Hyprpaper.cpp @@ -529,6 +529,7 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { const auto PWALLPAPERTARGET = m_mMonitorActiveWallpaperTargets[pMonitor]; const auto CONTAIN = m_mMonitorWallpaperRenderData[pMonitor->name].contain; const auto TILE = m_mMonitorWallpaperRenderData[pMonitor->name].tile; + const auto ROTATION = m_mMonitorWallpaperRenderData[pMonitor->name].rotation; if (!PWALLPAPERTARGET) { Debug::log(CRIT, "wallpaper target null in render??"); @@ -566,32 +567,55 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { // get scale // we always do cover - double scale; - Vector2D origin; + double scale = 1.0; + Vector2D origin; - const bool LOWASPECTRATIO = pMonitor->size.x / pMonitor->size.y > PWALLPAPERTARGET->m_vSize.x / PWALLPAPERTARGET->m_vSize.y; - if ((CONTAIN && !LOWASPECTRATIO) || (!CONTAIN && LOWASPECTRATIO)) { - scale = DIMENSIONS.x / PWALLPAPERTARGET->m_vSize.x; - origin.y = -(PWALLPAPERTARGET->m_vSize.y * scale - DIMENSIONS.y) / 2.0 / scale; - } else { - scale = DIMENSIONS.y / PWALLPAPERTARGET->m_vSize.y; - origin.x = -(PWALLPAPERTARGET->m_vSize.x * scale - DIMENSIONS.x) / 2.0 / scale; - } + double imgW = PWALLPAPERTARGET->m_vSize.x; + double imgH = 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); + if ((ROTATION % 4 == 1) || (ROTATION % 4 == 3)) + std::swap(imgW, imgH); + + cairo_save(PCAIRO); + + if (ROTATION != 0) { + cairo_translate(PCAIRO, DIMENSIONS.x / 2.0, DIMENSIONS.y / 2.0); + + if (ROTATION % 4 != 0) + cairo_rotate(PCAIRO, (ROTATION % 4) * M_PI_2); + + if (ROTATION >= 4) + cairo_scale(PCAIRO, -1, 1); + + cairo_translate(PCAIRO, -DIMENSIONS.x / 2.0, -DIMENSIONS.y / 2.0); + } 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); + cairo_pattern_destroy(pattern); } else { + + if (CONTAIN) + scale = std::min(DIMENSIONS.x / imgW, DIMENSIONS.y / imgH); + else + scale = std::max(DIMENSIONS.x / imgW, DIMENSIONS.y / imgH); + + origin.x = (DIMENSIONS.x / scale - PWALLPAPERTARGET->m_vSize.x) / 2.0; + origin.y = (DIMENSIONS.y / scale - PWALLPAPERTARGET->m_vSize.y) / 2.0; + cairo_scale(PCAIRO, scale, scale); cairo_set_source_surface(PCAIRO, PWALLPAPERTARGET->m_pCairoSurface->cairo(), origin.x, origin.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_paint(PCAIRO); + cairo_restore(PCAIRO); + if (*PRENDERSPLASH && getenv("HYPRLAND_INSTANCE_SIGNATURE")) { auto SPLASH = execAndGet("hyprctl splash"); if (!SPLASH.empty()) @@ -624,8 +648,6 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { cairo_surface_flush(PWALLPAPERTARGET->m_pCairoSurface->cairo()); } - cairo_restore(PCAIRO); - if (pMonitor->pCurrentLayerSurface) { pMonitor->pCurrentLayerSurface->pSurface->sendAttach(PBUFFER->buffer.get(), 0, 0); pMonitor->pCurrentLayerSurface->pSurface->sendSetBufferScale(pMonitor->pCurrentLayerSurface->pFractionalScaleInfo ? 1 : pMonitor->scale); diff --git a/src/Hyprpaper.hpp b/src/Hyprpaper.hpp index 0d6cb26..20c4ebf 100644 --- a/src/Hyprpaper.hpp +++ b/src/Hyprpaper.hpp @@ -17,8 +17,9 @@ #include "protocols/wlr-layer-shell-unstable-v1.hpp" struct SWallpaperRenderData { - bool contain = false; - bool tile = false; + bool contain = false; + bool tile = false; + uint32_t rotation = 0; }; class CHyprpaper { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 8d21aa0..0712c5d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -4,17 +4,18 @@ #include static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) { - const std::string COMMAND = C; - const std::string VALUE = V; - Hyprlang::CParseResult result; + const std::string COMMAND = C; + const std::string VALUE = V; + Hyprlang::CParseResult result; + Hyprutils::String::CVarList args(VALUE, 3, ',', false); - if (VALUE.find_first_of(',') == std::string::npos) { + if (args.size() < 2) { result.setError("wallpaper failed (syntax)"); return result; } - auto MONITOR = VALUE.substr(0, VALUE.find_first_of(',')); - auto WALLPAPER = g_pConfigManager->trimPath(VALUE.substr(VALUE.find_first_of(',') + 1)); + auto MONITOR = args[0]; + auto WALLPAPER = g_pConfigManager->trimPath(args[1]); bool contain = false; @@ -35,6 +36,20 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) { WALLPAPER = std::string(ENVHOME) + WALLPAPER.substr(1); } + uint32_t rotation = 0; + if (args.size() >= 3) { + try { + rotation = std::stoi(args[2]); + if (rotation > 7) { + result.setError("wallpaper failed (invalid rotation input: must be 0-7)"); + return result; + } + } catch (...) { + result.setError("wallpaper failed (invalid rotation: not a number)"); + return result; + } + } + std::error_code ec; if (!std::filesystem::exists(WALLPAPER, ec)) { @@ -49,17 +64,19 @@ 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; + g_pHyprpaper->m_mMonitorActiveWallpapers[MONITOR] = WALLPAPER; + g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].contain = contain; + g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].tile = tile; + g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].rotation = rotation; if (MONITOR.empty()) { for (auto& m : g_pHyprpaper->m_vMonitors) { if (!m->hasATarget || m->wildcard) { 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; + g_pHyprpaper->m_mMonitorActiveWallpapers[m->name] = WALLPAPER; + g_pHyprpaper->m_mMonitorWallpaperRenderData[m->name].contain = contain; + g_pHyprpaper->m_mMonitorWallpaperRenderData[m->name].tile = tile; + g_pHyprpaper->m_mMonitorWallpaperRenderData[m->name].rotation = rotation; } } } else { @@ -141,10 +158,18 @@ static Hyprlang::CParseResult handleUnload(const char* C, const char* V) { } static Hyprlang::CParseResult handleReload(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; + Hyprutils::String::CVarList args(VALUE, 3, ',', false); - auto WALLPAPER = g_pConfigManager->trimPath(VALUE.substr(VALUE.find_first_of(',') + 1)); + if (args.size() < 2) { + Hyprlang::CParseResult result; + result.setError("reload failed (syntax)"); + return result; + } + + auto MONITOR = args[0]; + auto WALLPAPER = g_pConfigManager->trimPath(args[1]); if (WALLPAPER.find("contain:") == 0) { WALLPAPER = WALLPAPER.substr(8); @@ -157,8 +182,6 @@ static Hyprlang::CParseResult handleReload(const char* C, const char* V) { if (preloadResult.error) return preloadResult; - auto MONITOR = VALUE.substr(0, VALUE.find_first_of(',')); - if (MONITOR.empty()) { for (auto& m : g_pHyprpaper->m_vMonitors) { auto OLD_WALLPAPER = g_pHyprpaper->m_mMonitorActiveWallpapers[m->name];