eloop: move prefix to "ev_" instead of "kmscon_"
[platform/upstream/kmscon.git] / tests / test_console.c
1 /*
2  * test_console - Test Console
3  *
4  * Copyright (c) 2011 David Herrmann <dh.herrmann@googlemail.com>
5  * Copyright (c) 2011 University of Tuebingen
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files
9  * (the "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 /*
28  * Test Console
29  * This prints a console onto all available outputs. The console is not
30  * interactive, but instead all input from stdin is read and printed as
31  * printable characters onto the console.
32  * This is no terminal emulation but instead an example how to print text with
33  * the console subsystem.
34  *
35  * This prints all text from stdin to all connected outputs:
36  * $ ./test_console
37  *
38  * This prints the text from the command "ls -la" to all outptus:
39  * $ ls -la | ./test_console
40  */
41
42 #include <errno.h>
43 #include <inttypes.h>
44 #include <locale.h>
45 #include <signal.h>
46 #include <stdbool.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 #include "console.h"
52 #include "eloop.h"
53 #include "font.h"
54 #include "log.h"
55 #include "output.h"
56 #include "unicode.h"
57 #include "vt.h"
58
59 static volatile sig_atomic_t terminate;
60
61 struct console {
62         struct ev_eloop *loop;
63         struct ev_signal *sig_term;
64         struct ev_signal *sig_int;
65         struct ev_fd *stdin_fd;
66         struct kmscon_symbol_table *st;
67         struct kmscon_font_factory *ff;
68         struct kmscon_compositor *comp;
69         struct kmscon_vt *vt;
70         struct kmscon_console *con;
71         struct ev_idle *idle;
72
73         uint32_t max_x;
74         uint32_t max_y;
75 };
76
77 static void stdin_cb(struct ev_fd *fd, int mask, void *data)
78 {
79         struct console *con = data;
80         char buf[512];
81         int ret;
82         unsigned int i, len;
83         kmscon_symbol_t ch;
84
85         if (!con || !fd)
86                 return;
87
88         ret = read(0, buf, sizeof(buf));
89         if (ret < 0) {
90                 log_info("stdin read error: %d\n", errno);
91         } else if (!ret) {
92                 log_info("stdin closed\n");
93                 ev_eloop_rm_fd(fd);
94                 con->stdin_fd = NULL;
95         } else {
96                 len = ret;
97                 log_debug("stdin input read (len: %d)\n", len);
98
99                 for (i = 0; i < len; ++i) {
100                         if (buf[i] == '\n') {
101                                 kmscon_console_newline(con->con);
102                         } else {
103                                 ch = buf[i];
104                                 kmscon_console_write(con->con, ch);
105                         }
106                 }
107         }
108 }
109
110 static void map_outputs(struct console *con)
111 {
112         int ret;
113         struct kmscon_output *iter;
114         struct kmscon_context *ctx;
115
116         if (kmscon_compositor_is_asleep(con->comp))
117                 return;
118
119         ctx = kmscon_compositor_get_context(con->comp);
120
121         iter = kmscon_compositor_get_outputs(con->comp);
122         for ( ; iter; iter = kmscon_output_next(iter)) {
123                 if (!kmscon_output_is_active(iter))
124                         continue;
125
126                 ret = kmscon_output_use(iter);
127                 if (ret)
128                         continue;
129
130                 kmscon_context_clear(ctx);
131                 kmscon_console_map(con->con);
132
133                 ret = kmscon_output_swap(iter);
134                 if (ret)
135                         continue;
136         }
137 }
138
139 static void draw(struct ev_idle *idle, void *data)
140 {
141         struct console *con = data;
142
143         ev_eloop_rm_idle(idle);
144         map_outputs(con);
145 }
146
147 static void schedule_draw(struct console *con)
148 {
149         int ret;
150
151         ret = ev_eloop_add_idle(con->loop, con->idle, draw, con);
152         if (ret && ret != -EALREADY)
153                 log_warn("Cannot schedule draw function\n");
154 }
155
156 static void activate_outputs(struct console *con)
157 {
158         struct kmscon_output *iter;
159         struct kmscon_mode *mode;
160         int ret;
161         uint32_t y;
162
163         con->max_y = 0;
164
165         iter = kmscon_compositor_get_outputs(con->comp);
166         for ( ; iter; iter = kmscon_output_next(iter)) {
167                 if (!kmscon_output_is_active(iter)) {
168                         ret = kmscon_output_activate(iter, NULL);
169                         if (ret)
170                                 continue;
171                 }
172
173                 mode = kmscon_output_get_current(iter);
174                 y = kmscon_mode_get_height(mode);
175                 if (y > con->max_y)
176                         con->max_y = y;
177         }
178
179         kmscon_console_resize(con->con, 0, 0, con->max_y);
180         schedule_draw(con);
181 }
182
183 static void sig_term(struct ev_signal *sig, int signum, void *data)
184 {
185         terminate = 1;
186 }
187
188 static bool vt_switch(struct kmscon_vt *vt, int action, void *data)
189 {
190         struct console *con = data;
191         int ret;
192
193         if (action == KMSCON_VT_ENTER) {
194                 ret = kmscon_compositor_wake_up(con->comp);
195                 if (ret == 0) {
196                         log_info("No output found\n");
197                 } else if (ret > 0) {
198                         activate_outputs(con);
199                 }
200         } else {
201                 kmscon_compositor_sleep(con->comp);
202         }
203
204         return true;
205 }
206
207 static const char help_text[] =
208 "test_console - KMS based console test\n"
209 "This application can be used to test the console subsystem. It copies stdin "
210 "to the console so you can use it to print arbitrary text like this:\n"
211 "    ls -la / | sudo ./test_console\n"
212 "Please be aware that the application needs root rights to access the VT. "
213 "If no VT support is compiled in you can run it without root rights but you "
214 "should not start it from inside X!\n\n";
215
216 static void print_help(struct console *con)
217 {
218         unsigned int i, len;
219         kmscon_symbol_t ch;
220
221         len = sizeof(help_text) - 1;
222         for (i = 0; i < len; ++i) {
223                 if (help_text[i] == '\n') {
224                         kmscon_console_newline(con->con);
225                 } else {
226                         ch = help_text[i];
227                         kmscon_console_write(con->con, ch);
228                 }
229         }
230 }
231
232 static void destroy_eloop(struct console *con)
233 {
234         ev_eloop_rm_idle(con->idle);
235         ev_idle_unref(con->idle);
236         kmscon_console_unref(con->con);
237         kmscon_compositor_unref(con->comp);
238         kmscon_vt_unref(con->vt);
239         kmscon_font_factory_unref(con->ff);
240         kmscon_symbol_table_unref(con->st);
241         ev_eloop_rm_fd(con->stdin_fd);
242         ev_eloop_rm_signal(con->sig_int);
243         ev_eloop_rm_signal(con->sig_term);
244         ev_eloop_unref(con->loop);
245 }
246
247 static int setup_eloop(struct console *con)
248 {
249         int ret;
250
251         ret = ev_eloop_new(&con->loop);
252         if (ret)
253                 return ret;
254
255         ret = ev_eloop_new_signal(con->loop, &con->sig_term, SIGTERM,
256                                                         sig_term, NULL);
257         if (ret)
258                 goto err_loop;
259
260         ret = ev_eloop_new_signal(con->loop, &con->sig_int, SIGINT,
261                                                         sig_term, NULL);
262         if (ret)
263                 goto err_loop;
264
265         ret = ev_eloop_new_fd(con->loop, &con->stdin_fd, 0,
266                                         EV_READABLE, stdin_cb, con);
267         if (ret)
268                 goto err_loop;
269
270         ret = kmscon_symbol_table_new(&con->st);
271         if (ret)
272                 goto err_loop;
273
274         ret = kmscon_compositor_new(&con->comp);
275         if (ret)
276                 goto err_loop;
277
278         ret = kmscon_compositor_use(con->comp);
279         if (ret)
280                 goto err_loop;
281
282         ret = kmscon_font_factory_new(&con->ff, con->st, con->comp);
283         if (ret)
284                 goto err_loop;
285
286         ret = kmscon_vt_new(&con->vt, vt_switch, con);
287         if (ret)
288                 goto err_loop;
289
290         ret = kmscon_vt_open(con->vt, KMSCON_VT_NEW, con->loop);
291         if (ret)
292                 goto err_loop;
293
294         ret = kmscon_console_new(&con->con, con->ff, con->comp);
295         if (ret)
296                 goto err_loop;
297
298         ret = ev_idle_new(&con->idle);
299         if (ret)
300                 goto err_loop;
301
302         print_help(con);
303         return 0;
304
305 err_loop:
306         destroy_eloop(con);
307         return ret;
308 }
309
310 int main(int argc, char **argv)
311 {
312         struct console con;
313         int ret;
314
315         setlocale(LC_ALL, "");
316         memset(&con, 0, sizeof(con));
317
318         ret = setup_eloop(&con);
319         if (ret) {
320                 log_err("Cannot setup eloop\n");
321                 return abs(ret);
322         }
323
324         log_info("Starting console\n");
325
326         schedule_draw(&con);
327
328         while (!terminate) {
329                 ret = ev_eloop_dispatch(con.loop, -1);
330                 if (ret)
331                         break;
332         }
333
334         log_info("Stopping console\n");
335
336         destroy_eloop(&con);
337         return abs(ret);
338 }