Index: uspace/app/uidemo/uidemo.c
===================================================================
--- uspace/app/uidemo/uidemo.c	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/app/uidemo/uidemo.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -40,4 +40,5 @@
 #include <str.h>
 #include <task.h>
+#include <ui/fixed.h>
 #include <ui/label.h>
 #include <ui/pbutton.h>
@@ -84,9 +85,8 @@
 
 	/* Make sure we don't process events until fully initialized */
-	if (demo->pb1 == NULL || demo->pb2 == NULL)
+	if (demo->fixed == NULL)
 		return;
 
-	ui_pbutton_pos_event(demo->pb1, event);
-	ui_pbutton_pos_event(demo->pb2, event);
+	ui_fixed_pos_event(demo->fixed, event);
 }
 
@@ -159,4 +159,10 @@
 	ui_window_get_app_rect(window, &app_rect);
 
+	rc = ui_fixed_create(&demo.fixed);
+	if (rc != EOK) {
+		printf("Error creating fixed layout.\n");
+		return rc;
+	}
+
 	rc = ui_label_create(ui_res, "Hello there!", &demo.label);
 	if (rc != EOK) {
@@ -172,4 +178,10 @@
 	ui_label_set_halign(demo.label, gfx_halign_center);
 
+	rc = ui_fixed_add(demo.fixed, ui_label_ctl(demo.label));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		return rc;
+	}
+
 	rc = ui_pbutton_create(ui_res, "Confirm", &demo.pb1);
 	if (rc != EOK) {
@@ -188,4 +200,10 @@
 	ui_pbutton_set_default(demo.pb1, true);
 
+	rc = ui_fixed_add(demo.fixed, ui_pbutton_ctl(demo.pb1));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		return rc;
+	}
+
 	rc = ui_pbutton_create(ui_res, "Cancel", &demo.pb2);
 	if (rc != EOK) {
@@ -202,4 +220,10 @@
 	ui_pbutton_set_rect(demo.pb2, &rect);
 
+	rc = ui_fixed_add(demo.fixed, ui_pbutton_ctl(demo.pb2));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		return rc;
+	}
+
 	rc = gfx_color_new_rgb_i16(0xc8c8, 0xc8c8, 0xc8c8, &color);
 	if (rc != EOK) {
@@ -239,4 +263,8 @@
 
 	ui_run(ui);
+
+	ui_fixed_remove(demo.fixed, ui_label_ctl(demo.label));
+	ui_fixed_remove(demo.fixed, ui_pbutton_ctl(demo.pb1));
+	ui_fixed_remove(demo.fixed, ui_pbutton_ctl(demo.pb2));
 
 	ui_pbutton_destroy(demo.pb1);
Index: uspace/app/uidemo/uidemo.h
===================================================================
--- uspace/app/uidemo/uidemo.h	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/app/uidemo/uidemo.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -38,4 +38,5 @@
 
 #include <display.h>
+#include <ui/fixed.h>
 #include <ui/label.h>
 #include <ui/pbutton.h>
@@ -47,4 +48,5 @@
 	ui_t *ui;
 	ui_window_t *window;
+	ui_fixed_t *fixed;
 	ui_label_t *label;
 	ui_pbutton_t *pb1;
Index: uspace/lib/ui/include/types/ui/control.h
===================================================================
--- uspace/lib/ui/include/types/ui/control.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/include/types/ui/control.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,54 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file UI control
+ */
+
+#ifndef _UI_TYPES_CONTROL_H
+#define _UI_TYPES_CONTROL_H
+
+#include <io/pos_event.h>
+#include <types/ui/event.h>
+
+struct ui_control;
+typedef struct ui_control ui_control_t;
+
+/** UI control ops */
+typedef struct ui_control_ops {
+	/** Position event */
+	ui_evclaim_t (*pos_event)(void *, pos_event_t *);
+} ui_control_ops_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/include/types/ui/fixed.h
===================================================================
--- uspace/lib/ui/include/types/ui/fixed.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/include/types/ui/fixed.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,45 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file Fixed layout
+ */
+
+#ifndef _UI_TYPES_FIXED_H
+#define _UI_TYPES_FIXED_H
+
+struct ui_fixed;
+typedef struct ui_fixed ui_fixed_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/include/ui/control.h
===================================================================
--- uspace/lib/ui/include/ui/control.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/include/ui/control.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,51 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file UI control
+ */
+
+#ifndef _UI_CONTROL_H
+#define _UI_CONTROL_H
+
+#include <errno.h>
+#include <io/pos_event.h>
+#include <types/ui/control.h>
+#include <types/ui/event.h>
+
+extern errno_t ui_control_new(ui_control_ops_t *, void *, ui_control_t **);
+extern void ui_control_delete(ui_control_t *);
+extern ui_evclaim_t ui_control_pos_event(ui_control_t *, pos_event_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/include/ui/fixed.h
===================================================================
--- uspace/lib/ui/include/ui/fixed.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/include/ui/fixed.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,54 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file Fixed layout
+ */
+
+#ifndef _UI_FIXED_H
+#define _UI_FIXED_H
+
+#include <errno.h>
+#include <io/pos_event.h>
+#include <types/ui/control.h>
+#include <types/ui/event.h>
+#include <types/ui/fixed.h>
+
+extern errno_t ui_fixed_create(ui_fixed_t **);
+extern void ui_fixed_destroy(ui_fixed_t *);
+extern errno_t ui_fixed_add(ui_fixed_t *, ui_control_t *);
+extern void ui_fixed_remove(ui_fixed_t *, ui_control_t *);
+extern ui_evclaim_t ui_fixed_pos_event(ui_fixed_t *, pos_event_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/include/ui/label.h
===================================================================
--- uspace/lib/ui/include/ui/label.h	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/include/ui/label.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -40,4 +40,5 @@
 #include <gfx/coord.h>
 #include <gfx/text.h>
+#include <types/ui/control.h>
 #include <types/ui/label.h>
 #include <types/ui/resource.h>
@@ -46,4 +47,5 @@
     ui_label_t **);
 extern void ui_label_destroy(ui_label_t *);
+extern ui_control_t *ui_label_ctl(ui_label_t *);
 extern void ui_label_set_rect(ui_label_t *, gfx_rect_t *);
 extern void ui_label_set_halign(ui_label_t *, gfx_halign_t);
Index: uspace/lib/ui/include/ui/pbutton.h
===================================================================
--- uspace/lib/ui/include/ui/pbutton.h	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/include/ui/pbutton.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -40,4 +40,5 @@
 #include <gfx/coord.h>
 #include <io/pos_event.h>
+#include <types/ui/control.h>
 #include <types/ui/event.h>
 #include <types/ui/pbutton.h>
@@ -48,4 +49,5 @@
     ui_pbutton_t **);
 extern void ui_pbutton_destroy(ui_pbutton_t *);
+extern ui_control_t *ui_pbutton_ctl(ui_pbutton_t *);
 extern void ui_pbutton_set_cb(ui_pbutton_t *, ui_pbutton_cb_t *, void *);
 extern void ui_pbutton_set_rect(ui_pbutton_t *, gfx_rect_t *);
Index: uspace/lib/ui/meson.build
===================================================================
--- uspace/lib/ui/meson.build	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/meson.build	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -29,5 +29,7 @@
 deps = [ 'gfx', 'gfxfont', 'display' ]
 src = files(
+	'src/control.c',
 	'src/dummygc.c',
+	'src/fixed.c',
 	'src/label.c',
 	'src/paint.c',
@@ -40,4 +42,6 @@
 
 test_src = files(
+	'test/control.c',
+	'test/fixed.c',
 	'test/label.c',
 	'test/main.c',
Index: uspace/lib/ui/private/control.h
===================================================================
--- uspace/lib/ui/private/control.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/private/control.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,62 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file UI control structure
+ *
+ */
+
+#ifndef _UI_PRIVATE_CONTROL_H
+#define _UI_PRIVATE_CONTROL_H
+
+#include <gfx/coord.h>
+#include <stdbool.h>
+
+/** Actual structure of UI control.
+ *
+ * UI control is the abstract base class to all UI controls (e.g. push button,
+ * label). This is private to libui.
+ */
+struct ui_control {
+	/** Pointer to layout element structure this control is attached to
+	 * or @c NULL if the control is not attached to a layout
+	 */
+	void *elemp;
+	/** Ops */
+	struct ui_control_ops *ops;
+	/** Extended data */
+	void *ext;
+};
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/private/fixed.h
===================================================================
--- uspace/lib/ui/private/fixed.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/private/fixed.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,70 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file Fixed layout structure
+ *
+ */
+
+#ifndef _UI_PRIVATE_FIXED_H
+#define _UI_PRIVATE_FIXED_H
+
+#include <adt/list.h>
+#include <gfx/coord.h>
+#include <stdbool.h>
+#include <types/ui/fixed.h>
+
+/** Actual structure of fixed layout.
+ *
+ * This is private to libui.
+ */
+struct ui_fixed {
+	/** Layout elements (ui_fixed_elem_t) */
+	list_t elem;
+};
+
+/** Fixed layout element. */
+typedef struct {
+	/** Containing fixed layout */
+	struct ui_fixed *fixed;
+	/** Link to @c fixed->elem list */
+	link_t lelems;
+	/** Control */
+	ui_control_t *control;
+} ui_fixed_elem_t;
+
+extern ui_fixed_elem_t *ui_fixed_first(ui_fixed_t *f);
+extern ui_fixed_elem_t *ui_fixed_next(ui_fixed_elem_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/private/label.h
===================================================================
--- uspace/lib/ui/private/label.h	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/private/label.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -46,4 +46,6 @@
  */
 struct ui_label {
+	/** Base control object */
+	struct ui_control *control;
 	/** UI resource */
 	struct ui_resource *res;
Index: uspace/lib/ui/private/pbutton.h
===================================================================
--- uspace/lib/ui/private/pbutton.h	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/private/pbutton.h	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -46,4 +46,6 @@
  */
 struct ui_pbutton {
+	/** Base control object */
+	struct ui_control *control;
 	/** UI resource */
 	struct ui_resource *res;
Index: uspace/lib/ui/src/control.c
===================================================================
--- uspace/lib/ui/src/control.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/src/control.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,88 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file UI control
+ */
+
+#include <errno.h>
+#include <io/pos_event.h>
+#include <stdlib.h>
+#include <ui/control.h>
+#include "../private/control.h"
+
+/** Allocate new UI control.
+ *
+ * @param ops Control ops
+ * @param ext Control extended data
+ * @param rcontrol Place to store pointer to new control
+ * @return EOK on success, ENOMEM if out of memory
+ */
+errno_t ui_control_new(ui_control_ops_t *ops, void *ext,
+    ui_control_t **rcontrol)
+{
+	ui_control_t *control;
+
+	control = calloc(1, sizeof(ui_control_t));
+	if (control == NULL)
+		return ENOMEM;
+
+	control->ops = ops;
+	control->ext = ext;
+	*rcontrol = control;
+	return EOK;
+}
+
+/** Delete UI control.
+ *
+ * @param control UI control or @c NULL
+ */
+void ui_control_delete(ui_control_t *control)
+{
+	if (control == NULL)
+		return;
+
+	free(control);
+}
+
+/** Deliver position event to UI control.
+ *
+ * @param control Push button
+ * @param pos_event Position event
+ * @return @c ui_claimed iff the event is claimed
+ */
+ui_evclaim_t ui_control_pos_event(ui_control_t *control, pos_event_t *event)
+{
+	return control->ops->pos_event(control->ext, event);
+}
+
+/** @}
+ */
Index: uspace/lib/ui/src/fixed.c
===================================================================
--- uspace/lib/ui/src/fixed.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/src/fixed.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,173 @@
+/*
+ * 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 libui
+ * @{
+ */
+/**
+ * @file Fixed layout
+ */
+
+#include <adt/list.h>
+#include <assert.h>
+#include <errno.h>
+#include <io/pos_event.h>
+#include <stdlib.h>
+#include <ui/control.h>
+#include <ui/fixed.h>
+#include "../private/control.h"
+#include "../private/fixed.h"
+
+/** Create new fixed layout.
+ *
+ * @param rfixed Place to store pointer to new fixed layout
+ * @return EOK on success, ENOMEM if out of memory
+ */
+errno_t ui_fixed_create(ui_fixed_t **rfixed)
+{
+	ui_fixed_t *fixed;
+
+	fixed = calloc(1, sizeof(ui_fixed_t));
+	if (fixed == NULL)
+		return ENOMEM;
+
+	list_initialize(&fixed->elem);
+	*rfixed = fixed;
+	return EOK;
+}
+
+/** Destroy fixed layout.
+ *
+ * @param fixed Fixed layout or @c NULL
+ */
+void ui_fixed_destroy(ui_fixed_t *fixed)
+{
+	if (fixed == NULL)
+		return;
+
+	assert(list_empty(&fixed->elem));
+	free(fixed);
+}
+
+/** Add control to fixed layout.
+ *
+ * @param fixed Fixed layout
+ * @param control Control
+ * @return EOK on success, ENOMEM if out of memory
+ */
+errno_t ui_fixed_add(ui_fixed_t *fixed, ui_control_t *control)
+{
+	ui_fixed_elem_t *elem;
+
+	elem = calloc(1, sizeof(ui_fixed_elem_t));
+	if (elem == NULL)
+		return ENOMEM;
+
+	elem->fixed = fixed;
+	elem->control = control;
+	control->elemp = (void *) elem;
+	list_append(&elem->lelems, &fixed->elem);
+
+	return EOK;
+}
+
+/** Remove control from fixed layout.
+ *
+ * @param fixed Fixed layout
+ * @param control Control
+ */
+void ui_fixed_remove(ui_fixed_t *fixed, ui_control_t *control)
+{
+	ui_fixed_elem_t *elem;
+
+	elem = (ui_fixed_elem_t *) control->elemp;
+	assert(elem->fixed == fixed);
+
+	list_remove(&elem->lelems);
+	control->elemp = NULL;
+
+	free(elem);
+}
+
+/** Get first element of fixed layout.
+ *
+ * @param fixed Fixed layout
+ * @return First element or @c NULL
+ */
+ui_fixed_elem_t *ui_fixed_first(ui_fixed_t *fixed)
+{
+	link_t *link;
+
+	link = list_first(&fixed->elem);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, ui_fixed_elem_t, lelems);
+}
+
+/** Get next element of fixed layout.
+ *
+ * @param cur Current element
+ * @return Next element or @c NULL
+ */
+ui_fixed_elem_t *ui_fixed_next(ui_fixed_elem_t *cur)
+{
+	link_t *link;
+
+	link = list_next(&cur->lelems, &cur->fixed->elem);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, ui_fixed_elem_t, lelems);
+}
+
+/** Handle fixed layout position event.
+ *
+ * @param fixed Fixed layout
+ * @param pos_event Position event
+ * @return @c ui_claimed iff the event is claimed
+ */
+ui_evclaim_t ui_fixed_pos_event(ui_fixed_t *fixed, pos_event_t *event)
+{
+	ui_fixed_elem_t *elem;
+	ui_evclaim_t claimed;
+
+	elem = ui_fixed_first(fixed);
+	while (elem != NULL) {
+		claimed = ui_control_pos_event(elem->control, event);
+		if (claimed == ui_claimed)
+			return ui_claimed;
+
+		elem = ui_fixed_next(elem);
+	}
+
+	return ui_unclaimed;
+}
+
+/** @}
+ */
Index: uspace/lib/ui/src/label.c
===================================================================
--- uspace/lib/ui/src/label.c	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/src/label.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -40,4 +40,5 @@
 #include <stdlib.h>
 #include <str.h>
+#include <ui/control.h>
 #include <ui/paint.h>
 #include <ui/label.h>
@@ -45,4 +46,11 @@
 #include "../private/resource.h"
 
+static ui_evclaim_t ui_label_ctl_pos_event(void *, pos_event_t *);
+
+/** Label control ops */
+ui_control_ops_t ui_label_ops = {
+	.pos_event = ui_label_ctl_pos_event
+};
+
 /** Create new label.
  *
@@ -56,4 +64,5 @@
 {
 	ui_label_t *label;
+	errno_t rc;
 
 	label = calloc(1, sizeof(ui_label_t));
@@ -61,6 +70,13 @@
 		return ENOMEM;
 
+	rc = ui_control_new(&ui_label_ops, (void *) label, &label->control);
+	if (rc != EOK) {
+		free(label);
+		return rc;
+	}
+
 	label->text = str_dup(text);
 	if (label->text == NULL) {
+		ui_control_delete(label->control);
 		free(label);
 		return ENOMEM;
@@ -82,5 +98,16 @@
 		return;
 
+	ui_control_delete(label->control);
 	free(label);
+}
+
+/** Get base control from label.
+ *
+ * @param label Label
+ * @return Control
+ */
+ui_control_t *ui_label_ctl(ui_label_t *label)
+{
+	return label->control;
 }
 
@@ -178,4 +205,18 @@
 }
 
+/** Handle label control position event.
+ *
+ * @param arg Argument (ui_label_t *)
+ * @param pos_event Position event
+ * @return @c ui_claimed iff the event is claimed
+ */
+ui_evclaim_t ui_label_ctl_pos_event(void *arg, pos_event_t *event)
+{
+	ui_label_t *label = (ui_label_t *) arg;
+
+	(void) label;
+	return ui_unclaimed;
+}
+
 /** @}
  */
Index: uspace/lib/ui/src/pbutton.c
===================================================================
--- uspace/lib/ui/src/pbutton.c	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/src/pbutton.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -42,4 +42,5 @@
 #include <stdlib.h>
 #include <str.h>
+#include <ui/control.h>
 #include <ui/paint.h>
 #include <ui/pbutton.h>
@@ -53,4 +54,11 @@
 };
 
+static ui_evclaim_t ui_pbutton_ctl_pos_event(void *, pos_event_t *);
+
+/** Push button control ops */
+ui_control_ops_t ui_pbutton_ops = {
+	.pos_event = ui_pbutton_ctl_pos_event
+};
+
 /** Create new push button.
  *
@@ -64,4 +72,5 @@
 {
 	ui_pbutton_t *pbutton;
+	errno_t rc;
 
 	pbutton = calloc(1, sizeof(ui_pbutton_t));
@@ -69,6 +78,14 @@
 		return ENOMEM;
 
+	rc = ui_control_new(&ui_pbutton_ops, (void *) pbutton,
+	    &pbutton->control);
+	if (rc != EOK) {
+		free(pbutton);
+		return rc;
+	}
+
 	pbutton->caption = str_dup(caption);
 	if (pbutton->caption == NULL) {
+		ui_control_delete(pbutton->control);
 		free(pbutton);
 		return ENOMEM;
@@ -89,5 +106,16 @@
 		return;
 
+	ui_control_delete(pbutton->control);
 	free(pbutton);
+}
+
+/** Get base control from push button.
+ *
+ * @param pbutton Push button
+ * @return Control
+ */
+ui_control_t *ui_pbutton_ctl(ui_pbutton_t *pbutton)
+{
+	return pbutton->control;
 }
 
@@ -388,4 +416,17 @@
 }
 
+/** Handle push button control position event.
+ *
+ * @param arg Argument (ui_pbutton_t *)
+ * @param pos_event Position event
+ * @return @c ui_claimed iff the event is claimed
+ */
+ui_evclaim_t ui_pbutton_ctl_pos_event(void *arg, pos_event_t *event)
+{
+	ui_pbutton_t *pbutton = (ui_pbutton_t *) arg;
+
+	return ui_pbutton_pos_event(pbutton, event);
+}
+
 /** @}
  */
Index: uspace/lib/ui/test/control.c
===================================================================
--- uspace/lib/ui/test/control.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/test/control.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#include <mem.h>
+#include <io/pos_event.h>
+#include <pcut/pcut.h>
+#include <ui/control.h>
+#include <stdbool.h>
+#include <types/ui/event.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(control);
+
+static ui_evclaim_t test_ctl_pos_event(void *, pos_event_t *);
+
+static ui_control_ops_t test_ctl_ops = {
+	.pos_event = test_ctl_pos_event
+};
+
+/** Test response */
+typedef struct {
+	/** Claim to return */
+	ui_evclaim_t claim;
+
+	/** @c true iff pos_event was called */
+	bool pos;
+	/** Position event that was sent */
+	pos_event_t pevent;
+} test_resp_t;
+
+/** Allocate and deallocate control */
+PCUT_TEST(new_delete)
+{
+	ui_control_t *control = NULL;
+	errno_t rc;
+
+	rc = ui_control_new(&test_ctl_ops, NULL, &control);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(control);
+
+	ui_control_delete(control);
+}
+
+/** ui_control_delete() can take NULL argument (no-op) */
+PCUT_TEST(delete_null)
+{
+	ui_control_delete(NULL);
+}
+
+/** Test sending position event to control */
+PCUT_TEST(pos_event)
+{
+	ui_control_t *control = NULL;
+	test_resp_t resp;
+	pos_event_t event;
+	ui_evclaim_t claim;
+	errno_t rc;
+
+	rc = ui_control_new(&test_ctl_ops, &resp, &control);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(control);
+
+	resp.claim = ui_claimed;
+	resp.pos = false;
+	event.pos_id = 1;
+	event.type = POS_PRESS;
+	event.btn_num = 2;
+	event.hpos = 3;
+	event.vpos = 4;
+
+	claim = ui_control_pos_event(control, &event);
+	PCUT_ASSERT_EQUALS(resp.claim, claim);
+	PCUT_ASSERT_TRUE(resp.pos);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.pos_id, event.pos_id);
+	PCUT_ASSERT_EQUALS(resp.pevent.type, event.type);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.btn_num, event.btn_num);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.hpos, event.hpos);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.vpos, event.vpos);
+
+	ui_control_delete(control);
+}
+
+static ui_evclaim_t test_ctl_pos_event(void *arg, pos_event_t *event)
+{
+	test_resp_t *resp = (test_resp_t *) arg;
+
+	resp->pos = true;
+	resp->pevent = *event;
+
+	return resp->claim;
+}
+
+PCUT_EXPORT(control);
Index: uspace/lib/ui/test/fixed.c
===================================================================
--- uspace/lib/ui/test/fixed.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
+++ uspace/lib/ui/test/fixed.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include <pcut/pcut.h>
+#include <stddef.h>
+#include <ui/control.h>
+#include <ui/fixed.h>
+#include "../private/fixed.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(fixed);
+
+static ui_evclaim_t test_ctl_pos_event(void *, pos_event_t *);
+
+static ui_control_ops_t test_ctl_ops = {
+	.pos_event = test_ctl_pos_event
+};
+
+/** Test response */
+typedef struct {
+	/** Claim to return */
+	ui_evclaim_t claim;
+
+	/** @c true iff pos_event was called */
+	bool pos;
+	/** Position event that was sent */
+	pos_event_t pevent;
+} test_resp_t;
+
+/** Create and destroy button */
+PCUT_TEST(create_destroy)
+{
+	ui_fixed_t *fixed = NULL;
+	errno_t rc;
+
+	rc = ui_fixed_create(&fixed);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(fixed);
+
+	ui_fixed_destroy(fixed);
+}
+
+/** ui_fixed_destroy() can take NULL argument (no-op) */
+PCUT_TEST(destroy_null)
+{
+	ui_fixed_destroy(NULL);
+}
+
+/** ui_fixed_add() / ui_fixed_remove() adds/removes control */
+PCUT_TEST(add_remove)
+{
+	ui_fixed_t *fixed = NULL;
+	ui_control_t *control;
+	ui_fixed_elem_t *e;
+	errno_t rc;
+
+	rc = ui_fixed_create(&fixed);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	e = ui_fixed_first(fixed);
+	PCUT_ASSERT_NULL(e);
+
+	rc = ui_control_new(NULL, NULL, &control);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ui_fixed_add(fixed, control);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	e = ui_fixed_first(fixed);
+	PCUT_ASSERT_NOT_NULL(e);
+	PCUT_ASSERT_EQUALS(control, e->control);
+	e = ui_fixed_next(e);
+	PCUT_ASSERT_NULL(e);
+
+	ui_fixed_remove(fixed, control);
+
+	e = ui_fixed_first(fixed);
+	PCUT_ASSERT_NULL(e);
+
+	ui_fixed_destroy(fixed);
+}
+
+/** ui_pos_event() delivers position event to control */
+PCUT_TEST(pos_event)
+{
+	ui_fixed_t *fixed = NULL;
+	ui_control_t *control;
+	ui_evclaim_t claim;
+	pos_event_t event;
+	test_resp_t resp;
+	errno_t rc;
+
+	rc = ui_fixed_create(&fixed);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ui_control_new(&test_ctl_ops, (void *) &resp, &control);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ui_fixed_add(fixed, control);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	resp.claim = ui_claimed;
+	resp.pos = false;
+	event.pos_id = 1;
+	event.type = POS_PRESS;
+	event.btn_num = 2;
+	event.hpos = 3;
+	event.vpos = 4;
+
+	claim = ui_fixed_pos_event(fixed, &event);
+	PCUT_ASSERT_EQUALS(resp.claim, claim);
+	PCUT_ASSERT_TRUE(resp.pos);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.pos_id, event.pos_id);
+	PCUT_ASSERT_EQUALS(resp.pevent.type, event.type);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.btn_num, event.btn_num);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.hpos, event.hpos);
+	PCUT_ASSERT_INT_EQUALS(resp.pevent.vpos, event.vpos);
+
+	ui_fixed_remove(fixed, control);
+	ui_fixed_destroy(fixed);
+}
+
+static ui_evclaim_t test_ctl_pos_event(void *arg, pos_event_t *event)
+{
+	test_resp_t *resp = (test_resp_t *) arg;
+
+	resp->pos = true;
+	resp->pevent = *event;
+
+	return resp->claim;
+}
+
+PCUT_EXPORT(fixed);
Index: uspace/lib/ui/test/main.c
===================================================================
--- uspace/lib/ui/test/main.c	(revision f03d1308db413ac682d3d6bf4340b8c21226d67a)
+++ uspace/lib/ui/test/main.c	(revision 8009dc27f6b9ffbcd5c537a5e39b830b1bb8c841)
@@ -31,4 +31,6 @@
 PCUT_INIT;
 
+PCUT_IMPORT(control);
+PCUT_IMPORT(fixed);
 PCUT_IMPORT(label);
 PCUT_IMPORT(paint);
