Add support for wl_shell_surface::set_popup and popup_done

Summary:
This extends the client side API to support creating popup ShellSurface
windows and the server side API to send out the popup_done request.

This is needed to properly support popup windows (e.g. context menus)
in KWin.

Reviewers: #plasma_on_wayland, #frameworks, #kwin

Subscribers: plasma-devel

Tags: #plasma_on_wayland, #frameworks

Differential Revision: https://phabricator.kde.org/D5174
This commit is contained in:
Martin Gräßlin 2017-03-25 17:42:08 +01:00
parent a1c8ea01d7
commit bccb1f4cba
3 changed files with 90 additions and 0 deletions

View file

@ -55,6 +55,7 @@ private Q_SLOTS:
void testToplevel(); void testToplevel();
void testTransient_data(); void testTransient_data();
void testTransient(); void testTransient();
void testTransientPopup();
void testPing(); void testPing();
void testTitle(); void testTitle();
void testWindowClass(); void testWindowClass();
@ -475,6 +476,72 @@ void TestWaylandShell::testTransient()
QVERIFY(serverSurface2->acceptsKeyboardFocus()); QVERIFY(serverSurface2->acceptsKeyboardFocus());
} }
void TestWaylandShell::testTransientPopup()
{
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());
QVERIFY(serverSurface->acceptsKeyboardFocus());
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);
QVERIFY(serverSurface2->acceptsKeyboardFocus());
// TODO: proper serial checking
surface->setTransientPopup(s2.data(), m_seat, 1, 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(), true);
QCOMPARE(serverSurface->isTransient(), true);
QCOMPARE(serverSurface->transientFor(), QPointer<SurfaceInterface>(serverSurface2->surface()));
QCOMPARE(serverSurface->transientOffset(), QPoint(10, 20));
// TODO: honor the flag
QCOMPARE(serverSurface->acceptsKeyboardFocus(), false);
QCOMPARE(serverSurface2->isToplevel(), true);
QCOMPARE(serverSurface2->isPopup(), false);
QCOMPARE(serverSurface2->isTransient(), false);
QCOMPARE(serverSurface2->transientFor(), QPointer<SurfaceInterface>());
QCOMPARE(serverSurface2->transientOffset(), QPoint());
// send popup done
QSignalSpy popupDoneSpy(surface, &ShellSurface::popupDone);
QVERIFY(popupDoneSpy.isValid());
serverSurface->popupDone();
QVERIFY(popupDoneSpy.wait());
}
void TestWaylandShell::testPing() void TestWaylandShell::testPing()
{ {
using namespace KWayland::Server; using namespace KWayland::Server;

View file

@ -379,6 +379,9 @@ void ShellSurfaceInterface::Private::setPopupCallback(wl_client *client, wl_reso
emit s->q_func()->transientChanged(!s->transientFor.isNull()); emit s->q_func()->transientChanged(!s->transientFor.isNull());
emit s->q_func()->transientOffsetChanged(s->transientOffset); emit s->q_func()->transientOffsetChanged(s->transientOffset);
emit s->q_func()->transientForChanged(); emit s->q_func()->transientForChanged();
// we ignore the flags as Qt requests keyboard focus for popups
// if we would honor the flag this could break compositors
// compare QtWayland (5.6), file qwaylandwlshellsurface.cpp:208
s->setAcceptsFocus(WL_SHELL_SURFACE_TRANSIENT_INACTIVE); s->setAcceptsFocus(WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
} }
@ -449,6 +452,14 @@ bool ShellSurfaceInterface::acceptsKeyboardFocus() const
return d->acceptsKeyboardFocus; return d->acceptsKeyboardFocus;
} }
void ShellSurfaceInterface::popupDone()
{
Q_D();
if (isPopup() && d->resource) {
wl_shell_surface_send_popup_done(d->resource);
}
}
QPointer< SurfaceInterface > ShellSurfaceInterface::transientFor() const QPointer< SurfaceInterface > ShellSurfaceInterface::transientFor() const
{ {
Q_D(); Q_D();

View file

@ -231,6 +231,18 @@ public:
**/ **/
bool acceptsKeyboardFocus() const; bool acceptsKeyboardFocus() const;
/**
* Sends a popup done event to the shell surface.
* This is only relevant for popup windows. It indicates that the popup grab
* got canceled. This happens when e.g. the user clicks outside of any surface
* of the same client as this ShellSurfaceInterface. It is the task of the
* compositor to send the popupDone event appropriately.
*
* @see isPopup
* @since 5.33
**/
void popupDone();
Q_SIGNALS: Q_SIGNALS:
/** /**
* Emitted whenever the title changes. * Emitted whenever the title changes.