File indexing completed on 2024-12-01 05:02:04
0001 /* 0002 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 #include "KWayland/Client/compositor.h" 0007 #include "KWayland/Client/connection_thread.h" 0008 #include "KWayland/Client/event_queue.h" 0009 #include "KWayland/Client/pointer.h" 0010 #include "KWayland/Client/registry.h" 0011 #include "KWayland/Client/seat.h" 0012 #include "KWayland/Client/shadow.h" 0013 #include "KWayland/Client/shell.h" 0014 #include "KWayland/Client/shm_pool.h" 0015 #include "KWayland/Client/surface.h" 0016 #include "KWayland/Client/xdgshell.h" 0017 // Qt 0018 #include <QGuiApplication> 0019 #include <QImage> 0020 #include <QPainter> 0021 #include <QThread> 0022 0023 using namespace KWayland::Client; 0024 0025 class XdgTest : public QObject 0026 { 0027 Q_OBJECT 0028 public: 0029 explicit XdgTest(QObject *parent = nullptr); 0030 virtual ~XdgTest(); 0031 0032 void init(); 0033 0034 private: 0035 void setupRegistry(Registry *registry); 0036 void createPopup(); 0037 void render(); 0038 void renderPopup(); 0039 QThread *m_connectionThread; 0040 ConnectionThread *m_connectionThreadObject; 0041 EventQueue *m_eventQueue = nullptr; 0042 Compositor *m_compositor = nullptr; 0043 ShmPool *m_shm = nullptr; 0044 Surface *m_surface = nullptr; 0045 XdgShell *m_xdgShell = nullptr; 0046 XdgShellSurface *m_xdgShellSurface = nullptr; 0047 Surface *m_popupSurface = nullptr; 0048 XdgShellPopup *m_xdgShellPopup = nullptr; 0049 }; 0050 0051 XdgTest::XdgTest(QObject *parent) 0052 : QObject(parent) 0053 , m_connectionThread(new QThread(this)) 0054 , m_connectionThreadObject(new ConnectionThread()) 0055 { 0056 } 0057 0058 XdgTest::~XdgTest() 0059 { 0060 m_connectionThread->quit(); 0061 m_connectionThread->wait(); 0062 m_connectionThreadObject->deleteLater(); 0063 } 0064 0065 void XdgTest::init() 0066 { 0067 connect( 0068 m_connectionThreadObject, 0069 &ConnectionThread::connected, 0070 this, 0071 [this] { 0072 m_eventQueue = new EventQueue(this); 0073 m_eventQueue->setup(m_connectionThreadObject); 0074 0075 Registry *registry = new Registry(this); 0076 setupRegistry(registry); 0077 }, 0078 Qt::QueuedConnection); 0079 m_connectionThreadObject->moveToThread(m_connectionThread); 0080 m_connectionThread->start(); 0081 0082 m_connectionThreadObject->initConnection(); 0083 } 0084 0085 void XdgTest::setupRegistry(Registry *registry) 0086 { 0087 connect(registry, &Registry::compositorAnnounced, this, [this, registry](quint32 name, quint32 version) { 0088 m_compositor = registry->createCompositor(name, version, this); 0089 }); 0090 connect(registry, &Registry::shmAnnounced, this, [this, registry](quint32 name, quint32 version) { 0091 m_shm = registry->createShmPool(name, version, this); 0092 }); 0093 connect(registry, &Registry::xdgShellUnstableV6Announced, this, [this, registry](quint32 name, quint32 version) { 0094 m_xdgShell = registry->createXdgShell(name, version, this); 0095 m_xdgShell->setEventQueue(m_eventQueue); 0096 }); 0097 connect(registry, &Registry::interfacesAnnounced, this, [this] { 0098 Q_ASSERT(m_compositor); 0099 Q_ASSERT(m_xdgShell); 0100 Q_ASSERT(m_shm); 0101 m_surface = m_compositor->createSurface(this); 0102 Q_ASSERT(m_surface); 0103 m_xdgShellSurface = m_xdgShell->createSurface(m_surface, this); 0104 Q_ASSERT(m_xdgShellSurface); 0105 connect(m_xdgShellSurface, 0106 &XdgShellSurface::configureRequested, 0107 this, 0108 [this](const QSize &size, KWayland::Client::XdgShellSurface::States states, int serial) { 0109 m_xdgShellSurface->ackConfigure(serial); 0110 render(); 0111 }); 0112 0113 m_xdgShellSurface->setTitle(QStringLiteral("Test Window")); 0114 0115 m_surface->commit(); 0116 }); 0117 connect(registry, &Registry::seatAnnounced, this, [this, registry](quint32 name) { 0118 Seat *s = registry->createSeat(name, 2, this); 0119 connect(s, &Seat::hasPointerChanged, this, [this, s](bool has) { 0120 if (!has) { 0121 return; 0122 } 0123 Pointer *p = s->createPointer(this); 0124 connect(p, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState state) { 0125 if (state == Pointer::ButtonState::Released) { 0126 if (m_popupSurface) { 0127 m_popupSurface->deleteLater(); 0128 m_popupSurface = nullptr; 0129 } else { 0130 createPopup(); 0131 } 0132 } 0133 }); 0134 }); 0135 }); 0136 0137 registry->setEventQueue(m_eventQueue); 0138 registry->create(m_connectionThreadObject); 0139 registry->setup(); 0140 } 0141 0142 void XdgTest::createPopup() 0143 { 0144 if (m_popupSurface) { 0145 m_popupSurface->deleteLater(); 0146 } 0147 0148 m_popupSurface = m_compositor->createSurface(this); 0149 0150 XdgPositioner positioner(QSize(200, 200), QRect(50, 50, 400, 400)); 0151 positioner.setAnchorEdge(Qt::BottomEdge | Qt::RightEdge); 0152 positioner.setGravity(Qt::BottomEdge); 0153 positioner.setConstraints(XdgPositioner::Constraint::FlipX | XdgPositioner::Constraint::SlideY); 0154 m_xdgShellPopup = m_xdgShell->createPopup(m_popupSurface, m_xdgShellSurface, positioner, m_popupSurface); 0155 renderPopup(); 0156 } 0157 0158 void XdgTest::render() 0159 { 0160 const QSize &size = m_xdgShellSurface->size().isValid() ? m_xdgShellSurface->size() : QSize(500, 500); 0161 auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef(); 0162 buffer->setUsed(true); 0163 QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); 0164 image.fill(QColor(255, 255, 255, 255)); 0165 // draw a red rectangle indicating the anchor of the top level 0166 QPainter painter(&image); 0167 painter.setBrush(Qt::red); 0168 painter.setPen(Qt::black); 0169 painter.drawRect(50, 50, 400, 400); 0170 0171 m_surface->attachBuffer(*buffer); 0172 m_surface->damage(QRect(QPoint(0, 0), size)); 0173 m_surface->commit(Surface::CommitFlag::None); 0174 buffer->setUsed(false); 0175 } 0176 0177 void XdgTest::renderPopup() 0178 { 0179 QSize size(200, 200); 0180 auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef(); 0181 buffer->setUsed(true); 0182 QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); 0183 image.fill(QColor(0, 0, 255, 255)); 0184 0185 m_popupSurface->attachBuffer(*buffer); 0186 m_popupSurface->damage(QRect(QPoint(0, 0), size)); 0187 m_popupSurface->commit(Surface::CommitFlag::None); 0188 buffer->setUsed(false); 0189 } 0190 0191 int main(int argc, char **argv) 0192 { 0193 QCoreApplication app(argc, argv); 0194 XdgTest client; 0195 client.init(); 0196 0197 return app.exec(); 0198 } 0199 0200 #include "xdgtest.moc"