Index: uspace/srv/hid/display/seat.c
===================================================================
--- uspace/srv/hid/display/seat.c	(revision 3c54869a5b618845c19d4f6200ee90ac99a446aa)
+++ uspace/srv/hid/display/seat.c	(revision 17c0f5d3dbc71d4acf0607c23f54e6519bcea40f)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2022 Jiri Svoboda
+ * Copyright (c) 2023 Jiri Svoboda
  * All rights reserved.
  *
@@ -142,5 +142,5 @@
  *
  * @param seat Seat
- * @param wnd Window to evacuate focus from
+ * @param wnd Window to evacuate references from
  */
 void ds_seat_evac_wnd_refs(ds_seat_t *seat, ds_window_t *wnd)
@@ -160,4 +160,30 @@
 	if (seat->popup == wnd)
 		ds_seat_set_popup(seat, NULL);
+}
+
+/** Unfocus window.
+ *
+ * If seat's focus is @a wnd, it will be set to a different window
+ * that is not minimized, preferably not a system window.
+ *
+ * @param seat Seat
+ * @param wnd Window to remove focus from
+ */
+void ds_seat_unfocus_wnd(ds_seat_t *seat, ds_window_t *wnd)
+{
+	ds_window_t *nwnd;
+
+	if (seat->focus != wnd)
+		return;
+
+	/* Find alternate window that is neither system nor minimized */
+	nwnd = ds_window_find_alt(wnd, ~(wndf_minimized | wndf_system));
+
+	if (nwnd == NULL) {
+		/* Find alternate window that is not minimized */
+		nwnd = ds_window_find_alt(wnd, ~wndf_minimized);
+	}
+
+	ds_seat_set_focus(seat, nwnd);
 }
 
Index: uspace/srv/hid/display/seat.h
===================================================================
--- uspace/srv/hid/display/seat.h	(revision 3c54869a5b618845c19d4f6200ee90ac99a446aa)
+++ uspace/srv/hid/display/seat.h	(revision 17c0f5d3dbc71d4acf0607c23f54e6519bcea40f)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2021 Jiri Svoboda
+ * Copyright (c) 2023 Jiri Svoboda
  * All rights reserved.
  *
@@ -51,4 +51,5 @@
 extern void ds_seat_set_popup(ds_seat_t *, ds_window_t *);
 extern void ds_seat_evac_wnd_refs(ds_seat_t *, ds_window_t *);
+extern void ds_seat_unfocus_wnd(ds_seat_t *, ds_window_t *);
 extern void ds_seat_switch_focus(ds_seat_t *);
 extern errno_t ds_seat_post_kbd_event(ds_seat_t *, kbd_event_t *);
Index: uspace/srv/hid/display/test/seat.c
===================================================================
--- uspace/srv/hid/display/test/seat.c	(revision 3c54869a5b618845c19d4f6200ee90ac99a446aa)
+++ uspace/srv/hid/display/test/seat.c	(revision 17c0f5d3dbc71d4acf0607c23f54e6519bcea40f)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2021 Jiri Svoboda
+ * Copyright (c) 2023 Jiri Svoboda
  * All rights reserved.
  *
@@ -224,4 +224,191 @@
 }
 
+/** Unfocus window when three windows are available */
+PCUT_TEST(unfocus_wnd_three_windows)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *w0;
+	ds_window_t *w1;
+	ds_window_t *w2;
+	display_wnd_params_t params;
+	bool called_cb = false;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_client_create(disp, &test_ds_client_cb, &called_cb, &client);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_seat_create(disp, &seat);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_wnd_params_init(&params);
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 1;
+
+	rc = ds_window_create(client, &params, &w2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_window_create(client, &params, &w1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_window_create(client, &params, &w0);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_EQUALS(w0, seat->focus);
+
+	ds_window_unfocus(w0);
+
+	/* The previous window, w2, should be focused now */
+	PCUT_ASSERT_EQUALS(w2, seat->focus);
+
+	ds_window_destroy(w0);
+	ds_window_destroy(w1);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
+/** Unfocus window when two windows and one system window are available */
+PCUT_TEST(unfocus_wnd_two_windows_one_sys)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *w0;
+	ds_window_t *w1;
+	ds_window_t *w2;
+	display_wnd_params_t params;
+	bool called_cb = false;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_client_create(disp, &test_ds_client_cb, &called_cb, &client);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_seat_create(disp, &seat);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_wnd_params_init(&params);
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 1;
+
+	params.flags |= wndf_system;
+	rc = ds_window_create(client, &params, &w2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	params.flags &= ~wndf_system;
+	rc = ds_window_create(client, &params, &w1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_window_create(client, &params, &w0);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_EQUALS(w0, seat->focus);
+
+	ds_window_unfocus(w0);
+
+	/* The previous non-system window is w1, w2 should be skipped */
+	PCUT_ASSERT_EQUALS(w1, seat->focus);
+
+	ds_window_destroy(w0);
+	ds_window_destroy(w1);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
+/** Unfocus window when one window and one system window is available */
+PCUT_TEST(unfocus_wnd_one_window_one_sys)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *w0;
+	ds_window_t *w1;
+	display_wnd_params_t params;
+	bool called_cb = false;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_client_create(disp, &test_ds_client_cb, &called_cb, &client);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_seat_create(disp, &seat);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_wnd_params_init(&params);
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 1;
+
+	params.flags |= wndf_system;
+	rc = ds_window_create(client, &params, &w1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	params.flags &= ~wndf_system;
+	rc = ds_window_create(client, &params, &w0);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_EQUALS(w0, seat->focus);
+
+	ds_window_unfocus(w0);
+
+	/* Since no non-system window is available, w1 should be focused */
+	PCUT_ASSERT_EQUALS(w1, seat->focus);
+
+	ds_window_destroy(w0);
+	ds_window_destroy(w1);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
+/** Unfocus window when one window is available */
+PCUT_TEST(unfocus_wnd_one_window)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *w0;
+	display_wnd_params_t params;
+	bool called_cb = false;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_client_create(disp, &test_ds_client_cb, &called_cb, &client);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_seat_create(disp, &seat);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_wnd_params_init(&params);
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 1;
+
+	rc = ds_window_create(client, &params, &w0);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_EQUALS(w0, seat->focus);
+
+	ds_window_unfocus(w0);
+
+	/* Since no other window is availabe, no window should be focused */
+	PCUT_ASSERT_EQUALS(NULL, seat->focus);
+
+	ds_window_destroy(w0);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
 /** Switch focus when another window is available. */
 PCUT_TEST(switch_focus_two_windows)
Index: uspace/srv/hid/display/test/window.c
===================================================================
--- uspace/srv/hid/display/test/window.c	(revision 3c54869a5b618845c19d4f6200ee90ac99a446aa)
+++ uspace/srv/hid/display/test/window.c	(revision 17c0f5d3dbc71d4acf0607c23f54e6519bcea40f)
@@ -1162,4 +1162,109 @@
 }
 
+/** ds_window_find_alt() finds alternate window by flags */
+PCUT_TEST(window_find_alt)
+{
+	gfx_context_t *gc;
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *w0;
+	ds_window_t *w1;
+	ds_window_t *w2;
+	ds_window_t *wnd;
+	display_wnd_params_t params;
+	errno_t rc;
+
+	rc = gfx_context_new(&dummy_ops, NULL, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_display_create(gc, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_client_create(disp, NULL, NULL, &client);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_seat_create(disp, &seat);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_wnd_params_init(&params);
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 1;
+
+	rc = ds_window_create(client, &params, &w0);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_window_create(client, &params, &w1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	w1->flags |= wndf_minimized;
+
+	rc = ds_window_create(client, &params, &w2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	w2->flags |= wndf_system;
+
+	wnd = ds_window_find_alt(w0, wndf_minimized);
+	PCUT_ASSERT_EQUALS(w1, wnd);
+
+	wnd = ds_window_find_alt(w0, wndf_system);
+	PCUT_ASSERT_EQUALS(w2, wnd);
+
+	wnd = ds_window_find_alt(w0, wndf_maximized);
+	PCUT_ASSERT_NULL(wnd);
+
+	ds_window_destroy(w0);
+	ds_window_destroy(w1);
+	ds_window_destroy(w2);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
+/** ds_window_unfocus() switches to another window */
+PCUT_TEST(window_unfocus)
+{
+	gfx_context_t *gc;
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *w0;
+	ds_window_t *w1;
+	display_wnd_params_t params;
+	errno_t rc;
+
+	rc = gfx_context_new(&dummy_ops, NULL, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_display_create(gc, df_none, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_client_create(disp, NULL, NULL, &client);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_seat_create(disp, &seat);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_wnd_params_init(&params);
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 1;
+
+	rc = ds_window_create(client, &params, &w1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_window_create(client, &params, &w0);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_EQUALS(w0, seat->focus);
+
+	ds_window_unfocus(w0);
+
+	PCUT_ASSERT_EQUALS(w1, seat->focus);
+
+	ds_window_destroy(w0);
+	ds_window_destroy(w1);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
 static errno_t dummy_set_color(void *arg, gfx_color_t *color)
 {
Index: uspace/srv/hid/display/window.c
===================================================================
--- uspace/srv/hid/display/window.c	(revision 3c54869a5b618845c19d4f6200ee90ac99a446aa)
+++ uspace/srv/hid/display/window.c	(revision 17c0f5d3dbc71d4acf0607c23f54e6519bcea40f)
@@ -67,10 +67,10 @@
  * @param client Client owning the window
  * @param params Window parameters
- * @param rgc Place to store pointer to new GC.
+ * @param rwnd Place to store pointer to new window.
  *
  * @return EOK on success or an error code
  */
 errno_t ds_window_create(ds_client_t *client, display_wnd_params_t *params,
-    ds_window_t **rgc)
+    ds_window_t **rwnd)
 {
 	ds_window_t *wnd = NULL;
@@ -155,5 +155,5 @@
 	(void) ds_display_paint(wnd->display, NULL);
 
-	*rgc = wnd;
+	*rwnd = wnd;
 	return EOK;
 error:
@@ -867,4 +867,6 @@
 		return EOK;
 
+	ds_window_unfocus(wnd);
+
 	wnd->flags |= wndf_minimized;
 	(void) ds_display_paint(wnd->display, NULL);
@@ -1044,4 +1046,61 @@
 }
 
+/** Find alternate window with the allowed flags.
+ *
+ * An alternate window is a *different* window that is preferably previous
+ * in the display order and only has the @a allowed flags.
+ *
+ * @param wnd Window
+ * @param allowed_flags Bitmask of flags that the window is allowed to have
+ *
+ * @return Alternate window matching the criteria or @c NULL if there is none
+ */
+ds_window_t *ds_window_find_alt(ds_window_t *wnd,
+    display_wnd_flags_t allowed_flags)
+{
+	ds_window_t *nwnd;
+
+	/* Try preceding windows in display order */
+	nwnd = ds_display_prev_window(wnd);
+	while (nwnd != NULL && (nwnd->flags & ~allowed_flags) != 0) {
+		nwnd = ds_display_prev_window(nwnd);
+	}
+
+	/* Do we already have a matching window? */
+	if (nwnd != NULL && (nwnd->flags & ~allowed_flags) == 0) {
+		return nwnd;
+	}
+
+	/* Try succeeding windows in display order */
+	nwnd = ds_display_last_window(wnd->display);
+	while (nwnd != NULL && nwnd != wnd &&
+	    (nwnd->flags & ~allowed_flags) != 0) {
+		nwnd = ds_display_prev_window(nwnd);
+	}
+
+	if (nwnd == wnd)
+		return NULL;
+
+	return nwnd;
+}
+
+/** Remove focus from window.
+ *
+ * Used to switch focus to another window when closing or minimizing window.
+ *
+ * @param wnd Window
+ */
+void ds_window_unfocus(ds_window_t *wnd)
+{
+	ds_seat_t *seat;
+
+	/* Make sure window is no longer focused in any seat */
+	seat = ds_display_first_seat(wnd->display);
+	while (seat != NULL) {
+		ds_seat_unfocus_wnd(seat, wnd);
+		seat = ds_display_next_seat(seat);
+	}
+}
+
 /** Window memory GC invalidate callback.
  *
Index: uspace/srv/hid/display/window.h
===================================================================
--- uspace/srv/hid/display/window.h	(revision 3c54869a5b618845c19d4f6200ee90ac99a446aa)
+++ uspace/srv/hid/display/window.h	(revision 17c0f5d3dbc71d4acf0607c23f54e6519bcea40f)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2022 Jiri Svoboda
+ * Copyright (c) 2023 Jiri Svoboda
  * All rights reserved.
  *
@@ -78,4 +78,6 @@
 extern errno_t ds_window_set_cursor(ds_window_t *, display_stock_cursor_t);
 extern errno_t ds_window_set_caption(ds_window_t *, const char *);
+extern ds_window_t *ds_window_find_alt(ds_window_t *, display_wnd_flags_t);
+extern void ds_window_unfocus(ds_window_t *);
 
 #endif
