Client: Add wl_output tests
Also removes overlapping old tests and adds a (currently failing) test for QTBUG-72828. Task-number: QTBUG-72828 Change-Id: Id93d5872ed1c4f181935c1e493e9d8d0ae9cfaf3 Reviewed-by: Pier Luigi Fiorini <pierluigi.fiorini@liri.io>
This commit is contained in:
parent
c34abdb08b
commit
badf0575a2
@ -4,6 +4,7 @@ SUBDIRS += \
|
|||||||
client \
|
client \
|
||||||
fullscreenshellv1 \
|
fullscreenshellv1 \
|
||||||
iviapplication \
|
iviapplication \
|
||||||
|
output \
|
||||||
seatv4 \
|
seatv4 \
|
||||||
surface \
|
surface \
|
||||||
wl_connect \
|
wl_connect \
|
||||||
|
@ -167,11 +167,6 @@ public slots:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void primaryScreen();
|
|
||||||
void screens();
|
|
||||||
void addScreenWithGeometryChange();
|
|
||||||
void windowScreens();
|
|
||||||
void removePrimaryScreen();
|
|
||||||
void createDestroyWindow();
|
void createDestroyWindow();
|
||||||
void activeWindowFollowsKeyboardFocus();
|
void activeWindowFollowsKeyboardFocus();
|
||||||
void events();
|
void events();
|
||||||
@ -188,117 +183,6 @@ private:
|
|||||||
MockCompositor *compositor = nullptr;
|
MockCompositor *compositor = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_WaylandClient::primaryScreen()
|
|
||||||
{
|
|
||||||
compositor->setOutputMode(screenSize);
|
|
||||||
QTRY_COMPARE(QGuiApplication::primaryScreen()->size(), screenSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_WaylandClient::screens()
|
|
||||||
{
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
|
||||||
compositor->sendAddOutput();
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
|
||||||
QSharedPointer<MockOutput> secondOutput;
|
|
||||||
QTRY_VERIFY(secondOutput = compositor->output(1));
|
|
||||||
compositor->sendRemoveOutput(secondOutput);
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//QTBUG-62044
|
|
||||||
void tst_WaylandClient::addScreenWithGeometryChange()
|
|
||||||
{
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
|
||||||
const QRect oldGeometry = QGuiApplication::primaryScreen()->geometry();
|
|
||||||
compositor->sendAddOutput();
|
|
||||||
|
|
||||||
// Move the primary screen to the right
|
|
||||||
const QRect newGeometry(QPoint(screenSize.width(), 0), screenSize);
|
|
||||||
Q_ASSERT(oldGeometry != newGeometry);
|
|
||||||
compositor->sendOutputGeometry(compositor->output(0), newGeometry);
|
|
||||||
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
|
||||||
QTRY_COMPARE(QGuiApplication::primaryScreen()->geometry(), newGeometry);
|
|
||||||
|
|
||||||
compositor->sendRemoveOutput(compositor->output(1));
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
|
||||||
|
|
||||||
// Move the screen back
|
|
||||||
compositor->sendOutputGeometry(compositor->output(0), oldGeometry);
|
|
||||||
QTRY_COMPARE(QGuiApplication::primaryScreen()->geometry(), oldGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_WaylandClient::windowScreens()
|
|
||||||
{
|
|
||||||
QSharedPointer<MockOutput> firstOutput;
|
|
||||||
QTRY_VERIFY(firstOutput = compositor->output());
|
|
||||||
|
|
||||||
TestWindow window;
|
|
||||||
window.show();
|
|
||||||
|
|
||||||
QSharedPointer<MockSurface> surface;
|
|
||||||
QTRY_VERIFY(surface = compositor->surface());
|
|
||||||
compositor->sendShellSurfaceConfigure(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);
|
|
||||||
|
|
||||||
compositor->sendRemoveOutput(secondOutput);
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
|
||||||
QCOMPARE(window.screen(), primaryScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_WaylandClient::removePrimaryScreen()
|
|
||||||
{
|
|
||||||
QSharedPointer<MockOutput> firstOutput;
|
|
||||||
QTRY_VERIFY(firstOutput = compositor->output());
|
|
||||||
|
|
||||||
TestWindow window;
|
|
||||||
window.show();
|
|
||||||
|
|
||||||
QSharedPointer<MockSurface> surface;
|
|
||||||
QTRY_VERIFY(surface = compositor->surface());
|
|
||||||
compositor->sendShellSurfaceConfigure(surface);
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
|
||||||
QScreen *primaryScreen = QGuiApplication::screens().first();
|
|
||||||
QCOMPARE(window.screen(), primaryScreen);
|
|
||||||
|
|
||||||
compositor->sendAddOutput();
|
|
||||||
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
|
||||||
QTRY_COMPARE(QGuiApplication::primaryScreen()->virtualSiblings().size(), 2);
|
|
||||||
QScreen *secondaryScreen = QGuiApplication::screens().at(1);
|
|
||||||
QVERIFY(secondaryScreen);
|
|
||||||
|
|
||||||
compositor->sendRemoveOutput(firstOutput);
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
|
||||||
|
|
||||||
compositor->sendMousePress(surface, window.frameOffset() + QPoint(10, 10));
|
|
||||||
QTRY_COMPARE(window.mousePressEventCount, 1);
|
|
||||||
compositor->sendMouseRelease(surface);
|
|
||||||
QTRY_COMPARE(window.mouseReleaseEventCount, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_WaylandClient::createDestroyWindow()
|
void tst_WaylandClient::createDestroyWindow()
|
||||||
{
|
{
|
||||||
TestWindow window;
|
TestWindow window;
|
||||||
|
5
tests/auto/wayland/output/output.pro
Normal file
5
tests/auto/wayland/output/output.pro
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include (../shared/shared.pri)
|
||||||
|
|
||||||
|
TARGET = tst_output
|
||||||
|
SOURCES += tst_output.cpp
|
||||||
|
|
231
tests/auto/wayland/output/tst_output.cpp
Normal file
231
tests/auto/wayland/output/tst_output.cpp
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 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$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "mockcompositor.h"
|
||||||
|
#include <QtGui/QScreen>
|
||||||
|
#include <QtGui/QRasterWindow>
|
||||||
|
|
||||||
|
using namespace MockCompositor;
|
||||||
|
|
||||||
|
class tst_output : public QObject, private DefaultCompositor
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void initTestCase()
|
||||||
|
{
|
||||||
|
m_config.autoConfigure = true;
|
||||||
|
m_config.autoEnter = false;
|
||||||
|
}
|
||||||
|
void cleanup()
|
||||||
|
{
|
||||||
|
QCOMPOSITOR_COMPARE(getAll<Output>().size(), 1); // Only the default output should be left
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage()));
|
||||||
|
}
|
||||||
|
void primaryScreen();
|
||||||
|
void secondaryHiDpiScreen();
|
||||||
|
void addScreenWithGeometryChange();
|
||||||
|
void windowScreens();
|
||||||
|
void removePrimaryScreen();
|
||||||
|
void screenOrder();
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_output::primaryScreen()
|
||||||
|
{
|
||||||
|
// Verify that the client has bound to the output global
|
||||||
|
QCOMPOSITOR_TRY_COMPARE(output()->resourceMap().size(), 1);
|
||||||
|
QTRY_VERIFY(QGuiApplication::primaryScreen());
|
||||||
|
QScreen *screen = QGuiApplication::primaryScreen();
|
||||||
|
QCOMPARE(screen->manufacturer(), "Make");
|
||||||
|
QCOMPARE(screen->model(), "Model");
|
||||||
|
QCOMPARE(screen->size(), QSize(1920, 1080));
|
||||||
|
QCOMPARE(screen->refreshRate(), 60);
|
||||||
|
QCOMPARE(qRound(screen->physicalDotsPerInch()), 96 / screen->devicePixelRatio());
|
||||||
|
QCOMPARE(screen->devicePixelRatio(), 1);
|
||||||
|
QCOMPARE(screen->logicalDotsPerInch(), 96);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_output::secondaryHiDpiScreen()
|
||||||
|
{
|
||||||
|
exec([=] {
|
||||||
|
OutputData d;
|
||||||
|
d.position = {1920, 0}; // in global compositor space (not pixels)
|
||||||
|
d.mode.resolution = {800, 640};
|
||||||
|
d.physicalSize = d.mode.physicalSizeForDpi(200);
|
||||||
|
d.scale = 2;
|
||||||
|
add<Output>(d);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that the client has bound to the output global
|
||||||
|
QCOMPOSITOR_TRY_VERIFY(output(1) && output(1)->resourceMap().size() == 1);
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
||||||
|
QScreen *screen = QGuiApplication::screens()[1];
|
||||||
|
QCOMPARE(screen->refreshRate(), 60);
|
||||||
|
QCOMPARE(screen->devicePixelRatio(), 2);
|
||||||
|
QCOMPARE(screen->logicalDotsPerInch(), 96);
|
||||||
|
|
||||||
|
// Dots currently means device pixels, not actual pixels (see QTBUG-62649)
|
||||||
|
QCOMPARE(qRound(screen->physicalDotsPerInch() * screen->devicePixelRatio()), 200);
|
||||||
|
|
||||||
|
// Size is in logical pixel coordinates
|
||||||
|
QCOMPARE(screen->size(), QSize(800, 640) / 2);
|
||||||
|
QCOMPARE(screen->geometry(), QRect(QPoint(1920, 0), QSize(400, 320)));
|
||||||
|
QCOMPARE(screen->virtualGeometry(), QRect(QPoint(0, 0), QSize(1920 + 800 / 2, 1080)));
|
||||||
|
|
||||||
|
exec([=] { remove(output(1)); });
|
||||||
|
}
|
||||||
|
|
||||||
|
// QTBUG-62044
|
||||||
|
void tst_output::addScreenWithGeometryChange()
|
||||||
|
{
|
||||||
|
const QPoint initialPosition = exec([=] { return output(0)->m_data.position; });
|
||||||
|
|
||||||
|
exec([=] {
|
||||||
|
auto *oldOutput = output(0);
|
||||||
|
auto *newOutput = add<Output>();
|
||||||
|
newOutput->m_data.mode.resolution = {1280, 720};
|
||||||
|
// Move the primary output to the right
|
||||||
|
QPoint newPosition(newOutput->m_data.mode.resolution.width(), 0);
|
||||||
|
Q_ASSERT(newPosition != initialPosition);
|
||||||
|
oldOutput->m_data.position = newPosition;
|
||||||
|
oldOutput->sendGeometry();
|
||||||
|
oldOutput->sendDone();
|
||||||
|
});
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
||||||
|
QTRY_COMPARE(QGuiApplication::primaryScreen()->geometry(), QRect(QPoint(1280, 0), QSize(1920, 1080)));
|
||||||
|
|
||||||
|
// Remove the extra output and move the old one back
|
||||||
|
exec([=] {
|
||||||
|
remove(output(1));
|
||||||
|
output()->m_data.position = initialPosition;
|
||||||
|
output()->sendGeometry();
|
||||||
|
output()->sendDone();
|
||||||
|
});
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
QTRY_COMPARE(QGuiApplication::primaryScreen()->geometry(), QRect(QPoint(0, 0), QSize(1920, 1080)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_output::windowScreens()
|
||||||
|
{
|
||||||
|
QRasterWindow window;
|
||||||
|
window.resize(400, 320);
|
||||||
|
window.show();
|
||||||
|
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
QScreen *primaryScreen = QGuiApplication::screens().first();
|
||||||
|
QCOMPARE(window.screen(), primaryScreen);
|
||||||
|
|
||||||
|
exec([=] { add<Output>(); });
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
||||||
|
QScreen *secondaryScreen = QGuiApplication::screens().at(1);
|
||||||
|
QVERIFY(secondaryScreen);
|
||||||
|
|
||||||
|
window.setScreen(secondaryScreen);
|
||||||
|
QCOMPARE(window.screen(), secondaryScreen);
|
||||||
|
|
||||||
|
exec([=] {
|
||||||
|
xdgToplevel()->surface()->sendEnter(output(0));
|
||||||
|
xdgToplevel()->surface()->sendEnter(output(1));
|
||||||
|
});
|
||||||
|
|
||||||
|
QTRY_COMPARE(window.screen(), primaryScreen);
|
||||||
|
|
||||||
|
exec([=] {
|
||||||
|
xdgToplevel()->surface()->sendLeave(output(0));
|
||||||
|
});
|
||||||
|
QTRY_COMPARE(window.screen(), secondaryScreen);
|
||||||
|
|
||||||
|
exec([=] {
|
||||||
|
remove(output(1));
|
||||||
|
});
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
QCOMPARE(window.screen(), primaryScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_output::removePrimaryScreen()
|
||||||
|
{
|
||||||
|
QRasterWindow window;
|
||||||
|
window.resize(400, 320);
|
||||||
|
window.show();
|
||||||
|
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
QScreen *primaryScreen = QGuiApplication::screens().first();
|
||||||
|
QCOMPARE(window.screen(), primaryScreen);
|
||||||
|
|
||||||
|
// Add a clone of the primary output
|
||||||
|
exec([&] { add<Output>(output()->m_data); });
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
||||||
|
QTRY_COMPARE(QGuiApplication::primaryScreen()->virtualSiblings().size(), 2);
|
||||||
|
QScreen *secondaryScreen = QGuiApplication::screens().at(1);
|
||||||
|
QVERIFY(secondaryScreen);
|
||||||
|
|
||||||
|
exec([&] { remove(output()); });
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
|
||||||
|
exec([&] {
|
||||||
|
auto *surface = xdgToplevel()->surface();
|
||||||
|
pointer()->sendEnter(surface, {32, 32});
|
||||||
|
pointer()->sendButton(client(), BTN_LEFT, 1);
|
||||||
|
pointer()->sendButton(client(), BTN_LEFT, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait to make sure mouse events dont't cause a crash now that the screen has changed
|
||||||
|
xdgPingAndWaitForPong();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QTBUG-72828
|
||||||
|
void tst_output::screenOrder()
|
||||||
|
{
|
||||||
|
exec([=] {
|
||||||
|
add<Output>()->m_data.model = "Screen 1";
|
||||||
|
add<Output>()->m_data.model = "Screen 2";
|
||||||
|
});
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 3);
|
||||||
|
const auto screens = QGuiApplication::screens();
|
||||||
|
|
||||||
|
QEXPECT_FAIL(nullptr, "TODO: fix screen order", Continue);
|
||||||
|
QCOMPARE(screens[1]->model(), "Screen 1");
|
||||||
|
|
||||||
|
QEXPECT_FAIL(nullptr, "TODO: fix screen order", Continue);
|
||||||
|
QCOMPARE(screens[2]->model(), "Screen 2");
|
||||||
|
|
||||||
|
exec([=] {
|
||||||
|
remove(output(2));
|
||||||
|
remove(output(1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPOSITOR_TEST_MAIN(tst_output)
|
||||||
|
#include "tst_output.moc"
|
@ -256,8 +256,10 @@ void tst_seatv4::scaledCursor()
|
|||||||
QSKIP("Currently broken and should be fixed");
|
QSKIP("Currently broken and should be fixed");
|
||||||
// Add a highdpi output
|
// Add a highdpi output
|
||||||
exec([&] {
|
exec([&] {
|
||||||
int scale = 2;
|
OutputData d;
|
||||||
add<Output>(scale);
|
d.scale = 2;
|
||||||
|
d.position = {1920, 0};
|
||||||
|
add<Output>(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
QRasterWindow window;
|
QRasterWindow window;
|
||||||
@ -282,7 +284,7 @@ void tst_seatv4::scaledCursor()
|
|||||||
QCOMPOSITOR_TRY_COMPARE(pointer()->cursorSurface()->m_committed.buffer->size(), unscaledPixelSize * 2);
|
QCOMPOSITOR_TRY_COMPARE(pointer()->cursorSurface()->m_committed.buffer->size(), unscaledPixelSize * 2);
|
||||||
|
|
||||||
// Remove the extra output to clean up for the next test
|
// Remove the extra output to clean up for the next test
|
||||||
exec([&] { remove(getAll<Output>()[1]); });
|
exec([&] { remove(output(1)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
QCOMPOSITOR_TEST_MAIN(tst_seatv4)
|
QCOMPOSITOR_TEST_MAIN(tst_seatv4)
|
||||||
|
@ -97,8 +97,8 @@ void CoreCompositor::add(Global *global)
|
|||||||
void CoreCompositor::remove(Global *global)
|
void CoreCompositor::remove(Global *global)
|
||||||
{
|
{
|
||||||
warnIfNotLockedByThread(Q_FUNC_INFO);
|
warnIfNotLockedByThread(Q_FUNC_INFO);
|
||||||
//TODO: Need to delete global as well!
|
|
||||||
m_globals.removeAll(global);
|
m_globals.removeAll(global);
|
||||||
|
delete global;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint CoreCompositor::nextSerial()
|
uint CoreCompositor::nextSerial()
|
||||||
|
@ -125,28 +125,55 @@ QString WlCompositor::dirtyMessage()
|
|||||||
return "Dirty, surfaces left:\n\t" + messages.join("\n\t");
|
return "Dirty, surfaces left:\n\t" + messages.join("\n\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Output::sendGeometry()
|
||||||
|
{
|
||||||
|
const auto resources = resourceMap().values();
|
||||||
|
for (auto r : resources)
|
||||||
|
sendGeometry(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Output::sendGeometry(Resource *resource)
|
||||||
|
{
|
||||||
|
// TODO: check resource version as well?
|
||||||
|
wl_output::send_geometry(resource->handle,
|
||||||
|
m_data.position.x(), m_data.position.y(),
|
||||||
|
m_data.physicalSize.width(), m_data.physicalSize.height(),
|
||||||
|
m_data.subpixel, m_data.make, m_data.model, m_data.transform);
|
||||||
|
}
|
||||||
|
|
||||||
void Output::sendScale(int factor)
|
void Output::sendScale(int factor)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_version >= WL_OUTPUT_SCALE_SINCE_VERSION);
|
Q_ASSERT(m_version >= WL_OUTPUT_SCALE_SINCE_VERSION);
|
||||||
m_scale = factor;
|
m_data.scale = factor;
|
||||||
const auto resources = resourceMap().values();
|
const auto resources = resourceMap().values();
|
||||||
for (auto r: resources)
|
for (auto r : resources)
|
||||||
wl_output::send_scale(r->handle, factor);
|
sendScale(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Output::sendScale(Resource *resource)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_version >= WL_OUTPUT_SCALE_SINCE_VERSION);
|
||||||
|
// TODO: check resource version as well?
|
||||||
|
wl_output::send_scale(resource->handle, m_data.scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::sendDone()
|
void Output::sendDone()
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_version >= WL_OUTPUT_DONE_SINCE_VERSION);
|
Q_ASSERT(m_version >= WL_OUTPUT_DONE_SINCE_VERSION);
|
||||||
|
// TODO: check resource version as well?
|
||||||
const auto resources = resourceMap().values();
|
const auto resources = resourceMap().values();
|
||||||
for (auto r: resources)
|
for (auto r : resources)
|
||||||
wl_output::send_done(r->handle);
|
wl_output::send_done(r->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
|
void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
|
||||||
{
|
{
|
||||||
|
sendGeometry(resource);
|
||||||
|
send_mode(resource->handle, mode_preferred | mode_current,
|
||||||
|
m_data.mode.resolution.width(), m_data.mode.resolution.height(), m_data.mode.refreshRate);
|
||||||
if (m_version >= WL_OUTPUT_SCALE_SINCE_VERSION)
|
if (m_version >= WL_OUTPUT_SCALE_SINCE_VERSION)
|
||||||
wl_output::send_scale(resource->handle, m_scale);
|
sendScale(resource);
|
||||||
//TODO: send other required stuff as well
|
|
||||||
if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
|
if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
|
||||||
wl_output::send_done(resource->handle);
|
wl_output::send_done(resource->handle);
|
||||||
}
|
}
|
||||||
|
@ -171,20 +171,59 @@ public:
|
|||||||
// TODO
|
// TODO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OutputMode {
|
||||||
|
explicit OutputMode() = default;
|
||||||
|
explicit OutputMode(const QSize &resolution, int refreshRate = 60000)
|
||||||
|
: resolution(resolution), refreshRate(refreshRate)
|
||||||
|
{}
|
||||||
|
QSize resolution = QSize(1920, 1080);
|
||||||
|
int refreshRate = 60000; // In mHz
|
||||||
|
//TODO: flags (they're currently hard-coded)
|
||||||
|
|
||||||
|
// in mm
|
||||||
|
QSize physicalSizeForDpi(int dpi) { return (QSizeF(resolution) * 25.4 / dpi).toSize(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OutputData {
|
||||||
|
using Subpixel = QtWaylandServer::wl_output::subpixel;
|
||||||
|
using Transform = QtWaylandServer::wl_output::transform;
|
||||||
|
explicit OutputData() = default;
|
||||||
|
|
||||||
|
// for geometry event
|
||||||
|
QPoint position;
|
||||||
|
QSize physicalSize = QSize(0, 0); // means unknown physical size
|
||||||
|
QString make = "Make";
|
||||||
|
QString model = "Model";
|
||||||
|
Subpixel subpixel = Subpixel::subpixel_unknown;
|
||||||
|
Transform transform = Transform::transform_normal;
|
||||||
|
|
||||||
|
int scale = 1; // for scale event
|
||||||
|
OutputMode mode; // for mode event
|
||||||
|
};
|
||||||
|
|
||||||
class Output : public Global, public QtWaylandServer::wl_output
|
class Output : public Global, public QtWaylandServer::wl_output
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit Output(CoreCompositor *compositor, int scale = 1, int version = 2)
|
explicit Output(CoreCompositor *compositor, OutputData data = OutputData(), int version = 2)
|
||||||
: QtWaylandServer::wl_output(compositor->m_display, version)
|
: QtWaylandServer::wl_output(compositor->m_display, version)
|
||||||
, m_scale(scale)
|
, m_data(std::move(data))
|
||||||
, m_version(version)
|
, m_version(version)
|
||||||
{}
|
{}
|
||||||
void sendScale(int factor);
|
|
||||||
|
void send_geometry() = delete;
|
||||||
|
void sendGeometry();
|
||||||
|
void sendGeometry(Resource *resource); // Sends to only one client
|
||||||
|
|
||||||
void send_scale(int32_t factor) = delete;
|
void send_scale(int32_t factor) = delete;
|
||||||
void send_scale(struct ::wl_resource *resource, int32_t factor) = delete;
|
void sendScale(int factor);
|
||||||
|
void sendScale(Resource *resource); // Sends current scale to only one client
|
||||||
|
|
||||||
void sendDone();
|
void sendDone();
|
||||||
int m_scale = 1;
|
|
||||||
|
int scale() const { return m_data.scale; }
|
||||||
|
|
||||||
|
OutputData m_data;
|
||||||
int m_version = 1; // TODO: remove on libwayland upgrade
|
int m_version = 1; // TODO: remove on libwayland upgrade
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -39,7 +39,8 @@ DefaultCompositor::DefaultCompositor()
|
|||||||
// Legacy versions can override in separate tests by removing and adding.
|
// Legacy versions can override in separate tests by removing and adding.
|
||||||
add<WlCompositor>();
|
add<WlCompositor>();
|
||||||
add<SubCompositor>();
|
add<SubCompositor>();
|
||||||
add<Output>();
|
auto *output = add<Output>();
|
||||||
|
output->m_data.physicalSize = output->m_data.mode.physicalSizeForDpi(96);
|
||||||
add<Seat>(Seat::capability_pointer);
|
add<Seat>(Seat::capability_pointer);
|
||||||
add<XdgWmBase>();
|
add<XdgWmBase>();
|
||||||
add<Shm>();
|
add<Shm>();
|
||||||
|
@ -47,6 +47,7 @@ class DefaultCompositor : public CoreCompositor
|
|||||||
public:
|
public:
|
||||||
explicit DefaultCompositor();
|
explicit DefaultCompositor();
|
||||||
// Convenience functions
|
// Convenience functions
|
||||||
|
Output *output(int i = 0) { return getAll<Output>().value(i, nullptr); }
|
||||||
Surface *surface(int i = 0) { return get<WlCompositor>()->m_surfaces.value(i, nullptr); }
|
Surface *surface(int i = 0) { return get<WlCompositor>()->m_surfaces.value(i, nullptr); }
|
||||||
XdgSurface *xdgSurface(int i = 0) { return get<XdgWmBase>()->m_xdgSurfaces.value(i, nullptr); }
|
XdgSurface *xdgSurface(int i = 0) { return get<XdgWmBase>()->m_xdgSurfaces.value(i, nullptr); }
|
||||||
XdgToplevel *xdgToplevel(int i = 0) { return get<XdgWmBase>()->toplevel(i); }
|
XdgToplevel *xdgToplevel(int i = 0) { return get<XdgWmBase>()->toplevel(i); }
|
||||||
|
@ -183,43 +183,6 @@ void MockCompositor::sendDataDeviceLeave(const QSharedPointer<MockSurface> &surf
|
|||||||
processCommand(command);
|
processCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MockCompositor::sendAddOutput()
|
|
||||||
{
|
|
||||||
Command command = makeCommand(Impl::Compositor::sendAddOutput, m_compositor);
|
|
||||||
processCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MockCompositor::sendRemoveOutput(const QSharedPointer<MockOutput> &output)
|
|
||||||
{
|
|
||||||
Command command = makeCommand(Impl::Compositor::sendRemoveOutput, m_compositor);
|
|
||||||
command.parameters << QVariant::fromValue(output);
|
|
||||||
processCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MockCompositor::sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry)
|
|
||||||
{
|
|
||||||
Command command = makeCommand(Impl::Compositor::sendOutputGeometry, m_compositor);
|
|
||||||
command.parameters << QVariant::fromValue(output);
|
|
||||||
command.parameters << QVariant::fromValue(geometry);
|
|
||||||
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::sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size)
|
void MockCompositor::sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size)
|
||||||
{
|
{
|
||||||
Command command = makeCommand(Impl::Compositor::sendShellSurfaceConfigure, m_compositor);
|
Command command = makeCommand(Impl::Compositor::sendShellSurfaceConfigure, m_compositor);
|
||||||
|
@ -98,11 +98,6 @@ public:
|
|||||||
static void sendDataDeviceLeave(void *data, const QList<QVariant> ¶meters);
|
static void sendDataDeviceLeave(void *data, const QList<QVariant> ¶meters);
|
||||||
static void waitForStartDrag(void *data, const QList<QVariant> ¶meters);
|
static void waitForStartDrag(void *data, const QList<QVariant> ¶meters);
|
||||||
static void setOutputMode(void *compositor, const QList<QVariant> ¶meters);
|
static void setOutputMode(void *compositor, const QList<QVariant> ¶meters);
|
||||||
static void sendAddOutput(void *data, const QList<QVariant> ¶meters);
|
|
||||||
static void sendRemoveOutput(void *data, const QList<QVariant> ¶meters);
|
|
||||||
static void sendOutputGeometry(void *data, const QList<QVariant> ¶meters);
|
|
||||||
static void sendSurfaceEnter(void *data, const QList<QVariant> ¶meters);
|
|
||||||
static void sendSurfaceLeave(void *data, const QList<QVariant> ¶meters);
|
|
||||||
static void sendShellSurfaceConfigure(void *data, const QList<QVariant> ¶meters);
|
static void sendShellSurfaceConfigure(void *data, const QList<QVariant> ¶meters);
|
||||||
static void sendIviSurfaceConfigure(void *data, const QList<QVariant> ¶meters);
|
static void sendIviSurfaceConfigure(void *data, const QList<QVariant> ¶meters);
|
||||||
static void sendXdgToplevelV6Configure(void *data, const QList<QVariant> ¶meters);
|
static void sendXdgToplevelV6Configure(void *data, const QList<QVariant> ¶meters);
|
||||||
@ -239,9 +234,6 @@ public:
|
|||||||
void sendDataDeviceMotion(const QPoint &position);
|
void sendDataDeviceMotion(const QPoint &position);
|
||||||
void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface);
|
void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface);
|
||||||
void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
|
void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
|
||||||
void sendAddOutput();
|
|
||||||
void sendRemoveOutput(const QSharedPointer<MockOutput> &output);
|
|
||||||
void sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry);
|
|
||||||
void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
||||||
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
||||||
void sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size = QSize(0, 0));
|
void sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size = QSize(0, 0));
|
||||||
|
@ -33,37 +33,6 @@
|
|||||||
|
|
||||||
namespace Impl {
|
namespace Impl {
|
||||||
|
|
||||||
void Compositor::sendAddOutput(void *data, const QList<QVariant> ¶meters) {
|
|
||||||
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::sendRemoveOutput(void *data, const QList<QVariant> ¶meters) {
|
|
||||||
Compositor *compositor = static_cast<Compositor *>(data);
|
|
||||||
Q_ASSERT(compositor);
|
|
||||||
Output *output = resolveOutput(parameters.first());
|
|
||||||
Q_ASSERT(output);
|
|
||||||
bool wasRemoved = compositor->m_outputs.removeOne(output);
|
|
||||||
Q_ASSERT(wasRemoved);
|
|
||||||
delete output;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Compositor::sendOutputGeometry(void *data, const QList<QVariant> ¶meters)
|
|
||||||
{
|
|
||||||
Compositor *compositor = static_cast<Compositor *>(data);
|
|
||||||
Q_ASSERT(compositor);
|
|
||||||
Output *output = resolveOutput(parameters.first());
|
|
||||||
Q_ASSERT(output);
|
|
||||||
QRect geometry = parameters.at(1).toRect();
|
|
||||||
output->sendGeometryAndMode(geometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Compositor::setOutputMode(void *data, const QList<QVariant> ¶meters)
|
void Compositor::setOutputMode(void *data, const QList<QVariant> ¶meters)
|
||||||
{
|
{
|
||||||
Compositor *compositor = static_cast<Compositor *>(data);
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
@ -91,17 +60,6 @@ void Output::setCurrentMode(const QSize &size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::sendGeometryAndMode(const QRect &geometry)
|
|
||||||
{
|
|
||||||
m_size = geometry.size();
|
|
||||||
m_position = geometry.topLeft();
|
|
||||||
for (Resource *resource : resourceMap()) {
|
|
||||||
sendGeometry(resource);
|
|
||||||
sendCurrentMode(resource);
|
|
||||||
send_done(resource->handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
|
void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
|
||||||
{
|
{
|
||||||
sendGeometry(resource);
|
sendGeometry(resource);
|
||||||
|
@ -44,7 +44,6 @@ public:
|
|||||||
|
|
||||||
QSharedPointer<MockOutput> mockOutput() const { return m_mockOutput; }
|
QSharedPointer<MockOutput> mockOutput() const { return m_mockOutput; }
|
||||||
void setCurrentMode(const QSize &size);
|
void setCurrentMode(const QSize &size);
|
||||||
void sendGeometryAndMode(const QRect &geometry);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void output_bind_resource(Resource *resource) override;
|
void output_bind_resource(Resource *resource) override;
|
||||||
|
@ -35,34 +35,6 @@
|
|||||||
|
|
||||||
namespace Impl {
|
namespace Impl {
|
||||||
|
|
||||||
void Compositor::sendSurfaceEnter(void *data, const QList<QVariant> ¶meters)
|
|
||||||
{
|
|
||||||
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> ¶meters)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Compositor::sendShellSurfaceConfigure(void *data, const QList<QVariant> ¶meters)
|
void Compositor::sendShellSurfaceConfigure(void *data, const QList<QVariant> ¶meters)
|
||||||
{
|
{
|
||||||
Compositor *compositor = static_cast<Compositor *>(data);
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user