diff --git a/abstract_client.cpp b/abstract_client.cpp index 356baf4f11..41e75c5503 100644 --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -1634,4 +1634,9 @@ QRect AbstractClient::inputGeometry() const return Toplevel::inputGeometry(); } +bool AbstractClient::dockWantsInput() const +{ + return false; +} + } diff --git a/abstract_client.h b/abstract_client.h index bfe5f6d3e8..b78f84ca61 100644 --- a/abstract_client.h +++ b/abstract_client.h @@ -416,6 +416,18 @@ public: virtual const WindowRules* rules() const = 0; virtual void takeFocus() = 0; virtual bool wantsInput() const = 0; + /** + * Whether a dock window wants input. + * + * By default KWin doesn't pass focus to a dock window unless a force activate + * request is provided. + * + * This method allows to have dock windows take focus also through flags set on + * the window. + * + * The default implementation returns @c false. + **/ + virtual bool dockWantsInput() const; void checkWorkspacePosition(QRect oldGeometry = QRect(), int oldDesktop = -2, QRect oldClientGeometry = QRect()); virtual xcb_timestamp_t userTime() const; virtual void updateWindowRules(Rules::Types selection) = 0; diff --git a/activation.cpp b/activation.cpp index b57fda886b..7f2a975522 100644 --- a/activation.cpp +++ b/activation.cpp @@ -371,8 +371,13 @@ void Workspace::takeActivity(AbstractClient* c, ActivityFlags flags) } cancelDelayFocus(); } - if (!flags.testFlag(ActivityFocusForce) && (c->isDock() || c->isSplash())) - flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced + if (!flags.testFlag(ActivityFocusForce) && (c->isDock() || c->isSplash())) { + // toplevel menus and dock windows don't take focus if not forced + // and don't have a flag that they take focus + if (!c->dockWantsInput()) { + flags &= ~ActivityFocus; + } + } if (c->isShade()) { if (c->wantsInput() && (flags & ActivityFocus)) { // client cannot accept focus, but at least the window should be active (window menu, et. al. ) diff --git a/autotests/integration/plasma_surface_test.cpp b/autotests/integration/plasma_surface_test.cpp index 9b96dadfc9..05436c88c9 100644 --- a/autotests/integration/plasma_surface_test.cpp +++ b/autotests/integration/plasma_surface_test.cpp @@ -59,6 +59,8 @@ private Q_SLOTS: void testOSDPlacement(); void testPanelTypeHasStrut_data(); void testPanelTypeHasStrut(); + void testPanelActivate_data(); + void testPanelActivate(); private: ConnectionThread *m_connection = nullptr; @@ -368,5 +370,36 @@ void PlasmaSurfaceTest::testPanelWindowsCanCover() QCOMPARE(stackingOrder.last(), panel); } +void PlasmaSurfaceTest::testPanelActivate_data() +{ + QTest::addColumn("wantsFocus"); + QTest::addColumn("active"); + + QTest::newRow("no focus") << false << false; + QTest::newRow("focus") << true << true; +} + +void PlasmaSurfaceTest::testPanelActivate() +{ + QScopedPointer surface(Test::createSurface()); + QVERIFY(!surface.isNull()); + QScopedPointer shellSurface(Test::createShellSurface(Test::ShellSurfaceType::WlShell, surface.data())); + QVERIFY(!shellSurface.isNull()); + QScopedPointer plasmaSurface(m_plasmaShell->createSurface(surface.data())); + QVERIFY(!plasmaSurface.isNull()); + plasmaSurface->setRole(PlasmaShellSurface::Role::Panel); + QFETCH(bool, wantsFocus); + plasmaSurface->setPanelTakesFocus(wantsFocus); + + auto panel = Test::renderAndWaitForShown(surface.data(), QSize(100, 200), Qt::blue); + + QVERIFY(panel); + QCOMPARE(panel->windowType(), NET::Dock); + QVERIFY(panel->isDock()); + QFETCH(bool, active); + QCOMPARE(panel->dockWantsInput(), active); + QCOMPARE(panel->isActive(), active); +} + WAYLANDTEST_MAIN(PlasmaSurfaceTest) #include "plasma_surface_test.moc" diff --git a/shell_client.cpp b/shell_client.cpp index dbdfd1dc70..dbf0b4da55 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -1373,4 +1373,14 @@ void ShellClient::showOnScreenEdge() } } +bool ShellClient::dockWantsInput() const +{ + if (m_plasmaShellSurface) { + if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Panel) { + return m_plasmaShellSurface->panelTakesFocus(); + } + } + return false; +} + } diff --git a/shell_client.h b/shell_client.h index 7df18fc1ea..e1c1d790fc 100644 --- a/shell_client.h +++ b/shell_client.h @@ -96,6 +96,7 @@ public: bool userCanSetFullScreen() const override; bool userCanSetNoBorder() const override; bool wantsInput() const override; + bool dockWantsInput() const override; using AbstractClient::resizeWithChecks; void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) override; using AbstractClient::setGeometry;