diff --git a/src/client/compositor.cpp b/src/client/compositor.cpp index 293d403..aa70f49 100644 --- a/src/client/compositor.cpp +++ b/src/client/compositor.cpp @@ -1,150 +1,147 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "compositor.h" #include "event_queue.h" #include "region.h" #include "surface.h" #include "wayland_pointer_p.h" // Qt #include #include #include #include namespace KWayland { namespace Client { class Q_DECL_HIDDEN Compositor::Private { public: Private() = default; WaylandPointer compositor; EventQueue *queue = nullptr; }; Compositor::Compositor(QObject *parent) : QObject(parent) , d(new Private) { } Compositor::~Compositor() { release(); } Compositor *Compositor::fromApplication(QObject *parent) { - if (!QGuiApplication::platformName().contains(QStringLiteral("wayland"), Qt::CaseInsensitive)) { - return nullptr; - } QPlatformNativeInterface *native = qApp->platformNativeInterface(); if (!native) { return nullptr; } wl_compositor *compositor = reinterpret_cast(native->nativeResourceForIntegration(QByteArrayLiteral("compositor"))); if (!compositor) { return nullptr; } Compositor *c = new Compositor(parent); c->d->compositor.setup(compositor, true); return c; } void Compositor::setup(wl_compositor *compositor) { Q_ASSERT(compositor); Q_ASSERT(!d->compositor); d->compositor.setup(compositor); } void Compositor::release() { d->compositor.release(); } void Compositor::destroy() { d->compositor.destroy(); } void Compositor::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *Compositor::eventQueue() { return d->queue; } Surface *Compositor::createSurface(QObject *parent) { Q_ASSERT(isValid()); Surface *s = new Surface(parent); auto w = wl_compositor_create_surface(d->compositor); if (d->queue) { d->queue->addProxy(w); } s->setup(w); return s; } Region *Compositor::createRegion(QObject *parent) { return createRegion(QRegion(), parent); } Region *Compositor::createRegion(const QRegion ®ion, QObject *parent) { Q_ASSERT(isValid()); Region *r = new Region(region, parent); auto w = wl_compositor_create_region(d->compositor); if (d->queue) { d->queue->addProxy(w); } r->setup(w); return r; } std::unique_ptr< Region > Compositor::createRegion(const QRegion ®ion) { return std::unique_ptr(createRegion(region, nullptr)); } Compositor::operator wl_compositor*() { return d->compositor; } Compositor::operator wl_compositor*() const { return d->compositor; } bool Compositor::isValid() const { return d->compositor.isValid(); } } } diff --git a/src/client/connection_thread.cpp b/src/client/connection_thread.cpp index d6fa5ac..7d90571 100644 --- a/src/client/connection_thread.cpp +++ b/src/client/connection_thread.cpp @@ -1,312 +1,309 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "connection_thread.h" #include "logging_p.h" // Qt #include #include #include #include #include #include #include #include #include // Wayland #include namespace KWayland { namespace Client { class Q_DECL_HIDDEN ConnectionThread::Private { public: Private(ConnectionThread *q); ~Private(); void doInitConnection(); void setupSocketNotifier(); void setupSocketFileWatcher(); wl_display *display = nullptr; int fd = -1; QString socketName; QDir runtimeDir; QScopedPointer socketNotifier; QScopedPointer socketWatcher; bool serverDied = false; bool foreign = false; QMetaObject::Connection eventDispatcherConnection; int error = 0; static QVector connections; static QMutex mutex; private: ConnectionThread *q; }; QVector ConnectionThread::Private::connections = QVector{}; QMutex ConnectionThread::Private::mutex{QMutex::Recursive}; ConnectionThread::Private::Private(ConnectionThread *q) : socketName(QString::fromUtf8(qgetenv("WAYLAND_DISPLAY"))) , runtimeDir(QString::fromUtf8(qgetenv("XDG_RUNTIME_DIR"))) , q(q) { if (socketName.isEmpty()) { socketName = QStringLiteral("wayland-0"); } { QMutexLocker lock(&mutex); connections << q; } } ConnectionThread::Private::~Private() { { QMutexLocker lock(&mutex); connections.removeOne(q); } if (display && !foreign) { wl_display_flush(display); wl_display_disconnect(display); } } void ConnectionThread::Private::doInitConnection() { if (fd != -1) { display = wl_display_connect_to_fd(fd); } else { display = wl_display_connect(socketName.toUtf8().constData()); } if (!display) { qCWarning(KWAYLAND_CLIENT) << "Failed connecting to Wayland display"; emit q->failed(); return; } if (fd != -1) { qCDebug(KWAYLAND_CLIENT) << "Connected to Wayland server over file descriptor:" << fd; } else { qCDebug(KWAYLAND_CLIENT) << "Connected to Wayland server at:" << socketName; } // setup socket notifier setupSocketNotifier(); setupSocketFileWatcher(); emit q->connected(); } void ConnectionThread::Private::setupSocketNotifier() { const int fd = wl_display_get_fd(display); socketNotifier.reset(new QSocketNotifier(fd, QSocketNotifier::Read)); QObject::connect(socketNotifier.data(), &QSocketNotifier::activated, q, [this]() { if (!display) { return; } if (wl_display_dispatch(display) == -1) { error = wl_display_get_error(display); if (error != 0) { if (display) { free(display); display = nullptr; } emit q->errorOccurred(); return; } } emit q->eventsRead(); } ); } void ConnectionThread::Private::setupSocketFileWatcher() { if (!runtimeDir.exists() || fd != -1) { return; } socketWatcher.reset(new QFileSystemWatcher); socketWatcher->addPath(runtimeDir.absoluteFilePath(socketName)); QObject::connect(socketWatcher.data(), &QFileSystemWatcher::fileChanged, q, [this] (const QString &file) { if (QFile::exists(file) || serverDied) { return; } qCWarning(KWAYLAND_CLIENT) << "Connection to server went away"; serverDied = true; if (display) { free(display); display = nullptr; } socketNotifier.reset(); // need a new filesystem watcher socketWatcher.reset(new QFileSystemWatcher); socketWatcher->addPath(runtimeDir.absolutePath()); QObject::connect(socketWatcher.data(), &QFileSystemWatcher::directoryChanged, q, [this]() { if (!serverDied) { return; } if (runtimeDir.exists(socketName)) { qCDebug(KWAYLAND_CLIENT) << "Socket reappeared"; socketWatcher.reset(); serverDied = false; error = 0; q->initConnection(); } } ); emit q->connectionDied(); } ); } ConnectionThread::ConnectionThread(QObject *parent) : QObject(parent) , d(new Private(this)) { d->eventDispatcherConnection = connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, [this] { if (d->display) { wl_display_flush(d->display); } }, Qt::DirectConnection); } ConnectionThread::ConnectionThread(wl_display *display, QObject *parent) : QObject(parent) , d(new Private(this)) { d->display = display; d->foreign = true; } ConnectionThread::~ConnectionThread() { disconnect(d->eventDispatcherConnection); } ConnectionThread *ConnectionThread::fromApplication(QObject *parent) { - if (!QGuiApplication::platformName().contains(QStringLiteral("wayland"), Qt::CaseInsensitive)) { - return nullptr; - } QPlatformNativeInterface *native = qApp->platformNativeInterface(); if (!native) { return nullptr; } wl_display *display = reinterpret_cast(native->nativeResourceForIntegration(QByteArrayLiteral("wl_display"))); if (!display) { return nullptr; } ConnectionThread *ct = new ConnectionThread(display, parent); connect(native, &QObject::destroyed, ct, &ConnectionThread::connectionDied); return ct; } void ConnectionThread::initConnection() { QMetaObject::invokeMethod(this, "doInitConnection", Qt::QueuedConnection); } void ConnectionThread::doInitConnection() { d->doInitConnection(); } void ConnectionThread::setSocketName(const QString &socketName) { if (d->display) { // already initialized return; } d->socketName = socketName; } void ConnectionThread::setSocketFd(int fd) { if (d->display) { // already initialized return; } d->fd = fd; } wl_display *ConnectionThread::display() { return d->display; } QString ConnectionThread::socketName() const { return d->socketName; } void ConnectionThread::flush() { if (!d->display) { return; } wl_display_flush(d->display); } void ConnectionThread::roundtrip() { if (!d->display) { return; } if (d->foreign) { // try to perform roundtrip through the QPA plugin if it's supported if (QPlatformNativeInterface *native = qApp->platformNativeInterface()) { // in case the platform provides a dedicated roundtrip function use that install of wl_display_roundtrip QFunctionPointer roundtripFunction = native->platformFunction(QByteArrayLiteral("roundtrip")); if (roundtripFunction) { roundtripFunction(); return; } } } wl_display_roundtrip(d->display); } bool ConnectionThread::hasError() const { return d->error != 0; } int ConnectionThread::errorCode() const { return d->error; } QVector ConnectionThread::connections() { return Private::connections; } } } diff --git a/src/client/shell.cpp b/src/client/shell.cpp index 4db9d72..2abdc7d 100644 --- a/src/client/shell.cpp +++ b/src/client/shell.cpp @@ -1,390 +1,387 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "shell.h" #include "event_queue.h" #include "output.h" #include "seat.h" #include "surface.h" #include "wayland_pointer_p.h" // Qt #include #include #include #include // Wayland #include namespace KWayland { namespace Client { class Q_DECL_HIDDEN Shell::Private { public: WaylandPointer shell; EventQueue *queue = nullptr; }; Shell::Shell(QObject *parent) : QObject(parent) , d(new Private) { } Shell::~Shell() { release(); } void Shell::destroy() { if (!d->shell) { return; } emit interfaceAboutToBeDestroyed(); d->shell.destroy(); } void Shell::release() { if (!d->shell) { return; } emit interfaceAboutToBeReleased(); d->shell.release(); } void Shell::setup(wl_shell *shell) { Q_ASSERT(!d->shell); Q_ASSERT(shell); d->shell.setup(shell); } void Shell::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *Shell::eventQueue() { return d->queue; } ShellSurface *Shell::createSurface(wl_surface *surface, QObject *parent) { Q_ASSERT(isValid()); ShellSurface *s = new ShellSurface(parent); connect(this, &Shell::interfaceAboutToBeReleased, s, &ShellSurface::release); connect(this, &Shell::interfaceAboutToBeDestroyed, s, &ShellSurface::destroy); auto w = wl_shell_get_shell_surface(d->shell, surface); if (d->queue) { d->queue->addProxy(w); } s->setup(w); return s; } ShellSurface *Shell::createSurface(Surface *surface, QObject *parent) { Q_ASSERT(surface); return createSurface(*surface, parent); } bool Shell::isValid() const { return d->shell.isValid(); } Shell::operator wl_shell*() { return d->shell; } Shell::operator wl_shell*() const { return d->shell; } class Q_DECL_HIDDEN ShellSurface::Private { public: Private(ShellSurface *q); void setup(wl_shell_surface *surface); WaylandPointer surface; QSize size; static QVector s_surfaces; private: void ping(uint32_t serial); static void pingCallback(void *data, struct wl_shell_surface *shellSurface, uint32_t serial); static void configureCallback(void *data, struct wl_shell_surface *shellSurface, uint32_t edges, int32_t width, int32_t height); static void popupDoneCallback(void *data, struct wl_shell_surface *shellSurface); ShellSurface *q; static const struct wl_shell_surface_listener s_listener; }; QVector ShellSurface::Private::s_surfaces = QVector(); ShellSurface::Private::Private(ShellSurface *q) : q(q) { } void ShellSurface::Private::setup(wl_shell_surface *s) { Q_ASSERT(s); Q_ASSERT(!surface); surface.setup(s); wl_shell_surface_add_listener(surface, &s_listener, this); } ShellSurface *ShellSurface::fromWindow(QWindow *window) { if (!window) { return nullptr; } - if (!QGuiApplication::platformName().contains(QStringLiteral("wayland"), Qt::CaseInsensitive)) { - return nullptr; - } QPlatformNativeInterface *native = qApp->platformNativeInterface(); if (!native) { return nullptr; } window->create(); wl_shell_surface *s = reinterpret_cast(native->nativeResourceForWindow(QByteArrayLiteral("wl_shell_surface"), window)); if (!s) { return nullptr; } if (auto surface = get(s)) { return surface; } ShellSurface *surface = new ShellSurface(window); surface->d->surface.setup(s, true); return surface; } ShellSurface *ShellSurface::fromQtWinId(WId wid) { QWindow *window = nullptr; for (auto win : qApp->allWindows()) { if (win->winId() == wid) { window = win; break; } } if (!window) { return nullptr; } return fromWindow(window); } ShellSurface *ShellSurface::get(wl_shell_surface *native) { auto it = std::find_if(Private::s_surfaces.constBegin(), Private::s_surfaces.constEnd(), [native](ShellSurface *s) { return s->d->surface == native; } ); if (it != Private::s_surfaces.constEnd()) { return *(it); } return nullptr; } ShellSurface::ShellSurface(QObject *parent) : QObject(parent) , d(new Private(this)) { Private::s_surfaces << this; } ShellSurface::~ShellSurface() { Private::s_surfaces.removeOne(this); release(); } void ShellSurface::release() { d->surface.release(); } void ShellSurface::destroy() { d->surface.destroy(); } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_shell_surface_listener ShellSurface::Private::s_listener = { pingCallback, configureCallback, popupDoneCallback }; #endif void ShellSurface::Private::configureCallback(void *data, wl_shell_surface *shellSurface, uint32_t edges, int32_t width, int32_t height) { Q_UNUSED(edges) auto s = reinterpret_cast(data); Q_ASSERT(s->surface == shellSurface); s->q->setSize(QSize(width, height)); } void ShellSurface::Private::pingCallback(void *data, wl_shell_surface *shellSurface, uint32_t serial) { auto s = reinterpret_cast(data); Q_ASSERT(s->surface == shellSurface); s->ping(serial); } void ShellSurface::Private::popupDoneCallback(void *data, wl_shell_surface *shellSurface) { auto s = reinterpret_cast(data); Q_ASSERT(s->surface == shellSurface); emit s->q->popupDone(); } void ShellSurface::setup(wl_shell_surface *surface) { d->setup(surface); } void ShellSurface::Private::ping(uint32_t serial) { wl_shell_surface_pong(surface, serial); emit q->pinged(); } void ShellSurface::setSize(const QSize &size) { if (d->size == size) { return; } d->size = size; emit sizeChanged(size); } void ShellSurface::setFullscreen(Output *output) { Q_ASSERT(isValid()); wl_shell_surface_set_fullscreen(d->surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, output ? output->output() : nullptr); } void ShellSurface::setMaximized(Output *output) { Q_ASSERT(isValid()); wl_shell_surface_set_maximized(d->surface, output ? output->output() : nullptr); } void ShellSurface::setToplevel() { Q_ASSERT(isValid()); wl_shell_surface_set_toplevel(d->surface); } void ShellSurface::setTransient(Surface *parent, const QPoint &offset, TransientFlags flags) { Q_ASSERT(isValid()); uint32_t wlFlags = 0; if (flags.testFlag(TransientFlag::NoFocus)) { wlFlags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE; } wl_shell_surface_set_transient(d->surface, *parent, offset.x(), offset.y(), wlFlags); } void ShellSurface::setTransientPopup(Surface *parent, Seat *grabbedSeat, quint32 grabSerial, const QPoint &offset, TransientFlags flags) { Q_ASSERT(isValid()); Q_ASSERT(parent); Q_ASSERT(grabbedSeat); uint32_t wlFlags = 0; if (flags.testFlag(TransientFlag::NoFocus)) { wlFlags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE; } wl_shell_surface_set_popup(d->surface, *grabbedSeat, grabSerial, *parent, offset.x(), offset.y(), wlFlags); } void ShellSurface::requestMove(Seat *seat, quint32 serial) { Q_ASSERT(isValid()); Q_ASSERT(seat); wl_shell_surface_move(d->surface, *seat, serial); } void ShellSurface::requestResize(Seat *seat, quint32 serial, Qt::Edges edges) { Q_ASSERT(isValid()); Q_ASSERT(seat); uint wlEdge = WL_SHELL_SURFACE_RESIZE_NONE; if (edges.testFlag(Qt::TopEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) { wlEdge = WL_SHELL_SURFACE_RESIZE_TOP_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) { wlEdge = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; } else if ((edges & ~Qt::TopEdge) == Qt::Edges()) { wlEdge = WL_SHELL_SURFACE_RESIZE_TOP; } } else if (edges.testFlag(Qt::BottomEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) { wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) { wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; } else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) { wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM; } } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) { wlEdge = WL_SHELL_SURFACE_RESIZE_RIGHT; } else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) { wlEdge = WL_SHELL_SURFACE_RESIZE_LEFT; } wl_shell_surface_resize(d->surface, *seat, serial, wlEdge); } QSize ShellSurface::size() const { return d->size; } bool ShellSurface::isValid() const { return d->surface.isValid(); } ShellSurface::operator wl_shell_surface*() { return d->surface; } ShellSurface::operator wl_shell_surface*() const { return d->surface; } } } diff --git a/src/client/surface.cpp b/src/client/surface.cpp index e8a1917..065f81c 100644 --- a/src/client/surface.cpp +++ b/src/client/surface.cpp @@ -1,351 +1,348 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "surface.h" #include "buffer.h" #include "region.h" #include "output.h" #include "wayland_pointer_p.h" #include #include #include #include #include // Wayland #include namespace KWayland { namespace Client { class Q_DECL_HIDDEN Surface::Private { public: Private(Surface *q); void setupFrameCallback(); WaylandPointer surface; bool frameCallbackInstalled = false; QSize size; bool foreign = false; qint32 scale = 1; QVector outputs; void setup(wl_surface *s); static QList s_surfaces; private: void handleFrameCallback(); static void frameCallback(void *data, wl_callback *callback, uint32_t time); static void enterCallback(void *data, wl_surface *wl_surface, wl_output *output); static void leaveCallback(void *data, wl_surface *wl_surface, wl_output *output); Surface *q; static const wl_callback_listener s_listener; static const wl_surface_listener s_surfaceListener; }; QList Surface::Private::s_surfaces = QList(); Surface::Private::Private(Surface *q) : q(q) { } Surface::Surface(QObject *parent) : QObject(parent) , d(new Private(this)) { Private::s_surfaces << this; } Surface::~Surface() { Private::s_surfaces.removeAll(this); release(); } Surface *Surface::fromWindow(QWindow *window) { if (!window) { return nullptr; } - if (!QGuiApplication::platformName().contains(QStringLiteral("wayland"), Qt::CaseInsensitive)) { - return nullptr; - } QPlatformNativeInterface *native = qApp->platformNativeInterface(); if (!native) { return nullptr; } window->create(); wl_surface *s = reinterpret_cast(native->nativeResourceForWindow(QByteArrayLiteral("surface"), window)); if (!s) { return nullptr; } if (auto surface = get(s)) { return surface; } Surface *surface = new Surface(window); surface->d->surface.setup(s, true); return surface; } Surface *Surface::fromQtWinId(WId wid) { QWindow *window = nullptr; for (auto win : qApp->allWindows()) { if (win->winId() == wid) { window = win; break; } } if (!window) { return nullptr; } return fromWindow(window); } void Surface::release() { d->surface.release(); } void Surface::destroy() { d->surface.destroy(); } void Surface::setup(wl_surface *surface) { d->setup(surface); } void Surface::Private::setup(wl_surface *s) { Q_ASSERT(s); Q_ASSERT(!surface); surface.setup(s); wl_surface_add_listener(s, &s_surfaceListener, this); } void Surface::Private::frameCallback(void *data, wl_callback *callback, uint32_t time) { Q_UNUSED(time) auto s = reinterpret_cast(data); if (callback) { wl_callback_destroy(callback); } s->handleFrameCallback(); } void Surface::Private::handleFrameCallback() { frameCallbackInstalled = false; emit q->frameRendered(); } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_callback_listener Surface::Private::s_listener = { frameCallback }; const struct wl_surface_listener Surface::Private::s_surfaceListener = { enterCallback, leaveCallback }; #endif void Surface::Private::enterCallback(void *data, wl_surface *surface, wl_output *output) { Q_UNUSED(surface); auto s = reinterpret_cast(data); Output *o = Output::get(output); if (!o) { return; } s->outputs << o; QObject::connect(o, &Output::removed, s->q, [s, o]() { if (!s->outputs.contains(o)) { return; } s->outputs.removeOne(o); s->q->outputLeft(o); }); emit s->q->outputEntered(o); } void Surface::Private::leaveCallback(void *data, wl_surface *surface, wl_output *output) { Q_UNUSED(surface); auto s = reinterpret_cast(data); Output *o = Output::get(output); if (!o) { return; } s->outputs.removeOne(o); emit s->q->outputLeft(o); } void Surface::Private::setupFrameCallback() { Q_ASSERT(!frameCallbackInstalled); wl_callback *callback = wl_surface_frame(surface); wl_callback_add_listener(callback, &s_listener, this); frameCallbackInstalled = true; } void Surface::setupFrameCallback() { Q_ASSERT(isValid()); d->setupFrameCallback(); } void Surface::commit(Surface::CommitFlag flag) { Q_ASSERT(isValid()); if (flag == CommitFlag::FrameCallback) { setupFrameCallback(); } wl_surface_commit(d->surface); } void Surface::damage(const QRegion ®ion) { for (const QRect &r : region.rects()) { damage(r); } } void Surface::damage(const QRect &rect) { Q_ASSERT(isValid()); wl_surface_damage(d->surface, rect.x(), rect.y(), rect.width(), rect.height()); } void Surface::attachBuffer(wl_buffer *buffer, const QPoint &offset) { Q_ASSERT(isValid()); wl_surface_attach(d->surface, buffer, offset.x(), offset.y()); } void Surface::attachBuffer(Buffer *buffer, const QPoint &offset) { attachBuffer(buffer ? buffer->buffer() : nullptr, offset); } void Surface::attachBuffer(Buffer::Ptr buffer, const QPoint &offset) { attachBuffer(buffer.toStrongRef().data(), offset); } void Surface::setInputRegion(const Region *region) { Q_ASSERT(isValid()); if (region) { wl_surface_set_input_region(d->surface, *region); } else { wl_surface_set_input_region(d->surface, nullptr); } } void Surface::setOpaqueRegion(const Region *region) { Q_ASSERT(isValid()); if (region) { wl_surface_set_opaque_region(d->surface, *region); } else { wl_surface_set_opaque_region(d->surface, nullptr); } } void Surface::setSize(const QSize &size) { if (d->size == size) { return; } d->size = size; emit sizeChanged(d->size); } Surface *Surface::get(wl_surface *native) { auto it = std::find_if(Private::s_surfaces.constBegin(), Private::s_surfaces.constEnd(), [native](Surface *s) { return s->d->surface == native; } ); if (it != Private::s_surfaces.constEnd()) { return *(it); } return nullptr; } const QList< Surface* > &Surface::all() { return Private::s_surfaces; } bool Surface::isValid() const { return d->surface.isValid(); } QSize Surface::size() const { return d->size; } Surface::operator wl_surface*() { return d->surface; } Surface::operator wl_surface*() const { return d->surface; } quint32 Surface::id() const { wl_surface *s = *this; return wl_proxy_get_id(reinterpret_cast(s)); } qint32 Surface::scale() const { return d->scale; } void Surface::setScale(qint32 scale) { d->scale = scale; wl_surface_set_buffer_scale(d->surface, scale); } QVector Surface::outputs() const { return d->outputs; } } }