Index: uspace/app/taskbar/taskbar.c
===================================================================
--- uspace/app/taskbar/taskbar.c	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/app/taskbar/taskbar.c	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -131,11 +131,26 @@
 	gfx_rect_t scr_rect;
 	gfx_rect_t rect;
+	char *dspec = NULL;
+	char *qmark;
 	errno_t rc;
 
 	taskbar = calloc(1, sizeof(taskbar_t));
 	if (taskbar == NULL) {
+		printf("Out of memory.\n");
 		rc = ENOMEM;
 		goto error;
 	}
+
+	dspec = str_dup(display_spec);
+	if (dspec == NULL) {
+		printf("Out of memory.\n");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	/* Remove additional arguments */
+	qmark = str_chr(dspec, '?');
+	if (qmark != NULL)
+		*qmark = '\0';
 
 	rc = ui_create(display_spec, &taskbar->ui);
@@ -198,5 +213,6 @@
 	}
 
-	rc = tbsmenu_create(taskbar->window, taskbar->fixed, &taskbar->tbsmenu);
+	rc = tbsmenu_create(taskbar->window, taskbar->fixed, dspec,
+	    &taskbar->tbsmenu);
 	if (rc != EOK) {
 		printf("Error creating start menu.\n");
@@ -293,7 +309,10 @@
 	}
 
+	free(dspec);
 	*rtaskbar = taskbar;
 	return EOK;
 error:
+	if (dspec != NULL)
+		free(dspec);
 	if (taskbar->lst != NULL)
 		tbarcfg_listener_destroy(taskbar->lst);
@@ -308,4 +327,5 @@
 	if (taskbar->ui != NULL)
 		ui_destroy(taskbar->ui);
+	free(taskbar);
 	return rc;
 
Index: uspace/app/taskbar/taskbar.sif
===================================================================
--- uspace/app/taskbar/taskbar.sif	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/app/taskbar/taskbar.sif	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,1 +1,1 @@
-[sif](){[entries](){[entry]([caption]=[~N~avigator][cmd]=[/app/nav][terminal]=[y]){}[entry]([caption]=[Text ~E~ditor][cmd]=[/app/edit][terminal]=[y]){}[entry]([caption]=[Co~m~mand Line][cmd]=[/app/bdsh][terminal]=[y]){}[entry]([caption]=[~C~alculator][cmd]=[/app/calculator][terminal]=[n]){}[entry]([separator]=[y]){}[entry]([caption]=[~U~I Demo][cmd]=[/app/uidemo][terminal]=[n]){}[entry]([caption]=[~G~FX Demo][cmd]=[/app/gfxdemo ui][terminal]=[n]){}[entry]([caption]=[~B~arber Pole][cmd]=[/app/barber][terminal]=[n]){}[entry]([caption]=[~T~etris][cmd]=[/app/tetris][terminal]=[y]){}[entry]([separator]=[y]){}[entry]([caption]=[~D~isplay Configuration][cmd]=[/app/display-cfg][terminal]=[n]){}[entry]([caption]=[Ta~s~kbar Configuration][cmd]=[/app/taskbar-cfg][terminal]=[n]){}[entry]([separator]=[y]){}[entry]([caption]=[Tas~k~ Monitor (top)][cmd]=[/app/top][terminal]=[y]){}[entry]([caption]=[~F~disk Disk Editor][cmd]=[/app/fdisk][terminal]=[y]){}}}
+[sif](){[entries](){[entry]([caption]=[~N~avigator][cmd]=[/app/nav][terminal]=[y]){}[entry]([caption]=[Text ~E~ditor][cmd]=[/app/edit][terminal]=[y]){}[entry]([caption]=[Co~m~mand Line][cmd]=[/app/bdsh][terminal]=[y]){}[entry]([caption]=[~C~alculator][cmd]=[/app/calculator -d %d][terminal]=[n]){}[entry]([separator]=[y]){}[entry]([caption]=[~U~I Demo][cmd]=[/app/uidemo -d %d][terminal]=[n]){}[entry]([caption]=[~G~FX Demo][cmd]=[/app/gfxdemo -d %d ui][terminal]=[n]){}[entry]([caption]=[~B~arber Pole][cmd]=[/app/barber -d %d][terminal]=[n]){}[entry]([caption]=[~T~etris][cmd]=[/app/tetris][terminal]=[y]){}[entry]([separator]=[y]){}[entry]([caption]=[~D~isplay Configuration][cmd]=[/app/display-cfg -d %d][terminal]=[n]){}[entry]([caption]=[Ta~s~kbar Configuration][cmd]=[/app/taskbar-cfg -d %d][terminal]=[n]){}[entry]([separator]=[y]){}[entry]([caption]=[Tas~k~ Monitor (top)][cmd]=[/app/top][terminal]=[y]){}[entry]([caption]=[~F~disk Disk Editor][cmd]=[/app/fdisk][terminal]=[y]){}}}
Index: uspace/app/taskbar/tbsmenu.c
===================================================================
--- uspace/app/taskbar/tbsmenu.c	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/app/taskbar/tbsmenu.c	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -64,4 +64,5 @@
 static void tbsmenu_smenu_entry_cb(ui_menu_entry_t *, void *);
 static errno_t tbsmenu_entry_start(tbsmenu_entry_t *);
+static void tbsmenu_cmd_fini(tbsmenu_cmd_t *);
 
 /** Create taskbar start menu.
@@ -69,9 +70,10 @@
  * @param window Containing window
  * @param fixed Fixed layout to which start button will be added
+ * @param dspec Display specification (for passing to applications)
  * @param rtbsmenu Place to store pointer to new start menu
  * @return @c EOK on success or an error code
  */
 errno_t tbsmenu_create(ui_window_t *window, ui_fixed_t *fixed,
-    tbsmenu_t **rtbsmenu)
+    const char *dspec, tbsmenu_t **rtbsmenu)
 {
 	ui_resource_t *res = ui_window_get_res(window);
@@ -85,4 +87,10 @@
 	}
 
+	tbsmenu->display_spec = str_dup(dspec);
+	if (tbsmenu->display_spec == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
 	rc = ui_pbutton_create(res, "Start", &tbsmenu->sbutton);
 	if (rc != EOK)
@@ -111,4 +119,6 @@
 	return EOK;
 error:
+	if (tbsmenu != NULL && tbsmenu->display_spec != NULL)
+		free(tbsmenu->display_spec);
 	if (tbsmenu != NULL)
 		ui_pbutton_destroy(tbsmenu->sbutton);
@@ -476,15 +486,16 @@
 static errno_t tbsmenu_cmd_split(const char *str, tbsmenu_cmd_t *cmd)
 {
+	char *buf;
 	char *arg;
 	char *next;
 	size_t cnt;
 
-	cmd->buf = str_dup(str);
-	if (cmd->buf == NULL)
+	buf = str_dup(str);
+	if (buf == NULL)
 		return ENOMEM;
 
 	/* Count the entries */
 	cnt = 0;
-	arg = str_tok(cmd->buf, " ", &next);
+	arg = str_tok(buf, " ", &next);
 	while (arg != NULL) {
 		++cnt;
@@ -493,20 +504,26 @@
 
 	/* Need to copy again as buf was mangled */
-	free(cmd->buf);
-	cmd->buf = str_dup(str);
-	if (cmd->buf == NULL)
+	free(buf);
+	buf = str_dup(str);
+	if (buf == NULL)
 		return ENOMEM;
 
 	cmd->argv = calloc(cnt + 1, sizeof(char *));
 	if (cmd->argv == NULL) {
-		free(cmd->buf);
+		free(buf);
 		return ENOMEM;
 	}
 
-	/* Fill in pointers */
+	/* Copy individual arguments */
 	cnt = 0;
-	arg = str_tok(cmd->buf, " ", &next);
+	arg = str_tok(buf, " ", &next);
 	while (arg != NULL) {
-		cmd->argv[cnt++] = arg;
+		cmd->argv[cnt] = str_dup(arg);
+		if (cmd->argv[cnt] == NULL) {
+			tbsmenu_cmd_fini(cmd);
+			return ENOMEM;
+		}
+		++cnt;
+
 		arg = str_tok(next, " ", &next);
 	}
@@ -523,6 +540,45 @@
 static void tbsmenu_cmd_fini(tbsmenu_cmd_t *cmd)
 {
+	char **cp;
+
+	/* Free all pointers in NULL-terminated list */
+	cp = cmd->argv;
+	while (*cp != NULL) {
+		free(*cp);
+		++cp;
+	}
+
+	/* Free the array of pointers */
 	free(cmd->argv);
-	free(cmd->buf);
+}
+
+/** Free command structure.
+ *
+ * @param cmd Command
+ * @param entry Start menu entry
+ * @param dspec Display specification
+ * @return EOK on success or an error code
+ */
+static errno_t tbsmenu_cmd_subst(tbsmenu_cmd_t *cmd, tbsmenu_entry_t *entry,
+    const char *dspec)
+{
+	char **cp;
+
+	(void)entry;
+
+	/* Walk NULL-terminated list of arguments */
+	cp = cmd->argv;
+	while (*cp != NULL) {
+		if (str_cmp(*cp, "%d") == 0) {
+			/* Display specification */
+			free(*cp);
+			*cp = str_dup(dspec);
+			if (*cp == NULL)
+				return ENOMEM;
+		}
+		++cp;
+	}
+
+	return EOK;
 }
 
@@ -545,4 +601,7 @@
 	char **cp;
 	const char **targv = NULL;
+	char *dspec = NULL;
+	sysarg_t idev_id;
+	int rv;
 	errno_t rc;
 	ui_t *ui;
@@ -551,7 +610,22 @@
 	suspended = false;
 
+	idev_id = ui_menu_get_idev_id(entry->tbsmenu->smenu);
+
+	rv = asprintf(&dspec, "%s?idev=%zu",
+	    entry->tbsmenu->display_spec, (size_t)idev_id);
+	if (rv < 0)
+		return ENOMEM;
+
+	/* Split command string into individual arguments */
 	rc = tbsmenu_cmd_split(entry->cmd, &cmd);
-	if (rc != EOK)
+	if (rc != EOK) {
+		free(dspec);
 		return rc;
+	}
+
+	/* Substitute metacharacters in command */
+	rc = tbsmenu_cmd_subst(&cmd, entry, dspec);
+	if (rc != EOK)
+		goto error;
 
 	/* Free up and clean console for the child task. */
@@ -571,13 +645,15 @@
 		}
 
-		targv = calloc(cnt + 3, sizeof(char **));
+		targv = calloc(cnt + 5, sizeof(char **));
 		if (targv == NULL)
 			goto error;
 
 		targv[0] = "/app/terminal";
-		targv[1] = "-c";
+		targv[1] = "-d";
+		targv[2] = dspec;
+		targv[3] = "-c";
 
 		for (i = 0; i <= cnt; i++) {
-			targv[2 + i] = cmd.argv[i];
+			targv[4 + i] = cmd.argv[i];
 		}
 
@@ -607,4 +683,5 @@
 	return EOK;
 error:
+	free(dspec);
 	if (targv != NULL)
 		free(targv);
Index: uspace/app/taskbar/tbsmenu.h
===================================================================
--- uspace/app/taskbar/tbsmenu.h	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/app/taskbar/tbsmenu.h	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -46,5 +46,6 @@
 #include "types/tbsmenu.h"
 
-extern errno_t tbsmenu_create(ui_window_t *, ui_fixed_t *, tbsmenu_t **);
+extern errno_t tbsmenu_create(ui_window_t *, ui_fixed_t *, const char *,
+    tbsmenu_t **);
 extern errno_t tbsmenu_load(tbsmenu_t *, const char *);
 extern void tbsmenu_reload(tbsmenu_t *);
Index: uspace/app/taskbar/test/tbsmenu.c
===================================================================
--- uspace/app/taskbar/test/tbsmenu.c	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/app/taskbar/test/tbsmenu.c	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2023 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -61,5 +61,5 @@
 	ui_window_add(window, ui_fixed_ctl(fixed));
 
-	rc = tbsmenu_create(window, fixed, &tbsmenu);
+	rc = tbsmenu_create(window, fixed, UI_DISPLAY_DEFAULT, &tbsmenu);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -92,5 +92,5 @@
 	ui_window_add(window, ui_fixed_ctl(fixed));
 
-	rc = tbsmenu_create(window, fixed, &tbsmenu);
+	rc = tbsmenu_create(window, fixed, UI_DISPLAY_DEFAULT, &tbsmenu);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
Index: uspace/app/taskbar/types/tbsmenu.h
===================================================================
--- uspace/app/taskbar/types/tbsmenu.h	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/app/taskbar/types/tbsmenu.h	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -91,10 +91,11 @@
 	/** Need to reload menu when possible */
 	bool needs_reload;
+
+	/** Display specification */
+	char *display_spec;
 } tbsmenu_t;
 
 /** Command split into individual parts */
 typedef struct {
-	/** Buffer holding broken down command */
-	char *buf;
 	/** NULL-terminated array of string pointers */
 	char **argv;
Index: uspace/lib/ui/include/ui/menu.h
===================================================================
--- uspace/lib/ui/include/ui/menu.h	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/lib/ui/include/ui/menu.h	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2023 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -59,4 +59,5 @@
 extern ui_evclaim_t ui_menu_pos_event(ui_menu_t *, gfx_coord2_t *,
     pos_event_t *);
+extern sysarg_t ui_menu_get_idev_id(ui_menu_t *);
 
 #endif
Index: uspace/lib/ui/include/ui/popup.h
===================================================================
--- uspace/lib/ui/include/ui/popup.h	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/lib/ui/include/ui/popup.h	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2021 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -54,4 +54,5 @@
 extern ui_resource_t *ui_popup_get_res(ui_popup_t *);
 extern gfx_context_t *ui_popup_get_gc(ui_popup_t *);
+extern sysarg_t ui_popup_get_idev_id(ui_popup_t *);
 
 #endif
Index: uspace/lib/ui/private/menu.h
===================================================================
--- uspace/lib/ui/private/menu.h	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/lib/ui/private/menu.h	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2023 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -70,4 +70,6 @@
 	/** Callback argument */
 	void *arg;
+	/** ID of device that activated entry */
+	sysarg_t idev_id;
 };
 
Index: uspace/lib/ui/private/popup.h
===================================================================
--- uspace/lib/ui/private/popup.h	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/lib/ui/private/popup.h	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2021 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -58,4 +58,6 @@
 	/** Placement rectangle */
 	gfx_rect_t place;
+	/** ID of device that sent input event */
+	sysarg_t idev_id;
 };
 
Index: uspace/lib/ui/src/menu.c
===================================================================
--- uspace/lib/ui/src/menu.c	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/lib/ui/src/menu.c	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2023 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -578,4 +578,5 @@
 	ui_menu_t *menu = (ui_menu_t *)arg;
 
+	menu->idev_id = ui_popup_get_idev_id(menu->popup);
 	ui_menu_kbd_event(menu, event);
 }
@@ -592,4 +593,6 @@
 	gfx_coord2_t spos;
 
+	menu->idev_id = ui_popup_get_idev_id(menu->popup);
+
 	spos.x = 0;
 	spos.y = 0;
@@ -641,4 +644,14 @@
 }
 
+/** Get ID of last device that input event.
+ *
+ * @param menu Menu
+ * @return Input device ID
+ */
+sysarg_t ui_menu_get_idev_id(ui_menu_t *menu)
+{
+	return menu->idev_id;
+}
+
 /** @}
  */
Index: uspace/lib/ui/src/popup.c
===================================================================
--- uspace/lib/ui/src/popup.c	(revision ee3b28a97324351b0acfb1161a2ed94632eab95c)
+++ uspace/lib/ui/src/popup.c	(revision d92b8e8f16d19c0ce7828d8dfbc2f178747ce076)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2023 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -190,4 +190,14 @@
 }
 
+/** Get ID of device that sent the last position event.
+ *
+ * @param popup Popup window
+ * @return Input device ID
+ */
+sysarg_t ui_popup_get_idev_id(ui_popup_t *popup)
+{
+	return popup->idev_id;
+}
+
 /** Handle close event in popup window.
  *
@@ -214,4 +224,7 @@
 	ui_popup_t *popup = (ui_popup_t *)arg;
 
+	/* Remember ID of device that sent the last event */
+	popup->idev_id = event->kbd_id;
+
 	if (popup->cb != NULL && popup->cb->kbd != NULL)
 		popup->cb->kbd(popup, popup->arg, event);
@@ -229,4 +242,7 @@
 	ui_popup_t *popup = (ui_popup_t *)arg;
 
+	/* Remember ID of device that sent the last event */
+	popup->idev_id = event->pos_id;
+
 	if (popup->cb != NULL && popup->cb->pos != NULL)
 		popup->cb->pos(popup, popup->arg, event);
