Merge branch 'Plasma/5.18' into Plasma/5.19

This commit is contained in:
Vlad Zahorodnii 2020-06-25 16:13:57 +03:00
commit 578ede2dd7
2 changed files with 72 additions and 0 deletions

View file

@ -60,6 +60,7 @@ private Q_SLOTS:
void testCaptionWmName(); void testCaptionWmName();
void testCaptionMultipleWindows(); void testCaptionMultipleWindows();
void testFullscreenWindowGroups(); void testFullscreenWindowGroups();
void testActivateFocusedWindow();
}; };
void X11ClientTest::initTestCase() void X11ClientTest::initTestCase()
@ -1000,5 +1001,71 @@ void X11ClientTest::testFullscreenWindowGroups()
QTRY_COMPARE(client->layer(), ActiveLayer); QTRY_COMPARE(client->layer(), ActiveLayer);
} }
void X11ClientTest::testActivateFocusedWindow()
{
// The window manager may call XSetInputFocus() on a window that already has focus, in which
// case no FocusIn event will be generated and the window won't be marked as active. This test
// verifies that we handle that subtle case properly.
QScopedPointer<xcb_connection_t, XcbConnectionDeleter> connection(xcb_connect(nullptr, nullptr));
QVERIFY(!xcb_connection_has_error(connection.data()));
QSignalSpy windowCreatedSpy(workspace(), &Workspace::clientAdded);
QVERIFY(windowCreatedSpy.isValid());
const QRect windowGeometry(0, 0, 100, 200);
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
// Create the first test window.
const xcb_window_t window1 = xcb_generate_id(connection.data());
xcb_create_window(connection.data(), XCB_COPY_FROM_PARENT, window1, rootWindow(),
windowGeometry.x(), windowGeometry.y(),
windowGeometry.width(), windowGeometry.height(),
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
xcb_icccm_set_wm_normal_hints(connection.data(), window1, &hints);
xcb_change_property(connection.data(), XCB_PROP_MODE_REPLACE, window1,
atoms->wm_client_leader, XCB_ATOM_WINDOW, 32, 1, &window1);
xcb_map_window(connection.data(), window1);
xcb_flush(connection.data());
QVERIFY(windowCreatedSpy.wait());
X11Client *client1 = windowCreatedSpy.first().first().value<X11Client *>();
QVERIFY(client1);
QCOMPARE(client1->windowId(), window1);
QCOMPARE(client1->isActive(), true);
// Create the second test window.
const xcb_window_t window2 = xcb_generate_id(connection.data());
xcb_create_window(connection.data(), XCB_COPY_FROM_PARENT, window2, rootWindow(),
windowGeometry.x(), windowGeometry.y(),
windowGeometry.width(), windowGeometry.height(),
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
xcb_icccm_set_wm_normal_hints(connection.data(), window2, &hints);
xcb_change_property(connection.data(), XCB_PROP_MODE_REPLACE, window2,
atoms->wm_client_leader, XCB_ATOM_WINDOW, 32, 1, &window2);
xcb_map_window(connection.data(), window2);
xcb_flush(connection.data());
QVERIFY(windowCreatedSpy.wait());
X11Client *client2 = windowCreatedSpy.last().first().value<X11Client *>();
QVERIFY(client2);
QCOMPARE(client2->windowId(), window2);
QCOMPARE(client2->isActive(), true);
// When the second test window is destroyed, the window manager will attempt to activate the
// next client in the focus chain, which is the first window.
xcb_set_input_focus(connection.data(), XCB_INPUT_FOCUS_POINTER_ROOT, window1, XCB_CURRENT_TIME);
xcb_destroy_window(connection.data(), window2);
xcb_flush(connection.data());
QVERIFY(Test::waitForWindowDestroyed(client2));
QVERIFY(client1->isActive());
// Destroy the first test window.
xcb_destroy_window(connection.data(), window1);
xcb_flush(connection.data());
QVERIFY(Test::waitForWindowDestroyed(client1));
}
WAYLANDTEST_MAIN(X11ClientTest) WAYLANDTEST_MAIN(X11ClientTest)
#include "x11_client_test.moc" #include "x11_client_test.moc"

View file

@ -2025,6 +2025,11 @@ void X11Client::setOnAllActivities(bool on)
*/ */
void X11Client::takeFocus() void X11Client::takeFocus()
{ {
// Force a FocusIn event if the window is already focused but inactive.
Xcb::CurrentInput currentInput;
if (!currentInput.isNull() && currentInput.window() == window())
workspace()->focusToNull();
if (rules()->checkAcceptFocus(info->input())) if (rules()->checkAcceptFocus(info->input()))
m_client.focus(); m_client.focus();
else else