#include "wallpapersurface.hpp" #include #include #include "wallpaperservice.hpp" namespace ZShell::internal { const QString kNamespace = "ZShell-Wallpaper"; void setQueue(void* proxy, struct wl_event_queue* queue) { wl_proxy_set_queue(static_cast(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(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(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::internal