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 @@ -49,6 +49,7 @@ void testSkipTaskbar(); void testPanelBehavior_data(); void testPanelBehavior(); + void testAutoHidePanel(); void testDisconnect(); void testWhileDestroying(); @@ -341,6 +342,60 @@ QCOMPARE(sps->panelBehavior(), PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible); } +void TestPlasmaShell::testAutoHidePanel() +{ + // this test verifies that auto-hiding panels work 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); + ps->setPanelBehavior(PlasmaShellSurface::PanelBehavior::AutoHide); + QVERIFY(plasmaSurfaceCreatedSpy.wait()); + QCOMPARE(plasmaSurfaceCreatedSpy.count(), 1); + auto sps = plasmaSurfaceCreatedSpy.first().first().value(); + QVERIFY(sps); + QCOMPARE(sps->panelBehavior(), PlasmaShellSurfaceInterface::PanelBehavior::AutoHide); + + QSignalSpy autoHideRequestedSpy(sps, &PlasmaShellSurfaceInterface::panelAutoHideHideRequested); + QVERIFY(autoHideRequestedSpy.isValid()); + QSignalSpy autoHideShowRequestedSpy(sps, &PlasmaShellSurfaceInterface::panelAutoHideShowRequested); + QVERIFY(autoHideShowRequestedSpy.isValid()); + ps->requestHideAutoHidingPanel(); + QVERIFY(autoHideRequestedSpy.wait()); + QCOMPARE(autoHideRequestedSpy.count(), 1); + QCOMPARE(autoHideShowRequestedSpy.count(), 0); + + QSignalSpy panelShownSpy(ps.data(), &PlasmaShellSurface::autoHidePanelShown); + QVERIFY(panelShownSpy.isValid()); + QSignalSpy panelHiddenSpy(ps.data(), &PlasmaShellSurface::autoHidePanelHidden); + QVERIFY(panelHiddenSpy.isValid()); + + sps->hideAutoHidingPanel(); + QVERIFY(panelHiddenSpy.wait()); + QCOMPARE(panelHiddenSpy.count(), 1); + QCOMPARE(panelShownSpy.count(), 0); + + ps->requestShowAutoHidingPanel(); + QVERIFY(autoHideShowRequestedSpy.wait()); + QCOMPARE(autoHideRequestedSpy.count(), 1); + QCOMPARE(autoHideShowRequestedSpy.count(), 1); + + sps->showAutoHidingPanel(); + QVERIFY(panelShownSpy.wait()); + QCOMPARE(panelHiddenSpy.count(), 1); + QCOMPARE(panelShownSpy.count(), 1); + + // change panel type + ps->setPanelBehavior(PlasmaShellSurface::PanelBehavior::AlwaysVisible); + // requesting auto hide should raise error + QSignalSpy errorSpy(m_connection, &ConnectionThread::errorOccurred); + QVERIFY(errorSpy.isValid()); + ps->requestHideAutoHidingPanel(); + QVERIFY(errorSpy.wait()); +} + 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 @@ -289,6 +289,53 @@ */ void setSkipTaskbar(bool skip); + /** + * Requests to hide a surface with Role Panel and PanelBahvior AutoHide. + * + * Once the compositor has hidden the panel the signal @link{autoHidePanelHidden} gets + * emitted. Once it is shown again the signal @link{autoHidePanelShown} gets emitted. + * + * To show the surface again from client side use @link{requestShowAutoHidingPanel}. + * + * @see autoHidePanelHidden + * @see autoHidePanelShown + * @see requestShowAutoHidingPanel + * @since 5.28 + **/ + void requestHideAutoHidingPanel(); + + /** + * Requests to show a surface with Role Panel and PanelBahvior AutoHide. + * + * This request allows the client to show a surface which it previously + * requested to be hidden with @link{requestHideAutoHidingPanel}. + * + * @see autoHidePanelHidden + * @see autoHidePanelShown + * @see requestHideAutoHidingPanel + * @since 5.28 + **/ + void requestShowAutoHidingPanel(); + +Q_SIGNALS: + /** + * Emitted when the compositor hided an auto hiding panel. + * @see requestHideAutoHidingPanel + * @see autoHidePanelShown + * @see requestShowAutoHidingPanel + * @since 5.28 + **/ + void autoHidePanelHidden(); + + /** + * Emitted when the compositor showed an auto hiding panel. + * @see requestHideAutoHidingPanel + * @see autoHidePanelHidden + * @see requestShowAutoHidingPanel + * @since 5.28 + **/ + void autoHidePanelShown(); + private: friend class PlasmaShell; class Private; diff --git a/src/client/plasmashell.cpp b/src/client/plasmashell.cpp --- a/src/client/plasmashell.cpp +++ b/src/client/plasmashell.cpp @@ -52,8 +52,12 @@ static PlasmaShellSurface *get(Surface *surface); private: + static void autoHidingPanelHiddenCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface); + static void autoHidingPanelShownCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface); + PlasmaShellSurface *q; static QVector s_surfaces; + static const org_kde_plasma_surface_listener s_listener; }; QVector PlasmaShellSurface::Private::s_surfaces; @@ -175,6 +179,26 @@ Q_ASSERT(s); Q_ASSERT(!surface); surface.setup(s); + org_kde_plasma_surface_add_listener(surface, &s_listener, this); +} + +const org_kde_plasma_surface_listener PlasmaShellSurface::Private::s_listener = { + autoHidingPanelHiddenCallback, + autoHidingPanelShownCallback +}; + +void PlasmaShellSurface::Private::autoHidingPanelHiddenCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface) +{ + auto p = reinterpret_cast(data); + Q_ASSERT(p->surface == org_kde_plasma_surface); + emit p->q->autoHidePanelHidden(); +} + +void PlasmaShellSurface::Private::autoHidingPanelShownCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface) +{ + auto p = reinterpret_cast(data); + Q_ASSERT(p->surface == org_kde_plasma_surface); + emit p->q->autoHidePanelShown(); } PlasmaShellSurface::PlasmaShellSurface(QObject *parent) @@ -298,5 +322,15 @@ org_kde_plasma_surface_set_skip_taskbar(d->surface, skip); } +void PlasmaShellSurface::requestHideAutoHidingPanel() +{ + org_kde_plasma_surface_panel_auto_hide_hide(d->surface); +} + +void PlasmaShellSurface::requestShowAutoHidingPanel() +{ + org_kde_plasma_surface_panel_auto_hide_show(d->surface); +} + } } 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 @@ -17,7 +17,7 @@ along with this program. If not, see . ]]> - + This interface is used by KF5 powered Wayland shells to communicate with the compositor and can only be bound one time. @@ -130,7 +130,7 @@ --> - + An interface that may be implemented by a wl_surface, for implementations that provide the shell user interface. @@ -335,23 +335,43 @@ - - - - + + + + A panel surface with panel_behavior auto_hide can perform this request to show the panel + again which got hidden with panel_auto_hide_hide. + + + + + + An auto-hiding panel got hidden by the compositor. + + + + + + An auto-hiding panel got shown by the compositor. + + diff --git a/src/client/registry.cpp b/src/client/registry.cpp --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -146,7 +146,7 @@ &Registry::subCompositorRemoved }}, {Registry::Interface::PlasmaShell, { - 3, + 4, QByteArrayLiteral("org_kde_plasma_shell"), &org_kde_plasma_shell_interface, &Registry::plasmaShellAnnounced, 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 @@ -139,6 +139,27 @@ bool skipTaskbar() const; /** + * Informs the PlasmaShellSurfaceInterface that the auto-hiding panel got hidden. + * Once it is shown again the method @link{showAutoHidingPanel} should be used. + * + * @see showAutoHidingPanel + * @see panelAutoHideHideRequested + * @see panelAutoHideShowRequested + * @since 5.28 + **/ + void hideAutoHidingPanel(); + + /** + * Informs the PlasmaShellSurfaceInterface that the auto-hiding panel got shown again. + * + * @see hideAutoHidingPanel + * @see panelAutoHideHideRequested + * @see panelAutoHideShowRequested + * @see 5.28 + **/ + void showAutoHidingPanel(); + + /** * @returns The PlasmaShellSurfaceInterface for the @p native resource. * @since 5.5 **/ @@ -162,6 +183,35 @@ */ void skipTaskbarChanged(); + /** + * A surface with Role Panel and PanelBehavior AutoHide requested to be hidden. + * + * The compositor should inform the PlasmaShellSurfaceInterface about the actual change. + * Once the surface is hidden it should invoke @link{hideAutoHidingPanel}. If the compositor + * cannot hide the surface (e.g. because it doesn't border a screen edge) it should inform + * the surface through invoking @link{showAutoHidingPanel}. This method should also be invoked + * whenever the surface gets shown again due to triggering the screen edge. + * + * @see hideAutoHidingPanel + * @see showAutoHidingPanel + * @see panelAutoHideShowRequested + * @since 5.28 + **/ + void panelAutoHideHideRequested(); + + /** + * A surface with Role Panel and PanelBehavior AutoHide requested to be shown. + * + * The compositor should inform the PlasmaShellSurfaceInterface about the actual change. + * Once the surface is shown it should invoke @link{showAutoHidingPanel}. + * + * @see hideAutoHidingPanel + * @see showAutoHidingPanel + * @see panelAutoHideHideRequested + * @since 5.28 + **/ + void panelAutoHideShowRequested(); + private: friend class PlasmaShellInterface; explicit PlasmaShellSurfaceInterface(PlasmaShellInterface *shell, SurfaceInterface *parent, wl_resource *parentResource); 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 @@ -50,7 +50,7 @@ static const quint32 s_version; }; -const quint32 PlasmaShellInterface::Private::s_version = 3; +const quint32 PlasmaShellInterface::Private::s_version = 4; PlasmaShellInterface::Private::Private(PlasmaShellInterface *q, Display *d) : Global::Private(d, &org_kde_plasma_shell_interface, s_version) @@ -84,6 +84,8 @@ static void setRoleCallback(wl_client *client, wl_resource *resource, uint32_t role); static void setPanelBehaviorCallback(wl_client *client, wl_resource *resource, uint32_t flag); 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); void setPosition(const QPoint &globalPos); void setRole(uint32_t role); @@ -158,7 +160,9 @@ setPositionCallback, setRoleCallback, setPanelBehaviorCallback, - setSkipTaskbarCallback + setSkipTaskbarCallback, + panelAutoHideHideCallback, + panelAutoHideShowCallback }; #endif @@ -270,6 +274,28 @@ emit s->q_func()->skipTaskbarChanged(); } +void PlasmaShellSurfaceInterface::Private::panelAutoHideHideCallback(wl_client *client, wl_resource *resource) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + if (s->m_role != Role::Panel || s->m_panelBehavior != PanelBehavior::AutoHide) { + wl_resource_post_error(s->resource, ORG_KDE_PLASMA_SURFACE_ERROR_PANEL_NOT_AUTO_HIDE, "Not an auto hide panel"); + return; + } + emit s->q_func()->panelAutoHideHideRequested(); +} + +void PlasmaShellSurfaceInterface::Private::panelAutoHideShowCallback(wl_client *client, wl_resource *resource) +{ + auto s = cast(resource); + Q_ASSERT(client == *s->client); + if (s->m_role != Role::Panel || s->m_panelBehavior != PanelBehavior::AutoHide) { + wl_resource_post_error(s->resource, ORG_KDE_PLASMA_SURFACE_ERROR_PANEL_NOT_AUTO_HIDE, "Not an auto hide panel"); + return; + } + emit s->q_func()->panelAutoHideShowRequested(); +} + void PlasmaShellSurfaceInterface::Private::setPanelBehavior(org_kde_plasma_surface_panel_behavior behavior) { PanelBehavior newBehavior = PanelBehavior::AlwaysVisible; @@ -325,6 +351,24 @@ return d->m_skipTaskbar; } +void PlasmaShellSurfaceInterface::hideAutoHidingPanel() +{ + Q_D(); + if (!d->resource) { + return; + } + org_kde_plasma_surface_send_auto_hidden_panel_hidden(d->resource); +} + +void PlasmaShellSurfaceInterface::showAutoHidingPanel() +{ + Q_D(); + if (!d->resource) { + return; + } + org_kde_plasma_surface_send_auto_hidden_panel_shown(d->resource); +} + PlasmaShellSurfaceInterface *PlasmaShellSurfaceInterface::get(wl_resource *native) { return Private::get(native);