Index: uspace/app/meson.build
===================================================================
--- uspace/app/meson.build	(revision 85ec7d459c810ac7328589525ff42bfa4a077966)
+++ uspace/app/meson.build	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -83,4 +83,5 @@
 	'sysinst',
 	'taskbar',
+	'taskbar-cfg',
 	'taskdump',
 	'terminal',
Index: uspace/app/taskbar-cfg/doc/doxygroups.h
===================================================================
--- uspace/app/taskbar-cfg/doc/doxygroups.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/doc/doxygroups.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,4 @@
+/** @addtogroup taskbar-cfg taskbar-cfg
+ * @brief Taskbar configuration utility (UI)
+ * @ingroup apps
+ */
Index: uspace/app/taskbar-cfg/main.c
===================================================================
--- uspace/app/taskbar-cfg/main.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/main.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2023 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 taskbar-cfg
+ * @{
+ */
+/** @file Taskbar configuration utility (UI) main
+ */
+
+#include <stdio.h>
+#include <str.h>
+#include <ui/ui.h>
+#include "taskbar-cfg.h"
+
+static void print_syntax(void)
+{
+	printf("Syntax: taskbarcfg [-d <display-spec>]\n");
+}
+
+int main(int argc, char *argv[])
+{
+	const char *display_spec = UI_ANY_DEFAULT;
+	taskbar_cfg_t *tbcfg;
+	errno_t rc;
+	int i;
+
+	i = 1;
+	while (i < argc && argv[i][0] == '-') {
+		if (str_cmp(argv[i], "-d") == 0) {
+			++i;
+			if (i >= argc) {
+				printf("Argument missing.\n");
+				print_syntax();
+				return 1;
+			}
+
+			display_spec = argv[i++];
+		} else {
+			printf("Invalid option '%s'.\n", argv[i]);
+			print_syntax();
+			return 1;
+		}
+	}
+
+	if (i < argc) {
+		print_syntax();
+		return 1;
+	}
+
+	rc = taskbar_cfg_create(display_spec, &tbcfg);
+	if (rc != EOK)
+		return 1;
+
+	rc = taskbar_cfg_open(tbcfg, "/cfg/taskbar.sif");
+	if (rc != EOK)
+		return 1;
+
+	rc = taskbar_cfg_populate(tbcfg);
+	if (rc != EOK)
+		return 1;
+
+	ui_run(tbcfg->ui);
+	taskbar_cfg_destroy(tbcfg);
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/taskbar-cfg/meson.build
===================================================================
--- uspace/app/taskbar-cfg/meson.build	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/meson.build	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2023 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.
+#
+
+deps = [ 'tbarcfg', 'ui' ]
+src = files(
+	'taskbar-cfg.c',
+	'main.c',
+	'startmenu.c'
+)
+
+#test_src = files(
+#	'taskbar-cfg.c',
+#	'startmenu.c',
+#	'test/taskbar-cfg.c',
+#	'test/main.c',
+#	'test/startmenu.c'
+#)
Index: uspace/app/taskbar-cfg/startmenu.c
===================================================================
--- uspace/app/taskbar-cfg/startmenu.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/startmenu.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2023 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 taskbar-cfg
+ * @{
+ */
+/** @file Start menu configuration tab
+ */
+
+#include <gfx/coord.h>
+#include <loc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <tbarcfg/tbarcfg.h>
+#include <ui/control.h>
+#include <ui/label.h>
+#include <ui/list.h>
+#include <ui/pbutton.h>
+#include <ui/resource.h>
+#include <ui/tab.h>
+#include <ui/window.h>
+#include "startmenu.h"
+#include "taskbar-cfg.h"
+
+static void startmenu_entry_selected(ui_list_entry_t *, void *);
+static void startmenu_new_entry_clicked(ui_pbutton_t *, void *);
+static void startmenu_delete_entry_clicked(ui_pbutton_t *, void *);
+
+/** Entry list callbacks */
+ui_list_cb_t startmenu_entry_list_cb = {
+	.selected = startmenu_entry_selected
+};
+
+/** New entry button callbacks */
+ui_pbutton_cb_t startmenu_new_entry_button_cb = {
+	.clicked = startmenu_new_entry_clicked
+};
+
+/** Remove seat button callbacks */
+ui_pbutton_cb_t startmenu_delete_entry_button_cb = {
+	.clicked = startmenu_delete_entry_clicked
+};
+
+/** Create start menu configuration tab
+ *
+ * @param tbcfg Taskbar configuration dialog
+ * @param rsmenu Place to store pointer to new start menu configuration tab
+ * @return EOK on success or an error code
+ */
+errno_t startmenu_create(taskbar_cfg_t *tbcfg, startmenu_t **rsmenu)
+{
+	ui_resource_t *ui_res;
+	startmenu_t *smenu;
+	gfx_rect_t rect;
+	errno_t rc;
+
+	ui_res = ui_window_get_res(tbcfg->window);
+
+	smenu = calloc(1, sizeof(startmenu_t));
+	if (smenu == NULL) {
+		printf("Out of memory.\n");
+		return ENOMEM;
+	}
+
+	smenu->tbarcfg = tbcfg;
+
+	/* 'Start Menu' tab */
+
+	rc = ui_tab_create(tbcfg->tabset, "Start Menu", &smenu->tab);
+	if (rc != EOK)
+		goto error;
+
+	rc = ui_fixed_create(&smenu->fixed);
+	if (rc != EOK) {
+		printf("Error creating fixed layout.\n");
+		goto error;
+	}
+
+	/* 'Start menu entries:' label */
+
+	rc = ui_label_create(ui_res, "Start menu entries:",
+	    &smenu->entries_label);
+	if (rc != EOK) {
+		printf("Error creating label.\n");
+		goto error;
+	}
+
+	if (ui_resource_is_textmode(ui_res)) {
+		rect.p0.x = 4;
+		rect.p0.y = 4;
+		rect.p1.x = 36;
+		rect.p1.y = 5;
+	} else {
+		rect.p0.x = 20;
+		rect.p0.y = 60;
+		rect.p1.x = 360;
+		rect.p1.y = 80;
+	}
+
+	ui_label_set_rect(smenu->entries_label, &rect);
+
+	rc = ui_fixed_add(smenu->fixed, ui_label_ctl(smenu->entries_label));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		goto error;
+	}
+
+	/* List of entries */
+
+	rc = ui_list_create(tbcfg->window, false, &smenu->entries_list);
+	if (rc != EOK) {
+		printf("Error creating list.\n");
+		goto error;
+	}
+
+	if (ui_resource_is_textmode(ui_res)) {
+		rect.p0.x = 4;
+		rect.p0.y = 5;
+		rect.p1.x = 56;
+		rect.p1.y = 10;
+	} else {
+		rect.p0.x = 20;
+		rect.p0.y = 80;
+		rect.p1.x = 360;
+		rect.p1.y = 180;
+	}
+
+	ui_list_set_rect(smenu->entries_list, &rect);
+
+	rc = ui_fixed_add(smenu->fixed, ui_list_ctl(smenu->entries_list));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		goto error;
+	}
+
+	ui_list_set_cb(smenu->entries_list, &startmenu_entry_list_cb,
+	    (void *)smenu);
+
+	/* 'New Entry' button */
+
+	rc = ui_pbutton_create(ui_res, "New...", &smenu->new_entry);
+	if (rc != EOK) {
+		printf("Error creating button.\n");
+		goto error;
+	}
+
+	if (ui_resource_is_textmode(ui_res)) {
+		rect.p0.x = 58;
+		rect.p0.y = 5;
+		rect.p1.x = 68;
+		rect.p1.y = 6;
+	} else {
+		rect.p0.x = 370;
+		rect.p0.y = 80;
+		rect.p1.x = 450;
+		rect.p1.y = 105;
+	}
+
+	ui_pbutton_set_rect(smenu->new_entry, &rect);
+
+	rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->new_entry));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		goto error;
+	}
+
+	ui_pbutton_set_cb(smenu->new_entry, &startmenu_new_entry_button_cb,
+	    (void *)smenu);
+
+	/* 'Delete Entry' button */
+
+	rc = ui_pbutton_create(ui_res, "Delete", &smenu->delete_entry);
+	if (rc != EOK) {
+		printf("Error creating button.\n");
+		goto error;
+	}
+
+	if (ui_resource_is_textmode(ui_res)) {
+		rect.p0.x = 58;
+		rect.p0.y = 7;
+		rect.p1.x = 68;
+		rect.p1.y = 8;
+	} else {
+		rect.p0.x = 370;
+		rect.p0.y = 110;
+		rect.p1.x = 450;
+		rect.p1.y = 135;
+	}
+
+	ui_pbutton_set_rect(smenu->delete_entry, &rect);
+
+	rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->delete_entry));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		goto error;
+	}
+
+	ui_pbutton_set_cb(smenu->delete_entry,
+	    &startmenu_delete_entry_button_cb, (void *)smenu);
+
+	ui_tab_add(smenu->tab, ui_fixed_ctl(smenu->fixed));
+
+	*rsmenu = smenu;
+	return EOK;
+error:
+	if (smenu->delete_entry != NULL)
+		ui_pbutton_destroy(smenu->delete_entry);
+	if (smenu->new_entry != NULL)
+		ui_pbutton_destroy(smenu->new_entry);
+	if (smenu->entries_label != NULL)
+		ui_label_destroy(smenu->entries_label);
+	if (smenu->entries_list != NULL)
+		ui_list_destroy(smenu->entries_list);
+	if (smenu->fixed != NULL)
+		ui_fixed_destroy(smenu->fixed);
+	free(smenu);
+	return rc;
+}
+
+/** Populate start menu tab with start menu configuration data
+ *
+ * @param smenu Start menu configuration tab
+ * @param tbarcfg Taskbar configuration
+ * @return EOK on success or an error code
+ */
+errno_t startmenu_populate(startmenu_t *smenu, tbarcfg_t *tbarcfg)
+{
+	smenu_entry_t *entry;
+	startmenu_entry_t *smentry;
+	const char *caption;
+	const char *cmd;
+	errno_t rc;
+
+	entry = tbarcfg_smenu_first(tbarcfg);
+	while (entry != NULL) {
+		caption = smenu_entry_get_caption(entry);
+		cmd = smenu_entry_get_cmd(entry);
+
+		rc = startmenu_insert(smenu, caption, cmd, &smentry);
+		if (rc != EOK)
+			return rc;
+
+		entry = tbarcfg_smenu_next(entry);
+	}
+
+	return EOK;
+}
+
+/** Destroy start menu configuration tab.
+ *
+ * @param smenu Start menu configuration tab
+ */
+void startmenu_destroy(startmenu_t *smenu)
+{
+	ui_list_entry_t *lentry;
+	startmenu_entry_t *entry;
+
+	lentry = ui_list_first(smenu->entries_list);
+	while (lentry != NULL) {
+		entry = (startmenu_entry_t *)ui_list_entry_get_arg(lentry);
+		free(entry->caption);
+		free(entry->cmd);
+		free(entry);
+		ui_list_entry_delete(lentry);
+		lentry = ui_list_first(smenu->entries_list);
+	}
+
+	/* This will automatically destroy all controls in the tab */
+	ui_tab_destroy(smenu->tab);
+	free(smenu);
+}
+
+/** Insert new entry into entries list.
+ *
+ * @param smenu Start menu configuration tab
+ * @param caption Entry caption
+ * @param cmd Command to run
+ * @param rentry Place to store pointer to new entry or NULL
+ * @return EOK on success or an error code
+ */
+errno_t startmenu_insert(startmenu_t *smenu, const char *caption,
+    const char *cmd, startmenu_entry_t **rentry)
+{
+	startmenu_entry_t *entry;
+	ui_list_entry_attr_t attr;
+	errno_t rc;
+
+	entry = calloc(1, sizeof(startmenu_entry_t));
+	if (entry == NULL)
+		return ENOMEM;
+
+	entry->startmenu = smenu;
+	entry->caption = str_dup(caption);
+	if (entry->caption == NULL) {
+		free(entry);
+		return ENOMEM;
+	}
+
+	entry->cmd = str_dup(cmd);
+	if (entry->caption == NULL) {
+		free(entry->caption);
+		free(entry);
+		return ENOMEM;
+	}
+
+	ui_list_entry_attr_init(&attr);
+	attr.caption = caption;
+	attr.arg = (void *)entry;
+	rc = ui_list_entry_append(smenu->entries_list, &attr, &entry->lentry);
+	if (rc != EOK) {
+		free(entry->caption);
+		free(entry->cmd);
+		free(entry);
+		return rc;
+	}
+
+	if (rentry != NULL)
+		*rentry = entry;
+	return EOK;
+}
+
+/** Entry in entry list is selected.
+ *
+ * @param lentry UI list entry
+ * @param arg Argument (dcfg_seats_entry_t *)
+ */
+static void startmenu_entry_selected(ui_list_entry_t *lentry, void *arg)
+{
+	(void)lentry;
+	(void)arg;
+}
+
+/** New Entry' button clicked.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (dcfg_seats_entry_t *)
+ */
+static void startmenu_new_entry_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	(void)pbutton;
+	(void)arg;
+}
+
+/** "Delete Entry' button clicked.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (dcfg_seats_entry_t *)
+ */
+static void startmenu_delete_entry_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	(void)pbutton;
+	(void)arg;
+}
+
+/** @}
+ */
Index: uspace/app/taskbar-cfg/startmenu.h
===================================================================
--- uspace/app/taskbar-cfg/startmenu.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/startmenu.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2023 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 taskbar-cfg
+ * @{
+ */
+/**
+ * @file Start menu configuration tab
+ */
+
+#ifndef STARTMENU_H
+#define STARTMENU_H
+
+#include <tbarcfg/tbarcfg.h>
+#include "types/startmenu.h"
+#include "types/taskbar-cfg.h"
+
+extern errno_t startmenu_create(taskbar_cfg_t *, startmenu_t **);
+extern errno_t startmenu_populate(startmenu_t *, tbarcfg_t *);
+extern void startmenu_destroy(startmenu_t *);
+extern errno_t startmenu_insert(startmenu_t *, const char *, const char *,
+    startmenu_entry_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/taskbar-cfg/taskbar-cfg.c
===================================================================
--- uspace/app/taskbar-cfg/taskbar-cfg.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/taskbar-cfg.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2023 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 taskbar-cfg
+ * @{
+ */
+/** @file Taskbar configuration utility (UI)
+ */
+
+#include <gfx/coord.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ui/fixed.h>
+#include <ui/resource.h>
+#include <ui/tabset.h>
+#include <ui/ui.h>
+#include <ui/window.h>
+#include "taskbar-cfg.h"
+#include "startmenu.h"
+
+static void wnd_close(ui_window_t *, void *);
+
+static ui_window_cb_t window_cb = {
+	.close = wnd_close
+};
+
+/** Window close button was clicked.
+ *
+ * @param window Window
+ * @param arg Argument (tbcfg)
+ */
+static void wnd_close(ui_window_t *window, void *arg)
+{
+	taskbar_cfg_t *tbcfg = (taskbar_cfg_t *) arg;
+
+	ui_quit(tbcfg->ui);
+}
+
+/** Create Taskbar configuration window.
+ *
+ * @param display_spec Display specification
+ * @param rdcfg Place to store pointer to new taskbar configuration
+ * @return EOK on success or an error code
+ */
+errno_t taskbar_cfg_create(const char *display_spec, taskbar_cfg_t **rdcfg)
+{
+	ui_t *ui = NULL;
+	ui_wnd_params_t params;
+	ui_window_t *window = NULL;
+	taskbar_cfg_t *tbcfg = NULL;
+	gfx_rect_t rect;
+	ui_resource_t *ui_res;
+	errno_t rc;
+
+	tbcfg = calloc(1, sizeof(taskbar_cfg_t));
+	if (tbcfg == NULL) {
+		printf("Out of memory.\n");
+		return ENOMEM;
+	}
+
+	rc = ui_create(display_spec, &ui);
+	if (rc != EOK) {
+		printf("Error creating UI on display %s.\n", display_spec);
+		goto error;
+	}
+
+	ui_wnd_params_init(&params);
+	params.caption = "Taskbar Configuration";
+	if (ui_is_textmode(ui)) {
+		params.rect.p0.x = 0;
+		params.rect.p0.y = 0;
+		params.rect.p1.x = 70;
+		params.rect.p1.y = 23;
+	} else {
+		params.rect.p0.x = 0;
+		params.rect.p0.y = 0;
+		params.rect.p1.x = 470;
+		params.rect.p1.y = 350;
+	}
+
+	tbcfg->ui = ui;
+
+	rc = ui_window_create(ui, &params, &window);
+	if (rc != EOK) {
+		printf("Error creating window.\n");
+		goto error;
+	}
+
+	ui_window_set_cb(window, &window_cb, (void *)tbcfg);
+	tbcfg->window = window;
+
+	ui_res = ui_window_get_res(window);
+
+	rc = ui_fixed_create(&tbcfg->fixed);
+	if (rc != EOK) {
+		printf("Error creating fixed layout.\n");
+		return rc;
+	}
+
+	rc = ui_tab_set_create(ui_res, &tbcfg->tabset);
+	if (rc != EOK) {
+		printf("Error creating tab set.\n");
+		return rc;
+	}
+
+	ui_window_get_app_rect(window, &rect);
+	ui_tab_set_set_rect(tbcfg->tabset, &rect);
+
+	rc = ui_fixed_add(tbcfg->fixed, ui_tab_set_ctl(tbcfg->tabset));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		return rc;
+	}
+
+	rc = startmenu_create(tbcfg, &tbcfg->startmenu);
+	if (rc != EOK)
+		goto error;
+
+	ui_window_add(window, ui_fixed_ctl(tbcfg->fixed));
+
+	*rdcfg = tbcfg;
+	return EOK;
+error:
+	if (tbcfg->startmenu != NULL)
+		startmenu_destroy(tbcfg->startmenu);
+	if (tbcfg->tabset != NULL)
+		ui_tab_set_destroy(tbcfg->tabset);
+	if (tbcfg->fixed != NULL)
+		ui_fixed_destroy(tbcfg->fixed);
+	if (tbcfg->ui != NULL)
+		ui_destroy(ui);
+	free(tbcfg);
+	return rc;
+}
+
+/** Open Taskbar configuration.
+ *
+ * @param tbcfg Taskbar configuration dialog
+ * @param cfg_repo Path to configuration repository
+ * @return EOK on success or an error code
+ */
+errno_t taskbar_cfg_open(taskbar_cfg_t *tbcfg, const char *cfg_repo)
+{
+	errno_t rc;
+
+	rc = tbarcfg_open(cfg_repo, &tbcfg->tbarcfg);
+	if (rc != EOK) {
+		printf("Error opening Taskbar configuration.\n");
+		goto error;
+	}
+
+	return EOK;
+error:
+	return rc;
+}
+
+/** Populate task configuration from configuration repository.
+ *
+ * @param tbcfg Taskbar configuration dialog
+ * @return EOK on success or an error code
+ */
+errno_t taskbar_cfg_populate(taskbar_cfg_t *tbcfg)
+{
+	errno_t rc;
+
+	rc = startmenu_populate(tbcfg->startmenu, tbcfg->tbarcfg);
+	if (rc != EOK)
+		return rc;
+
+	rc = ui_window_paint(tbcfg->window);
+	if (rc != EOK) {
+		printf("Error painting window.\n");
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Destroy Taskbar configuration window.
+ *
+ * @param tbcfg Taskbar configuration window
+ */
+void taskbar_cfg_destroy(taskbar_cfg_t *tbcfg)
+{
+	if (tbcfg->tbarcfg != NULL)
+		tbarcfg_close(tbcfg->tbarcfg);
+	ui_window_destroy(tbcfg->window);
+	ui_destroy(tbcfg->ui);
+}
+
+/** @}
+ */
Index: uspace/app/taskbar-cfg/taskbar-cfg.h
===================================================================
--- uspace/app/taskbar-cfg/taskbar-cfg.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/taskbar-cfg.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2023 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 taskbar-cfg
+ * @{
+ */
+/**
+ * @file Taskbar configuration utility (in UI)
+ */
+
+#ifndef TASKBAR_CFG_H
+#define TASKBAR_CFG_H
+
+#include "types/taskbar-cfg.h"
+
+extern errno_t taskbar_cfg_create(const char *, taskbar_cfg_t **);
+extern errno_t taskbar_cfg_open(taskbar_cfg_t *, const char *);
+extern errno_t taskbar_cfg_populate(taskbar_cfg_t *);
+extern void taskbar_cfg_destroy(taskbar_cfg_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/taskbar-cfg/test/main.c
===================================================================
--- uspace/app/taskbar-cfg/test/main.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/test/main.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2023 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>
+
+PCUT_INIT;
+
+PCUT_IMPORT(taskbar_cfg);
+PCUT_IMPORT(startmenu);
+
+PCUT_MAIN();
Index: uspace/app/taskbar-cfg/test/startmenu.c
===================================================================
--- uspace/app/taskbar-cfg/test/startmenu.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/test/startmenu.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2023 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 <async.h>
+#include <dispcfg.h>
+#include <dispcfg_srv.h>
+#include <errno.h>
+#include <pcut/pcut.h>
+#include <str.h>
+#include <testdc.h>
+#include "../display-cfg.h"
+#include "../seats.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(seats);
+
+static const char *test_dispcfg_server = "test-dispcfg";
+static const char *test_dispcfg_svc = "test/dispcfg";
+
+/** Test dcfg_seats_create() and dcfg_seats_destroy() */
+PCUT_TEST(create_destroy)
+{
+	display_cfg_t *dcfg;
+	dcfg_seats_t *seats;
+	errno_t rc;
+
+	rc = display_cfg_create(UI_DISPLAY_NULL, &dcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_seats_create(dcfg, &seats);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	dcfg_seats_destroy(seats);
+	display_cfg_destroy(dcfg);
+}
+
+/** dcfg_seats_insert() inserts an entry into the seat list */
+PCUT_TEST(seats_insert)
+{
+	display_cfg_t *dcfg;
+	dcfg_seats_t *seats;
+	dcfg_seats_entry_t *entry = NULL;
+	errno_t rc;
+
+	rc = display_cfg_create(UI_DISPLAY_NULL, &dcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_seats_create(dcfg, &seats);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_seats_insert(seats, "Alice", 42, &entry);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(entry);
+
+	PCUT_ASSERT_STR_EQUALS("Alice", entry->name);
+	PCUT_ASSERT_INT_EQUALS(42, entry->seat_id);
+
+	dcfg_seats_destroy(seats);
+	display_cfg_destroy(dcfg);
+}
+
+/** dcfg_seats_list_populate() populates seat list */
+PCUT_TEST(seats_list_populate)
+{
+	display_cfg_t *dcfg;
+	dcfg_seats_t *seats;
+	errno_t rc;
+	service_id_t sid;
+	test_response_t resp;
+	loc_srv_t *srv;
+
+	async_set_fallback_port_handler(test_dispcfg_conn, &resp);
+
+	// FIXME This causes this test to be non-reentrant!
+	rc = loc_server_register(test_dispcfg_server, &srv);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = loc_service_register(srv, test_dispcfg_svc, &sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = display_cfg_create(UI_DISPLAY_NULL, &dcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = display_cfg_open(dcfg, test_dispcfg_svc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_seats_create(dcfg, &seats);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/*
+	 * dcfg_seat_list_populate() calls dispcfg_get_seat_list()
+	 * and dispcfg_get_seat_info()
+	 */
+	resp.rc = EOK;
+	resp.get_seat_list_rlist = calloc(1, sizeof(dispcfg_seat_list_t));
+	PCUT_ASSERT_NOT_NULL(resp.get_seat_list_rlist);
+	resp.get_seat_list_rlist->nseats = 1;
+	resp.get_seat_list_rlist->seats = calloc(1, sizeof(sysarg_t));
+	PCUT_ASSERT_NOT_NULL(resp.get_seat_list_rlist->seats);
+	resp.get_seat_list_rlist->seats[0] = 42;
+
+	resp.get_seat_info_rinfo = calloc(1, sizeof(dispcfg_seat_info_t));
+	PCUT_ASSERT_NOT_NULL(resp.get_seat_info_rinfo);
+	resp.get_seat_info_rinfo->name = str_dup("Alice");
+	PCUT_ASSERT_NOT_NULL(resp.get_seat_info_rinfo->name);
+
+	rc = dcfg_seats_list_populate(seats);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	dcfg_seats_destroy(seats);
+	display_cfg_destroy(dcfg);
+
+	rc = loc_service_unregister(srv, sid);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	loc_server_unregister(srv);
+}
+
+/** dcfg_devices_insert() inserts an entry into the device list */
+PCUT_TEST(devices_insert)
+{
+	display_cfg_t *dcfg;
+	dcfg_seats_t *seats;
+	ui_list_entry_t *lentry;
+	dcfg_devices_entry_t *entry;
+	errno_t rc;
+
+	rc = display_cfg_create(UI_DISPLAY_NULL, &dcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_seats_create(dcfg, &seats);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_devices_insert(seats, "mydevice", 42);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	lentry = ui_list_first(seats->device_list);
+	PCUT_ASSERT_NOT_NULL(lentry);
+	entry = (dcfg_devices_entry_t *)ui_list_entry_get_arg(lentry);
+	PCUT_ASSERT_NOT_NULL(entry);
+
+	PCUT_ASSERT_STR_EQUALS("mydevice", entry->name);
+	PCUT_ASSERT_INT_EQUALS(42, entry->svc_id);
+
+	dcfg_seats_destroy(seats);
+	display_cfg_destroy(dcfg);
+}
+
+/** dcfg_avail_devices_insert() inserts entry into available devices list */
+PCUT_TEST(avail_devices_insert)
+{
+	display_cfg_t *dcfg;
+	dcfg_seats_t *seats;
+	ui_list_entry_t *lentry;
+	dcfg_devices_entry_t *entry;
+	ui_select_dialog_t *dialog;
+	ui_select_dialog_params_t sdparams;
+	errno_t rc;
+
+	rc = display_cfg_create(UI_DISPLAY_NULL, &dcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_seats_create(dcfg, &seats);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_select_dialog_params_init(&sdparams);
+	sdparams.caption = "Dialog";
+	sdparams.prompt = "Select";
+
+	rc = ui_select_dialog_create(seats->dcfg->ui, &sdparams, &dialog);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = dcfg_avail_devices_insert(seats, dialog, "mydevice", 42);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	lentry = ui_list_first(ui_select_dialog_list(dialog));
+	PCUT_ASSERT_NOT_NULL(lentry);
+	entry = (dcfg_devices_entry_t *)ui_list_entry_get_arg(lentry);
+	PCUT_ASSERT_NOT_NULL(entry);
+
+	PCUT_ASSERT_STR_EQUALS("mydevice", entry->name);
+	PCUT_ASSERT_INT_EQUALS(42, entry->svc_id);
+
+	ui_select_dialog_destroy(dialog);
+	dcfg_seats_destroy(seats);
+	display_cfg_destroy(dcfg);
+}
+
+PCUT_TEST(asgn_dev_list_populate)
+{
+}
+
+PCUT_TEST(avail_dev_list_populate)
+{
+}
+
+PCUT_TEST(seats_get_selected)
+{
+}
+
+PCUT_TEST(devices_get_selected)
+{
+}
+
+PCUT_TEST(seats_list_selected)
+{
+}
+
+PCUT_TEST(add_seat_clicked)
+{
+}
+
+PCUT_TEST(remove_seat_clicked)
+{
+}
+
+PCUT_TEST(add_seat_dialog_bok)
+{
+}
+
+PCUT_TEST(add_seat_dialog_bcancel)
+{
+}
+
+PCUT_TEST(add_seat_dialog_close)
+{
+}
+
+PCUT_TEST(add_device_clicked)
+{
+}
+
+PCUT_TEST(remove_device_clicked)
+{
+}
+
+PCUT_TEST(add_device_dialog_bok)
+{
+}
+
+PCUT_TEST(add_device_dialog_bcancel)
+{
+}
+
+PCUT_TEST(add_device_dialog_close)
+{
+}
+
+PCUT_EXPORT(seats);
Index: uspace/app/taskbar-cfg/test/taskbar-cfg.c
===================================================================
--- uspace/app/taskbar-cfg/test/taskbar-cfg.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/test/taskbar-cfg.c	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023 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 <errno.h>
+#include <pcut/pcut.h>
+#include <ui/ui.h>
+#include "../display-cfg.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(display_cfg);
+
+/** Test display_cfg_create() and display_cfg_destroy() */
+PCUT_TEST(create_destroy)
+{
+	display_cfg_t *dcfg;
+	errno_t rc;
+
+	rc = display_cfg_create(UI_DISPLAY_NULL, &dcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	display_cfg_destroy(dcfg);
+}
+
+PCUT_EXPORT(display_cfg);
Index: uspace/app/taskbar-cfg/types/startmenu.h
===================================================================
--- uspace/app/taskbar-cfg/types/startmenu.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/types/startmenu.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023 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 taskbar-cfg
+ * @{
+ */
+/**
+ * @file Start menu configuration tab
+ */
+
+#ifndef TYPES_STARTMENU_H
+#define TYPES_STARTMENU_H
+
+#include <ui/fixed.h>
+#include <ui/label.h>
+#include <ui/list.h>
+#include <ui/pbutton.h>
+#include <ui/tab.h>
+
+/** Start menu configuration tab */
+typedef struct startmenu {
+	/** Containing taskbar configuration */
+	struct taskbar_cfg *tbarcfg;
+	/** UI tab */
+	ui_tab_t *tab;
+	/** Fixed layout */
+	ui_fixed_t *fixed;
+	/** 'Start menu entries' label */
+	ui_label_t *entries_label;
+	/** List of start menu entries */
+	ui_list_t *entries_list;
+	/** New entry button */
+	ui_pbutton_t *new_entry;
+	/** Delete entry button */
+	ui_pbutton_t *delete_entry;
+	/** Edit entry button */
+	ui_pbutton_t *edit_entry;
+} startmenu_t;
+
+/** Start menu entry */
+typedef struct {
+	/** Containing start menu configuration tab */
+	struct startmenu *startmenu;
+	/** List entry */
+	ui_list_entry_t *lentry;
+	/** Caption */
+	char *caption;
+	/** Command */
+	char *cmd;
+} startmenu_entry_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/app/taskbar-cfg/types/taskbar-cfg.h
===================================================================
--- uspace/app/taskbar-cfg/types/taskbar-cfg.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
+++ uspace/app/taskbar-cfg/types/taskbar-cfg.h	(revision cb2894e55cad399c5f6a5b3b0e3a0e59833acac4)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2023 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 taskbar-cfg
+ * @{
+ */
+/**
+ * @file Taskbar configuration utility (UI) types
+ */
+
+#ifndef TYPES_TASKBAR_CFG_H
+#define TYPES_TASKBAR_CFG_H
+
+#include <tbarcfg/tbarcfg.h>
+#include <ui/fixed.h>
+#include <ui/label.h>
+#include <ui/tabset.h>
+#include <ui/ui.h>
+#include <ui/window.h>
+
+/** Taskbar configuration utility (UI) */
+typedef struct taskbar_cfg {
+	/** Taskbar configuration */
+	tbarcfg_t *tbarcfg;
+	/** UI */
+	ui_t *ui;
+	/** Containing window */
+	ui_window_t *window;
+	/** Fixed layout */
+	ui_fixed_t *fixed;
+	/** Tab set */
+	ui_tab_set_t *tabset;
+	/** Start menu configuration tab */
+	struct startmenu *startmenu;
+} taskbar_cfg_t;
+
+#endif
+
+/** @}
+ */
