Cancel popup if the user clicked window decoration of parent window
Summary: So far the window decoration was not considered and e.g. right clicking the window decoration resulted in two open popups - one by KWin and one by the application. This change addresses the problem by ensuring the popup gets cancelled if the decoration is clicked. It's considered not being part of the window. Test Plan: Added test case which fails without the change Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D5388
This commit is contained in:
parent
d966302de7
commit
3259d5e113
2 changed files with 89 additions and 1 deletions
|
@ -37,6 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include <KWayland/Client/pointer.h>
|
#include <KWayland/Client/pointer.h>
|
||||||
#include <KWayland/Client/shell.h>
|
#include <KWayland/Client/shell.h>
|
||||||
#include <KWayland/Client/seat.h>
|
#include <KWayland/Client/seat.h>
|
||||||
|
#include <KWayland/Client/server_decoration.h>
|
||||||
#include <KWayland/Client/shm_pool.h>
|
#include <KWayland/Client/shm_pool.h>
|
||||||
#include <KWayland/Client/surface.h>
|
#include <KWayland/Client/surface.h>
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ private Q_SLOTS:
|
||||||
void testCursorImage();
|
void testCursorImage();
|
||||||
void testEffectOverrideCursorImage();
|
void testEffectOverrideCursorImage();
|
||||||
void testPopup();
|
void testPopup();
|
||||||
|
void testDecoCancelsPopup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void render(KWayland::Client::Surface *surface, const QSize &size = QSize(100, 50));
|
void render(KWayland::Client::Surface *surface, const QSize &size = QSize(100, 50));
|
||||||
|
@ -108,7 +110,7 @@ void PointerInputTest::initTestCase()
|
||||||
|
|
||||||
void PointerInputTest::init()
|
void PointerInputTest::init()
|
||||||
{
|
{
|
||||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat));
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::Decoration));
|
||||||
QVERIFY(Test::waitForWaylandPointer());
|
QVERIFY(Test::waitForWaylandPointer());
|
||||||
m_compositor = Test::waylandCompositor();
|
m_compositor = Test::waylandCompositor();
|
||||||
m_shell = Test::waylandShell();
|
m_shell = Test::waylandShell();
|
||||||
|
@ -1045,6 +1047,84 @@ void PointerInputTest::testPopup()
|
||||||
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++);
|
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PointerInputTest::testDecoCancelsPopup()
|
||||||
|
{
|
||||||
|
// this test verifies that clicking the window decoration of parent window
|
||||||
|
// cancels the popup
|
||||||
|
|
||||||
|
// first create a parent surface
|
||||||
|
using namespace KWayland::Client;
|
||||||
|
auto pointer = m_seat->createPointer(m_seat);
|
||||||
|
QVERIFY(pointer);
|
||||||
|
QVERIFY(pointer->isValid());
|
||||||
|
QSignalSpy enteredSpy(pointer, &Pointer::entered);
|
||||||
|
QVERIFY(enteredSpy.isValid());
|
||||||
|
QSignalSpy leftSpy(pointer, &Pointer::left);
|
||||||
|
QVERIFY(leftSpy.isValid());
|
||||||
|
QSignalSpy buttonStateChangedSpy(pointer, &Pointer::buttonStateChanged);
|
||||||
|
QVERIFY(buttonStateChangedSpy.isValid());
|
||||||
|
QSignalSpy motionSpy(pointer, &Pointer::motion);
|
||||||
|
QVERIFY(motionSpy.isValid());
|
||||||
|
|
||||||
|
Cursor::setPos(800, 800);
|
||||||
|
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
|
||||||
|
QVERIFY(clientAddedSpy.isValid());
|
||||||
|
Surface *surface = Test::createSurface(m_compositor);
|
||||||
|
QVERIFY(surface);
|
||||||
|
ShellSurface *shellSurface = Test::createShellSurface(surface, surface);
|
||||||
|
QVERIFY(shellSurface);
|
||||||
|
|
||||||
|
auto deco = Test::waylandServerSideDecoration()->create(surface, surface);
|
||||||
|
QSignalSpy decoSpy(deco, &ServerSideDecoration::modeChanged);
|
||||||
|
QVERIFY(decoSpy.isValid());
|
||||||
|
QVERIFY(decoSpy.wait());
|
||||||
|
deco->requestMode(ServerSideDecoration::Mode::Server);
|
||||||
|
QVERIFY(decoSpy.wait());
|
||||||
|
QCOMPARE(deco->mode(), ServerSideDecoration::Mode::Server);
|
||||||
|
render(surface);
|
||||||
|
QVERIFY(clientAddedSpy.wait());
|
||||||
|
AbstractClient *window = workspace()->activeClient();
|
||||||
|
QVERIFY(window);
|
||||||
|
QCOMPARE(window->hasPopupGrab(), false);
|
||||||
|
QVERIFY(window->isDecorated());
|
||||||
|
|
||||||
|
// move pointer into window
|
||||||
|
QVERIFY(!window->geometry().contains(QPoint(800, 800)));
|
||||||
|
Cursor::setPos(window->geometry().center());
|
||||||
|
QVERIFY(enteredSpy.wait());
|
||||||
|
// click inside window to create serial
|
||||||
|
quint32 timestamp = 0;
|
||||||
|
kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, timestamp++);
|
||||||
|
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++);
|
||||||
|
QVERIFY(buttonStateChangedSpy.wait());
|
||||||
|
|
||||||
|
// now create the popup surface
|
||||||
|
Surface *popupSurface = Test::createSurface(m_compositor);
|
||||||
|
QVERIFY(popupSurface);
|
||||||
|
ShellSurface *popupShellSurface = Test::createShellSurface(popupSurface, popupSurface);
|
||||||
|
QVERIFY(popupShellSurface);
|
||||||
|
QSignalSpy popupDoneSpy(popupShellSurface, &ShellSurface::popupDone);
|
||||||
|
QVERIFY(popupDoneSpy.isValid());
|
||||||
|
// TODO: proper serial
|
||||||
|
popupShellSurface->setTransientPopup(surface, m_seat, 0, QPoint(80, 20));
|
||||||
|
render(popupSurface);
|
||||||
|
QVERIFY(clientAddedSpy.wait());
|
||||||
|
auto popupClient = clientAddedSpy.last().first().value<ShellClient*>();
|
||||||
|
QVERIFY(popupClient);
|
||||||
|
QVERIFY(popupClient != window);
|
||||||
|
QCOMPARE(window, workspace()->activeClient());
|
||||||
|
QCOMPARE(popupClient->transientFor(), window);
|
||||||
|
QCOMPARE(popupClient->pos(), window->pos() + window->clientPos() + QPoint(80, 20));
|
||||||
|
QCOMPARE(popupClient->hasPopupGrab(), true);
|
||||||
|
|
||||||
|
// let's move the pointer into the center of the deco
|
||||||
|
Cursor::setPos(window->geometry().center().x(), window->y() + (window->height() - window->clientSize().height()) / 2);
|
||||||
|
|
||||||
|
kwinApp()->platform()->pointerButtonPressed(BTN_RIGHT, timestamp++);
|
||||||
|
QVERIFY(popupDoneSpy.wait());
|
||||||
|
kwinApp()->platform()->pointerButtonReleased(BTN_RIGHT, timestamp++);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WAYLANDTEST_MAIN(KWin::PointerInputTest)
|
WAYLANDTEST_MAIN(KWin::PointerInputTest)
|
||||||
|
|
|
@ -65,6 +65,14 @@ bool PopupInputFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton)
|
||||||
// filter out this press
|
// filter out this press
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (pointerFocus && pointerFocus->isDecorated()) {
|
||||||
|
// test whether it is on the decoration
|
||||||
|
const QRect clientRect = QRect(pointerFocus->clientPos(), pointerFocus->clientSize()).translated(pointerFocus->pos());
|
||||||
|
if (!clientRect.contains(event->globalPos())) {
|
||||||
|
cancelPopups();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue