xref: /kernel/linux/linux-5.10/tools/perf/ui/tui/util.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <signal.h>
38c2ecf20Sopenharmony_ci#include <stdbool.h>
48c2ecf20Sopenharmony_ci#include <string.h>
58c2ecf20Sopenharmony_ci#include <stdlib.h>
68c2ecf20Sopenharmony_ci#include <sys/ttydefaults.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "../browser.h"
98c2ecf20Sopenharmony_ci#include "../keysyms.h"
108c2ecf20Sopenharmony_ci#include "../helpline.h"
118c2ecf20Sopenharmony_ci#include "../ui.h"
128c2ecf20Sopenharmony_ci#include "../util.h"
138c2ecf20Sopenharmony_ci#include "../libslang.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic void ui_browser__argv_write(struct ui_browser *browser,
168c2ecf20Sopenharmony_ci				   void *entry, int row)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	char **arg = entry;
198c2ecf20Sopenharmony_ci	bool current_entry = ui_browser__is_current_entry(browser, row);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
228c2ecf20Sopenharmony_ci						       HE_COLORSET_NORMAL);
238c2ecf20Sopenharmony_ci	ui_browser__write_nstring(browser, *arg, browser->width);
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int popup_menu__run(struct ui_browser *menu, int *keyp)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	int key;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
318c2ecf20Sopenharmony_ci		return -1;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	while (1) {
348c2ecf20Sopenharmony_ci		key = ui_browser__run(menu, 0);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci		switch (key) {
378c2ecf20Sopenharmony_ci		case K_RIGHT:
388c2ecf20Sopenharmony_ci		case K_ENTER:
398c2ecf20Sopenharmony_ci			key = menu->index;
408c2ecf20Sopenharmony_ci			break;
418c2ecf20Sopenharmony_ci		case K_LEFT:
428c2ecf20Sopenharmony_ci		case K_ESC:
438c2ecf20Sopenharmony_ci		case 'q':
448c2ecf20Sopenharmony_ci		case CTRL('c'):
458c2ecf20Sopenharmony_ci			key = -1;
468c2ecf20Sopenharmony_ci			break;
478c2ecf20Sopenharmony_ci		default:
488c2ecf20Sopenharmony_ci			if (keyp) {
498c2ecf20Sopenharmony_ci				*keyp = key;
508c2ecf20Sopenharmony_ci				key = menu->nr_entries;
518c2ecf20Sopenharmony_ci				break;
528c2ecf20Sopenharmony_ci			}
538c2ecf20Sopenharmony_ci			continue;
548c2ecf20Sopenharmony_ci		}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		break;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	ui_browser__hide(menu);
608c2ecf20Sopenharmony_ci	return key;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciint ui__popup_menu(int argc, char * const argv[], int *keyp)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct ui_browser menu = {
668c2ecf20Sopenharmony_ci		.entries    = (void *)argv,
678c2ecf20Sopenharmony_ci		.refresh    = ui_browser__argv_refresh,
688c2ecf20Sopenharmony_ci		.seek	    = ui_browser__argv_seek,
698c2ecf20Sopenharmony_ci		.write	    = ui_browser__argv_write,
708c2ecf20Sopenharmony_ci		.nr_entries = argc,
718c2ecf20Sopenharmony_ci	};
728c2ecf20Sopenharmony_ci	return popup_menu__run(&menu, keyp);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint ui_browser__input_window(const char *title, const char *text, char *input,
768c2ecf20Sopenharmony_ci			     const char *exit_msg, int delay_secs)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	int x, y, len, key;
798c2ecf20Sopenharmony_ci	int max_len = 60, nr_lines = 0;
808c2ecf20Sopenharmony_ci	static char buf[50];
818c2ecf20Sopenharmony_ci	const char *t;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	t = text;
848c2ecf20Sopenharmony_ci	while (1) {
858c2ecf20Sopenharmony_ci		const char *sep = strchr(t, '\n');
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		if (sep == NULL)
888c2ecf20Sopenharmony_ci			sep = strchr(t, '\0');
898c2ecf20Sopenharmony_ci		len = sep - t;
908c2ecf20Sopenharmony_ci		if (max_len < len)
918c2ecf20Sopenharmony_ci			max_len = len;
928c2ecf20Sopenharmony_ci		++nr_lines;
938c2ecf20Sopenharmony_ci		if (*sep == '\0')
948c2ecf20Sopenharmony_ci			break;
958c2ecf20Sopenharmony_ci		t = sep + 1;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	pthread_mutex_lock(&ui__lock);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	max_len += 2;
1018c2ecf20Sopenharmony_ci	nr_lines += 8;
1028c2ecf20Sopenharmony_ci	y = SLtt_Screen_Rows / 2 - nr_lines / 2;
1038c2ecf20Sopenharmony_ci	x = SLtt_Screen_Cols / 2 - max_len / 2;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	SLsmg_set_color(0);
1068c2ecf20Sopenharmony_ci	SLsmg_draw_box(y, x++, nr_lines, max_len);
1078c2ecf20Sopenharmony_ci	if (title) {
1088c2ecf20Sopenharmony_ci		SLsmg_gotorc(y, x + 1);
1098c2ecf20Sopenharmony_ci		SLsmg_write_string((char *)title);
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci	SLsmg_gotorc(++y, x);
1128c2ecf20Sopenharmony_ci	nr_lines -= 7;
1138c2ecf20Sopenharmony_ci	max_len -= 2;
1148c2ecf20Sopenharmony_ci	SLsmg_write_wrapped_string((unsigned char *)text, y, x,
1158c2ecf20Sopenharmony_ci				   nr_lines, max_len, 1);
1168c2ecf20Sopenharmony_ci	y += nr_lines;
1178c2ecf20Sopenharmony_ci	len = 5;
1188c2ecf20Sopenharmony_ci	while (len--) {
1198c2ecf20Sopenharmony_ci		SLsmg_gotorc(y + len - 1, x);
1208c2ecf20Sopenharmony_ci		SLsmg_write_nstring((char *)" ", max_len);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	SLsmg_gotorc(y + 3, x);
1258c2ecf20Sopenharmony_ci	SLsmg_write_nstring((char *)exit_msg, max_len);
1268c2ecf20Sopenharmony_ci	SLsmg_refresh();
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&ui__lock);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	x += 2;
1318c2ecf20Sopenharmony_ci	len = 0;
1328c2ecf20Sopenharmony_ci	key = ui__getch(delay_secs);
1338c2ecf20Sopenharmony_ci	while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
1348c2ecf20Sopenharmony_ci		pthread_mutex_lock(&ui__lock);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		if (key == K_BKSPC) {
1378c2ecf20Sopenharmony_ci			if (len == 0) {
1388c2ecf20Sopenharmony_ci				pthread_mutex_unlock(&ui__lock);
1398c2ecf20Sopenharmony_ci				goto next_key;
1408c2ecf20Sopenharmony_ci			}
1418c2ecf20Sopenharmony_ci			SLsmg_gotorc(y, x + --len);
1428c2ecf20Sopenharmony_ci			SLsmg_write_char(' ');
1438c2ecf20Sopenharmony_ci		} else {
1448c2ecf20Sopenharmony_ci			buf[len] = key;
1458c2ecf20Sopenharmony_ci			SLsmg_gotorc(y, x + len++);
1468c2ecf20Sopenharmony_ci			SLsmg_write_char(key);
1478c2ecf20Sopenharmony_ci		}
1488c2ecf20Sopenharmony_ci		SLsmg_refresh();
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		pthread_mutex_unlock(&ui__lock);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		/* XXX more graceful overflow handling needed */
1538c2ecf20Sopenharmony_ci		if (len == sizeof(buf) - 1) {
1548c2ecf20Sopenharmony_ci			ui_helpline__push("maximum size of symbol name reached!");
1558c2ecf20Sopenharmony_ci			key = K_ENTER;
1568c2ecf20Sopenharmony_ci			break;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_cinext_key:
1598c2ecf20Sopenharmony_ci		key = ui__getch(delay_secs);
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	buf[len] = '\0';
1638c2ecf20Sopenharmony_ci	strncpy(input, buf, len+1);
1648c2ecf20Sopenharmony_ci	return key;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_civoid __ui__info_window(const char *title, const char *text, const char *exit_msg)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	int x, y;
1708c2ecf20Sopenharmony_ci	int max_len = 0, nr_lines = 0;
1718c2ecf20Sopenharmony_ci	const char *t;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	t = text;
1748c2ecf20Sopenharmony_ci	while (1) {
1758c2ecf20Sopenharmony_ci		const char *sep = strchr(t, '\n');
1768c2ecf20Sopenharmony_ci		int len;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		if (sep == NULL)
1798c2ecf20Sopenharmony_ci			sep = strchr(t, '\0');
1808c2ecf20Sopenharmony_ci		len = sep - t;
1818c2ecf20Sopenharmony_ci		if (max_len < len)
1828c2ecf20Sopenharmony_ci			max_len = len;
1838c2ecf20Sopenharmony_ci		++nr_lines;
1848c2ecf20Sopenharmony_ci		if (*sep == '\0')
1858c2ecf20Sopenharmony_ci			break;
1868c2ecf20Sopenharmony_ci		t = sep + 1;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	max_len += 2;
1908c2ecf20Sopenharmony_ci	nr_lines += 2;
1918c2ecf20Sopenharmony_ci	if (exit_msg)
1928c2ecf20Sopenharmony_ci		nr_lines += 2;
1938c2ecf20Sopenharmony_ci	y = SLtt_Screen_Rows / 2 - nr_lines / 2,
1948c2ecf20Sopenharmony_ci	x = SLtt_Screen_Cols / 2 - max_len / 2;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	SLsmg_set_color(0);
1978c2ecf20Sopenharmony_ci	SLsmg_draw_box(y, x++, nr_lines, max_len);
1988c2ecf20Sopenharmony_ci	if (title) {
1998c2ecf20Sopenharmony_ci		SLsmg_gotorc(y, x + 1);
2008c2ecf20Sopenharmony_ci		SLsmg_write_string((char *)title);
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci	SLsmg_gotorc(++y, x);
2038c2ecf20Sopenharmony_ci	if (exit_msg)
2048c2ecf20Sopenharmony_ci		nr_lines -= 2;
2058c2ecf20Sopenharmony_ci	max_len -= 2;
2068c2ecf20Sopenharmony_ci	SLsmg_write_wrapped_string((unsigned char *)text, y, x,
2078c2ecf20Sopenharmony_ci				   nr_lines, max_len, 1);
2088c2ecf20Sopenharmony_ci	if (exit_msg) {
2098c2ecf20Sopenharmony_ci		SLsmg_gotorc(y + nr_lines - 2, x);
2108c2ecf20Sopenharmony_ci		SLsmg_write_nstring((char *)" ", max_len);
2118c2ecf20Sopenharmony_ci		SLsmg_gotorc(y + nr_lines - 1, x);
2128c2ecf20Sopenharmony_ci		SLsmg_write_nstring((char *)exit_msg, max_len);
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_civoid ui__info_window(const char *title, const char *text)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	pthread_mutex_lock(&ui__lock);
2198c2ecf20Sopenharmony_ci	__ui__info_window(title, text, NULL);
2208c2ecf20Sopenharmony_ci	SLsmg_refresh();
2218c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&ui__lock);
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ciint ui__question_window(const char *title, const char *text,
2258c2ecf20Sopenharmony_ci			const char *exit_msg, int delay_secs)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	pthread_mutex_lock(&ui__lock);
2288c2ecf20Sopenharmony_ci	__ui__info_window(title, text, exit_msg);
2298c2ecf20Sopenharmony_ci	SLsmg_refresh();
2308c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&ui__lock);
2318c2ecf20Sopenharmony_ci	return ui__getch(delay_secs);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ciint ui__help_window(const char *text)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	return ui__question_window("Help", text, "Press any key...", 0);
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ciint ui__dialog_yesno(const char *msg)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int __ui__warning(const char *title, const char *format, va_list args)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	char *s;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (vasprintf(&s, format, args) > 0) {
2498c2ecf20Sopenharmony_ci		int key;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci		key = ui__question_window(title, s, "Press any key...", 0);
2528c2ecf20Sopenharmony_ci		free(s);
2538c2ecf20Sopenharmony_ci		return key;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	fprintf(stderr, "%s\n", title);
2578c2ecf20Sopenharmony_ci	vfprintf(stderr, format, args);
2588c2ecf20Sopenharmony_ci	return K_ESC;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic int perf_tui__error(const char *format, va_list args)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	return __ui__warning("Error:", format, args);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic int perf_tui__warning(const char *format, va_list args)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	return __ui__warning("Warning:", format, args);
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistruct perf_error_ops perf_tui_eops = {
2728c2ecf20Sopenharmony_ci	.error		= perf_tui__error,
2738c2ecf20Sopenharmony_ci	.warning	= perf_tui__warning,
2748c2ecf20Sopenharmony_ci};
275