Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 36 additions & 14 deletions src/Hyprpaper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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??");
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions src/Hyprpaper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
57 changes: 40 additions & 17 deletions src/config/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
#include <filesystem>

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;

Expand All @@ -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)) {
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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];
Expand Down