Index: uspace/app/uidemo/uidemo.c
===================================================================
--- uspace/app/uidemo/uidemo.c	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/app/uidemo/uidemo.c	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -252,11 +252,5 @@
 	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);
-	ui_pbutton_destroy(demo.pb2);
-
+	ui_fixed_destroy(demo.fixed);
 	ui_window_destroy(window);
 	ui_destroy(ui);
Index: uspace/lib/ui/include/types/ui/control.h
===================================================================
--- uspace/lib/ui/include/types/ui/control.h	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/include/types/ui/control.h	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -46,4 +46,6 @@
 /** UI control ops */
 typedef struct ui_control_ops {
+	/** Destroy control */
+	void (*destroy)(void *);
 	/** Paint */
 	errno_t (*paint)(void *);
Index: uspace/lib/ui/include/ui/control.h
===================================================================
--- uspace/lib/ui/include/ui/control.h	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/include/ui/control.h	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -44,4 +44,5 @@
 extern errno_t ui_control_new(ui_control_ops_t *, void *, ui_control_t **);
 extern void ui_control_delete(ui_control_t *);
+extern void ui_control_destroy(ui_control_t *);
 extern errno_t ui_control_paint(ui_control_t *);
 extern ui_evclaim_t ui_control_pos_event(ui_control_t *, pos_event_t *);
Index: uspace/lib/ui/src/control.c
===================================================================
--- uspace/lib/ui/src/control.c	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/src/control.c	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -64,4 +64,6 @@
 /** Delete UI control.
  *
+ * Deletes the base control (not the extended data).
+ *
  * @param control UI control or @c NULL
  */
@@ -74,7 +76,19 @@
 }
 
+/** Destroy UI control.
+ *
+ * Run the virtual control destructor (destroy complete control including
+ * extended data).
+ *
+ * @param control Control
+ */
+void ui_control_destroy(ui_control_t *control)
+{
+	return control->ops->destroy(control->ext);
+}
+
 /** Paint UI control.
  *
- * @param control Push button
+ * @param control Control
  * @return EOK on success or an error code
  */
@@ -86,5 +100,5 @@
 /** Deliver position event to UI control.
  *
- * @param control Push button
+ * @param control Control
  * @param pos_event Position event
  * @return @c ui_claimed iff the event is claimed
Index: uspace/lib/ui/src/fixed.c
===================================================================
--- uspace/lib/ui/src/fixed.c	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/src/fixed.c	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -68,8 +68,19 @@
 void ui_fixed_destroy(ui_fixed_t *fixed)
 {
+	ui_fixed_elem_t *elem;
+	ui_control_t *control;
+
 	if (fixed == NULL)
 		return;
 
-	assert(list_empty(&fixed->elem));
+	elem = ui_fixed_first(fixed);
+	while (elem != NULL) {
+		control = elem->control;
+		ui_fixed_remove(fixed, control);
+		ui_control_destroy(control);
+
+		elem = ui_fixed_first(fixed);
+	}
+
 	free(fixed);
 }
Index: uspace/lib/ui/src/label.c
===================================================================
--- uspace/lib/ui/src/label.c	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/src/label.c	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -46,4 +46,5 @@
 #include "../private/resource.h"
 
+static void ui_label_ctl_destroy(void *);
 static errno_t ui_label_ctl_paint(void *);
 static ui_evclaim_t ui_label_ctl_pos_event(void *, pos_event_t *);
@@ -51,4 +52,5 @@
 /** Label control ops */
 ui_control_ops_t ui_label_ops = {
+	.destroy = ui_label_ctl_destroy,
 	.paint = ui_label_ctl_paint,
 	.pos_event = ui_label_ctl_pos_event
@@ -207,5 +209,16 @@
 }
 
-/** Paint lable control.
+/** Destroy label control.
+ *
+ * @param arg Argument (ui_label_t *)
+ */
+void ui_label_ctl_destroy(void *arg)
+{
+	ui_label_t *label = (ui_label_t *) arg;
+
+	ui_label_destroy(label);
+}
+
+/** Paint label control.
  *
  * @param arg Argument (ui_label_t *)
Index: uspace/lib/ui/src/pbutton.c
===================================================================
--- uspace/lib/ui/src/pbutton.c	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/src/pbutton.c	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -54,4 +54,5 @@
 };
 
+static void ui_pbutton_ctl_destroy(void *);
 static errno_t ui_pbutton_ctl_paint(void *);
 static ui_evclaim_t ui_pbutton_ctl_pos_event(void *, pos_event_t *);
@@ -59,4 +60,5 @@
 /** Push button control ops */
 ui_control_ops_t ui_pbutton_ops = {
+	.destroy = ui_pbutton_ctl_destroy,
 	.paint = ui_pbutton_ctl_paint,
 	.pos_event = ui_pbutton_ctl_pos_event
@@ -418,4 +420,15 @@
 }
 
+/** Destroy push button control.
+ *
+ * @param arg Argument (ui_pbutton_t *)
+ */
+void ui_pbutton_ctl_destroy(void *arg)
+{
+	ui_pbutton_t *pbutton = (ui_pbutton_t *) arg;
+
+	ui_pbutton_destroy(pbutton);
+}
+
 /** Paint push button control.
  *
Index: uspace/lib/ui/test/control.c
===================================================================
--- uspace/lib/ui/test/control.c	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/test/control.c	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -21,5 +21,5 @@
  * 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
+ * DATA, OR PROFITS; OR BUSINESS INTvvhhzccgggrERRUPTION) 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
@@ -39,8 +39,10 @@
 PCUT_TEST_SUITE(control);
 
+static void test_ctl_destroy(void *);
 static errno_t test_ctl_paint(void *);
 static ui_evclaim_t test_ctl_pos_event(void *, pos_event_t *);
 
 static ui_control_ops_t test_ctl_ops = {
+	.destroy = test_ctl_destroy,
 	.paint = test_ctl_paint,
 	.pos_event = test_ctl_pos_event
@@ -53,4 +55,7 @@
 	/** Result code to return */
 	errno_t rc;
+
+	/** @c true iff destroy was called */
+	bool destroy;
 
 	/** @c true iff paint was called */
@@ -80,4 +85,22 @@
 {
 	ui_control_delete(NULL);
+}
+
+/** Test sending destroy request to control */
+PCUT_TEST(destroy)
+{
+	ui_control_t *control = NULL;
+	test_resp_t resp;
+	errno_t rc;
+
+	rc = ui_control_new(&test_ctl_ops, &resp, &control);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(control);
+
+	resp.rc = EOK;
+	resp.destroy = false;
+
+	ui_control_destroy(control);
+	PCUT_ASSERT_TRUE(resp.destroy);
 }
 
@@ -143,4 +166,11 @@
 }
 
+static void test_ctl_destroy(void *arg)
+{
+	test_resp_t *resp = (test_resp_t *) arg;
+
+	resp->destroy = true;
+}
+
 static errno_t test_ctl_paint(void *arg)
 {
Index: uspace/lib/ui/test/fixed.c
===================================================================
--- uspace/lib/ui/test/fixed.c	(revision 4df6607cfca7bfd6049896be621a9b2b967d22db)
+++ uspace/lib/ui/test/fixed.c	(revision c6f00b40609fb2466fea3e6ae6e2a0cb88de98ef)
@@ -38,8 +38,10 @@
 PCUT_TEST_SUITE(fixed);
 
+static void test_ctl_destroy(void *);
 static errno_t test_ctl_paint(void *);
 static ui_evclaim_t test_ctl_pos_event(void *, pos_event_t *);
 
 static ui_control_ops_t test_ctl_ops = {
+	.destroy = test_ctl_destroy,
 	.paint = test_ctl_paint,
 	.pos_event = test_ctl_pos_event
@@ -52,8 +54,8 @@
 	/** Result code to return */
 	errno_t rc;
-
+	/** @c true iff destroy was called */
+	bool destroy;
 	/** @c true iff paint was called */
 	bool paint;
-
 	/** @c true iff pos_event was called */
 	bool pos;
@@ -113,4 +115,28 @@
 
 	ui_fixed_destroy(fixed);
+	ui_control_delete(control);
+}
+
+/** ui_fixed_destroy() delivers destroy request to control */
+PCUT_TEST(destroy)
+{
+	ui_fixed_t *fixed = NULL;
+	ui_control_t *control;
+	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.destroy = false;
+
+	ui_fixed_destroy(fixed);
+	PCUT_ASSERT_TRUE(resp.destroy);
 }
 
@@ -146,5 +172,4 @@
 	PCUT_ASSERT_TRUE(resp.paint);
 
-	ui_fixed_remove(fixed, control);
 	ui_fixed_destroy(fixed);
 }
@@ -186,6 +211,12 @@
 	PCUT_ASSERT_INT_EQUALS(resp.pevent.vpos, event.vpos);
 
-	ui_fixed_remove(fixed, control);
-	ui_fixed_destroy(fixed);
+	ui_fixed_destroy(fixed);
+}
+
+static void test_ctl_destroy(void *arg)
+{
+	test_resp_t *resp = (test_resp_t *) arg;
+
+	resp->destroy = true;
 }
 
