Client: Test that the current screen is updated by surface events

Change-Id: If96691a2d844263a1e01a86df8b0d58f23848a4c
Reviewed-by: Pier Luigi Fiorini <pierluigi.fiorini@liri.io>
This commit is contained in:
Johan Klokkhammer Helsing 2017-08-18 17:28:01 +02:00 committed by Johan Helsing
parent 7f8e7b4195
commit 679dc2e281
9 changed files with 269 additions and 46 deletions

View File

@ -137,7 +137,8 @@ public slots:
}
private slots:
void screen();
void primaryScreen();
void windowScreens();
void createDestroyWindow();
void events();
void backingStore();
@ -151,11 +152,49 @@ private:
MockCompositor *compositor;
};
void tst_WaylandClient::screen()
void tst_WaylandClient::primaryScreen()
{
compositor->setOutputMode(screenSize);
QTRY_COMPARE(QGuiApplication::primaryScreen()->size(), screenSize);
}
void tst_WaylandClient::windowScreens()
{
QSharedPointer<MockOutput> firstOutput;
QTRY_VERIFY(firstOutput = compositor->output());
TestWindow window;
window.show();
QSharedPointer<MockSurface> surface;
QTRY_VERIFY(surface = compositor->surface());
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
QScreen *primaryScreen = QGuiApplication::screens().first();
QCOMPARE(window.screen(), primaryScreen);
compositor->sendAddOutput();
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
QScreen *secondaryScreen = QGuiApplication::screens().at(1);
QVERIFY(secondaryScreen);
window.setScreen(secondaryScreen);
QCOMPARE(window.screen(), secondaryScreen);
QSharedPointer<MockOutput> secondOutput;
QTRY_VERIFY(secondOutput = compositor->output(1));
compositor->sendSurfaceEnter(surface, firstOutput);
compositor->sendSurfaceEnter(surface, secondOutput);
QTRY_COMPARE(window.screen(), primaryScreen);
compositor->sendSurfaceLeave(surface, firstOutput);
QTRY_COMPARE(window.screen(), secondaryScreen);
window.destroy();
QTRY_VERIFY(!compositor->surface());
}
void tst_WaylandClient::createDestroyWindow()
{
TestWindow window;
@ -417,7 +456,7 @@ int main(int argc, char **argv)
setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1);
MockCompositor compositor;
compositor.setOutputGeometry(QRect(QPoint(), screenSize));
compositor.setOutputMode(screenSize);
QGuiApplication app(argc, argv);
compositor.applicationInitialized();

View File

@ -28,6 +28,7 @@
#include "mockcompositor.h"
#include "mockinput.h"
#include "mockoutput.h"
#include "mocksurface.h"
#include <wayland-xdg-shell-unstable-v6-server-protocol.h>
@ -77,10 +78,10 @@ void MockCompositor::processWaylandEvents()
m_waitCondition.wakeOne();
}
void MockCompositor::setOutputGeometry(const QRect &rect)
void MockCompositor::setOutputMode(const QSize &size)
{
Command command = makeCommand(Impl::Compositor::setOutputGeometry, m_compositor);
command.parameters << rect;
Command command = makeCommand(Impl::Compositor::setOutputMode, m_compositor);
command.parameters << size;
processCommand(command);
}
@ -182,6 +183,28 @@ void MockCompositor::sendDataDeviceLeave(const QSharedPointer<MockSurface> &surf
processCommand(command);
}
void MockCompositor::sendAddOutput()
{
Command command = makeCommand(Impl::Compositor::sendAddOutput, m_compositor);
processCommand(command);
}
void MockCompositor::sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
{
Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor);
command.parameters << QVariant::fromValue(surface);
command.parameters << QVariant::fromValue(output);
processCommand(command);
}
void MockCompositor::sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
{
Command command = makeCommand(Impl::Compositor::sendSurfaceLeave, m_compositor);
command.parameters << QVariant::fromValue(surface);
command.parameters << QVariant::fromValue(output);
processCommand(command);
}
void MockCompositor::waitForStartDrag()
{
Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor);
@ -204,6 +227,15 @@ QSharedPointer<MockSurface> MockCompositor::surface()
return result;
}
QSharedPointer<MockOutput> MockCompositor::output(int index)
{
QSharedPointer<MockOutput> result;
lock();
result = m_compositor->outputs().at(index)->mockOutput();
unlock();
return result;
}
MockCompositor::Command MockCompositor::makeCommand(Command::Callback callback, void *target)
{
Command command;
@ -267,8 +299,6 @@ namespace Impl {
Compositor::Compositor()
: m_display(wl_display_create())
{
wl_list_init(&m_outputResources);
if (wl_display_add_socket(m_display, 0)) {
fprintf(stderr, "Fatal: Failed to open server socket\n");
exit(EXIT_FAILURE);
@ -285,7 +315,7 @@ Compositor::Compositor()
m_keyboard = m_seat->keyboard();
m_touch = m_seat->touch();
wl_global_create(m_display, &wl_output_interface, 1, this, bindOutput);
m_outputs.append(new Output(m_display, QSize(1920, 1080), QPoint(0, 0)));
wl_global_create(m_display, &wl_shell_interface, 1, this, bindShell);
wl_global_create(m_display, &zxdg_shell_v6_interface, 1, this, bindXdgShellV6);
@ -350,6 +380,11 @@ QVector<Surface *> Compositor::surfaces() const
return m_surfaces;
}
QVector<Output *> Compositor::outputs() const
{
return m_outputs;
}
uint32_t Compositor::nextSerial()
{
return wl_display_next_serial(m_display);
@ -367,5 +402,17 @@ void Compositor::removeSurface(Surface *surface)
m_pointer->handleSurfaceDestroyed(surface);
}
Surface *Compositor::resolveSurface(const QVariant &v)
{
QSharedPointer<MockSurface> mockSurface = v.value<QSharedPointer<MockSurface> >();
return mockSurface ? mockSurface->handle() : nullptr;
}
Output *Compositor::resolveOutput(const QVariant &v)
{
QSharedPointer<MockOutput> mockOutput = v.value<QSharedPointer<MockOutput> >();
return mockOutput ? mockOutput->handle() : nullptr;
}
}

View File

@ -51,6 +51,7 @@ class Touch;
class Seat;
class DataDeviceManager;
class Surface;
class Output;
class Compositor
{
@ -64,9 +65,8 @@ public:
uint32_t nextSerial();
uint32_t time() { return ++m_time; }
static void setOutputGeometry(void *compositor, const QList<QVariant> &parameters);
QVector<Surface *> surfaces() const;
QVector<Output *> outputs() const;
void addSurface(Surface *surface);
void removeSurface(Surface *surface);
@ -86,21 +86,23 @@ public:
static void sendDataDeviceDrop(void *data, const QList<QVariant> &parameters);
static void sendDataDeviceLeave(void *data, const QList<QVariant> &parameters);
static void waitForStartDrag(void *data, const QList<QVariant> &parameters);
static void setOutputMode(void *compositor, const QList<QVariant> &parameters);
static void sendAddOutput(void *data, const QList<QVariant> &parameters);
static void sendSurfaceEnter(void *data, const QList<QVariant> &parameters);
static void sendSurfaceLeave(void *data, const QList<QVariant> &parameters);
public:
bool m_startDragSeen = false;
private:
static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id);
static void bindOutput(wl_client *client, void *data, uint32_t version, uint32_t id);
static void bindShell(wl_client *client, void *data, uint32_t version, uint32_t id);
static void bindXdgShellV6(wl_client *client, void *compositorData, uint32_t version, uint32_t id);
static Surface *resolveSurface(const QVariant &v);
static Output *resolveOutput(const QVariant &v);
void initShm();
void sendOutputGeometry(wl_resource *resource);
void sendOutputMode(wl_resource *resource);
QRect m_outputGeometry;
wl_display *m_display = nullptr;
@ -108,7 +110,6 @@ private:
wl_shm *m_shm = nullptr;
int m_fd = -1;
wl_list m_outputResources;
uint32_t m_time = 0;
QScopedPointer<Seat> m_seat;
@ -117,6 +118,7 @@ private:
Touch *m_touch = nullptr;
QScopedPointer<DataDeviceManager> m_data_device_manager;
QVector<Surface *> m_surfaces;
QVector<Output *> m_outputs;
};
void registerResource(wl_list *list, wl_resource *resource);
@ -140,6 +142,16 @@ private:
Q_DECLARE_METATYPE(QSharedPointer<MockSurface>)
class MockOutput {
public:
Impl::Output *handle() const { return m_output; }
MockOutput(Impl::Output *output);
private:
Impl::Output *m_output;
};
Q_DECLARE_METATYPE(QSharedPointer<MockOutput>)
class MockCompositor
{
public:
@ -151,7 +163,7 @@ public:
int waylandFileDescriptor() const;
void processWaylandEvents();
void setOutputGeometry(const QRect &rect);
void setOutputMode(const QSize &size);
void setKeyboardFocus(const QSharedPointer<MockSurface> &surface);
void sendMousePress(const QSharedPointer<MockSurface> &surface, const QPoint &pos);
void sendMouseRelease(const QSharedPointer<MockSurface> &surface);
@ -166,9 +178,13 @@ public:
void sendDataDeviceMotion(const QPoint &position);
void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface);
void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
void sendAddOutput();
void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
void waitForStartDrag();
QSharedPointer<MockSurface> surface();
QSharedPointer<MockOutput> output(int index = 0);
void lock();
void unlock();

View File

@ -32,12 +32,6 @@
namespace Impl {
static Surface *resolveSurface(const QVariant &v)
{
QSharedPointer<MockSurface> mockSurface = v.value<QSharedPointer<MockSurface> >();
return mockSurface ? mockSurface->handle() : 0;
}
void Compositor::setKeyboardFocus(void *data, const QList<QVariant> &parameters)
{
Compositor *compositor = static_cast<Compositor *>(data);

View File

@ -27,41 +27,76 @@
****************************************************************************/
#include "mockcompositor.h"
#include "mockoutput.h"
#include <QDebug>
namespace Impl {
void Compositor::bindOutput(wl_client *client, void *compositorData, uint32_t version, uint32_t id)
void Compositor::sendAddOutput(void *data, const QList<QVariant> &parameters) {
Q_UNUSED(parameters);
Compositor *compositor = static_cast<Compositor *>(data);
auto output = new Output(compositor->m_display, QSize(1920, 1200), QPoint(0, 0));
compositor->m_outputs.append(output);
// Wait for the client to bind to the output
while (output->resourceMap().isEmpty())
compositor->dispatchEvents();
}
void Compositor::setOutputMode(void *data, const QList<QVariant> &parameters)
{
wl_resource *resource = wl_resource_create(client, &wl_output_interface, static_cast<int>(version), id);
Compositor *compositor = static_cast<Compositor *>(compositorData);
registerResource(&compositor->m_outputResources, resource);
compositor->sendOutputGeometry(resource);
compositor->sendOutputMode(resource);
Compositor *compositor = static_cast<Compositor *>(data);
QSize size = parameters.first().toSize();
Output *output = compositor->m_outputs.first();
Q_ASSERT(output);
output->setCurrentMode(size);
}
void Compositor::sendOutputGeometry(wl_resource *resource)
Output::Output(wl_display *display, const QSize &resolution, const QPoint &position)
: wl_output(display, 2)
, m_size(resolution)
, m_position(position)
, m_physicalSize(520, 320)
, m_mockOutput(new MockOutput(this))
{
const QRect &r = m_outputGeometry;
wl_output_send_geometry(resource, r.x(), r.y(), r.width(), r.height(), 0, "", "",0);
}
void Compositor::sendOutputMode(wl_resource *resource)
void Output::setCurrentMode(const QSize &size)
{
const QRect &r = m_outputGeometry;
wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, r.width(), r.height(), 60);
qDebug() << Q_FUNC_INFO << size;
m_size = size;
for (Resource *resource : resourceMap())
sendCurrentMode(resource);
}
void Compositor::setOutputGeometry(void *c, const QList<QVariant> &parameters)
void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
{
Compositor *compositor = static_cast<Compositor *>(c);
compositor->m_outputGeometry = parameters.first().toRect();
wl_resource *resource;
wl_list_for_each(resource, &compositor->m_outputResources, link)
compositor->sendOutputGeometry(resource);
sendGeometry(resource);
sendCurrentMode(resource);
}
void Output::sendGeometry(Resource *resource)
{
const int subPixel = 0;
const int transform = 0;
send_geometry(resource->handle,
m_position.x(), m_position.y(),
m_physicalSize.width(), m_physicalSize.height(),
subPixel, "", "", transform );
}
void Output::sendCurrentMode(Resource *resource)
{
send_mode(resource->handle,
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED,
m_size.width(), m_size.height(), 60000);
}
} // Impl
MockOutput::MockOutput(Impl::Output *output)
: m_output(output)
{
}

View File

@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef MOCKOUTPUT_H
#define MOCKOUTPUT_H
#include <qglobal.h>
#include "qwayland-server-wayland.h"
#include "mockcompositor.h"
namespace Impl {
class Output : public QtWaylandServer::wl_output
{
public:
Output(::wl_display *display, const QSize &resolution, const QPoint &position);
QSharedPointer<MockOutput> mockOutput() const { return m_mockOutput; }
void setCurrentMode(const QSize &size);
protected:
void output_bind_resource(Resource *resource) override;
private:
void sendGeometry(Resource *resource);
void sendCurrentMode(Resource *resource);
QSize m_size;
QPoint m_position;
const QSize m_physicalSize;
QSharedPointer<MockOutput> m_mockOutput;
};
}
#endif // MOCKOUTPUT_H

View File

@ -27,10 +27,39 @@
****************************************************************************/
#include "mocksurface.h"
#include "mockoutput.h"
#include "mockcompositor.h"
namespace Impl {
void Compositor::sendSurfaceEnter(void *data, const QList<QVariant> &parameters)
{
Q_UNUSED(data);
Surface *surface = resolveSurface(parameters.at(0));
Output *output = resolveOutput(parameters.at(1));
Q_ASSERT(surface && surface->resource());
Q_ASSERT(output);
auto outputResources = output->resourceMap().values(surface->resource()->client());
Q_ASSERT(!outputResources.isEmpty());
for (auto outputResource : outputResources)
surface->send_enter(outputResource->handle);
}
void Compositor::sendSurfaceLeave(void *data, const QList<QVariant> &parameters)
{
Q_UNUSED(data);
Surface *surface = resolveSurface(parameters.at(0));
Output *output = resolveOutput(parameters.at(1));
Q_ASSERT(surface && surface->resource());
Q_ASSERT(output);
auto outputResources = output->resourceMap().values(surface->resource()->client());
Q_ASSERT(!outputResources.isEmpty());
for (auto outputResource : outputResources)
surface->send_leave(outputResource->handle);
}
Surface::Surface(wl_client *client, uint32_t id, int v, Compositor *compositor)
: QtWaylandServer::wl_surface(client, id, v)
, m_buffer(nullptr)

View File

@ -21,4 +21,5 @@ SOURCES += \
HEADERS += \
../shared/mockcompositor.h \
../shared/mockinput.h \
../shared/mocksurface.h
../shared/mocksurface.h \
../shared/mockoutput.h

View File

@ -108,7 +108,7 @@ int main(int argc, char **argv)
setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1);
MockCompositor compositor;
compositor.setOutputGeometry(QRect(QPoint(), screenSize));
compositor.setOutputMode(screenSize);
QGuiApplication app(argc, argv);
compositor.applicationInitialized();