diff --git a/autotests/client/test_plasmashell.cpp b/autotests/client/test_plasmashell.cpp --- a/autotests/client/test_plasmashell.cpp +++ b/autotests/client/test_plasmashell.cpp @@ -50,6 +50,7 @@ void testPanelBehavior_data(); void testPanelBehavior(); void testAutoHidePanel(); + void testPanelTakesFocus(); void testDisconnect(); void testWhileDestroying(); @@ -396,6 +397,29 @@ QVERIFY(errorSpy.wait()); } +void TestPlasmaShell::testPanelTakesFocus() +{ + // this test verifies that whether a panel wants to take focus is passed through correctly + QSignalSpy plasmaSurfaceCreatedSpy(m_plasmaShellInterface, &PlasmaShellInterface::surfaceCreated); + QVERIFY(plasmaSurfaceCreatedSpy.isValid()); + QScopedPointer s(m_compositor->createSurface()); + QScopedPointer ps(m_plasmaShell->createSurface(s.data())); + ps->setRole(PlasmaShellSurface::Role::Panel); + QVERIFY(plasmaSurfaceCreatedSpy.wait()); + QCOMPARE(plasmaSurfaceCreatedSpy.count(), 1); + auto sps = plasmaSurfaceCreatedSpy.first().first().value(); + QVERIFY(sps); + QCOMPARE(sps->role(), PlasmaShellSurfaceInterface::Role::Panel); + QCOMPARE(sps->panelTakesFocus(), false); + + ps->setPanelTakesFocus(true); + m_connection->flush(); + QTRY_COMPARE(sps->panelTakesFocus(), true); + ps->setPanelTakesFocus(false); + m_connection->flush(); + QTRY_COMPARE(sps->panelTakesFocus(), false); +} + void TestPlasmaShell::testDisconnect() { // this test verifies that a disconnect cleans up diff --git a/src/client/plasmashell.h b/src/client/plasmashell.h --- a/src/client/plasmashell.h +++ b/src/client/plasmashell.h @@ -317,6 +317,17 @@ **/ void requestShowAutoHidingPanel(); + /** + * Set whether a PlasmaShellSurface with Role Panel should get focus or not. + * + * By default a Panel does not take focus. With this request the compositor + * can be instructed to also pass focus to a panel + * + * @param takesFocus Set to @c true if the Panel should gain focus. + * @since 5.28 + **/ + void setPanelTakesFocus(bool takesFocus); + Q_SIGNALS: /** * Emitted when the compositor hided an auto hiding panel. diff --git a/src/client/plasmashell.cpp b/src/client/plasmashell.cpp --- a/src/client/plasmashell.cpp +++ b/src/client/plasmashell.cpp @@ -332,5 +332,10 @@ org_kde_plasma_surface_panel_auto_hide_show(d->surface); } +void PlasmaShellSurface::setPanelTakesFocus(bool takesFocus) +{ + org_kde_plasma_surface_set_panel_takes_focus(d->surface, takesFocus); +} + } } diff --git a/src/client/protocols/plasma-shell.xml b/src/client/protocols/plasma-shell.xml --- a/src/client/protocols/plasma-shell.xml +++ b/src/client/protocols/plasma-shell.xml @@ -362,6 +362,17 @@ + + + By default a org_kde_plasma_surface with role panel does not take focus and cannot be + activated. With this request the compositor can be instructed to pass focus also to this + org_kde_plasma_surface. + + For org_kde_plasma_surface with another role than panel the request does not have any effect. + + + + An auto-hiding panel got hidden by the compositor. diff --git a/src/server/plasmashell_interface.h b/src/server/plasmashell_interface.h --- a/src/server/plasmashell_interface.h +++ b/src/server/plasmashell_interface.h @@ -160,6 +160,16 @@ void showAutoHidingPanel(); /** + * Whether a PlasmaShellSurfaceInterface with Role Panel wants to have focus. + * + * By default a Panel does not get focus, but the PlasmaShellSurfaceInterface can + * request that it wants to have focus. The compositor can use this information to + * pass focus to the panel. + * @since 5.28 + **/ + bool panelTakesFocus() const; + + /** * @returns The PlasmaShellSurfaceInterface for the @p native resource. * @since 5.5 **/ diff --git a/src/server/plasmashell_interface.cpp b/src/server/plasmashell_interface.cpp --- a/src/server/plasmashell_interface.cpp +++ b/src/server/plasmashell_interface.cpp @@ -76,6 +76,7 @@ bool m_positionSet = false; PanelBehavior m_panelBehavior = PanelBehavior::AlwaysVisible; bool m_skipTaskbar = false; + bool panelTakesFocus = false; private: // interface callbacks @@ -86,6 +87,7 @@ static void setSkipTaskbarCallback(wl_client *client, wl_resource *resource, uint32_t skip); static void panelAutoHideHideCallback(wl_client *client, wl_resource *resource); static void panelAutoHideShowCallback(wl_client *client, wl_resource *resource); + static void panelTakesFocusCallback(wl_client *client, wl_resource *resource, uint32_t takesFocus); void setPosition(const QPoint &globalPos); void setRole(uint32_t role); @@ -162,7 +164,8 @@ setPanelBehaviorCallback, setSkipTaskbarCallback, panelAutoHideHideCallback, - panelAutoHideShowCallback + panelAutoHideShowCallback, + panelTakesFocusCallback }; #endif @@ -296,6 +299,13 @@ emit s->q_func()->panelAutoHideShowRequested(); } +void PlasmaShellSurfaceInterface::Private::panelTakesFocusCallback(wl_client *client, wl_resource *resource, uint32_t takesFocus) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + s->panelTakesFocus = takesFocus; +} + void PlasmaShellSurfaceInterface::Private::setPanelBehavior(org_kde_plasma_surface_panel_behavior behavior) { PanelBehavior newBehavior = PanelBehavior::AlwaysVisible; @@ -369,6 +379,12 @@ org_kde_plasma_surface_send_auto_hidden_panel_shown(d->resource); } +bool PlasmaShellSurfaceInterface::panelTakesFocus() const +{ + Q_D(); + return d->panelTakesFocus; +} + PlasmaShellSurfaceInterface *PlasmaShellSurfaceInterface::get(wl_resource *native) { return Private::get(native);