Index: uspace/app/uidemo/uidemo.c
===================================================================
--- uspace/app/uidemo/uidemo.c	(revision 477286789bd81a33ed42d124b747013d7d1da8d8)
+++ uspace/app/uidemo/uidemo.c	(revision f6df5a3d9b2985d969e8f80c26d0cec2273f3b7e)
@@ -39,15 +39,19 @@
 #include <ui/pbutton.h>
 #include <ui/resource.h>
+#include "uidemo.h"
 
 static void wnd_close_event(void *);
 static void wnd_kbd_event(void *, kbd_event_t *);
+static void wnd_pos_event(void *, pos_event_t *);
 
 static display_wnd_cb_t wnd_cb = {
 	.close_event = wnd_close_event,
-	.kbd_event = wnd_kbd_event
+	.kbd_event = wnd_kbd_event,
+	.pos_event = wnd_pos_event
 };
 
 static bool quit = false;
 
+/** Print syntax. */
 static void print_syntax(void)
 {
@@ -55,4 +59,5 @@
 }
 
+/** Handle window close event. */
 static void wnd_close_event(void *arg)
 {
@@ -61,4 +66,5 @@
 }
 
+/** Handle window keyboard event */
 static void wnd_kbd_event(void *arg, kbd_event_t *event)
 {
@@ -66,4 +72,55 @@
 	if (event->type == KEY_PRESS)
 		quit = true;
+}
+
+/** Handle window position event */
+static void wnd_pos_event(void *arg, pos_event_t *event)
+{
+	ui_demo_t *demo = (ui_demo_t *) arg;
+	gfx_rect_t rect1;
+	gfx_rect_t rect2;
+	gfx_coord2_t pos;
+
+	rect1.p0.x = 20;
+	rect1.p0.y = 50;
+	rect1.p1.x = 100;
+	rect1.p1.y = 80;
+
+	rect2.p0.x = 120;
+	rect2.p0.y = 50;
+	rect2.p1.x = 200;
+	rect2.p1.y = 80;
+
+	pos.x = event->hpos;
+	pos.y = event->vpos;
+
+	if (event->type == POS_PRESS) {
+		printf("Button press\n");
+
+		if (gfx_pix_inside_rect(&pos, &rect1)) {
+			printf("Press button 1\n");
+			ui_pbutton_press(demo->pb1);
+			(void) ui_pbutton_paint(demo->pb1);
+		}
+		if (gfx_pix_inside_rect(&pos, &rect2)) {
+			printf("Press button 2\n");
+			ui_pbutton_press(demo->pb2);
+			(void) ui_pbutton_paint(demo->pb2);
+		}
+	}
+
+	if (event->type == POS_RELEASE) {
+		printf("Button release\n");
+		if (gfx_pix_inside_rect(&pos, &rect1)) {
+			printf("Release button 1\n");
+			ui_pbutton_release(demo->pb1);
+			(void) ui_pbutton_paint(demo->pb1);
+		}
+		if (gfx_pix_inside_rect(&pos, &rect2)) {
+			printf("Release button 2\n");
+			ui_pbutton_release(demo->pb2);
+			(void) ui_pbutton_paint(demo->pb2);
+		}
+	}
 }
 
@@ -76,6 +133,5 @@
 	display_window_t *window = NULL;
 	ui_resource_t *ui_res;
-	ui_pbutton_t *pb1;
-	ui_pbutton_t *pb2;
+	ui_demo_t demo;
 	gfx_rect_t rect;
 	errno_t rc;
@@ -95,5 +151,6 @@
 	params.rect.p1.y = 100;
 
-	rc = display_window_create(display, &params, &wnd_cb, NULL, &window);
+	rc = display_window_create(display, &params, &wnd_cb, (void *) &demo,
+	    &window);
 	if (rc != EOK) {
 		printf("Error creating window.\n");
@@ -112,11 +169,11 @@
 	if (rc != EOK) {
 		printf("Error creating UI.\n");
-		return 1;
-	}
-
-	rc = ui_pbutton_create(ui_res, "Confirm", &pb1);
+		return rc;
+	}
+
+	rc = ui_pbutton_create(ui_res, "Confirm", &demo.pb1);
 	if (rc != EOK) {
 		printf("Error creating button.\n");
-		return 1;
+		return rc;
 	}
 
@@ -125,10 +182,10 @@
 	rect.p1.x = 100;
 	rect.p1.y = 80;
-	ui_pbutton_set_rect(pb1, &rect);
-
-	rc = ui_pbutton_create(ui_res, "Cancel", &pb2);
+	ui_pbutton_set_rect(demo.pb1, &rect);
+
+	rc = ui_pbutton_create(ui_res, "Cancel", &demo.pb2);
 	if (rc != EOK) {
 		printf("Error creating button.\n");
-		return 1;
+		return rc;
 	}
 
@@ -137,16 +194,16 @@
 	rect.p1.x = 200;
 	rect.p1.y = 80;
-	ui_pbutton_set_rect(pb2, &rect);
-
-	rc = ui_pbutton_paint(pb1);
+	ui_pbutton_set_rect(demo.pb2, &rect);
+
+	rc = ui_pbutton_paint(demo.pb1);
 	if (rc != EOK) {
 		printf("Error painting button.\n");
-		return 1;
-	}
-
-	rc = ui_pbutton_paint(pb2);
+		return rc;
+	}
+
+	rc = ui_pbutton_paint(demo.pb2);
 	if (rc != EOK) {
 		printf("Error painting button.\n");
-		return 1;
+		return rc;
 	}
 
@@ -155,6 +212,6 @@
 	}
 
-	ui_pbutton_destroy(pb1);
-	ui_pbutton_destroy(pb2);
+	ui_pbutton_destroy(demo.pb1);
+	ui_pbutton_destroy(demo.pb2);
 
 	rc = gfx_context_delete(gc);
Index: uspace/app/uidemo/uidemo.h
===================================================================
--- uspace/app/uidemo/uidemo.h	(revision f6df5a3d9b2985d969e8f80c26d0cec2273f3b7e)
+++ uspace/app/uidemo/uidemo.h	(revision f6df5a3d9b2985d969e8f80c26d0cec2273f3b7e)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup uidemo
+ * @{
+ */
+/**
+ * @file User interface demo
+ */
+
+#ifndef UIDEMO_H
+#define UIDEMO_H
+
+/** User interface demo */
+typedef struct {
+	ui_pbutton_t *pb1;
+	ui_pbutton_t *pb2;
+} ui_demo_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/include/ui/pbutton.h
===================================================================
--- uspace/lib/ui/include/ui/pbutton.h	(revision 477286789bd81a33ed42d124b747013d7d1da8d8)
+++ uspace/lib/ui/include/ui/pbutton.h	(revision f6df5a3d9b2985d969e8f80c26d0cec2273f3b7e)
@@ -47,4 +47,6 @@
 extern void ui_pbutton_set_rect(ui_pbutton_t *, gfx_rect_t *);
 extern errno_t ui_pbutton_paint(ui_pbutton_t *);
+extern void ui_pbutton_press(ui_pbutton_t *);
+extern void ui_pbutton_release(ui_pbutton_t *);
 
 #endif
Index: uspace/lib/ui/private/pbutton.h
===================================================================
--- uspace/lib/ui/private/pbutton.h	(revision 477286789bd81a33ed42d124b747013d7d1da8d8)
+++ uspace/lib/ui/private/pbutton.h	(revision f6df5a3d9b2985d969e8f80c26d0cec2273f3b7e)
@@ -40,4 +40,5 @@
 #include <gfx/context.h>
 #include <gfx/coord.h>
+#include <stdbool.h>
 
 /** Actual structure of push button.
@@ -52,4 +53,6 @@
 	/** Caption */
 	const char *caption;
+	/** Button is currently held down */
+	bool held;
 };
 
Index: uspace/lib/ui/src/pbutton.c
===================================================================
--- uspace/lib/ui/src/pbutton.c	(revision 477286789bd81a33ed42d124b747013d7d1da8d8)
+++ uspace/lib/ui/src/pbutton.c	(revision f6df5a3d9b2985d969e8f80c26d0cec2273f3b7e)
@@ -44,4 +44,10 @@
 #include "../private/pbutton.h"
 #include "../private/resource.h"
+
+/** Caption movement when button is pressed down */
+enum {
+	ui_pb_press_dx = 2,
+	ui_pb_press_dy = 2
+};
 
 /** Create new push button.
@@ -106,7 +112,13 @@
 	errno_t rc;
 
-	rc = gfx_color_new_rgb_i16(0xc8c8, 0xc8c8, 0xc8c8, &color);
-	if (rc != EOK)
-		goto error;
+	if (pbutton->held) {
+		rc = gfx_color_new_rgb_i16(0x8000, 0, 0, &color);
+		if (rc != EOK)
+			goto error;
+	} else {
+		rc = gfx_color_new_rgb_i16(0xc8c8, 0xc8c8, 0xc8c8, &color);
+		if (rc != EOK)
+			goto error;
+	}
 
 	rc = gfx_set_color(pbutton->res->gc, color);
@@ -132,4 +144,9 @@
 	pos.y = (pbutton->rect.p0.y + pbutton->rect.p1.y) / 2;
 
+	if (pbutton->held) {
+		pos.x += ui_pb_press_dx;
+		pos.y += ui_pb_press_dy;
+	}
+
 	gfx_text_fmt_init(&fmt);
 	fmt.halign = gfx_halign_center;
@@ -149,4 +166,26 @@
 }
 
+/** Press down button.
+ *
+ * This does not automatically repaint the button.
+ *
+ * @param pbutton Push button
+ */
+void ui_pbutton_press(ui_pbutton_t *pbutton)
+{
+	pbutton->held = true;
+}
+
+/** Release button.
+ *
+ * This does not automatically repaint the button.
+ *
+ * @param pbutton Push button
+ */
+void ui_pbutton_release(ui_pbutton_t *pbutton)
+{
+	pbutton->held = false;
+}
+
 /** @}
  */
