diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd
index fe468cd1..aa524d3f 100644
--- a/docs/labwc-actions.5.scd
+++ b/docs/labwc-actions.5.scd
@@ -424,6 +424,11 @@ Actions are used in menus and keyboard/mouse bindings.
Toggle the screen magnifier on or off at the last magnification level
used.
+**
+ Hide all windows in the current workspace so that the desktop is visible. On
+ calling the action again the hidden windows are un-minimized, as long as no
+ windows were un-minimized in the meantime.
+
**++
**
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..2a9da708
--- /dev/null
+++ b/include/show-desktop.h
@@ -0,0 +1,9 @@
+/* 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);
+void show_desktop_finish(void);
+
+#endif /* LABWC_SHOW_DESKTOP_H */
diff --git a/include/view.h b/include/view.h
index c2764f94..55c8073e 100644
--- a/include/view.h
+++ b/include/view.h
@@ -487,6 +487,7 @@ void view_resize_relative(struct view *view,
void view_move_relative(struct view *view, int x, int y);
void view_move(struct view *view, int x, int y);
void view_moved(struct view *view);
+void view_minimize_no_show_desktop_reset(struct view *view, bool minimized);
void view_minimize(struct view *view, bool minimized);
bool view_compute_centered_position(struct view *view,
const struct wlr_box *ref, int w, int h, int *x, int *y);
diff --git a/src/action.c b/src/action.c
index 66fa9b20..4bb2929b 100644
--- a/src/action.c
+++ b/src/action.c
@@ -27,6 +27,7 @@
#include "output.h"
#include "output-virtual.h"
#include "regions.h"
+#include "show-desktop.h"
#include "ssd.h"
#include "theme.h"
#include "translate.h"
@@ -132,6 +133,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")
@@ -1560,6 +1562,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/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/server.c b/src/server.c
index fd48efed..298a36e5 100644
--- a/src/server.c
+++ b/src/server.c
@@ -68,6 +68,7 @@
#include "resize-indicator.h"
#include "scaled-buffer/scaled-buffer.h"
#include "session-lock.h"
+#include "show-desktop.h"
#include "ssd.h"
#include "theme.h"
#include "view.h"
@@ -786,6 +787,8 @@ server_finish(void)
wl_display_destroy_clients(server.wl_display);
+ show_desktop_finish();
+
seat_finish();
output_finish();
xdg_shell_finish();
diff --git a/src/show-desktop.c b/src/show-desktop.c
new file mode 100644
index 00000000..fe0e054d
--- /dev/null
+++ b/src/show-desktop.c
@@ -0,0 +1,90 @@
+// 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 struct wl_array views;
+static bool is_showing_desktop;
+
+static void
+stash_unminimized_windows_on_current_workspace(void)
+{
+ struct view *view;
+ for_each_view(view, &server.views, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE) {
+ if (view->minimized) {
+ continue;
+ }
+ array_add(&views, view);
+ }
+}
+
+static void
+show(void)
+{
+ /*
+ * Build array before acting on it because actions like minimize change
+ * server.views
+ */
+ stash_unminimized_windows_on_current_workspace();
+
+ struct view **view;
+ wl_array_for_each(view, &views) {
+ view_minimize_no_show_desktop_reset(*view, true);
+ }
+
+ is_showing_desktop = true;
+}
+
+static void
+restore(void)
+{
+ struct view **view;
+ wl_array_for_each_reverse(view, &views) {
+ if (!*view) {
+ continue;
+ }
+ view_minimize_no_show_desktop_reset(*view, false);
+ }
+ show_desktop_reset();
+}
+
+static void
+init(void)
+{
+ static bool has_been_initialized;
+ if (has_been_initialized) {
+ return;
+ }
+ has_been_initialized = true;
+ wl_array_init(&views);
+}
+
+void
+show_desktop_toggle(void)
+{
+ init();
+ if (is_showing_desktop) {
+ restore();
+ } else {
+ show();
+ }
+}
+
+void
+show_desktop_reset(void)
+{
+ init();
+ wl_array_release(&views);
+ wl_array_init(&views);
+ is_showing_desktop = false;
+}
+
+void
+show_desktop_finish(void)
+{
+ init();
+ wl_array_release(&views);
+}
diff --git a/src/view.c b/src/view.c
index 1d43fcfa..240265b2 100644
--- a/src/view.c
+++ b/src/view.c
@@ -26,6 +26,7 @@
#include "regions.h"
#include "resize-indicator.h"
#include "session-lock.h"
+#include "show-desktop.h"
#include "snap-constraints.h"
#include "snap.h"
#include "ssd.h"
@@ -782,7 +783,7 @@ minimize_sub_views(struct view *view, bool minimized, bool *need_refocus)
* versa.
*/
void
-view_minimize(struct view *view, bool minimized)
+view_minimize_no_show_desktop_reset(struct view *view, bool minimized)
{
assert(view);
bool need_refocus = false;
@@ -814,6 +815,13 @@ view_minimize(struct view *view, bool minimized)
}
}
+void
+view_minimize(struct view *view, bool minimized)
+{
+ view_minimize_no_show_desktop_reset(view, minimized);
+ show_desktop_reset();
+}
+
bool
view_compute_centered_position(struct view *view, const struct wlr_box *ref,
int w, int h, int *x, int *y)