Client test for xdg-shell v6 configure events

Task-number: QTBUG-66689
Change-Id: Ifdf38a9ab73357fdbe61e77f0464b227ddd2e8ac
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Johan Klokkhammer Helsing 2018-02-22 15:33:40 +01:00 committed by Johan Helsing
parent 1605c84bbf
commit 9df7980958
6 changed files with 176 additions and 34 deletions

View File

@ -153,6 +153,7 @@ public slots:
// make sure the surfaces from the last test are properly cleaned up
// and don't show up as false positives in the next test
QTRY_VERIFY(!compositor->surface());
QTRY_VERIFY(!compositor->xdgToplevelV6());
}
private slots:

View File

@ -219,6 +219,14 @@ void MockCompositor::sendSurfaceLeave(const QSharedPointer<MockSurface> &surface
processCommand(command);
}
void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size)
{
Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor);
command.parameters << QVariant::fromValue(toplevel);
command.parameters << QVariant::fromValue(size);
processCommand(command);
}
void MockCompositor::waitForStartDrag()
{
Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor);
@ -251,6 +259,16 @@ QSharedPointer<MockOutput> MockCompositor::output(int index)
return result;
}
QSharedPointer<MockXdgToplevelV6> MockCompositor::xdgToplevelV6(int index)
{
QSharedPointer<MockXdgToplevelV6> result;
lock();
if (Impl::XdgToplevelV6 *toplevel = m_compositor->xdgShellV6()->toplevels().value(index, nullptr))
result = toplevel->mockToplevel();
unlock();
return result;
}
MockCompositor::Command MockCompositor::makeCommand(Command::Callback callback, void *target)
{
Command command;
@ -400,6 +418,11 @@ QVector<Output *> Compositor::outputs() const
return m_outputs;
}
XdgShellV6 *Compositor::xdgShellV6() const
{
return m_xdgShellV6.data();
}
uint32_t Compositor::nextSerial()
{
return wl_display_next_serial(m_display);
@ -429,5 +452,10 @@ Output *Compositor::resolveOutput(const QVariant &v)
return mockOutput ? mockOutput->handle() : nullptr;
}
XdgToplevelV6 *Compositor::resolveToplevel(const QVariant &v)
{
QSharedPointer<MockXdgToplevelV6> mockToplevel = v.value<QSharedPointer<MockXdgToplevelV6>>();
return mockToplevel ? mockToplevel->handle() : nullptr;
}
}

View File

@ -29,6 +29,8 @@
#ifndef MOCKCOMPOSITOR_H
#define MOCKCOMPOSITOR_H
#include "mockxdgshellv6.h"
#include <pthread.h>
#include <qglobal.h>
#include <wayland-server.h>
@ -70,6 +72,8 @@ public:
QVector<Surface *> surfaces() const;
QVector<Output *> outputs() const;
XdgShellV6 *xdgShellV6() const;
void addSurface(Surface *surface);
void removeSurface(Surface *surface);
@ -93,6 +97,7 @@ public:
static void sendRemoveOutput(void *data, const QList<QVariant> &parameters);
static void sendOutputGeometry(void *data, const QList<QVariant> &parameters);
static void sendSurfaceEnter(void *data, const QList<QVariant> &parameters);
static void sendXdgToplevelV6Configure(void *data, const QList<QVariant> &parameters);
static void sendSurfaceLeave(void *data, const QList<QVariant> &parameters);
public:
@ -102,6 +107,7 @@ private:
static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id);
static Surface *resolveSurface(const QVariant &v);
static Output *resolveOutput(const QVariant &v);
static XdgToplevelV6 *resolveToplevel(const QVariant &v);
void initShm();
@ -146,6 +152,22 @@ private:
Q_DECLARE_METATYPE(QSharedPointer<MockSurface>)
class MockXdgToplevelV6
{
public:
Impl::XdgToplevelV6 *handle() const { return m_toplevel; }
void sendConfigure(const QSharedPointer<MockXdgToplevelV6> toplevel);
private:
MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {}
friend class Impl::Compositor;
friend class Impl::XdgToplevelV6;
Impl::XdgToplevelV6 *m_toplevel;
};
Q_DECLARE_METATYPE(QSharedPointer<MockXdgToplevelV6>)
class MockOutput {
public:
Impl::Output *handle() const { return m_output; }
@ -187,10 +209,12 @@ public:
void sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry);
void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size);
void waitForStartDrag();
QSharedPointer<MockSurface> surface();
QSharedPointer<MockOutput> output(int index = 0);
QSharedPointer<MockXdgToplevelV6> xdgToplevelV6(int index = 0);
void lock();
void unlock();

View File

@ -28,47 +28,26 @@
#include "mockxdgshellv6.h"
#include "mocksurface.h"
#include "mockcompositor.h"
namespace Impl {
class XdgSurfaceV6;
class XdgToplevelV6 : public QtWaylandServer::zxdg_toplevel_v6
void Compositor::sendXdgToplevelV6Configure(void *data, const QList<QVariant> &parameters)
{
public:
XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version)
: QtWaylandServer::zxdg_toplevel_v6(client, id, version)
, m_xdgSurface(xdgSurface)
{}
void zxdg_toplevel_v6_destroy_resource(Resource *) override { delete this; }
void zxdg_toplevel_v6_destroy(Resource *resource) override;
XdgSurfaceV6 *m_xdgSurface = nullptr;
};
class XdgSurfaceV6 : public QtWaylandServer::zxdg_surface_v6
{
public:
XdgSurfaceV6(wl_client *client, uint32_t id, Surface *surface);
void zxdg_surface_v6_destroy_resource(Resource *) override { delete this; }
void zxdg_surface_v6_get_toplevel(Resource *resource, uint32_t id) override;
void zxdg_surface_v6_destroy(Resource *resource) override
{
Q_ASSERT(!m_toplevel);
wl_resource_destroy(resource->handle);
}
Surface *m_surface = nullptr;
XdgToplevelV6 *m_toplevel = nullptr;
};
void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
{
m_xdgSurface->m_toplevel = nullptr;
wl_resource_destroy(resource->handle);
Compositor *compositor = static_cast<Compositor *>(data);
XdgToplevelV6 *toplevel = resolveToplevel(parameters.at(0));
Q_ASSERT(toplevel && toplevel->resource());
QSize size = parameters.at(1).toSize();
Q_ASSERT(size.isValid());
QByteArray states;
toplevel->send_configure(size.width(), size.height(), states);
toplevel->xdgSurface()->send_configure(compositor->nextSerial());
}
XdgSurfaceV6::XdgSurfaceV6(wl_client *client, uint32_t id, Surface *surface)
XdgSurfaceV6::XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *client, uint32_t id)
: QtWaylandServer::zxdg_surface_v6(client, id, 1)
, m_surface(surface)
, m_shell(shell)
{
}
@ -79,9 +58,35 @@ void XdgSurfaceV6::zxdg_surface_v6_get_toplevel(QtWaylandServer::zxdg_surface_v6
m_surface->map();
}
void XdgSurfaceV6::zxdg_surface_v6_destroy(QtWaylandServer::zxdg_surface_v6::Resource *resource)
{
Q_ASSERT(!m_toplevel);
wl_resource_destroy(resource->handle);
}
XdgToplevelV6::XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version)
: QtWaylandServer::zxdg_toplevel_v6(client, id, version)
, m_xdgSurface(xdgSurface)
, m_mockToplevel(new MockXdgToplevelV6(this))
{
m_xdgSurface->shell()->addToplevel(this);
}
XdgToplevelV6::~XdgToplevelV6()
{
m_xdgSurface->shell()->removeToplevel(this);
m_mockToplevel->m_toplevel = nullptr;
}
void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
{
m_xdgSurface->m_toplevel = nullptr;
wl_resource_destroy(resource->handle);
}
void Impl::XdgShellV6::zxdg_shell_v6_get_xdg_surface(QtWaylandServer::zxdg_shell_v6::Resource *resource, uint32_t id, wl_resource *surface)
{
new XdgSurfaceV6(resource->client(), id, Surface::fromResource(surface));
new XdgSurfaceV6(this, Surface::fromResource(surface), resource->client(), id);
}
} // namespace Impl

View File

@ -28,16 +28,72 @@
#include <qwayland-server-xdg-shell-unstable-v6.h>
#include <QSharedPointer>
#include <QVector>
#ifndef MOCKXDGSHELLV6_H
#define MOCKXDGSHELLV6_H
class MockXdgToplevelV6;
namespace Impl {
class XdgToplevelV6;
class XdgShellV6;
class Surface;
class XdgSurfaceV6 : public QtWaylandServer::zxdg_surface_v6
{
public:
XdgSurfaceV6(XdgShellV6 *shell, Surface *surface, wl_client *client, uint32_t id);
XdgShellV6 *shell() const { return m_shell; }
protected:
void zxdg_surface_v6_destroy_resource(Resource *) override { delete this; }
void zxdg_surface_v6_get_toplevel(Resource *resource, uint32_t id) override;
void zxdg_surface_v6_destroy(Resource *resource) override;
private:
Surface *m_surface = nullptr;
XdgToplevelV6 *m_toplevel = nullptr;
XdgShellV6 *m_shell = nullptr;
friend class XdgToplevelV6;
};
class XdgToplevelV6 : public QtWaylandServer::zxdg_toplevel_v6
{
public:
XdgToplevelV6(XdgSurfaceV6 *xdgSurface, wl_client *client, uint32_t id, int version);
~XdgToplevelV6() override;
XdgSurfaceV6 *xdgSurface() const { return m_xdgSurface; }
QSharedPointer<MockXdgToplevelV6> mockToplevel() const { return m_mockToplevel; }
protected:
void zxdg_toplevel_v6_destroy_resource(Resource *) override { delete this; }
void zxdg_toplevel_v6_destroy(Resource *resource) override;
private:
XdgSurfaceV6 *m_xdgSurface = nullptr;
QSharedPointer<MockXdgToplevelV6> m_mockToplevel;
};
class XdgShellV6 : public QtWaylandServer::zxdg_shell_v6
{
public:
explicit XdgShellV6(::wl_display *display) : zxdg_shell_v6(display, 1) {}
QVector<XdgToplevelV6 *> toplevels() const { return m_toplevels; }
protected:
void zxdg_shell_v6_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override;
private:
void addToplevel(XdgToplevelV6 *toplevel) { m_toplevels.append(toplevel); }
void removeToplevel(XdgToplevelV6 *toplevel) { m_toplevels.removeOne(toplevel); }
QVector<XdgToplevelV6 *> m_toplevels;
friend class XdgToplevelV6;
};
} // namespace Impl

View File

@ -76,10 +76,12 @@ public slots:
// make sure the surfaces from the last test are properly cleaned up
// and don't show up as false positives in the next test
QTRY_VERIFY(!m_compositor->surface());
QTRY_VERIFY(!m_compositor->xdgToplevelV6());
}
private slots:
void createDestroyWindow();
void configure();
private:
MockCompositor *m_compositor = nullptr;
@ -96,6 +98,32 @@ void tst_WaylandClientXdgShellV6::createDestroyWindow()
QTRY_VERIFY(!m_compositor->surface());
}
void tst_WaylandClientXdgShellV6::configure()
{
QSharedPointer<MockOutput> output;
QTRY_VERIFY(output = m_compositor->output());
TestWindow window;
window.show();
QSharedPointer<MockSurface> surface;
QTRY_VERIFY(surface = m_compositor->surface());
m_compositor->processWaylandEvents();
QTRY_VERIFY(window.isVisible());
QTRY_VERIFY(!window.isExposed()); //Window should not be exposed before the first configure event
//TODO: according to xdg-shell protocol, a buffer should not be attached to a the surface
//until it's configured. Ensure this in the test!
QSharedPointer<MockXdgToplevelV6> toplevel;
QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
const QSize newSize(123, 456);
m_compositor->sendXdgToplevelV6Configure(toplevel, newSize);
QTRY_VERIFY(window.isExposed());
QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), newSize));
}
int main(int argc, char **argv)
{
setenv("XDG_RUNTIME_DIR", ".", 1);