Index: uspace/app/uidemo/uidemo.c
===================================================================
--- uspace/app/uidemo/uidemo.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/app/uidemo/uidemo.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -609,5 +609,6 @@
 	ui_wnd_params_init(&params);
 	params.caption = "UI Demo";
-	params.style |= ui_wds_maximize_btn | ui_wds_resizable;
+	params.style |= ui_wds_minimize_btn | ui_wds_maximize_btn |
+	    ui_wds_resizable;
 
 	/* FIXME: Auto layout */
Index: uspace/lib/display/include/disp_srv.h
===================================================================
--- uspace/lib/display/include/disp_srv.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/display/include/disp_srv.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -64,4 +64,5 @@
 	errno_t (*window_get_max_rect)(void *, sysarg_t, gfx_rect_t *);
 	errno_t (*window_resize)(void *, sysarg_t, gfx_coord2_t *, gfx_rect_t *);
+	errno_t (*window_minimize)(void *, sysarg_t);
 	errno_t (*window_maximize)(void *, sysarg_t);
 	errno_t (*window_unmaximize)(void *, sysarg_t);
Index: uspace/lib/display/include/display.h
===================================================================
--- uspace/lib/display/include/display.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/display/include/display.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -62,4 +62,5 @@
 extern errno_t display_window_resize(display_window_t *,
     gfx_coord2_t *, gfx_rect_t *);
+extern errno_t display_window_minimize(display_window_t *);
 extern errno_t display_window_maximize(display_window_t *);
 extern errno_t display_window_unmaximize(display_window_t *);
Index: uspace/lib/display/include/ipc/display.h
===================================================================
--- uspace/lib/display/include/ipc/display.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/display/include/ipc/display.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -42,4 +42,5 @@
 	DISPLAY_WINDOW_CREATE,
 	DISPLAY_WINDOW_DESTROY,
+	DISPLAY_WINDOW_MINIMIZE,
 	DISPLAY_WINDOW_MAXIMIZE,
 	DISPLAY_WINDOW_MOVE,
Index: uspace/lib/display/include/types/display/wndparams.h
===================================================================
--- uspace/lib/display/include/types/display/wndparams.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/display/include/types/display/wndparams.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -46,10 +46,12 @@
 	/** Set specific initial window position */
 	wndf_setpos = 0x4,
+	/** Window is minimized */
+	wndf_minimized = 0x8,
 	/** Window is maximized */
-	wndf_maximized = 0x8,
+	wndf_maximized = 0x10,
 	/** Special system window */
-	wndf_system = 0x10,
+	wndf_system = 0x20,
 	/** Maximized windows should avoid this window */
-	wndf_avoid = 0x20
+	wndf_avoid = 0x40
 } display_wnd_flags_t;
 
Index: uspace/lib/display/src/disp_srv.c
===================================================================
--- uspace/lib/display/src/disp_srv.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/display/src/disp_srv.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -391,4 +391,20 @@
 }
 
+static void display_window_minimize_srv(display_srv_t *srv, ipc_call_t *icall)
+{
+	sysarg_t wnd_id;
+	errno_t rc;
+
+	wnd_id = ipc_get_arg1(icall);
+
+	if (srv->ops->window_minimize == NULL) {
+		async_answer_0(icall, ENOTSUP);
+		return;
+	}
+
+	rc = srv->ops->window_minimize(srv->arg, wnd_id);
+	async_answer_0(icall, rc);
+}
+
 static void display_window_maximize_srv(display_srv_t *srv, ipc_call_t *icall)
 {
@@ -610,4 +626,7 @@
 		case DISPLAY_WINDOW_RESIZE:
 			display_window_resize_srv(srv, &call);
+			break;
+		case DISPLAY_WINDOW_MINIMIZE:
+			display_window_minimize_srv(srv, &call);
 			break;
 		case DISPLAY_WINDOW_MAXIMIZE:
Index: uspace/lib/display/src/display.c
===================================================================
--- uspace/lib/display/src/display.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/display/src/display.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -508,4 +508,21 @@
 
 	return EOK;
+}
+
+/** Minimize window.
+ *
+ * @param window Window
+ * @return EOK on success or an error code
+ */
+errno_t display_window_minimize(display_window_t *window)
+{
+	async_exch_t *exch;
+	errno_t rc;
+
+	exch = async_exchange_begin(window->display->sess);
+	rc = async_req_1_0(exch, DISPLAY_WINDOW_MINIMIZE, window->id);
+	async_exchange_end(exch);
+
+	return rc;
 }
 
Index: uspace/lib/display/test/display.c
===================================================================
--- uspace/lib/display/test/display.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/display/test/display.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -66,4 +66,5 @@
 static errno_t test_window_resize(void *, sysarg_t, gfx_coord2_t *,
     gfx_rect_t *);
+static errno_t test_window_minimize(void *, sysarg_t);
 static errno_t test_window_maximize(void *, sysarg_t);
 static errno_t test_window_unmaximize(void *, sysarg_t);
@@ -84,4 +85,5 @@
 	.window_resize_req = test_window_resize_req,
 	.window_resize = test_window_resize,
+	.window_minimize = test_window_minimize,
 	.window_maximize = test_window_maximize,
 	.window_unmaximize = test_window_unmaximize,
@@ -145,4 +147,5 @@
 	sysarg_t resize_wnd_id;
 
+	bool window_minimize_called;
 	bool window_maximize_called;
 	bool window_unmaximize_called;
@@ -1050,4 +1053,100 @@
 	PCUT_ASSERT_INT_EQUALS(nrect.p1.x, resp.resize_nbound.p1.x);
 	PCUT_ASSERT_INT_EQUALS(nrect.p1.y, resp.resize_nbound.p1.y);
+
+	display_window_destroy(wnd);
+	display_close(disp);
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** display_window_minimize() with server returning error response works. */
+PCUT_TEST(window_minimize_failure)
+{
+	errno_t rc;
+	service_id_t sid;
+	display_t *disp = NULL;
+	display_wnd_params_t params;
+	display_window_t *wnd;
+	test_response_t resp;
+
+	async_set_fallback_port_handler(test_display_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_display_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_display_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = display_open(test_display_svc, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(disp);
+
+	resp.rc = EOK;
+	display_wnd_params_init(&params);
+	params.rect.p0.x = 0;
+	params.rect.p0.y = 0;
+	params.rect.p0.x = 100;
+	params.rect.p0.y = 100;
+
+	rc = display_window_create(disp, &params, &test_display_wnd_cb,
+	    (void *) &resp, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(wnd);
+
+	resp.rc = EIO;
+	resp.window_minimize_called = false;
+
+	rc = display_window_minimize(wnd);
+	PCUT_ASSERT_TRUE(resp.window_minimize_called);
+	PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
+
+	display_window_destroy(wnd);
+	display_close(disp);
+	rc = loc_service_unregister(sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** display_window_minimize() with server returning success response works. */
+PCUT_TEST(window_minimize_success)
+{
+	errno_t rc;
+	service_id_t sid;
+	display_t *disp = NULL;
+	display_wnd_params_t params;
+	display_window_t *wnd;
+	test_response_t resp;
+
+	async_set_fallback_port_handler(test_display_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_display_server);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(test_display_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = display_open(test_display_svc, &disp);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(disp);
+
+	resp.rc = EOK;
+	display_wnd_params_init(&params);
+	params.rect.p0.x = 0;
+	params.rect.p0.y = 0;
+	params.rect.p0.x = 100;
+	params.rect.p0.y = 100;
+
+	rc = display_window_create(disp, &params, &test_display_wnd_cb,
+	    (void *) &resp, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(wnd);
+
+	resp.rc = EOK;
+	resp.window_minimize_called = false;
+
+	rc = display_window_minimize(wnd);
+	PCUT_ASSERT_TRUE(resp.window_minimize_called);
+	PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
 
 	display_window_destroy(wnd);
@@ -2103,4 +2202,13 @@
 }
 
+static errno_t test_window_minimize(void *arg, sysarg_t wnd_id)
+{
+	test_response_t *resp = (test_response_t *) arg;
+
+	resp->window_minimize_called = true;
+	resp->resize_wnd_id = wnd_id;
+	return resp->rc;
+}
+
 static errno_t test_window_maximize(void *arg, sysarg_t wnd_id)
 {
Index: uspace/lib/ui/include/types/ui/wdecor.h
===================================================================
--- uspace/lib/ui/include/types/ui/wdecor.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/include/types/ui/wdecor.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -51,10 +51,12 @@
 	/** Window has a title bar */
 	ui_wds_titlebar = 0x2,
+	/** Window has a minimize button */
+	ui_wds_minimize_btn = 0x4,
 	/** Window has a maximize button */
-	ui_wds_maximize_btn = 0x4,
+	ui_wds_maximize_btn = 0x8,
 	/** Window has a close button */
-	ui_wds_close_btn = 0x8,
+	ui_wds_close_btn = 0x10,
 	/** Window is resizable */
-	ui_wds_resizable = 0x10,
+	ui_wds_resizable = 0x20,
 	/** Window is decorated (default decoration) */
 	ui_wds_decorated = ui_wds_frame | ui_wds_titlebar | ui_wds_close_btn
@@ -78,4 +80,5 @@
 /** Window decoration callbacks */
 typedef struct ui_wdecor_cb {
+	void (*minimize)(ui_wdecor_t *, void *);
 	void (*maximize)(ui_wdecor_t *, void *);
 	void (*unmaximize)(ui_wdecor_t *, void *);
Index: uspace/lib/ui/include/types/ui/window.h
===================================================================
--- uspace/lib/ui/include/types/ui/window.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/include/types/ui/window.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -93,4 +93,5 @@
 /** Window callbacks */
 typedef struct ui_window_cb {
+	void (*minimize)(ui_window_t *, void *);
 	void (*maximize)(ui_window_t *, void *);
 	void (*unmaximize)(ui_window_t *, void *);
Index: uspace/lib/ui/include/ui/paint.h
===================================================================
--- uspace/lib/ui/include/ui/paint.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/include/ui/paint.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -65,4 +65,6 @@
 extern errno_t ui_paint_cross(gfx_context_t *, gfx_coord2_t *, gfx_coord_t,
     gfx_coord_t, gfx_coord_t);
+extern errno_t ui_paint_minicon(ui_resource_t *, gfx_coord2_t *, gfx_coord_t,
+    gfx_coord_t);
 extern errno_t ui_paint_maxicon(ui_resource_t *, gfx_coord2_t *, gfx_coord_t,
     gfx_coord_t);
Index: uspace/lib/ui/include/ui/window.h
===================================================================
--- uspace/lib/ui/include/ui/window.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/include/ui/window.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -65,4 +65,5 @@
 extern void ui_window_set_ctl_cursor(ui_window_t *, ui_stock_cursor_t);
 extern errno_t ui_window_paint(ui_window_t *);
+extern errno_t ui_window_def_minimize(ui_window_t *);
 extern errno_t ui_window_def_maximize(ui_window_t *);
 extern errno_t ui_window_def_unmaximize(ui_window_t *);
Index: uspace/lib/ui/private/wdecor.h
===================================================================
--- uspace/lib/ui/private/wdecor.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/private/wdecor.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -65,4 +65,6 @@
 	/** Window is maximized */
 	bool maximized;
+	/** Minimize button */
+	struct ui_pbutton *btn_min;
 	/** Maximize button */
 	struct ui_pbutton *btn_max;
@@ -82,4 +84,6 @@
 	/** Window caption rectangle */
 	gfx_rect_t caption_rect;
+	/** Minimize button rectangle */
+	gfx_rect_t btn_min_rect;
 	/** Maximize button rectangle */
 	gfx_rect_t btn_max_rect;
@@ -90,4 +94,5 @@
 } ui_wdecor_geom_t;
 
+extern void ui_wdecor_minimize(ui_wdecor_t *);
 extern void ui_wdecor_maximize(ui_wdecor_t *);
 extern void ui_wdecor_unmaximize(ui_wdecor_t *);
Index: uspace/lib/ui/private/window.h
===================================================================
--- uspace/lib/ui/private/window.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/private/window.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -112,4 +112,5 @@
 
 extern display_stock_cursor_t wnd_dcursor_from_cursor(ui_stock_cursor_t);
+extern void ui_window_send_minimize(ui_window_t *);
 extern void ui_window_send_maximize(ui_window_t *);
 extern void ui_window_send_unmaximize(ui_window_t *);
Index: uspace/lib/ui/src/paint.c
===================================================================
--- uspace/lib/ui/src/paint.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/src/paint.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -529,4 +529,33 @@
 }
 
+/** Paint minimize icon.
+ *
+ * @param resource UI resource
+ * @param pos Center position
+ * @param w Icon width
+ * @param h Icon height
+ * @return EOK on success or an error code
+ */
+errno_t ui_paint_minicon(ui_resource_t *resource, gfx_coord2_t *pos,
+    gfx_coord_t w, gfx_coord_t h)
+{
+	gfx_rect_t rect;
+	errno_t rc;
+
+	rc = gfx_set_color(resource->gc, resource->btn_text_color);
+	if (rc != EOK)
+		return rc;
+
+	rect.p0.x = pos->x - w / 2;
+	rect.p0.y = pos->y + h / 2 - 2;
+	rect.p1.x = rect.p0.x + w;
+	rect.p1.y = rect.p0.y + 2;
+	rc = gfx_fill_rect(resource->gc, &rect);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
 /** Paint maximize icon.
  *
Index: uspace/lib/ui/src/wdecor.c
===================================================================
--- uspace/lib/ui/src/wdecor.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/src/wdecor.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -49,4 +49,8 @@
 #include "../private/wdecor.h"
 
+static void ui_wdecor_btn_min_clicked(ui_pbutton_t *, void *);
+static errno_t ui_wdecor_btn_min_paint(ui_pbutton_t *, void *,
+    gfx_coord2_t *);
+
 static void ui_wdecor_btn_max_clicked(ui_pbutton_t *, void *);
 static errno_t ui_wdecor_btn_max_paint(ui_pbutton_t *, void *,
@@ -56,4 +60,12 @@
 static errno_t ui_wdecor_btn_close_paint(ui_pbutton_t *, void *,
     gfx_coord2_t *);
+
+static ui_pbutton_cb_t ui_wdecor_btn_min_cb = {
+	.clicked = ui_wdecor_btn_min_clicked
+};
+
+static ui_pbutton_decor_ops_t ui_wdecor_btn_min_decor_ops = {
+	.paint = ui_wdecor_btn_min_paint
+};
 
 static ui_pbutton_cb_t ui_wdecor_btn_max_cb = {
@@ -98,4 +110,8 @@
 	/** Close button cross pen height */
 	wdecor_close_cross_h = 1,
+	/** Minimize icon width */
+	wdecor_min_w = 10,
+	/** Minimize icon height */
+	wdecor_min_h = 10,
 	/** Maximize icon width */
 	wdecor_max_w = 10,
@@ -136,4 +152,18 @@
 	}
 
+	if ((style & ui_wds_minimize_btn) != 0) {
+		rc = ui_pbutton_create(resource, "_", &wdecor->btn_min);
+		if (rc != EOK) {
+			ui_wdecor_destroy(wdecor);
+			return rc;
+		}
+
+		ui_pbutton_set_cb(wdecor->btn_min, &ui_wdecor_btn_min_cb,
+		    (void *)wdecor);
+
+		ui_pbutton_set_decor_ops(wdecor->btn_min,
+		    &ui_wdecor_btn_min_decor_ops, (void *)wdecor);
+	}
+
 	if ((style & ui_wds_maximize_btn) != 0) {
 		rc = ui_pbutton_create(resource, "^", &wdecor->btn_max);
@@ -180,4 +210,5 @@
 		return;
 
+	ui_pbutton_destroy(wdecor->btn_min);
 	ui_pbutton_destroy(wdecor->btn_max);
 	ui_pbutton_destroy(wdecor->btn_close);
@@ -211,4 +242,6 @@
 	ui_wdecor_get_geom(wdecor, &geom);
 
+	if (wdecor->btn_min != NULL)
+		ui_pbutton_set_rect(wdecor->btn_min, &geom.btn_min_rect);
 	if (wdecor->btn_max != NULL)
 		ui_pbutton_set_rect(wdecor->btn_max, &geom.btn_max_rect);
@@ -362,4 +395,10 @@
 			return rc;
 
+		if (wdecor->btn_min != NULL) {
+			rc = ui_pbutton_paint(wdecor->btn_min);
+			if (rc != EOK)
+				return rc;
+		}
+
 		if (wdecor->btn_max != NULL) {
 			rc = ui_pbutton_paint(wdecor->btn_max);
@@ -380,4 +419,14 @@
 
 	return EOK;
+}
+
+/** Send decoration minimize event.
+ *
+ * @param wdecor Window decoration
+ */
+void ui_wdecor_minimize(ui_wdecor_t *wdecor)
+{
+	if (wdecor->cb != NULL && wdecor->cb->minimize != NULL)
+		wdecor->cb->minimize(wdecor, wdecor->arg);
 }
 
@@ -554,4 +603,28 @@
 	}
 
+	/* Does window have a minimize button? */
+	if ((wdecor->style & ui_wds_minimize_btn) != 0) {
+		if (wdecor->res->textmode == false) {
+			geom->btn_min_rect.p0.x = btn_x - 20;
+			geom->btn_min_rect.p0.y = btn_y;
+			geom->btn_min_rect.p1.x = btn_x;
+			geom->btn_min_rect.p1.y = btn_y + 20;
+
+			btn_x -= 20;
+		} else {
+			geom->btn_min_rect.p0.x = btn_x - 3;
+			geom->btn_min_rect.p0.y = btn_y;
+			geom->btn_min_rect.p1.x = btn_x;
+			geom->btn_min_rect.p1.y = btn_y + 1;
+
+			btn_x -= 3;
+		}
+	} else {
+		geom->btn_min_rect.p0.x = 0;
+		geom->btn_min_rect.p0.y = 0;
+		geom->btn_min_rect.p1.x = 0;
+		geom->btn_min_rect.p1.y = 0;
+	}
+
 	if (wdecor->res->textmode == false)
 		cap_hmargin = wdecor_cap_hmargin;
@@ -773,4 +846,10 @@
 	ui_wdecor_get_geom(wdecor, &geom);
 
+	if (wdecor->btn_min != NULL) {
+		claim = ui_pbutton_pos_event(wdecor->btn_min, event);
+		if (claim == ui_claimed)
+			return ui_claimed;
+	}
+
 	if (wdecor->btn_max != NULL) {
 		claim = ui_pbutton_pos_event(wdecor->btn_max, event);
@@ -798,7 +877,21 @@
 }
 
+/** Window decoration minimize button was clicked.
+ *
+ * @param pbutton Minimize button
+ * @param arg Argument (ui_wdecor_t)
+ */
+static void ui_wdecor_btn_min_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	ui_wdecor_t *wdecor = (ui_wdecor_t *) arg;
+
+	(void) pbutton;
+
+	ui_wdecor_minimize(wdecor);
+}
+
 /** Window decoration (un)maximize button was clicked.
  *
- * @param pbutton Close button
+ * @param pbutton (Un)maximize button
  * @param arg Argument (ui_wdecor_t)
  */
@@ -813,4 +906,22 @@
 	else
 		ui_wdecor_maximize(wdecor);
+}
+
+/** Paint minimize button decoration.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (ui_wdecor_t *)
+ * @param pos Center position
+ */
+static errno_t ui_wdecor_btn_min_paint(ui_pbutton_t *pbutton,
+    void *arg, gfx_coord2_t *pos)
+{
+	ui_wdecor_t *wdecor = (ui_wdecor_t *)arg;
+	errno_t rc;
+
+	rc = ui_paint_minicon(wdecor->res, pos, wdecor_min_w,
+	    wdecor_min_h);
+
+	return rc;
 }
 
Index: uspace/lib/ui/src/window.c
===================================================================
--- uspace/lib/ui/src/window.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/src/window.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -74,4 +74,5 @@
 };
 
+static void wd_minimize(ui_wdecor_t *, void *);
 static void wd_maximize(ui_wdecor_t *, void *);
 static void wd_unmaximize(ui_wdecor_t *, void *);
@@ -83,4 +84,5 @@
 
 static ui_wdecor_cb_t wdecor_cb = {
+	.minimize = wd_minimize,
 	.maximize = wd_maximize,
 	.unmaximize = wd_unmaximize,
@@ -917,4 +919,16 @@
 }
 
+/** Window decoration requested window minimization.
+ *
+ * @param wdecor Window decoration
+ * @param arg Argument (window)
+ */
+static void wd_minimize(ui_wdecor_t *wdecor, void *arg)
+{
+	ui_window_t *window = (ui_window_t *) arg;
+
+	ui_window_send_minimize(window);
+}
+
 /** Window decoration requested window maximization.
  *
@@ -1041,4 +1055,16 @@
 }
 
+/** Send window minimize event.
+ *
+ * @param window Window
+ */
+void ui_window_send_minimize(ui_window_t *window)
+{
+	if (window->cb != NULL && window->cb->maximize != NULL)
+		window->cb->minimize(window, window->arg);
+	else
+		ui_window_def_minimize(window);
+}
+
 /** Send window maximize event.
  *
@@ -1131,4 +1157,24 @@
 	else
 		return ui_window_def_unfocus(window);
+}
+
+/** Default window minimize routine.
+ *
+ * @param window Window
+ * @return EOK on success or an error code
+ */
+errno_t ui_window_def_minimize(ui_window_t *window)
+{
+	errno_t rc;
+
+	if (window->dwindow != NULL) {
+		rc = display_window_minimize(window->dwindow);
+		if (rc != EOK)
+			goto error;
+	}
+
+	return EOK;
+error:
+	return rc;
 }
 
Index: uspace/lib/ui/test/paint.c
===================================================================
--- uspace/lib/ui/test/paint.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/test/paint.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -354,4 +354,32 @@
 }
 
+/** Paint mimimize icon */
+PCUT_TEST(minicon)
+{
+	errno_t rc;
+	gfx_context_t *gc = NULL;
+	ui_resource_t *resource = NULL;
+	test_gc_t tgc;
+	gfx_coord2_t center;
+
+	memset(&tgc, 0, sizeof(tgc));
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ui_resource_create(gc, false, &resource);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(resource);
+
+	center.x = 0;
+	center.y = 0;
+
+	rc = ui_paint_minicon(resource, &center, 8, 6);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_resource_destroy(resource);
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
 /** Paint maximize icon */
 PCUT_TEST(maxicon)
Index: uspace/lib/ui/test/wdecor.c
===================================================================
--- uspace/lib/ui/test/wdecor.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/test/wdecor.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -62,4 +62,5 @@
 };
 
+static void test_wdecor_minimize(ui_wdecor_t *, void *);
 static void test_wdecor_maximize(ui_wdecor_t *, void *);
 static void test_wdecor_unmaximize(ui_wdecor_t *, void *);
@@ -71,4 +72,5 @@
 
 static ui_wdecor_cb_t test_wdecor_cb = {
+	.minimize = test_wdecor_minimize,
 	.maximize = test_wdecor_maximize,
 	.unmaximize = test_wdecor_unmaximize,
@@ -100,4 +102,5 @@
 
 typedef struct {
+	bool minimize;
 	bool maximize;
 	bool unmaximize;
@@ -222,4 +225,30 @@
 	rc = gfx_context_delete(gc);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+/** Test ui_wdecor_minimize() */
+PCUT_TEST(minimize)
+{
+	errno_t rc;
+	ui_wdecor_t *wdecor;
+	test_cb_resp_t resp;
+
+	rc = ui_wdecor_create(NULL, "Hello", ui_wds_none, &wdecor);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Minimize callback with no callbacks set */
+	ui_wdecor_minimize(wdecor);
+
+	/* Minimize callback with minimize callback not implemented */
+	ui_wdecor_set_cb(wdecor, &dummy_wdecor_cb, NULL);
+	ui_wdecor_minimize(wdecor);
+
+	/* Minimize callback with real callback set */
+	resp.minimize = false;
+	ui_wdecor_set_cb(wdecor, &test_wdecor_cb, &resp);
+	ui_wdecor_minimize(wdecor);
+	PCUT_ASSERT_TRUE(resp.minimize);
+
+	ui_wdecor_destroy(wdecor);
 }
 
@@ -1014,4 +1043,11 @@
 }
 
+static void test_wdecor_minimize(ui_wdecor_t *wdecor, void *arg)
+{
+	test_cb_resp_t *resp = (test_cb_resp_t *) arg;
+
+	resp->minimize = true;
+}
+
 static void test_wdecor_maximize(ui_wdecor_t *wdecor, void *arg)
 {
Index: uspace/lib/ui/test/window.c
===================================================================
--- uspace/lib/ui/test/window.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/lib/ui/test/window.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -45,4 +45,5 @@
 PCUT_TEST_SUITE(window);
 
+static void test_window_minimize(ui_window_t *, void *);
 static void test_window_maximize(ui_window_t *, void *);
 static void test_window_unmaximize(ui_window_t *, void *);
@@ -55,4 +56,5 @@
 
 static ui_window_cb_t test_window_cb = {
+	.minimize = test_window_minimize,
 	.maximize = test_window_maximize,
 	.unmaximize = test_window_unmaximize,
@@ -80,4 +82,5 @@
 typedef struct {
 	errno_t rc;
+	bool minimize;
 	bool maximize;
 	bool unmaximize;
@@ -537,4 +540,40 @@
 }
 
+/** ui_window_send_minimize() calls minimize callback set via ui_window_set_cb() */
+PCUT_TEST(send_minimize)
+{
+	errno_t rc;
+	ui_t *ui = NULL;
+	ui_wnd_params_t params;
+	ui_window_t *window = NULL;
+	test_cb_resp_t resp;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_wnd_params_init(&params);
+	params.caption = "Hello";
+
+	rc = ui_window_create(ui, &params, &window);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(window);
+
+	/* Minimize callback with no callbacks set */
+	ui_window_send_minimize(window);
+
+	/* Minimize callback with minimize callback not implemented */
+	ui_window_set_cb(window, &dummy_window_cb, NULL);
+	ui_window_send_minimize(window);
+
+	/* Minimize callback with real callback set */
+	resp.minimize = false;
+	ui_window_set_cb(window, &test_window_cb, &resp);
+	ui_window_send_minimize(window);
+	PCUT_ASSERT_TRUE(resp.minimize);
+
+	ui_window_destroy(window);
+	ui_destroy(ui);
+}
+
 /** ui_window_send_maximize() calls maximize callback set via ui_window_set_cb() */
 PCUT_TEST(send_maximize)
@@ -849,4 +888,11 @@
 }
 
+static void test_window_minimize(ui_window_t *window, void *arg)
+{
+	test_cb_resp_t *resp = (test_cb_resp_t *) arg;
+
+	resp->minimize = true;
+}
+
 static void test_window_maximize(ui_window_t *window, void *arg)
 {
Index: uspace/srv/hid/display/display.c
===================================================================
--- uspace/srv/hid/display/display.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/srv/hid/display/display.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -304,5 +304,6 @@
 		gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
 
-		if (gfx_pix_inside_rect(pos, &drect))
+		if (gfx_pix_inside_rect(pos, &drect) &&
+		    ds_window_is_visible(wnd))
 			return wnd;
 
Index: uspace/srv/hid/display/dsops.c
===================================================================
--- uspace/srv/hid/display/dsops.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/srv/hid/display/dsops.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -54,4 +54,5 @@
 static errno_t disp_window_resize(void *, sysarg_t, gfx_coord2_t *,
     gfx_rect_t *);
+static errno_t disp_window_minimize(void *, sysarg_t);
 static errno_t disp_window_maximize(void *, sysarg_t);
 static errno_t disp_window_unmaximize(void *, sysarg_t);
@@ -70,4 +71,5 @@
 	.window_resize_req = disp_window_resize_req,
 	.window_resize = disp_window_resize,
+	.window_minimize = disp_window_minimize,
 	.window_maximize = disp_window_maximize,
 	.window_unmaximize = disp_window_unmaximize,
@@ -247,4 +249,24 @@
 }
 
+static errno_t disp_window_minimize(void *arg, sysarg_t wnd_id)
+{
+	ds_client_t *client = (ds_client_t *) arg;
+	ds_window_t *wnd;
+	errno_t rc;
+
+	ds_display_lock(client->display);
+
+	wnd = ds_client_find_window(client, wnd_id);
+	if (wnd == NULL) {
+		ds_display_unlock(client->display);
+		return ENOENT;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "disp_window_maximize()");
+	rc = ds_window_minimize(wnd);
+	ds_display_unlock(client->display);
+	return rc;
+}
+
 static errno_t disp_window_maximize(void *arg, sysarg_t wnd_id)
 {
Index: uspace/srv/hid/display/seat.c
===================================================================
--- uspace/srv/hid/display/seat.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/srv/hid/display/seat.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -90,7 +90,15 @@
 void ds_seat_set_focus(ds_seat_t *seat, ds_window_t *wnd)
 {
+	errno_t rc;
+
 	if (wnd == seat->focus) {
 		/* Focus is not changing */
 		return;
+	}
+
+	if (wnd != NULL) {
+		rc = ds_window_unminimize(wnd);
+		if (rc != EOK)
+			return;
 	}
 
Index: uspace/srv/hid/display/test/window.c
===================================================================
--- uspace/srv/hid/display/test/window.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/srv/hid/display/test/window.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -261,4 +261,79 @@
 }
 
+/** Test ds_window_minimize(). */
+PCUT_TEST(window_minimize)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *wnd;
+	display_wnd_params_t params;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, 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 = 10;
+
+	rc = ds_window_create(client, &params, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_window_minimize(wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_INT_EQUALS(wndf_minimized, wnd->flags & wndf_minimized);
+
+	ds_window_destroy(wnd);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
+/** Test ds_window_unminimize(). */
+PCUT_TEST(window_unminimize)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *wnd;
+	display_wnd_params_t params;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, 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.flags |= wndf_minimized;
+	params.rect.p0.x = params.rect.p0.y = 0;
+	params.rect.p1.x = params.rect.p1.y = 10;
+
+	rc = ds_window_create(client, &params, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ds_window_unminimize(wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_INT_EQUALS(0, wnd->flags & wndf_minimized);
+
+	ds_window_destroy(wnd);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
 /** Test ds_window_maximize(). */
 PCUT_TEST(window_maximize)
@@ -373,4 +448,42 @@
 	gc = ds_window_get_ctx(wnd);
 	PCUT_ASSERT_NOT_NULL(gc);
+
+	ds_window_destroy(wnd);
+	ds_seat_destroy(seat);
+	ds_client_destroy(client);
+	ds_display_destroy(disp);
+}
+
+/** Test ds_window_is_visible() */
+PCUT_TEST(is_visible)
+{
+	ds_display_t *disp;
+	ds_client_t *client;
+	ds_seat_t *seat;
+	ds_window_t *wnd;
+	display_wnd_params_t params;
+	errno_t rc;
+
+	rc = ds_display_create(NULL, 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 = 10;
+
+	rc = ds_window_create(client, &params, &wnd);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	PCUT_ASSERT_TRUE(ds_window_is_visible(wnd));
+
+	wnd->flags |= wndf_minimized;
+
+	PCUT_ASSERT_FALSE(ds_window_is_visible(wnd));
 
 	ds_window_destroy(wnd);
Index: uspace/srv/hid/display/window.c
===================================================================
--- uspace/srv/hid/display/window.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/srv/hid/display/window.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -220,4 +220,14 @@
 }
 
+/** Determine if window is visible.
+ *
+ * @param wnd Window
+ * @return @c true iff window is visible
+ */
+bool ds_window_is_visible(ds_window_t *wnd)
+{
+	return (wnd->flags & wndf_minimized) == 0;
+}
+
 /** Paint a window using its backing bitmap.
  *
@@ -233,4 +243,8 @@
 
 	log_msg(LOG_DEFAULT, LVL_DEBUG2, "ds_window_paint");
+
+	/* Skip painting the window if not visible */
+	if (!ds_window_is_visible(wnd))
+		return EOK;
 
 	if (rect != NULL) {
@@ -808,4 +822,36 @@
 }
 
+/** Minimize window.
+ *
+ * @param wnd Window
+ * @return EOK on success or an error code
+ */
+errno_t ds_window_minimize(ds_window_t *wnd)
+{
+	/* If already minimized, do nothing and return success. */
+	if ((wnd->flags & wndf_minimized) != 0)
+		return EOK;
+
+	wnd->flags |= wndf_minimized;
+	(void) ds_display_paint(wnd->display, NULL);
+	return EOK;
+}
+
+/** Unminimize window.
+ *
+ * @param wnd Window
+ * @return EOK on success or an error code
+ */
+errno_t ds_window_unminimize(ds_window_t *wnd)
+{
+	/* If not minimized, do nothing and return success. */
+	if ((wnd->flags & wndf_minimized) == 0)
+		return EOK;
+
+	wnd->flags &= ~wndf_minimized;
+	(void) ds_display_paint(wnd->display, NULL);
+	return EOK;
+}
+
 /** Maximize window.
  *
Index: uspace/srv/hid/display/window.h
===================================================================
--- uspace/srv/hid/display/window.h	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/srv/hid/display/window.h	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -41,4 +41,5 @@
 #include <errno.h>
 #include <io/pos_event.h>
+#include <stdbool.h>
 #include <types/gfx/context.h>
 #include <types/gfx/coord.h>
@@ -55,4 +56,5 @@
 extern void ds_window_bring_to_top(ds_window_t *);
 extern gfx_context_t *ds_window_get_ctx(ds_window_t *);
+extern bool ds_window_is_visible(ds_window_t *);
 extern errno_t ds_window_paint(ds_window_t *, gfx_rect_t *);
 errno_t ds_window_paint_preview(ds_window_t *, gfx_rect_t *);
@@ -68,4 +70,6 @@
     gfx_coord2_t *);
 extern errno_t ds_window_resize(ds_window_t *, gfx_coord2_t *, gfx_rect_t *);
+extern errno_t ds_window_minimize(ds_window_t *);
+extern errno_t ds_window_unminimize(ds_window_t *);
 extern errno_t ds_window_maximize(ds_window_t *);
 extern errno_t ds_window_unmaximize(ds_window_t *);
Index: uspace/srv/hid/display/wmops.c
===================================================================
--- uspace/srv/hid/display/wmops.c	(revision d46ac7333a9a0d174db0107e091c553e138660e6)
+++ uspace/srv/hid/display/wmops.c	(revision 06176e1f247c6c0450877aea38262568fcb8b9d7)
@@ -41,4 +41,5 @@
 #include "display.h"
 #include "seat.h"
+#include "window.h"
 #include "wmclient.h"
 
