191 lines
4.7 KiB
C++
191 lines
4.7 KiB
C++
#include "wallpapersurface.hpp"
|
|
|
|
#include <QDebug>
|
|
|
|
#include <cmath>
|
|
|
|
#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<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);
|
|
}
|
|
|
|
} // namespace ZShell::internal
|