diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd
index a70c0086..de1dc00d 100644
--- a/docs/labwc-actions.5.scd
+++ b/docs/labwc-actions.5.scd
@@ -424,6 +424,13 @@ Actions are used in menus and keyboard/mouse bindings.
Toggle the screen magnifier on or off at the last magnification level
used.
+**
+ Minimize all windows in the current workspace so that the desktop becomes
+ visible. On calling the action again the hidden windows are unminimized,
+ provided that - since the initial `ShowDesktop` - (a) no windows have been
+ unminimized; (b) workspaces have not been switched; and (c) no new
+ applications have been started.
+
**++
**
Increase or decrease the magnification level for the screen magnifier.
diff --git a/include/show-desktop.h b/include/show-desktop.h
new file mode 100644
index 00000000..cc86bcb4
--- /dev/null
+++ b/include/show-desktop.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_SHOW_DESKTOP_H
+#define LABWC_SHOW_DESKTOP_H
+
+void show_desktop_toggle(void);
+void show_desktop_reset(void);
+
+#endif /* LABWC_SHOW_DESKTOP_H */
diff --git a/include/view.h b/include/view.h
index c2764f94..da7aef02 100644
--- a/include/view.h
+++ b/include/view.h
@@ -184,6 +184,7 @@ struct view {
enum ssd_preference ssd_preference;
bool shaded;
bool minimized;
+ bool was_minimized_by_show_desktop_action;
enum view_axis maximized;
bool fullscreen;
bool tearing_hint;
diff --git a/src/action.c b/src/action.c
index 2cfa6be6..34435e02 100644
--- a/src/action.c
+++ b/src/action.c
@@ -28,6 +28,7 @@
#include "output.h"
#include "output-virtual.h"
#include "regions.h"
+#include "show-desktop.h"
#include "ssd.h"
#include "theme.h"
#include "translate.h"
@@ -133,6 +134,7 @@ struct action_arg_list {
X(TOGGLE_MAGNIFY, "ToggleMagnify") \
X(ZOOM_IN, "ZoomIn") \
X(ZOOM_OUT, "ZoomOut") \
+ X(TOGGLE_SHOW_DESKTOP, "ToggleShowDesktop") \
X(WARP_CURSOR, "WarpCursor") \
X(HIDE_CURSOR, "HideCursor") \
X(DEBUG_TOGGLE_KEY_STATE_INDICATOR, "DebugToggleKeyStateIndicator")
@@ -1562,6 +1564,9 @@ run_action(struct view *view, struct action *action,
case ACTION_TYPE_ZOOM_OUT:
magnifier_set_scale(MAGNIFY_DECREASE);
break;
+ case ACTION_TYPE_TOGGLE_SHOW_DESKTOP:
+ show_desktop_toggle();
+ break;
case ACTION_TYPE_WARP_CURSOR: {
const char *to = action_get_str(action, "to", "output");
const char *x = action_get_str(action, "x", "center");
diff --git a/src/desktop.c b/src/desktop.c
index 28bf4464..4c7870f1 100644
--- a/src/desktop.c
+++ b/src/desktop.c
@@ -14,6 +14,7 @@
#include "layers.h"
#include "node.h"
#include "output.h"
+#include "show-desktop.h"
#include "ssd.h"
#include "view.h"
#include "workspaces.h"
@@ -113,6 +114,8 @@ desktop_focus_view(struct view *view, bool raise)
*/
struct view *dialog = view_get_modal_dialog(view);
set_or_offer_focus(dialog ? dialog : view);
+
+ show_desktop_reset();
}
/* TODO: focus layer-shell surfaces also? */
diff --git a/src/meson.build b/src/meson.build
index 40ec3170..05163cfa 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -22,6 +22,7 @@ labwc_sources = files(
'seat.c',
'server.c',
'session-lock.c',
+ 'show-desktop.c',
'snap-constraints.c',
'snap.c',
'tearing.c',
diff --git a/src/show-desktop.c b/src/show-desktop.c
new file mode 100644
index 00000000..efddf2de
--- /dev/null
+++ b/src/show-desktop.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include "show-desktop.h"
+#include
+#include "common/array.h"
+#include "config/types.h"
+#include "labwc.h"
+#include "view.h"
+
+static bool is_showing_desktop;
+
+static void
+minimize_views(struct wl_array *views, bool minimize)
+{
+ struct view **view;
+ wl_array_for_each_reverse(view, views) {
+ view_minimize(*view, minimize);
+ }
+}
+
+static void
+show(void)
+{
+ static struct wl_array views;
+ wl_array_init(&views);
+
+ /* Build array first as minimize changes server.views */
+ struct view *view;
+ for_each_view(view, &server.views, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE) {
+ if (view->minimized) {
+ continue;
+ }
+ view->was_minimized_by_show_desktop_action = true;
+ array_add(&views, view);
+ }
+ minimize_views(&views, true);
+ is_showing_desktop = true;
+
+ wl_array_release(&views);
+}
+
+static void
+restore(void)
+{
+ static struct wl_array views;
+ wl_array_init(&views);
+
+ struct view *view;
+ for_each_view(view, &server.views, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE) {
+ if (view->was_minimized_by_show_desktop_action) {
+ array_add(&views, view);
+ }
+ }
+ minimize_views(&views, false);
+ show_desktop_reset();
+
+ wl_array_release(&views);
+}
+
+void
+show_desktop_toggle(void)
+{
+ if (is_showing_desktop) {
+ restore();
+ } else {
+ show();
+ }
+}
+
+void
+show_desktop_reset(void)
+{
+ is_showing_desktop = false;
+
+ struct view *view;
+ for_each_view(view, &server.views, LAB_VIEW_CRITERIA_NONE) {
+ view->was_minimized_by_show_desktop_action = false;
+ }
+}
diff --git a/src/workspaces.c b/src/workspaces.c
index 7ff471a5..a1ed9112 100644
--- a/src/workspaces.c
+++ b/src/workspaces.c
@@ -21,6 +21,7 @@
#include "input/keyboard.h"
#include "labwc.h"
#include "output.h"
+#include "show-desktop.h"
#include "theme.h"
#include "view.h"
@@ -495,6 +496,8 @@ workspaces_switch_to(struct workspace *target, bool update_focus)
desktop_update_top_layer_visibility();
wlr_ext_workspace_handle_v1_set_active(target->ext_workspace, true);
+
+ show_desktop_reset();
}
void