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