refactor: Implement wallpaper rotation with cleaner code structure

This commit is contained in:
Lucas Christiansson 2025-09-24 23:27:47 +02:00
parent bcb1ffa322
commit 08c0bda7c0
3 changed files with 64 additions and 14 deletions

View file

@ -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,58 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
// get scale
// we always do cover
double scale;
double scale = 1.0;
Vector2D origin;
double imgW = PWALLPAPERTARGET->m_vSize.x;
double imgH = PWALLPAPERTARGET->m_vSize.y;
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;
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);
}
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 (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 +651,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);

View file

@ -19,6 +19,7 @@
struct SWallpaperRenderData {
bool contain = false;
bool tile = false;
uint32_t rotation = 0;
};
class CHyprpaper {

View file

@ -13,8 +13,15 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
return result;
}
auto MONITOR = VALUE.substr(0, VALUE.find_first_of(','));
auto WALLPAPER = g_pConfigManager->trimPath(VALUE.substr(VALUE.find_first_of(',') + 1));
auto firstComma = VALUE.find_first_of(',');
auto secondComma = VALUE.find_first_of(',', firstComma + 1);
auto MONITOR = VALUE.substr(0, firstComma);
auto WALLPAPER = g_pConfigManager->trimPath(
VALUE.substr(firstComma + 1,
(secondComma == std::string::npos ? std::string::npos : secondComma - firstComma - 1))
);
bool contain = false;
@ -35,6 +42,21 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
WALLPAPER = std::string(ENVHOME) + WALLPAPER.substr(1);
}
int rotation = 0;
if (secondComma != std::string::npos) {
std::string rotationStr = VALUE.substr(secondComma + 1);
try {
rotation = std::stoi(rotationStr);
if (rotation < 0 || 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)) {
@ -52,6 +74,7 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
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) {
@ -60,6 +83,7 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
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 {