mirror of
https://github.com/hyprwm/hyprpaper.git
synced 2026-05-09 01:58:17 +02:00
feat: Added per-monitor wallpaper rotation support
Added support for rotating wallpapers per monitor using config syntax: monitor_name,wallpaper_path,rotation_degrees
This commit is contained in:
parent
bcb1ffa322
commit
6b1b348b9c
4 changed files with 97 additions and 21 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#include "Hyprpaper.hpp"
|
||||
#include "render/WallpaperTransform.hpp"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <signal.h>
|
||||
|
|
@ -520,6 +521,7 @@ SPoolBuffer* CHyprpaper::getPoolBuffer(SMonitor* pMonitor, CWallpaperTarget* pWa
|
|||
}
|
||||
|
||||
void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
|
||||
#include "render/WallpaperTransform.hpp"
|
||||
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");
|
||||
|
||||
|
|
@ -564,30 +566,21 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
|
|||
cairo_fill(PCAIRO);
|
||||
cairo_surface_flush(PBUFFER->surface);
|
||||
|
||||
// get scale
|
||||
// we always do cover
|
||||
double scale;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
// Apply wallpaper transform (handles scaling, rotation, and centering)
|
||||
applyWallpaperTransform(
|
||||
PCAIRO,
|
||||
Vector2D(PWALLPAPERTARGET->m_vSize.x, PWALLPAPERTARGET->m_vSize.y),
|
||||
DIMENSIONS,
|
||||
pMonitor->wallpaperRotation
|
||||
);
|
||||
|
||||
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);
|
||||
// No additional scaling/positioning - the transform handles it all
|
||||
cairo_set_source_surface(PCAIRO, PWALLPAPERTARGET->m_pCairoSurface->cairo(), 0, 0);
|
||||
}
|
||||
|
||||
cairo_paint(PCAIRO);
|
||||
|
|
@ -601,6 +594,15 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
|
|||
|
||||
cairo_select_font_face(PCAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
|
||||
// Calculate scale for splash text (same logic as transform function)
|
||||
int rot = pMonitor->wallpaperRotation % 360;
|
||||
bool swapWH = (rot == 90 || rot == 270);
|
||||
double imgW = swapWH ? PWALLPAPERTARGET->m_vSize.y : PWALLPAPERTARGET->m_vSize.x;
|
||||
double imgH = swapWH ? PWALLPAPERTARGET->m_vSize.x : PWALLPAPERTARGET->m_vSize.y;
|
||||
double scaleX = DIMENSIONS.x / imgW;
|
||||
double scaleY = DIMENSIONS.y / imgH;
|
||||
double scale = std::max(scaleX, scaleY);
|
||||
|
||||
const auto FONTSIZE = (int)(DIMENSIONS.y / 76.0 / scale);
|
||||
cairo_set_font_size(PCAIRO, FONTSIZE);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,29 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
|
|||
const std::string VALUE = V;
|
||||
Hyprlang::CParseResult result;
|
||||
|
||||
if (VALUE.find_first_of(',') == std::string::npos) {
|
||||
|
||||
// Support syntax: monitor_name,wallpaper_path[,rotation]
|
||||
size_t firstComma = VALUE.find_first_of(',');
|
||||
if (firstComma == std::string::npos) {
|
||||
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));
|
||||
size_t secondComma = VALUE.find_first_of(',', firstComma + 1);
|
||||
auto MONITOR = VALUE.substr(0, firstComma);
|
||||
std::string WALLPAPER;
|
||||
int rotation = 0;
|
||||
if (secondComma == std::string::npos) {
|
||||
WALLPAPER = g_pConfigManager->trimPath(VALUE.substr(firstComma + 1));
|
||||
} else {
|
||||
WALLPAPER = g_pConfigManager->trimPath(VALUE.substr(firstComma + 1, secondComma - firstComma - 1));
|
||||
std::string rotationStr = VALUE.substr(secondComma + 1);
|
||||
try {
|
||||
rotation = std::stoi(rotationStr);
|
||||
} catch (...) {
|
||||
rotation = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool contain = false;
|
||||
|
||||
|
|
@ -48,11 +64,20 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
g_pHyprpaper->clearWallpaperFromMonitor(MONITOR);
|
||||
g_pHyprpaper->m_mMonitorActiveWallpapers[MONITOR] = WALLPAPER;
|
||||
g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].contain = contain;
|
||||
g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].tile = tile;
|
||||
|
||||
// Set wallpaper rotation for the monitor
|
||||
for (auto& m : g_pHyprpaper->m_vMonitors) {
|
||||
if (m->name == MONITOR) {
|
||||
m->wallpaperRotation = rotation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (MONITOR.empty()) {
|
||||
for (auto& m : g_pHyprpaper->m_vMonitors) {
|
||||
if (!m->hasATarget || m->wildcard) {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ struct SMonitor {
|
|||
bool wantsACK = false;
|
||||
bool initialized = false;
|
||||
|
||||
// Wallpaper rotation in degrees (0, 90, 180, 270)
|
||||
int wallpaperRotation = 0;
|
||||
|
||||
std::vector<std::unique_ptr<CLayerSurface>> layerSurfaces;
|
||||
CLayerSurface* pCurrentLayerSurface = nullptr;
|
||||
|
||||
|
|
|
|||
46
src/render/WallpaperTransform.hpp
Normal file
46
src/render/WallpaperTransform.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
#include <cairo/cairo.h>
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
|
||||
// Applies robust rotation, scaling, and centering for wallpaper rendering
|
||||
// Always fills the monitor (cover mode), centers image, and handles all rotations correctly
|
||||
inline void applyWallpaperTransform(cairo_t* cr, const Vector2D& imgSize, const Vector2D& monSize, int rotation) {
|
||||
double imgW = imgSize.x;
|
||||
double imgH = imgSize.y;
|
||||
double monW = monSize.x;
|
||||
double monH = monSize.y;
|
||||
|
||||
// Normalize rotation
|
||||
int rot = rotation % 360;
|
||||
if (rot < 0) rot += 360;
|
||||
|
||||
// For 90/270 degrees, the image dimensions are effectively swapped
|
||||
bool isRotated90or270 = (rot == 90 || rot == 270);
|
||||
double effectiveImgW = isRotated90or270 ? imgH : imgW;
|
||||
double effectiveImgH = isRotated90or270 ? imgW : imgH;
|
||||
|
||||
// Calculate scale to cover the monitor (larger scale wins)
|
||||
double scaleX = monW / effectiveImgW;
|
||||
double scaleY = monH / effectiveImgH;
|
||||
double scale = std::max(scaleX, scaleY);
|
||||
|
||||
// Debug output
|
||||
printf("DEBUG Transform: rotation=%d, imgSize=[%.1f,%.1f], monSize=[%.1f,%.1f]\n",
|
||||
rot, imgW, imgH, monW, monH);
|
||||
printf("DEBUG effective=[%.1f,%.1f], scales=[%.3f,%.3f], final_scale=%.3f\n",
|
||||
effectiveImgW, effectiveImgH, scaleX, scaleY, scale);
|
||||
printf("DEBUG transforms: translate=[%.1f,%.1f], rotate=%.1f°, scale=%.3f, img_center=[%.1f,%.1f]\n",
|
||||
monW/2.0, monH/2.0, (double)rot, scale, imgW/2.0, imgH/2.0);
|
||||
|
||||
// Move to center of monitor
|
||||
cairo_translate(cr, monW / 2.0, monH / 2.0);
|
||||
|
||||
// Rotate around center
|
||||
cairo_rotate(cr, rot * M_PI / 180.0);
|
||||
|
||||
// Scale the image
|
||||
cairo_scale(cr, scale, scale);
|
||||
|
||||
// Move to center of image (so image center aligns with rotation center)
|
||||
cairo_translate(cr, -imgW / 2.0, -imgH / 2.0);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue