File indexing completed on 2024-05-19 05:30:35
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 "../src/client/compositor.h" 0007 #include "../src/client/connection_thread.h" 0008 #include "../src/client/event_queue.h" 0009 #include "../src/client/pointer.h" 0010 #include "../src/client/registry.h" 0011 #include "../src/client/seat.h" 0012 #include "../src/client/shadow.h" 0013 #include "../src/client/shell.h" 0014 #include "../src/client/shm_pool.h" 0015 #include "../src/client/surface.h" 0016 #include "../src/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 ~XdgTest() override; 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::xdgShellStableAnnounced, 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 Q_UNUSED(size); 0110 Q_UNUSED(states); 0111 m_xdgShellSurface->ackConfigure(serial); 0112 render(); 0113 }); 0114 0115 m_xdgShellSurface->setTitle(QStringLiteral("Test Window")); 0116 0117 m_surface->commit(); 0118 }); 0119 connect(registry, &Registry::seatAnnounced, this, [this, registry](quint32 name) { 0120 Seat *s = registry->createSeat(name, 2, this); 0121 connect(s, &Seat::hasPointerChanged, this, [this, s](bool has) { 0122 if (!has) { 0123 return; 0124 } 0125 Pointer *p = s->createPointer(this); 0126 connect(p, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState state) { 0127 Q_UNUSED(button) 0128 Q_UNUSED(serial) 0129 Q_UNUSED(time) 0130 if (state == Pointer::ButtonState::Released) { 0131 if (m_popupSurface) { 0132 m_popupSurface->deleteLater(); 0133 m_popupSurface = nullptr; 0134 } else { 0135 createPopup(); 0136 } 0137 } 0138 }); 0139 }); 0140 }); 0141 0142 registry->setEventQueue(m_eventQueue); 0143 registry->create(m_connectionThreadObject); 0144 registry->setup(); 0145 } 0146 0147 void XdgTest::createPopup() 0148 { 0149 if (m_popupSurface) { 0150 m_popupSurface->deleteLater(); 0151 } 0152 0153 m_popupSurface = m_compositor->createSurface(this); 0154 0155 XdgPositioner positioner(QSize(200, 200), QRect(50, 50, 400, 400)); 0156 positioner.setAnchorEdge(Qt::BottomEdge | Qt::RightEdge); 0157 positioner.setGravity(Qt::BottomEdge); 0158 positioner.setConstraints(XdgPositioner::Constraint::FlipX | XdgPositioner::Constraint::SlideY); 0159 m_xdgShellPopup = m_xdgShell->createPopup(m_popupSurface, m_xdgShellSurface, positioner, m_popupSurface); 0160 renderPopup(); 0161 } 0162 0163 void XdgTest::render() 0164 { 0165 const QSize &size = m_xdgShellSurface->size().isValid() ? m_xdgShellSurface->size() : QSize(500, 500); 0166 auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef(); 0167 buffer->setUsed(true); 0168 QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); 0169 image.fill(QColor(255, 255, 255, 255)); 0170 // draw a red rectangle indicating the anchor of the top level 0171 QPainter painter(&image); 0172 painter.setBrush(Qt::red); 0173 painter.setPen(Qt::black); 0174 painter.drawRect(50, 50, 400, 400); 0175 0176 m_surface->attachBuffer(*buffer); 0177 m_surface->damage(QRect(QPoint(0, 0), size)); 0178 m_surface->commit(Surface::CommitFlag::None); 0179 buffer->setUsed(false); 0180 } 0181 0182 void XdgTest::renderPopup() 0183 { 0184 QSize size(200, 200); 0185 auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef(); 0186 buffer->setUsed(true); 0187 QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); 0188 image.fill(QColor(0, 0, 255, 255)); 0189 0190 m_popupSurface->attachBuffer(*buffer); 0191 m_popupSurface->damage(QRect(QPoint(0, 0), size)); 0192 m_popupSurface->commit(Surface::CommitFlag::None); 0193 buffer->setUsed(false); 0194 } 0195 0196 int main(int argc, char **argv) 0197 { 0198 QCoreApplication app(argc, argv); 0199 XdgTest client; 0200 client.init(); 0201 0202 return app.exec(); 0203 } 0204 0205 #include "xdgtest.moc"