Files
z-bar-qt/Plugins/ZShell/Wallpaper/wallpapersurface.cpp
zach b0cb43f75c
C++ / fmt (pull_request) Failing after 6s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 11s
JS/TS / fmt (pull_request) Successful in 10s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Failing after 32s
Rust / build (pull_request) Successful in 52s
Python / verify (pull_request) Failing after 1m23s
Rust / fmt (pull_request) Successful in 51s
Rust / clippy (pull_request) Successful in 1m2s
feat: add vaapi path for video wallpapers on generic gpus
2026-10-27 02:15:16 +01:00

192 lines
4.7 KiB
C++

#include "wallpapersurface.hpp"
#include <QDebug>
#include <cmath>
#include "wallpaperservice.hpp"
namespace ZShell::wallpaper {
const QString kNamespace = "ZShell-Wallpaper";
void setQueue(void* proxy, struct wl_event_queue* queue) {
wl_proxy_set_queue(static_cast<struct wl_proxy*>(proxy), queue);
}
WallpaperSurface::WallpaperSurface(
WallpaperService* service,
wl_surface* surface,
wl_output* output,
const QString& screen)
: m_service(service), m_screen(screen), m_surface(surface) {
if (!surface) {
qWarning() << "WallpaperSurface: no surface for" << screen;
return;
}
setQueue(m_surface, m_service->eventQueue());
auto* layer = m_service->m_layerShell->get_layer_surface(
m_surface,
output,
QtWayland::zwlr_layer_shell_v1::layer_background,
kNamespace);
setQueue(layer, m_service->eventQueue());
QtWayland::zwlr_layer_surface_v1::init(layer);
set_size(0, 0);
set_anchor(anchor_top | anchor_bottom | anchor_left | anchor_right);
set_exclusive_zone(-1);
set_keyboard_interactivity(keyboard_interactivity_none);
set_margin(0, 0, 0, 0);
auto* viewport = m_service->m_viewporter->get_viewport(m_surface);
setQueue(viewport, m_service->eventQueue());
QtWayland::wp_viewport::init(viewport);
auto* scale = m_service->m_scaleManager->get_fractional_scale(m_surface);
setQueue(scale, m_service->eventQueue());
QtWayland::wp_fractional_scale_v1::init(scale);
wl_surface_commit(m_surface);
}
WallpaperSurface::~WallpaperSurface() {
if (m_frameCallback) {
wl_callback_destroy(m_frameCallback);
m_frameCallback = nullptr;
}
if (m_eglSurface != EGL_NO_SURFACE)
eglDestroySurface(m_service->m_eglDisplay, m_eglSurface);
if (m_window) wl_egl_window_destroy(m_window);
if (QtWayland::wp_viewport::isInitialized())
QtWayland::wp_viewport::destroy();
if (QtWayland::wp_fractional_scale_v1::isInitialized())
QtWayland::wp_fractional_scale_v1::destroy();
if (QtWayland::zwlr_layer_surface_v1::isInitialized())
QtWayland::zwlr_layer_surface_v1::destroy();
if (m_surface) wl_surface_destroy(m_surface);
}
void WallpaperSurface::markDirty() {
m_dirty.store(true, std::memory_order_relaxed);
}
bool WallpaperSurface::needsDraw() const {
return m_dirty.load(std::memory_order_relaxed);
}
bool WallpaperSurface::frameReady() const {
return m_frameReady.load(std::memory_order_relaxed);
}
void WallpaperSurface::requestFrame() {
if (!m_surface || m_frameCallback) return;
m_frameCallback = wl_surface_frame(m_surface);
static const struct wl_callback_listener listener = {
[](void* data, struct wl_callback*, uint32_t) {
static_cast<WallpaperSurface*>(data)->onFrameDone();
},
};
wl_callback_add_listener(m_frameCallback, &listener, this);
}
void WallpaperSurface::onFrameDone() {
if (m_frameCallback) {
wl_callback_destroy(m_frameCallback);
m_frameCallback = nullptr;
}
m_frameReady.store(true, std::memory_order_relaxed);
m_service->wake();
}
void WallpaperSurface::endDraw() {
m_dirty.store(false, std::memory_order_relaxed);
m_frameReady.store(false, std::memory_order_relaxed);
}
void WallpaperSurface::zwlr_layer_surface_v1_configure(
uint32_t serial, uint32_t width, uint32_t height) {
ack_configure(serial);
if (width == 0 || height == 0) return;
m_size = QSize(int(width), int(height));
if (!configured) configured = true;
updateBuffer();
}
void WallpaperSurface::wp_fractional_scale_v1_preferred_scale(uint32_t scale) {
if (scale == 0) return;
qreal newScale = qreal(scale) / 120.0;
if (qFuzzyCompare(newScale, m_scale)) return;
m_scale = newScale;
updateBuffer();
}
void WallpaperSurface::zwlr_layer_surface_v1_closed() {}
void WallpaperSurface::updateBuffer() {
if (m_size.isEmpty()) return;
QSize buffer = QSize(
int(std::llround(m_size.width() * m_scale)),
int(std::llround(m_size.height() * m_scale)));
if (buffer.isEmpty()) return;
if (m_bufferSize != buffer) {
m_bufferSize = buffer;
if (m_window) {
wl_egl_window_resize(
m_window, buffer.width(), buffer.height(), 0, 0);
} else {
m_window =
wl_egl_window_create(m_surface, buffer.width(), buffer.height());
if (!m_window) {
qWarning()
<< "WallpaperSurface: could not make a window surface for"
<< m_screen;
return;
}
}
if (m_eglSurface == EGL_NO_SURFACE) {
m_eglSurface = eglCreateWindowSurface(
m_service->m_eglDisplay,
m_service->m_config,
reinterpret_cast<EGLNativeWindowType>(m_window),
nullptr);
if (m_eglSurface == EGL_NO_SURFACE) {
qWarning()
<< "WallpaperSurface: eglCreateWindowSurface failed for"
<< m_screen;
return;
}
}
}
if (QtWayland::wp_viewport::isInitialized())
set_destination(m_size.width(), m_size.height());
requestFrame();
m_service->queue(this);
m_service->notifyBufferSizes();
}
} // namespace ZShell::wallpaper