File indexing completed on 2024-12-01 05:02:03

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/datadevice.h"
0009 #include "KWayland/Client/datadevicemanager.h"
0010 #include "KWayland/Client/dataoffer.h"
0011 #include "KWayland/Client/event_queue.h"
0012 #include "KWayland/Client/keyboard.h"
0013 #include "KWayland/Client/plasmashell.h"
0014 #include "KWayland/Client/plasmawindowmanagement.h"
0015 #include "KWayland/Client/pointer.h"
0016 #include "KWayland/Client/registry.h"
0017 #include "KWayland/Client/seat.h"
0018 #include "KWayland/Client/shell.h"
0019 #include "KWayland/Client/shm_pool.h"
0020 #include "KWayland/Client/surface.h"
0021 // Qt
0022 #include <QDebug>
0023 #include <QFile>
0024 #include <QGuiApplication>
0025 #include <QImage>
0026 #include <QMimeType>
0027 #include <QThread>
0028 // system
0029 #include <unistd.h>
0030 
0031 #include <linux/input.h>
0032 
0033 using namespace KWayland::Client;
0034 
0035 class PanelTest : public QObject
0036 {
0037     Q_OBJECT
0038 public:
0039     explicit PanelTest(QObject *parent = nullptr);
0040     virtual ~PanelTest();
0041 
0042     void init();
0043 
0044 private:
0045     void setupRegistry(Registry *registry);
0046     void render();
0047     void showTooltip(const QPointF &pos);
0048     void hideTooltip();
0049     void moveTooltip(const QPointF &pos);
0050     QThread *m_connectionThread;
0051     ConnectionThread *m_connectionThreadObject;
0052     EventQueue *m_eventQueue = nullptr;
0053     Compositor *m_compositor = nullptr;
0054     Seat *m_seat = nullptr;
0055     Shell *m_shell = nullptr;
0056     ShellSurface *m_shellSurface = nullptr;
0057     ShmPool *m_shm = nullptr;
0058     Surface *m_surface = nullptr;
0059     PlasmaShell *m_plasmaShell = nullptr;
0060     PlasmaShellSurface *m_plasmaShellSurface = nullptr;
0061     PlasmaWindowManagement *m_windowManagement = nullptr;
0062     struct
0063     {
0064         Surface *surface = nullptr;
0065         ShellSurface *shellSurface = nullptr;
0066         PlasmaShellSurface *plasmaSurface = nullptr;
0067         bool visible = false;
0068     } m_tooltip;
0069 };
0070 
0071 PanelTest::PanelTest(QObject *parent)
0072     : QObject(parent)
0073     , m_connectionThread(new QThread(this))
0074     , m_connectionThreadObject(new ConnectionThread())
0075 {
0076 }
0077 
0078 PanelTest::~PanelTest()
0079 {
0080     m_connectionThread->quit();
0081     m_connectionThread->wait();
0082     m_connectionThreadObject->deleteLater();
0083 }
0084 
0085 void PanelTest::init()
0086 {
0087     connect(
0088         m_connectionThreadObject,
0089         &ConnectionThread::connected,
0090         this,
0091         [this] {
0092             m_eventQueue = new EventQueue(this);
0093             m_eventQueue->setup(m_connectionThreadObject);
0094 
0095             Registry *registry = new Registry(this);
0096             setupRegistry(registry);
0097         },
0098         Qt::QueuedConnection);
0099     m_connectionThreadObject->moveToThread(m_connectionThread);
0100     m_connectionThread->start();
0101 
0102     m_connectionThreadObject->initConnection();
0103 }
0104 
0105 void PanelTest::showTooltip(const QPointF &pos)
0106 {
0107     if (!m_tooltip.surface) {
0108         m_tooltip.surface = m_compositor->createSurface(this);
0109         m_tooltip.shellSurface = m_shell->createSurface(m_tooltip.surface, this);
0110         if (m_plasmaShell) {
0111             m_tooltip.plasmaSurface = m_plasmaShell->createSurface(m_tooltip.surface, this);
0112         }
0113     }
0114     m_tooltip.shellSurface->setTransient(m_surface, pos.toPoint());
0115 
0116     if (!m_tooltip.visible) {
0117         const QSize size(100, 50);
0118         auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef();
0119         buffer->setUsed(true);
0120         QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
0121         image.fill(Qt::red);
0122 
0123         m_tooltip.surface->attachBuffer(*buffer);
0124         m_tooltip.surface->damage(QRect(QPoint(0, 0), size));
0125         m_tooltip.surface->commit(Surface::CommitFlag::None);
0126         m_tooltip.visible = true;
0127     }
0128 }
0129 
0130 void PanelTest::hideTooltip()
0131 {
0132     if (!m_tooltip.visible) {
0133         return;
0134     }
0135     m_tooltip.surface->attachBuffer(Buffer::Ptr());
0136     m_tooltip.surface->commit(Surface::CommitFlag::None);
0137     m_tooltip.visible = false;
0138 }
0139 
0140 void PanelTest::moveTooltip(const QPointF &pos)
0141 {
0142     if (m_tooltip.plasmaSurface) {
0143         m_tooltip.plasmaSurface->setPosition(QPoint(10, 0) + pos.toPoint());
0144     }
0145 }
0146 
0147 void PanelTest::setupRegistry(Registry *registry)
0148 {
0149     connect(registry, &Registry::compositorAnnounced, this, [this, registry](quint32 name, quint32 version) {
0150         m_compositor = registry->createCompositor(name, version, this);
0151     });
0152     connect(registry, &Registry::shellAnnounced, this, [this, registry](quint32 name, quint32 version) {
0153         m_shell = registry->createShell(name, version, this);
0154     });
0155     connect(registry, &Registry::shmAnnounced, this, [this, registry](quint32 name, quint32 version) {
0156         m_shm = registry->createShmPool(name, version, this);
0157     });
0158     connect(registry, &Registry::seatAnnounced, this, [this, registry](quint32 name, quint32 version) {
0159         m_seat = registry->createSeat(name, version, this);
0160         connect(m_seat, &Seat::hasPointerChanged, this, [this](bool has) {
0161             if (!has) {
0162                 return;
0163             }
0164             auto p = m_seat->createPointer(this);
0165             connect(p, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, KWayland::Client::Pointer::ButtonState state) {
0166                 if (!m_windowManagement) {
0167                     return;
0168                 }
0169                 if (state == Pointer::ButtonState::Released) {
0170                     return;
0171                 }
0172                 if (button == BTN_LEFT) {
0173                     m_windowManagement->showDesktop();
0174                 } else if (button == BTN_RIGHT) {
0175                     m_windowManagement->hideDesktop();
0176                 }
0177             });
0178             connect(p, &Pointer::entered, this, [this, p](quint32 serial, const QPointF &relativeToSurface) {
0179                 if (p->enteredSurface() == m_surface) {
0180                     showTooltip(relativeToSurface);
0181                 }
0182             });
0183             connect(p, &Pointer::motion, this, [this, p](const QPointF &relativeToSurface) {
0184                 if (p->enteredSurface() == m_surface) {
0185                     moveTooltip(relativeToSurface);
0186                 }
0187             });
0188             connect(p, &Pointer::left, this, [this] {
0189                 hideTooltip();
0190             });
0191         });
0192     });
0193     connect(registry, &Registry::plasmaShellAnnounced, this, [this, registry](quint32 name, quint32 version) {
0194         m_plasmaShell = registry->createPlasmaShell(name, version, this);
0195     });
0196     connect(registry, &Registry::plasmaWindowManagementAnnounced, this, [this, registry](quint32 name, quint32 version) {
0197         m_windowManagement = registry->createPlasmaWindowManagement(name, version, this);
0198         connect(m_windowManagement, &PlasmaWindowManagement::showingDesktopChanged, this, [](bool set) {
0199             qDebug() << "Showing desktop changed, new state: " << set;
0200         });
0201         connect(m_windowManagement, &PlasmaWindowManagement::windowCreated, this, [this](PlasmaWindow *w) {
0202             connect(w, &PlasmaWindow::titleChanged, this, [w] {
0203                 qDebug() << "Window title changed to: " << w->title();
0204             });
0205             connect(w, &PlasmaWindow::activeChanged, this, [w] {
0206                 qDebug() << "Window active changed: " << w->isActive();
0207             });
0208             connect(w, &PlasmaWindow::maximizedChanged, this, [w] {
0209                 qDebug() << "Window maximized changed: " << w->isMaximized();
0210             });
0211             connect(w, &PlasmaWindow::maximizedChanged, this, [w] {
0212                 qDebug() << "Window minimized changed: " << w->isMinimized();
0213             });
0214             connect(w, &PlasmaWindow::keepAboveChanged, this, [w] {
0215                 qDebug() << "Window keep above changed: " << w->isKeepAbove();
0216             });
0217             connect(w, &PlasmaWindow::keepBelowChanged, this, [w] {
0218                 qDebug() << "Window keep below changed: " << w->isKeepBelow();
0219             });
0220             connect(w, &PlasmaWindow::onAllDesktopsChanged, this, [w] {
0221                 qDebug() << "Window on all desktops changed: " << w->isOnAllDesktops();
0222             });
0223             connect(w, &PlasmaWindow::fullscreenChanged, this, [w] {
0224                 qDebug() << "Window full screen changed: " << w->isFullscreen();
0225             });
0226             connect(w, &PlasmaWindow::demandsAttentionChanged, this, [w] {
0227                 qDebug() << "Window demands attention changed: " << w->isDemandingAttention();
0228             });
0229             connect(w, &PlasmaWindow::closeableChanged, this, [w] {
0230                 qDebug() << "Window is closeable changed: " << w->isCloseable();
0231             });
0232             connect(w, &PlasmaWindow::minimizeableChanged, this, [w] {
0233                 qDebug() << "Window is minimizeable changed: " << w->isMinimizeable();
0234             });
0235             connect(w, &PlasmaWindow::maximizeableChanged, this, [w] {
0236                 qDebug() << "Window is maximizeable changed: " << w->isMaximizeable();
0237             });
0238             connect(w, &PlasmaWindow::fullscreenableChanged, this, [w] {
0239                 qDebug() << "Window is fullscreenable changed: " << w->isFullscreenable();
0240             });
0241             connect(w, &PlasmaWindow::iconChanged, this, [w] {
0242                 qDebug() << "Window icon changed: " << w->icon().name();
0243             });
0244         });
0245     });
0246     connect(registry, &Registry::interfacesAnnounced, this, [this] {
0247         Q_ASSERT(m_compositor);
0248         Q_ASSERT(m_seat);
0249         Q_ASSERT(m_shell);
0250         Q_ASSERT(m_shm);
0251         m_surface = m_compositor->createSurface(this);
0252         Q_ASSERT(m_surface);
0253         m_shellSurface = m_shell->createSurface(m_surface, this);
0254         Q_ASSERT(m_shellSurface);
0255         m_shellSurface->setToplevel();
0256         connect(m_shellSurface, &ShellSurface::sizeChanged, this, &PanelTest::render);
0257         if (m_plasmaShell) {
0258             m_plasmaShellSurface = m_plasmaShell->createSurface(m_surface, this);
0259             m_plasmaShellSurface->setPosition(QPoint(10, 0));
0260             m_plasmaShellSurface->setRole(PlasmaShellSurface::Role::Panel);
0261         }
0262         render();
0263     });
0264     registry->setEventQueue(m_eventQueue);
0265     registry->create(m_connectionThreadObject);
0266     registry->setup();
0267 }
0268 
0269 void PanelTest::render()
0270 {
0271     const QSize &size = m_shellSurface->size().isValid() ? m_shellSurface->size() : QSize(300, 20);
0272     auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef();
0273     buffer->setUsed(true);
0274     QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
0275     image.fill(Qt::blue);
0276 
0277     m_surface->attachBuffer(*buffer);
0278     m_surface->damage(QRect(QPoint(0, 0), size));
0279     m_surface->commit(Surface::CommitFlag::None);
0280     buffer->setUsed(false);
0281 }
0282 
0283 int main(int argc, char **argv)
0284 {
0285     QGuiApplication app(argc, argv);
0286     PanelTest client;
0287     client.init();
0288 
0289     return app.exec();
0290 }
0291 
0292 #include "paneltest.moc"