1 /*
2  * simple skeleton for using TUI, useful as template to
3  * only have to deal with a minimum of boilerplate
4  */
5 #define _GNU_SOURCE
6 #include <arcan_shmif.h>
7 #include <arcan_tui.h>
8 #include <inttypes.h>
9 #include <stdarg.h>
10 #include <errno.h>
11 #include <stdio.h>
12 
13 static char* media_arg;
14 
15 #define TRACE_ENABLE
trace(const char * msg,...)16 static inline void trace(const char* msg, ...)
17 {
18 #ifdef TRACE_ENABLE
19 	va_list args;
20 	va_start( args, msg );
21 		vfprintf(stderr,  msg, args );
22 	va_end( args);
23 	fprintf(stderr, "\n");
24 #endif
25 }
26 
query_label(struct tui_context * ctx,size_t ind,const char * country,const char * lang,struct tui_labelent * dstlbl,void * t)27 static bool query_label(struct tui_context* ctx,
28 	size_t ind, const char* country, const char* lang,
29 	struct tui_labelent* dstlbl, void* t)
30 {
31 	trace("query_label(%zu for %s:%s)\n",
32 		ind, country ? country : "unknown(country)",
33 		lang ? lang : "unknown(language)");
34 
35 	return false;
36 }
37 
fill(struct tui_context * c)38 static void fill(struct tui_context* c)
39 {
40 	arcan_tui_erase_screen(c, NULL);
41 	arcan_tui_move_to(c, 0, 0);
42 }
43 
on_label(struct tui_context * c,const char * label,bool act,void * t)44 static bool on_label(struct tui_context* c, const char* label, bool act, void* t)
45 {
46 	trace("label(%s)", label);
47 	return true;
48 }
49 
on_alabel(struct tui_context * c,const char * label,const int16_t * smpls,size_t n,bool rel,uint8_t datatype,void * t)50 static bool on_alabel(struct tui_context* c, const char* label,
51 		const int16_t* smpls, size_t n, bool rel, uint8_t datatype, void* t)
52 {
53 	trace("a-label(%s)", label);
54 	return false;
55 }
56 
on_mouse(struct tui_context * c,bool relative,int x,int y,int modifiers,void * t)57 static void on_mouse(struct tui_context* c,
58 	bool relative, int x, int y, int modifiers, void* t)
59 {
60 	trace("mouse(%d:%d, mods:%d, rel: %d", x, y, modifiers, (int) relative);
61 }
62 
on_key(struct tui_context * c,uint32_t xkeysym,uint8_t scancode,uint8_t mods,uint16_t subid,void * t)63 static void on_key(struct tui_context* c, uint32_t xkeysym,
64 	uint8_t scancode, uint8_t mods, uint16_t subid, void* t)
65 {
66 	trace("unknown_key(%"PRIu32",%"PRIu8",%"PRIu16")", xkeysym, scancode, subid);
67 }
68 
on_u8(struct tui_context * c,const char * u8,size_t len,void * t)69 static bool on_u8(struct tui_context* c, const char* u8, size_t len, void* t)
70 {
71 	uint8_t buf[5] = {0};
72 	memcpy(buf, u8, len >= 5 ? 4 : len);
73 	trace("utf8-input: %s", buf);
74 	return true;
75 }
76 
on_misc(struct tui_context * c,const arcan_ioevent * ev,void * t)77 static void on_misc(struct tui_context* c, const arcan_ioevent* ev, void* t)
78 {
79 	trace("on_ioevent()");
80 }
81 
on_state(struct tui_context * c,bool input,int fd,void * t)82 static void on_state(struct tui_context* c, bool input, int fd, void* t)
83 {
84 	trace("on-state(in:%d)", (int)input);
85 }
86 
on_bchunk(struct tui_context * c,bool input,uint64_t size,int fd,const char * id,void * t)87 static void on_bchunk(struct tui_context* c,
88 	bool input, uint64_t size, int fd, const char* id, void* t)
89 {
90 	close(fd);
91 	trace("on_bchunk(%"PRIu64", in:%d)", size, (int)input);
92 }
93 
on_vpaste(struct tui_context * c,shmif_pixel * vidp,size_t w,size_t h,size_t stride,void * t)94 static void on_vpaste(struct tui_context* c,
95 		shmif_pixel* vidp, size_t w, size_t h, size_t stride, void* t)
96 {
97 	trace("on_vpaste(%zu, %zu str %zu)", w, h, stride);
98 }
99 
on_apaste(struct tui_context * c,shmif_asample * audp,size_t n_samples,size_t frequency,size_t nch,void * t)100 static void on_apaste(struct tui_context* c,
101 	shmif_asample* audp, size_t n_samples, size_t frequency, size_t nch, void* t)
102 {
103 	trace("on_apaste(%zu @ %zu:%zu)", n_samples, frequency, nch);
104 }
105 
on_tick(struct tui_context * c,void * t)106 static void on_tick(struct tui_context* c, void* t)
107 {
108 	char line[256];
109 	fgets(line, 256, stdin);
110 	arcan_tui_printf(c, NULL, "s\n", line);
111 	arcan_tui_newline(c);
112 	/* ignore this, rather noise:	trace("[tick]"); */
113 }
114 
on_utf8_paste(struct tui_context * c,const uint8_t * str,size_t len,bool cont,void * t)115 static void on_utf8_paste(struct tui_context* c,
116 	const uint8_t* str, size_t len, bool cont, void* t)
117 {
118 	trace("utf8-paste(%s):%d", str, (int) cont);
119 }
120 
on_resize(struct tui_context * c,size_t neww,size_t newh,size_t col,size_t row,void * t)121 static void on_resize(struct tui_context* c,
122 	size_t neww, size_t newh, size_t col, size_t row, void* t)
123 {
124 	trace("resize(%zu(%zu),%zu(%zu))", neww, col, newh, row);
125 	fill(c);
126 }
127 
on_subwindow(struct tui_context * c,arcan_tui_conn * conn,uint32_t id,uint8_t type,void * tag)128 static bool on_subwindow(struct tui_context* c,
129 	arcan_tui_conn* conn, uint32_t id, uint8_t type, void* tag)
130 {
131 /* hand over to afsrv_decode in a loop */
132 	trace("window(%"PRIu32", ok: %s)", id, conn ? "yes" : "no");
133 	if (!conn)
134 		return false;
135 
136 	if (type == TUI_WND_HANDOVER){
137 		char* env[2] = {NULL, NULL};
138 		asprintf(&env[0], "ARCAN_ARG=%s", media_arg);
139 
140 		return arcan_tui_handover(c, conn, NULL,
141 			"/usr/bin/afsrv_decode", NULL, env, 15) != -1;
142 	}
143 	else
144 		return false;
145 }
146 
main(int argc,char ** argv)147 int main(int argc, char** argv)
148 {
149 	arcan_tui_conn* conn = arcan_tui_open_display("tui-test", "");
150 	if (argc == 1){
151 		fprintf(stderr, "missing: afsrv_decode arg\n");
152 		return EXIT_FAILURE;
153 	}
154 	media_arg = argv[1];
155 
156 /*
157  * only the ones that are relevant needs to be filled
158  */
159 	struct tui_cbcfg cbcfg = {
160 		.query_label = query_label,
161 		.input_label = on_label,
162 		.input_alabel = on_alabel,
163 		.input_mouse_motion = on_mouse,
164 		.input_utf8 = on_u8,
165 		.input_key = on_key,
166 		.input_misc = on_misc,
167 		.state = on_state,
168 		.bchunk = on_bchunk,
169 		.vpaste = on_vpaste,
170 		.apaste = on_apaste,
171 		.tick = on_tick,
172 		.utf8 = on_utf8_paste,
173 		.resized = on_resize,
174 		.subwindow = on_subwindow,
175 	};
176 
177 	struct tui_context* tui = arcan_tui_setup(conn, NULL, &cbcfg, sizeof(cbcfg));
178 	arcan_tui_reset_flags(tui, TUI_ALTERNATE);
179 
180 	if (!tui){
181 		fprintf(stderr, "failed to setup TUI connection\n");
182 		return EXIT_FAILURE;
183 	}
184 
185 /* grab a handover video that we will pass to afsrv_decode */
186 	arcan_tui_request_subwnd(tui, TUI_WND_HANDOVER, 0xa);
187 
188 	while (1){
189 		struct tui_process_res res = arcan_tui_process(&tui, 1, NULL, 0, -1);
190 		if (res.errc == TUI_ERRC_OK){
191 			if (-1 == arcan_tui_refresh(tui) && errno == EINVAL)
192 				break;
193 		}
194 		else
195 			break;
196 	}
197 
198 	arcan_tui_destroy(tui, NULL);
199 
200 	return EXIT_SUCCESS;
201 }
202