From b8d2b97e13fe3e45fa2e88594540717915ff0ca1 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Sun, 29 Jan 2023 14:00:08 +0000 Subject: [PATCH] fractional scaling impl --- CMakeLists.txt | 2 ++ Makefile | 22 +++++++++++++++++++++- README.md | 7 +++++++ src/Hyprpaper.cpp | 34 ++++++++++++++++++++++------------ src/Hyprpaper.hpp | 10 ++++++---- src/events/Events.cpp | 19 ++++++++++++++++++- src/events/Events.hpp | 4 ++++ src/includes.hpp | 2 ++ src/render/LayerSurface.cpp | 14 ++++++++++++++ src/render/LayerSurface.hpp | 4 ++++ 10 files changed, 100 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb3cfa7..13bbc26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,8 @@ target_link_libraries(hyprpaper ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_SOURCE_DIR}/wlr-layer-shell-unstable-v1-protocol.o ${CMAKE_SOURCE_DIR}/xdg-shell-protocol.o + ${CMAKE_SOURCE_DIR}/fractional-scale-v1-protocol.o + ${CMAKE_SOURCE_DIR}/viewporter-protocol.o wayland-cursor ) diff --git a/Makefile b/Makefile index 69debfb..84eca74 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,27 @@ xdg-shell-protocol.c: xdg-shell-protocol.o: xdg-shell-protocol.h -protocols: wlr-layer-shell-unstable-v1-protocol.o xdg-shell-protocol.o +fractional-scale-v1-protocol.h: + $(WAYLAND_SCANNER) client-header \ + $(WAYLAND_PROTOCOLS)/staging/fractional-scale/fractional-scale-v1.xml $@ + +fractional-scale-v1-protocol.c: + $(WAYLAND_SCANNER) private-code \ + $(WAYLAND_PROTOCOLS)/staging/fractional-scale/fractional-scale-v1.xml $@ + +fractional-scale-v1-protocol.o: fractional-scale-v1-protocol.h + +viewporter-protocol.h: + $(WAYLAND_SCANNER) client-header \ + $(WAYLAND_PROTOCOLS)/stable/viewporter/viewporter.xml $@ + +viewporter-protocol.c: + $(WAYLAND_SCANNER) private-code \ + $(WAYLAND_PROTOCOLS)/stable/viewporter/viewporter.xml $@ + +viewporter-protocol.o: viewporter-protocol.h + +protocols: wlr-layer-shell-unstable-v1-protocol.o xdg-shell-protocol.o fractional-scale-v1-protocol.o viewporter-protocol.o clear: rm -rf build diff --git a/README.md b/README.md index eea06fa..198e0b0 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,13 @@ Hyprpaper is a blazing fast wallpaper utility for Hyprland with the ability to dynamically change wallpapers through sockets. It will work on all wlroots-based compositors, though. +# Features + - Per-output wallpapers + - fill or contain modes + - fractional scaling support + - IPC for blazing fast wallpaper switches + - preloading targets into memory + # Installation [AUR](https://aur.archlinux.org/packages/hyprpaper-git): `yay -S hyprpaper-git` diff --git a/src/Hyprpaper.cpp b/src/Hyprpaper.cpp index b142084..d54554b 100644 --- a/src/Hyprpaper.cpp +++ b/src/Hyprpaper.cpp @@ -419,6 +419,9 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { } } + const Vector2D DIMENSIONS = pMonitor->pCurrentLayerSurface->pFractionalScaleInfo ? Vector2D{pMonitor->size.x * pMonitor->pCurrentLayerSurface->fScale, pMonitor->size.y * pMonitor->pCurrentLayerSurface->fScale} : Vector2D{pMonitor->size.x * pMonitor->scale, pMonitor->size.y * pMonitor->scale}; + const double SURFACESCALE = pMonitor->pCurrentLayerSurface->pFractionalScaleInfo ? pMonitor->pCurrentLayerSurface->fScale : pMonitor->scale; + const auto PCAIRO = PBUFFER->cairo; cairo_save(PCAIRO); cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR); @@ -427,7 +430,7 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { if (CONTAIN) { cairo_set_source_rgb(PCAIRO, 0, 0, 0); - cairo_rectangle(PCAIRO, 0, 0, pMonitor->size.x * pMonitor->scale, pMonitor->size.y * pMonitor->scale); + cairo_rectangle(PCAIRO, 0, 0, DIMENSIONS.x, DIMENSIONS.y); cairo_fill(PCAIRO); @@ -441,38 +444,45 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { if (!CONTAIN) { if (pMonitor->size.x / pMonitor->size.y > PWALLPAPERTARGET->m_vSize.x / PWALLPAPERTARGET->m_vSize.y) { - scale = pMonitor->size.x * pMonitor->scale / PWALLPAPERTARGET->m_vSize.x; + scale = DIMENSIONS.x / PWALLPAPERTARGET->m_vSize.x; - origin.y = -(PWALLPAPERTARGET->m_vSize.y * scale - pMonitor->size.y * pMonitor->scale) / 2.f / scale; + origin.y = -(PWALLPAPERTARGET->m_vSize.y * scale - DIMENSIONS.y) / 2.f / scale; } else { - scale = pMonitor->size.y * pMonitor->scale / PWALLPAPERTARGET->m_vSize.y; + scale = DIMENSIONS.y / PWALLPAPERTARGET->m_vSize.y; - origin.x = -(PWALLPAPERTARGET->m_vSize.x * scale - pMonitor->size.x * pMonitor->scale) / 2.f / scale; + origin.x = -(PWALLPAPERTARGET->m_vSize.x * scale - DIMENSIONS.x) / 2.f / scale; } } else { if (pMonitor->size.x / pMonitor->size.y > PWALLPAPERTARGET->m_vSize.x / PWALLPAPERTARGET->m_vSize.y) { - scale = (pMonitor->size.y * pMonitor->scale) / PWALLPAPERTARGET->m_vSize.y; + scale = (DIMENSIONS.y) / PWALLPAPERTARGET->m_vSize.y; - origin.x = (pMonitor->size.x * pMonitor->scale - PWALLPAPERTARGET->m_vSize.x * scale); + origin.x = (DIMENSIONS.x - PWALLPAPERTARGET->m_vSize.x * scale); } else { - scale = (pMonitor->size.x * pMonitor->scale) / PWALLPAPERTARGET->m_vSize.x; + scale = (DIMENSIONS.x) / PWALLPAPERTARGET->m_vSize.x; - origin.y = (pMonitor->size.y * pMonitor->scale - PWALLPAPERTARGET->m_vSize.y * scale); + origin.y = (DIMENSIONS.y - PWALLPAPERTARGET->m_vSize.y * 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); - cairo_scale(PCAIRO, scale, scale); + cairo_scale(PCAIRO, scale * (DIMENSIONS.x / (pMonitor->size.x * pMonitor->scale)), scale * (DIMENSIONS.x / (pMonitor->size.x * pMonitor->scale))); cairo_set_source_surface(PCAIRO, PWALLPAPERTARGET->m_pCairoSurface, origin.x, origin.y); cairo_paint(PCAIRO); cairo_restore(PCAIRO); wl_surface_attach(pMonitor->pCurrentLayerSurface->pSurface, PBUFFER->buffer, 0, 0); - wl_surface_set_buffer_scale(pMonitor->pCurrentLayerSurface->pSurface, pMonitor->scale); - wl_surface_damage_buffer(pMonitor->pCurrentLayerSurface->pSurface, 0, 0, pMonitor->size.x, pMonitor->size.y); + wl_surface_set_buffer_scale(pMonitor->pCurrentLayerSurface->pSurface, SURFACESCALE); + wl_surface_damage_buffer(pMonitor->pCurrentLayerSurface->pSurface, 0, 0, 0xFFFF, 0xFFFF); + if (pMonitor->pCurrentLayerSurface->pFractionalScaleInfo) { + wl_fixed_t w, h; + w = wl_fixed_from_int((int)DIMENSIONS.x); + h = wl_fixed_from_int((int)DIMENSIONS.y); + + wp_viewport_set_source(pMonitor->pCurrentLayerSurface->pViewport, wl_fixed_from_int(0), wl_fixed_from_int(0), w, h); + } wl_surface_commit(pMonitor->pCurrentLayerSurface->pSurface); // check if we dont need to remove a wallpaper diff --git a/src/Hyprpaper.hpp b/src/Hyprpaper.hpp index 2b9aaf4..d942676 100644 --- a/src/Hyprpaper.hpp +++ b/src/Hyprpaper.hpp @@ -16,10 +16,12 @@ struct SWallpaperRenderData { class CHyprpaper { public: // important - wl_display* m_sDisplay; - wl_compositor* m_sCompositor; - wl_shm* m_sSHM; - zwlr_layer_shell_v1* m_sLayerShell; + wl_display* m_sDisplay; // assured + wl_compositor* m_sCompositor; // assured + wl_shm* m_sSHM; // assured + zwlr_layer_shell_v1* m_sLayerShell = nullptr; // expected + wp_fractional_scale_manager_v1* m_sFractionalScale = nullptr; // will remain null if not bound + wp_viewporter* m_sViewporter = nullptr; // expected // init the utility CHyprpaper(); diff --git a/src/events/Events.cpp b/src/events/Events.cpp index 19e6e26..6740828 100644 --- a/src/events/Events.cpp +++ b/src/events/Events.cpp @@ -120,7 +120,11 @@ void Events::handleGlobal(void *data, struct wl_registry *registry, uint32_t nam } else if (strcmp(interface, wl_seat_interface.name) == 0) { g_pHyprpaper->createSeat((wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1)); } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { - g_pHyprpaper->m_sLayerShell = (zwlr_layer_shell_v1 *)wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1); + g_pHyprpaper->m_sLayerShell = (zwlr_layer_shell_v1*)wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1); + } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { + g_pHyprpaper->m_sFractionalScale = (wp_fractional_scale_manager_v1*)wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1); + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { + g_pHyprpaper->m_sViewporter = (wp_viewporter*)wl_registry_bind(registry, name, &wp_viewporter_interface, 1); } } @@ -134,3 +138,16 @@ void Events::handleGlobalRemove(void *data, struct wl_registry *registry, uint32 } } +void Events::handlePreferredScale(void *data, wp_fractional_scale_v1* fractionalScaleInfo, uint32_t scale) { + const double SCALE = scale / 120.0; + + CLayerSurface *const pLS = (CLayerSurface*)data; + + Debug::log(LOG, "handlePreferredScale: %.2lf for %lx", SCALE, pLS); + + if (pLS->fScale != SCALE) { + pLS->fScale = SCALE; + g_pHyprpaper->tick(true); + } +} + diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 8f6f09a..d3e9edb 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -35,6 +35,8 @@ namespace Events { void handlePointerLeave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface); + void handlePreferredScale(void *data, wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale); + inline const wl_output_listener outputListener = {.geometry = geometry, .mode = mode, .done = done, .scale = scale, .name = name, .description = description}; inline const zwlr_layer_surface_v1_listener layersurfaceListener = { .configure = ls_configure, .closed = handleLSClosed }; @@ -44,4 +46,6 @@ namespace Events { inline const wl_pointer_listener pointerListener = { .enter = handlePointerEnter, .leave = handlePointerLeave, .motion = handlePointerMotion, .button = handlePointerButton, .axis = handlePointerAxis }; inline const wl_seat_listener seatListener = { .capabilities = handleCapabilities }; + + inline const wp_fractional_scale_v1_listener scaleListener = { .preferred_scale = handlePreferredScale }; } diff --git a/src/includes.hpp b/src/includes.hpp index a3895e9..4bbe124 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -18,6 +18,8 @@ extern "C" { #include "wlr-layer-shell-unstable-v1-protocol.h" #include "xdg-shell-protocol.h" +#include "fractional-scale-v1-protocol.h" +#include "viewporter-protocol.h" #include #include } diff --git a/src/render/LayerSurface.cpp b/src/render/LayerSurface.cpp index d66e8c3..9425802 100644 --- a/src/render/LayerSurface.cpp +++ b/src/render/LayerSurface.cpp @@ -37,10 +37,24 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { wl_region_destroy(PINPUTREGION); + // fractional scale, if supported by the compositor + if (g_pHyprpaper->m_sFractionalScale) { + pFractionalScaleInfo = wp_fractional_scale_manager_v1_get_fractional_scale(g_pHyprpaper->m_sFractionalScale, pSurface); + wp_fractional_scale_v1_add_listener(pFractionalScaleInfo, &Events::scaleListener, this); + pViewport = wp_viewporter_get_viewport(g_pHyprpaper->m_sViewporter, pSurface); + wl_surface_commit(pSurface); + } + wl_display_flush(g_pHyprpaper->m_sDisplay); } CLayerSurface::~CLayerSurface() { + if (g_pHyprpaper->m_sFractionalScale && pFractionalScaleInfo) { + wp_fractional_scale_v1_destroy(pFractionalScaleInfo); + + wp_viewport_destroy(pViewport); + } + zwlr_layer_surface_v1_destroy(pLayerSurface); wl_surface_destroy(pSurface); diff --git a/src/render/LayerSurface.hpp b/src/render/LayerSurface.hpp index 42dde3a..d030540 100644 --- a/src/render/LayerSurface.hpp +++ b/src/render/LayerSurface.hpp @@ -16,4 +16,8 @@ public: wl_cursor_image* pCursorImg = nullptr; wl_surface* pCursorSurface = nullptr; + + wp_fractional_scale_v1* pFractionalScaleInfo = nullptr; + wp_viewport* pViewport = nullptr; + double fScale = 1.0; };