Add support for transient to ShellSurface(Interface)

On client side a setTransient method is added which wraps the semantic
of wl_shell_surface_set_transient.

On server side both set_transient and set_popup are implemented, though
for popup only the transient part is implemented. In particular the grab
is not yet handled and also no popup done is provided.

For the transient on server side the flags are ignored. Main reason is
that Qt does not use the flag, so testing whether it works is tricky
(needs a test application).

REVIEW: 125223
This commit is contained in:
Martin Gräßlin 2015-09-14 16:27:13 +02:00
parent 265504a088
commit 2bd8a8b98a
3 changed files with 181 additions and 9 deletions

View file

@ -47,6 +47,7 @@ private Q_SLOTS:
void testFullscreen();
void testMaximize();
void testToplevel();
void testTransient();
void testPing();
void testTitle();
void testWindowClass();
@ -334,6 +335,61 @@ void TestWaylandShell::testToplevel()
QVERIFY(!toplevelSpy.first().first().toBool());
}
void TestWaylandShell::testTransient()
{
using namespace KWayland::Server;
using namespace KWayland::Client;
QScopedPointer<Surface> s(m_compositor->createSurface());
QVERIFY(!s.isNull());
QVERIFY(s->isValid());
ShellSurface *surface = m_shell->createSurface(s.data(), m_shell);
QSignalSpy serverSurfaceSpy(m_shellInterface, &ShellInterface::surfaceCreated);
QVERIFY(serverSurfaceSpy.isValid());
QVERIFY(serverSurfaceSpy.wait());
ShellSurfaceInterface *serverSurface = serverSurfaceSpy.first().first().value<ShellSurfaceInterface*>();
QVERIFY(serverSurface);
QCOMPARE(serverSurface->isToplevel(), true);
QCOMPARE(serverSurface->isPopup(), false);
QCOMPARE(serverSurface->isTransient(), false);
QCOMPARE(serverSurface->transientFor(), QPointer<SurfaceInterface>());
QCOMPARE(serverSurface->transientOffset(), QPoint());
QSignalSpy transientSpy(serverSurface, &ShellSurfaceInterface::transientChanged);
QVERIFY(transientSpy.isValid());
QSignalSpy transientOffsetSpy(serverSurface, &ShellSurfaceInterface::transientOffsetChanged);
QVERIFY(transientOffsetSpy.isValid());
QSignalSpy transientForChangedSpy(serverSurface, &ShellSurfaceInterface::transientForChanged);
QVERIFY(transientForChangedSpy.isValid());
QScopedPointer<Surface> s2(m_compositor->createSurface());
m_shell->createSurface(s2.data(), m_shell);
serverSurfaceSpy.clear();
QVERIFY(serverSurfaceSpy.wait());
ShellSurfaceInterface *serverSurface2 = serverSurfaceSpy.first().first().value<ShellSurfaceInterface*>();
QVERIFY(serverSurface2 != serverSurface);
QVERIFY(serverSurface2);
surface->setTransient(s2.data(), QPoint(10, 20));
QVERIFY(transientSpy.wait());
QCOMPARE(transientSpy.count(), 1);
QCOMPARE(transientSpy.first().first().toBool(), true);
QCOMPARE(transientOffsetSpy.count(), 1);
QCOMPARE(transientOffsetSpy.first().first().toPoint(), QPoint(10, 20));
QCOMPARE(transientForChangedSpy.count(), 1);
QCOMPARE(serverSurface->isToplevel(), false);
QCOMPARE(serverSurface->isPopup(), false);
QCOMPARE(serverSurface->isTransient(), true);
QCOMPARE(serverSurface->transientFor(), QPointer<SurfaceInterface>(serverSurface2->surface()));
QCOMPARE(serverSurface->transientOffset(), QPoint(10, 20));
QCOMPARE(serverSurface2->isToplevel(), true);
QCOMPARE(serverSurface2->isPopup(), false);
QCOMPARE(serverSurface2->isTransient(), false);
QCOMPARE(serverSurface2->transientFor(), QPointer<SurfaceInterface>());
QCOMPARE(serverSurface2->transientOffset(), QPoint());
}
void TestWaylandShell::testPing()
{
using namespace KWayland::Server;

View file

@ -78,9 +78,13 @@ public:
enum class WindowMode {
Fullscreen,
Toplevel,
Maximized
Maximized,
Transient,
Popup
};
WindowMode windowMode = WindowMode::Toplevel;
QPoint transientOffset;
QPointer<SurfaceInterface> transientFor;
void setWindowMode(WindowMode newWindowMode);
private:
@ -274,13 +278,15 @@ void ShellSurfaceInterface::Private::setToplevelCallback(wl_client *client, wl_r
void ShellSurfaceInterface::Private::setTransientCallback(wl_client *client, wl_resource *resource, wl_resource *parent,
int32_t x, int32_t y, uint32_t flags)
{
Q_UNUSED(parent)
Q_UNUSED(x)
Q_UNUSED(y)
Q_UNUSED(flags)
auto s = cast<Private>(resource);
Q_ASSERT(client == *s->client);
// TODO: implement
s->transientFor = QPointer<SurfaceInterface>(SurfaceInterface::get(parent));
s->transientOffset = QPoint(x, y);
s->setWindowMode(WindowMode::Transient);
// TODO: flags
emit s->q_func()->transientOffsetChanged(s->transientOffset);
emit s->q_func()->transientForChanged();
}
void ShellSurfaceInterface::Private::setFullscreenCallback(wl_client *client, wl_resource *resource, uint32_t method,
@ -312,6 +318,13 @@ void ShellSurfaceInterface::Private::setWindowMode(WindowMode newWindowMode)
if (oldWindowMode == WindowMode::Maximized || newWindowMode == WindowMode::Maximized) {
emit q->maximizedChanged(windowMode == WindowMode::Maximized);
}
if (oldWindowMode == WindowMode::Popup || newWindowMode == WindowMode::Popup) {
emit q->popupChanged(windowMode == WindowMode::Popup);
emit q->transientChanged(windowMode == WindowMode::Popup || windowMode == WindowMode::Transient);
}
if (oldWindowMode == WindowMode::Transient || newWindowMode == WindowMode::Transient) {
emit q->transientChanged(windowMode == WindowMode::Popup || windowMode == WindowMode::Transient);
}
}
void ShellSurfaceInterface::Private::setPopupCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial,
@ -319,13 +332,16 @@ void ShellSurfaceInterface::Private::setPopupCallback(wl_client *client, wl_reso
{
Q_UNUSED(seat)
Q_UNUSED(serial)
Q_UNUSED(parent)
Q_UNUSED(x)
Q_UNUSED(y)
Q_UNUSED(flags)
auto s = cast<Private>(resource);
Q_ASSERT(client == *s->client);
// TODO: implement
// TODO: what about seat and serial?
s->transientFor = QPointer<SurfaceInterface>(SurfaceInterface::get(parent));
s->transientOffset = QPoint(x, y);
s->setWindowMode(WindowMode::Popup);
// TODO: flags
emit s->q_func()->transientOffsetChanged(s->transientOffset);
emit s->q_func()->transientForChanged();
}
void ShellSurfaceInterface::Private::setMaximizedCallback(wl_client *client, wl_resource *resource, wl_resource *output)
@ -405,6 +421,30 @@ bool ShellSurfaceInterface::isMaximized() const {
return d->windowMode == Private::WindowMode::Maximized;
}
bool ShellSurfaceInterface::isPopup() const
{
Q_D();
return d->windowMode == Private::WindowMode::Popup;
}
bool ShellSurfaceInterface::isTransient() const
{
Q_D();
return isPopup() || d->windowMode == Private::WindowMode::Transient;
}
QPoint ShellSurfaceInterface::transientOffset() const
{
Q_D();
return d->transientOffset;
}
QPointer< SurfaceInterface > ShellSurfaceInterface::transientFor() const
{
Q_D();
return d->transientFor;
}
ShellSurfaceInterface::Private *ShellSurfaceInterface::d_func() const
{
return reinterpret_cast<ShellSurfaceInterface::Private*>(d.data());

View file

@ -97,6 +97,25 @@ class KWAYLANDSERVER_EXPORT ShellSurfaceInterface : public Resource
* Whether the window is maximized.
**/
Q_PROPERTY(bool maximized READ isMaximized NOTIFY maximizedChanged)
/**
* Whether the ShellSurfaceInterface is a popup for another SurfaceInterface.
*
* Popup implies transient.
* @since 5.5
**/
Q_PROPERTY(bool popup READ isPopup NOTIFY popupChanged)
/**
* Whether the ShellSurfaceInterface is a transient for another SurfaceInterface.
*
* Popup implies transient.
* @since 5.5
**/
Q_PROPERTY(bool transient READ isTransient NOTIFY transientChanged)
/**
* Offset of the upper left corner in the parent SurfaceInterface's coordinate system.
* @since 5.5
**/
Q_PROPERTY(QPoint transientOffset READ transientOffset NOTIFY transientOffsetChanged)
public:
virtual ~ShellSurfaceInterface();
@ -144,6 +163,47 @@ public:
bool isFullscreen() const;
bool isToplevel() const;
bool isMaximized() const;
/**
* @returns @c true if the ShellSurfaceInterface is a popup.
* @see isTransient
* @see transientOffset
* @see transientFor
* @since 5.5
**/
bool isPopup() const;
/**
* @returns @c true if the ShellSurfaceInterface is a transient or popup for another SurfaceInterface.
* @see isPopup
* @see transientOffset
* @see transientFor
* @since 5.5
**/
bool isTransient() const;
/**
* In case the ShellSurfaceInterface is a transient this is the offset of the ShellSurfaceInterface
* in the coordinate system of the SurfaceInterface this surface is a transient for.
*
* @returns offset in parent coordinate system.
* @see isTransient
* @see transientFor
* @since 5.5
**/
QPoint transientOffset() const;
/**
* The SurfaceInterface for which this ShellSurfaceInterface is a transient.
* This is only relevant if the ShellSurfaceInterface is either a transient or a
* popup.
*
* The transientOffset is in the local coordinate system of the SurfaceInterface
* returned by this method.
*
* @returns The SurfaceInterface for which this Surface is a transient
* @see isTransient
* @see isPopup
* @see transientOffset
* @since 5.5
**/
QPointer<SurfaceInterface> transientFor() const;
Q_SIGNALS:
/**
@ -168,6 +228,22 @@ Q_SIGNALS:
void fullscreenChanged(bool);
void toplevelChanged(bool);
void maximizedChanged(bool);
/**
* @since 5.5
**/
void popupChanged(bool);
/**
* @since 5.5
**/
void transientChanged(bool);
/**
* @since 5.5
**/
void transientOffsetChanged(const QPoint&);
/**
* @since 5.5
**/
void transientForChanged();
private:
friend class ShellInterface;