blob: 33e953ba5cc4d5538d52fee2d66270432cb0016c [file] [log] [blame]
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <ctype.h>
8#include <libtsm.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07009#include <stdio.h>
Dominik Behr93899452014-08-18 22:16:21 -070010#include <sys/select.h>
David Sodmanbf3f2842014-11-12 08:26:58 -080011#include <sys/types.h>
12#include <sys/wait.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070013
14#include "font.h"
15#include "input.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070016#include "shl_pty.h"
17#include "term.h"
18#include "util.h"
19#include "video.h"
20
Stéphane Marchesin08c08e72016-01-07 16:44:08 -080021static terminal_t* terminals[MAX_TERMINALS];
Dominik Behr4defb362016-01-13 12:36:14 -080022static uint32_t current_terminal = 0;
Stéphane Marchesin08c08e72016-01-07 16:44:08 -080023
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070024struct term {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080025 struct tsm_screen* screen;
26 struct tsm_vte* vte;
27 struct shl_pty* pty;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070028 int pty_bridge;
29 int pid;
30 tsm_age_t age;
31 int char_x, char_y;
32 int pitch;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080033 uint32_t* dst_image;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070034};
35
David Sodmanf0a925a2015-05-04 11:19:19 -070036struct _terminal_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080037 uint32_t background;
38 bool background_valid;
39 video_t* video;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080040 struct term* term;
41 bool active;
42 char** exec;
David Sodmanf0a925a2015-05-04 11:19:19 -070043};
44
David Sodman8ef20062015-01-06 09:23:40 -080045
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080046static char* interactive_cmd_line[] = {
David Sodman8ef20062015-01-06 09:23:40 -080047 "/sbin/agetty",
48 "-",
49 "9600",
50 "xterm",
51 NULL
52};
53
54
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080055static char* noninteractive_cmd_line[] = {
David Sodman8ef20062015-01-06 09:23:40 -080056 "/bin/cat",
57 NULL
58};
59
60
61static void __attribute__ ((noreturn)) term_run_child(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070062{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070063 /* XXX figure out how to fix "top" for xterm-256color */
64 setenv("TERM", "xterm", 1);
David Sodman8ef20062015-01-06 09:23:40 -080065 execve(terminal->exec[0], terminal->exec, environ);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070066 exit(1);
67}
68
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080069static int term_draw_cell(struct tsm_screen* screen, uint32_t id,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080070 const uint32_t* ch, size_t len,
71 unsigned int cwidth, unsigned int posx,
72 unsigned int posy,
73 const struct tsm_screen_attr* attr,
74 tsm_age_t age, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070075{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080076 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070077 uint32_t front_color, back_color;
David Sodmanf0a925a2015-05-04 11:19:19 -070078 uint8_t br, bb, bg;
Stéphane Marchesinedece332015-12-14 15:10:58 -080079 uint32_t luminance;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070080
David Sodmanbbcb0522014-09-19 10:34:07 -070081 if (age && terminal->term->age && age <= terminal->term->age)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070082 return 0;
83
David Sodmanf0a925a2015-05-04 11:19:19 -070084 if (terminal->background_valid) {
85 br = (terminal->background >> 16) & 0xFF;
86 bg = (terminal->background >> 8) & 0xFF;
87 bb = (terminal->background) & 0xFF;
Stéphane Marchesinedece332015-12-14 15:10:58 -080088 luminance = (3 * br + bb + 4 * bg) >> 3;
David Sodmanf0a925a2015-05-04 11:19:19 -070089
Stéphane Marchesinedece332015-12-14 15:10:58 -080090 /*
91 * FIXME: black is chosen on a dark background, but it uses the
92 * default color for light backgrounds
93 */
94 if (luminance > 128) {
David Sodmanf0a925a2015-05-04 11:19:19 -070095 front_color = 0;
96 back_color = terminal->background;
97 } else {
98 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
99 back_color = terminal->background;
100 }
101 } else {
102 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
103 back_color = (attr->br << 16) | (attr->bg << 8) | attr->bb;
104 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700105
106 if (attr->inverse) {
107 uint32_t tmp = front_color;
108 front_color = back_color;
109 back_color = tmp;
110 }
111
112 if (len)
David Sodmanbbcb0522014-09-19 10:34:07 -0700113 font_render(terminal->term->dst_image, posx, posy, terminal->term->pitch, *ch,
114 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700115 else
David Sodmanbbcb0522014-09-19 10:34:07 -0700116 font_fillchar(terminal->term->dst_image, posx, posy, terminal->term->pitch,
117 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700118
119 return 0;
120}
121
Stéphane Marchesine2a46cd2016-01-07 16:45:24 -0800122static void term_redraw(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700123{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800124 uint32_t* video_buffer;
David Sodmanbbcb0522014-09-19 10:34:07 -0700125 video_buffer = video_lock(terminal->video);
126 if (video_buffer != NULL) {
127 terminal->term->dst_image = video_buffer;
128 terminal->term->age =
129 tsm_screen_draw(terminal->term->screen, term_draw_cell, terminal);
130 video_unlock(terminal->video);
131 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700132}
133
David Sodmanbbcb0522014-09-19 10:34:07 -0700134void term_key_event(terminal_t* terminal, uint32_t keysym, int32_t unicode)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700135{
David Sodmanbbcb0522014-09-19 10:34:07 -0700136 if (tsm_vte_handle_keyboard(terminal->term->vte, keysym, 0, 0, unicode))
137 tsm_screen_sb_reset(terminal->term->screen);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700138
David Sodmanbbcb0522014-09-19 10:34:07 -0700139 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700140}
141
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800142static void term_read_cb(struct shl_pty* pty, char* u8, size_t len, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700143{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800144 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700145
David Sodmanbbcb0522014-09-19 10:34:07 -0700146 tsm_vte_input(terminal->term->vte, u8, len);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700147
David Sodmanbbcb0522014-09-19 10:34:07 -0700148 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700149}
150
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800151static void term_write_cb(struct tsm_vte* vte, const char* u8, size_t len,
152 void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700153{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800154 struct term* term = data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700155 int r;
156
157 r = shl_pty_write(term->pty, u8, len);
158 if (r < 0)
David Sodmanbbcb0522014-09-19 10:34:07 -0700159 LOG(ERROR, "OOM in pty-write (%d)", r);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700160
161 shl_pty_dispatch(term->pty);
162}
163
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800164static const char* sev2str_table[] = {
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700165 "FATAL",
166 "ALERT",
167 "CRITICAL",
168 "ERROR",
169 "WARNING",
170 "NOTICE",
171 "INFO",
172 "DEBUG"
173};
174
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800175static const char* sev2str(unsigned int sev)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700176{
177 if (sev > 7)
178 return "DEBUG";
179
180 return sev2str_table[sev];
181}
182
Dominik Behr00003502014-08-15 16:42:37 -0700183#ifdef __clang__
184__attribute__((__format__ (__printf__, 7, 0)))
185#endif
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800186static void log_tsm(void* data, const char* file, int line, const char* fn,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800187 const char* subs, unsigned int sev, const char* format,
188 va_list args)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700189{
190 fprintf(stderr, "%s: %s: ", sev2str(sev), subs);
191 vfprintf(stderr, format, args);
192 fprintf(stderr, "\n");
193}
194
Stéphane Marchesin78310662016-01-06 16:09:39 -0800195static int term_resize(terminal_t* term)
196{
197 uint32_t char_width, char_height;
198 int status;
199
200 font_init(video_getscaling(term->video));
201 font_get_size(&char_width, &char_height);
202
203 term->term->char_x = video_getwidth(term->video) / char_width;
204 term->term->char_y = video_getheight(term->video) / char_height;
205 term->term->pitch = video_getpitch(term->video);
206
207 status = tsm_screen_resize(term->term->screen,
208 term->term->char_x, term->term->char_y);
209 if (status < 0) {
210 font_free();
211 return -1;
212 }
213
214 status = shl_pty_resize(term->term->pty, term->term->char_x,
215 term->term->char_y);
216 if (status < 0) {
217 font_free();
218 return -1;
219 }
220
221 return 0;
222}
223
David Sodmanf0a925a2015-05-04 11:19:19 -0700224terminal_t* term_init(bool interactive, video_t* video)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700225{
226 const int scrollback_size = 200;
David Sodmanbbcb0522014-09-19 10:34:07 -0700227 int status;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800228 terminal_t* new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700229
David Sodmanbbcb0522014-09-19 10:34:07 -0700230 new_terminal = (terminal_t*)calloc(1, sizeof(*new_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800231 if (!new_terminal)
232 return NULL;
David Sodmanbbcb0522014-09-19 10:34:07 -0700233
David Sodmanf0a925a2015-05-04 11:19:19 -0700234 new_terminal->background_valid = false;
235
David Sodman30a94ef2015-07-26 17:37:12 -0700236 if (video) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700237 new_terminal->video = video;
David Sodman30a94ef2015-07-26 17:37:12 -0700238 video_addref(video);
239 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700240 else
241 new_terminal->video = video_init();
242
David Sodmanbf3f2842014-11-12 08:26:58 -0800243 if (!new_terminal->video) {
244 term_close(new_terminal);
245 return NULL;
246 }
247
248 new_terminal->term = (struct term*)calloc(1, sizeof(*new_terminal->term));
249 if (!new_terminal->term) {
250 term_close(new_terminal);
251 return NULL;
252 }
253
David Sodman8ef20062015-01-06 09:23:40 -0800254 if (interactive)
255 new_terminal->exec = interactive_cmd_line;
256 else
257 new_terminal->exec = noninteractive_cmd_line;
258
David Sodmanbbcb0522014-09-19 10:34:07 -0700259 status = tsm_screen_new(&new_terminal->term->screen,
260 log_tsm, new_terminal->term);
zhuo-hao471f1e22015-08-12 14:55:56 +0800261 if (status < 0) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700262 term_close(new_terminal);
263 return NULL;
264 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700265
David Sodmanbbcb0522014-09-19 10:34:07 -0700266 tsm_screen_set_max_sb(new_terminal->term->screen, scrollback_size);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700267
David Sodmanbbcb0522014-09-19 10:34:07 -0700268 status = tsm_vte_new(&new_terminal->term->vte, new_terminal->term->screen,
269 term_write_cb, new_terminal->term, log_tsm, new_terminal->term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700270
David Sodmanbbcb0522014-09-19 10:34:07 -0700271 if (status < 0) {
272 term_close(new_terminal);
273 return NULL;
274 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700275
David Sodmanbbcb0522014-09-19 10:34:07 -0700276 new_terminal->term->pty_bridge = shl_pty_bridge_new();
277 if (new_terminal->term->pty_bridge < 0) {
278 term_close(new_terminal);
279 return NULL;
280 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700281
David Sodmanbbcb0522014-09-19 10:34:07 -0700282 status = shl_pty_open(&new_terminal->term->pty,
Stéphane Marchesin78310662016-01-06 16:09:39 -0800283 term_read_cb, new_terminal, 1, 1);
David Sodman8ef20062015-01-06 09:23:40 -0800284
David Sodmanbbcb0522014-09-19 10:34:07 -0700285 if (status < 0) {
286 term_close(new_terminal);
287 return NULL;
288 } else if (status == 0) {
David Sodman8ef20062015-01-06 09:23:40 -0800289 term_run_child(new_terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700290 exit(1);
291 }
292
David Sodmanbbcb0522014-09-19 10:34:07 -0700293 status = shl_pty_bridge_add(new_terminal->term->pty_bridge, new_terminal->term->pty);
294 if (status) {
295 shl_pty_close(new_terminal->term->pty);
296 term_close(new_terminal);
297 return NULL;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700298 }
299
David Sodmanbbcb0522014-09-19 10:34:07 -0700300 new_terminal->term->pid = shl_pty_get_child(new_terminal->term->pty);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700301
Stéphane Marchesin78310662016-01-06 16:09:39 -0800302 status = term_resize(new_terminal);
David Sodmanbbcb0522014-09-19 10:34:07 -0700303 if (status < 0) {
304 shl_pty_close(new_terminal->term->pty);
305 term_close(new_terminal);
306 return NULL;
307 }
David Sodman8ef20062015-01-06 09:23:40 -0800308
309 if (interactive)
310 new_terminal->active = true;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700311
David Sodmanbbcb0522014-09-19 10:34:07 -0700312 return new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700313}
314
David Sodman8ef20062015-01-06 09:23:40 -0800315void term_activate(terminal_t* terminal)
316{
Dominik Behr4defb362016-01-13 12:36:14 -0800317 term_set_current_to(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800318 terminal->active = true;
319 video_setmode(terminal->video);
320 term_redraw(terminal);
321}
322
David Sodmanf0a925a2015-05-04 11:19:19 -0700323void term_deactivate(terminal_t* terminal)
324{
325 if (!terminal->active)
326 return;
327
David Sodmanf0a925a2015-05-04 11:19:19 -0700328 terminal->active = false;
329 video_release(terminal->video);
330}
331
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800332void term_close(terminal_t* term)
David Sodmanbbcb0522014-09-19 10:34:07 -0700333{
334 if (!term)
335 return;
336
David Sodmanbf3f2842014-11-12 08:26:58 -0800337 if (term->video) {
338 video_close(term->video);
339 term->video = NULL;
340 }
341
David Sodmanbbcb0522014-09-19 10:34:07 -0700342 if (term->term) {
343 free(term->term);
344 term->term = NULL;
345 }
346
Haixia Shi95d680e2015-04-27 20:29:17 -0700347 font_free();
David Sodmanbbcb0522014-09-19 10:34:07 -0700348 free(term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700349}
David Sodmanbf3f2842014-11-12 08:26:58 -0800350
351bool term_is_child_done(terminal_t* terminal)
352{
353 int status;
354 int ret;
355 ret = waitpid(terminal->term->pid, &status, WNOHANG);
356
David Sodmanf0a925a2015-05-04 11:19:19 -0700357 if ((ret == -1) && (errno == ECHILD)) {
358 return false;
359 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800360 return ret != 0;
361}
362
363void term_page_up(terminal_t* terminal)
364{
365 tsm_screen_sb_page_up(terminal->term->screen, 1);
366 term_redraw(terminal);
367}
368
369void term_page_down(terminal_t* terminal)
370{
371 tsm_screen_sb_page_down(terminal->term->screen, 1);
372 term_redraw(terminal);
373}
374
375void term_line_up(terminal_t* terminal)
376{
377 tsm_screen_sb_up(terminal->term->screen, 1);
378 term_redraw(terminal);
379}
380
381void term_line_down(terminal_t* terminal)
382{
383 tsm_screen_sb_down(terminal->term->screen, 1);
384 term_redraw(terminal);
385}
386
387bool term_is_valid(terminal_t* terminal)
388{
389 return ((terminal != NULL) && (terminal->term != NULL));
390}
391
392int term_fd(terminal_t* terminal)
393{
394 if (term_is_valid(terminal))
395 return terminal->term->pty_bridge;
396 else
397 return -1;
398}
399
400void term_dispatch_io(terminal_t* terminal, fd_set* read_set)
401{
402 if (term_is_valid(terminal))
403 if (FD_ISSET(terminal->term->pty_bridge, read_set))
404 shl_pty_bridge_dispatch(terminal->term->pty_bridge, 0);
405}
406
407bool term_exception(terminal_t* terminal, fd_set* exception_set)
408{
409 if (term_is_valid(terminal)) {
410 if (terminal->term->pty_bridge >= 0) {
411 return FD_ISSET(terminal->term->pty_bridge,
412 exception_set);
413 }
414 }
415
416 return false;
417}
418
419bool term_is_active(terminal_t* terminal)
420{
421 if (term_is_valid(terminal))
422 return terminal->active;
423
424 return false;
425}
426
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800427int term_add_fds(terminal_t* terminal, fd_set* read_set, fd_set* exception_set)
David Sodmanbf3f2842014-11-12 08:26:58 -0800428{
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800429 int maxfd = 0;
430
David Sodmanbf3f2842014-11-12 08:26:58 -0800431 if (term_is_valid(terminal)) {
432 if (terminal->term->pty_bridge >= 0) {
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800433 maxfd = MAX(maxfd, terminal->term->pty_bridge);
David Sodmanbf3f2842014-11-12 08:26:58 -0800434 FD_SET(terminal->term->pty_bridge, read_set);
435 FD_SET(terminal->term->pty_bridge, exception_set);
436 }
437 }
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800438 return maxfd;
David Sodmanbf3f2842014-11-12 08:26:58 -0800439}
David Sodman8ef20062015-01-06 09:23:40 -0800440
441const char* term_get_ptsname(terminal_t* terminal)
442{
443 return ptsname(shl_pty_get_fd(terminal->term->pty));
444}
David Sodmanf0a925a2015-05-04 11:19:19 -0700445
446void term_set_background(terminal_t* terminal, uint32_t bg)
447{
448 terminal->background = bg;
449 terminal->background_valid = true;
450}
451
452int term_show_image(terminal_t* terminal, image_t* image)
453{
454 return image_show(image, terminal->video);
455}
456
457void term_write_message(terminal_t* terminal, char* message)
458{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800459 FILE* fp;
David Sodmanf0a925a2015-05-04 11:19:19 -0700460
461 fp = fopen(term_get_ptsname(terminal), "w");
462 if (fp) {
463 fputs(message, fp);
464 fclose(fp);
465 }
466}
467
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800468static void term_hide_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700469{
470 term_write_message(terminal, "\033[?25l");
471}
472
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800473__attribute__ ((unused))
474static void term_show_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700475{
476 term_write_message(terminal, "\033[?25h");
477}
David Sodman30a94ef2015-07-26 17:37:12 -0700478
479video_t* term_getvideo(terminal_t* terminal)
480{
481 return terminal->video;
482}
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800483
484terminal_t* term_get_terminal(int num)
485{
486 return terminals[num];
487}
488
489void term_set_terminal(int num, terminal_t* terminal)
490{
491 terminals[num] = terminal;
492}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800493
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -0800494terminal_t* term_create_term(int vt)
495{
496 terminal_t* terminal;
497
498 terminal = term_get_terminal(vt - 1);
499 if (term_is_active(terminal))
500 return terminal;
501
502 if (terminal == NULL) {
503 term_set_terminal(vt - 1, term_init(false, NULL));
504 terminal = term_get_terminal(vt - 1);
505 if (!term_is_valid(terminal)) {
506 LOG(ERROR, "create_term: Term init failed");
507 }
508 }
509
510 return terminal;
511}
512
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800513terminal_t* term_create_splash_term(video_t* video)
514{
515 terminal_t* splash_terminal = term_init(false, video);
516 term_set_terminal(SPLASH_TERMINAL, splash_terminal);
517
518 // Hide the cursor on the splash screen
519 term_hide_cursor(splash_terminal);
520
521 return splash_terminal;
522}
523
524void term_destroy_splash_term()
525{
526 term_set_terminal(SPLASH_TERMINAL, NULL);
527}
528
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800529unsigned int term_get_max_terminals()
530{
531 return MAX_STD_TERMINALS;
532}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800533
Dominik Behr4defb362016-01-13 12:36:14 -0800534void term_set_current(uint32_t t)
535{
536 if (t >= MAX_TERMINALS)
537 LOG(ERROR, "set_current: larger than max");
538 else
539 current_terminal = t;
540}
541
542uint32_t term_get_current(void)
543{
544 return current_terminal;
545}
546
547terminal_t *term_get_current_terminal(void)
548{
549 return terminals[current_terminal];
550}
551
552void term_set_current_terminal(terminal_t *terminal)
553{
554 terminals[current_terminal] = terminal;
555}
556
557void term_set_current_to(terminal_t* terminal)
558{
559 if (!terminal) {
560 terminals[current_terminal] = NULL;
561 current_terminal = 0;
562 return;
563 }
564
565 for (int i = 0; i < MAX_TERMINALS; i++) {
566 if (terminal == terminals[i]) {
567 current_terminal = i;
568 return;
569 }
570 }
571 LOG(ERROR, "set_current_to: terminal not in array");
572}