10#include "compositor.h"
17#include <KWayland/Client/compositor.h>
18#include <KWayland/Client/pointer.h>
19#include <KWayland/Client/pointerconstraints.h>
20#include <KWayland/Client/surface.h>
21#include <KWayland/Client/xdgdecoration.h>
23#include <KLocalizedString>
35static const int s_refreshRate = 60000;
38 : m_surface(backend->display()->compositor()->createSurface())
56 m_pointer->setCursor(m_surface.get(), m_hotspot);
62 if (m_enabled != enable) {
70 if (m_buffer != buffer || m_scale != scale || m_hotspot != hotspot) {
79void WaylandCursor::sync()
82 m_surface->attachBuffer(KWayland::Client::Buffer::Ptr());
83 m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
85 m_surface->attachBuffer(m_buffer);
86 m_surface->setScale(std::ceil(m_scale));
87 m_surface->damageBuffer(QRect(0, 0, INT32_MAX, INT32_MAX));
88 m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
92 m_pointer->setCursor(m_surface.get(), m_hotspot);
98 , m_renderLoop(std::make_unique<
RenderLoop>(this))
99 , m_surface(backend->display()->compositor()->createSurface())
100 , m_xdgShellSurface(backend->display()->xdgShell()->createSurface(m_surface.get()))
105 m_xdgDecoration.reset(manager->getToplevelDecoration(m_xdgShellSurface.get()));
106 m_xdgDecoration->setMode(KWayland::Client::XdgDecoration::Mode::ServerSide);
115 m_turnOffTimer.setSingleShot(
true);
117 connect(&m_turnOffTimer, &QTimer::timeout,
this, [
this] {
121 m_configureThrottleTimer.setSingleShot(
true);
122 connect(&m_configureThrottleTimer, &QTimer::timeout,
this, [
this]() {
123 applyConfigure(m_pendingConfigureSize, m_pendingConfigureSerial);
126 connect(m_surface.get(), &KWayland::Client::Surface::frameRendered,
this, [
this]() {
128 const auto primary = Compositor::self()->backend()->primaryLayer(this);
129 m_frame->presented(std::chrono::nanoseconds(1'000'000'000'000 / refreshRate()), std::chrono::steady_clock::now().time_since_epoch(), primary ? primary->queryRenderTime() : std::chrono::nanoseconds::zero(), PresentationMode::VSync);
135 connect(m_xdgShellSurface.get(), &XdgShellSurface::configureRequested,
this, &WaylandOutput::handleConfigure);
136 connect(m_xdgShellSurface.get(), &XdgShellSurface::closeRequested, qApp, &QCoreApplication::quit);
143 m_xdgDecoration.reset();
144 m_xdgShellSurface.reset();
160 return m_surface.get();
165 return m_cursor.get();
175 return m_renderLoop.get();
180 if (m_hasPointerLock) {
181 m_cursor->setEnabled(
false);
192 m_renderLoop->setRefreshRate(s_refreshRate);
194 auto mode = std::make_shared<OutputMode>(
pixelSize, s_refreshRate);
197 initialState.
modes = {mode};
202 m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
207 auto mode = std::make_shared<OutputMode>(
pixelSize, s_refreshRate);
220 if (!m_turnOffTimer.isActive()) {
221 Q_EMIT
aboutToTurnOff(std::chrono::milliseconds(m_turnOffTimer.interval()));
222 m_turnOffTimer.start();
225 m_turnOffTimer.stop();
247void WaylandOutput::handleConfigure(
const QSize &size, XdgShellSurface::States states, quint32 serial)
252 applyConfigure(size, serial);
255 m_pendingConfigureSerial = serial;
256 m_pendingConfigureSize = size;
258 if (!m_configureThrottleTimer.isActive()) {
264void WaylandOutput::applyConfigure(
const QSize &size, quint32 serial)
266 m_xdgShellSurface->ackConfigure(serial);
267 if (!size.isEmpty()) {
272void WaylandOutput::updateWindowTitle()
275 if (m_hasPointerLock) {
276 grab = i18n(
"Press right control to ungrab pointer");
278 grab = i18n(
"Press right control key to grab pointer");
281 QString title = i18nc(
"Title of nested KWin Wayland with Wayland socket identifier as argument",
282 "KDE Wayland Compositor %1",
name());
285 title += i18n(
"- Output disabled");
287 title += i18n(
"- Output dimmed");
288 }
else if (!grab.isEmpty()) {
289 title += QStringLiteral(
" — ") + grab;
291 m_xdgShellSurface->setTitle(title);
297 const bool surfaceWasLocked = m_pointerLock && m_hasPointerLock;
298 m_pointerLock.reset();
299 m_hasPointerLock =
false;
300 if (surfaceWasLocked) {
308 Q_ASSERT(!m_pointerLock);
310 if (!m_pointerLock->isValid()) {
311 m_pointerLock.reset();
314 connect(m_pointerLock.get(), &LockedPointer::locked,
this, [
this]() {
315 m_hasPointerLock = true;
318 Q_EMIT m_backend->pointerLockChanged(true);
320 connect(m_pointerLock.get(), &LockedPointer::unlocked,
this, [
this]() {
321 m_pointerLock.reset();
322 m_hasPointerLock = false;
325 Q_EMIT m_backend->pointerLockChanged(false);
332#include "moc_wayland_output.cpp"
static Compositor * self()
void setInformation(const Information &information)
void setState(const State &state)
static std::chrono::milliseconds dimAnimationTime()
void aboutToTurnOff(std::chrono::milliseconds time)
DpmsMode dpmsMode() const
Class encapsulating all Wayland data structures needed by the Egl backend.
WaylandDisplay * display() const
void pointerLockChanged(bool locked)
KWayland::Client::Pointer * pointer() const
WaylandCursor(WaylandBackend *backend)
void update(wl_buffer *buffer, qreal scale, const QPoint &hotspot)
void setEnabled(bool enable)
void setPointer(KWayland::Client::Pointer *pointer)
KWayland::Client::PointerConstraints * pointerConstraints() const
KWayland::Client::XdgDecorationManager * xdgDecorationManager() const
void lockPointer(KWayland::Client::Pointer *pointer, bool lock)
void init(const QSize &pixelSize, qreal scale)
WaylandCursor * cursor() const
void resize(const QSize &pixelSize)
void framePending(const std::shared_ptr< OutputFrame > &frame)
WaylandBackend * backend() const
void updateDpmsMode(DpmsMode dpmsMode)
void setDpmsMode(DpmsMode mode) override
void updateEnabled(bool enabled)
~WaylandOutput() override
bool updateCursorLayer() override
WaylandOutput(const QString &name, WaylandBackend *backend)
RenderLoop * renderLoop() const override
KWayland::Client::Surface * surface() const
std::shared_ptr< OutputMode > currentMode
QList< std::shared_ptr< OutputMode > > modes