blob: e81df22c712175861c2cd577689256bfb6f71932 [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
Dominik Behr83010f82016-03-18 18:43:08 -070014#include "fb.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070015#include "font.h"
16#include "input.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070017#include "shl_pty.h"
18#include "term.h"
19#include "util.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070020
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;
Dominik Behr83010f82016-03-18 18:43:08 -070039 fb_t* fb;
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{
Dominik Behr83010f82016-03-18 18:43:08 -0700124 uint32_t* fb_buffer;
125 fb_buffer = fb_lock(terminal->fb);
126 if (fb_buffer != NULL) {
127 terminal->term->dst_image = fb_buffer;
David Sodmanbbcb0522014-09-19 10:34:07 -0700128 terminal->term->age =
129 tsm_screen_draw(terminal->term->screen, term_draw_cell, terminal);
Dominik Behr83010f82016-03-18 18:43:08 -0700130 fb_unlock(terminal->fb);
David Sodmanbbcb0522014-09-19 10:34:07 -0700131 }
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
Dominik Behr83010f82016-03-18 18:43:08 -0700200 font_init(fb_getscaling(term->fb));
Stéphane Marchesin78310662016-01-06 16:09:39 -0800201 font_get_size(&char_width, &char_height);
202
Dominik Behr83010f82016-03-18 18:43:08 -0700203 term->term->char_x = fb_getwidth(term->fb) / char_width;
204 term->term->char_y = fb_getheight(term->fb) / char_height;
205 term->term->pitch = fb_getpitch(term->fb);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800206
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
Dominik Behr83010f82016-03-18 18:43:08 -0700224terminal_t* term_init(bool interactive)
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
Dominik Behr83010f82016-03-18 18:43:08 -0700236 new_terminal->fb = fb_init();
David Sodmanf0a925a2015-05-04 11:19:19 -0700237
Dominik Behr83010f82016-03-18 18:43:08 -0700238 if (!new_terminal->fb) {
David Sodmanbf3f2842014-11-12 08:26:58 -0800239 term_close(new_terminal);
240 return NULL;
241 }
242
243 new_terminal->term = (struct term*)calloc(1, sizeof(*new_terminal->term));
244 if (!new_terminal->term) {
245 term_close(new_terminal);
246 return NULL;
247 }
248
David Sodman8ef20062015-01-06 09:23:40 -0800249 if (interactive)
250 new_terminal->exec = interactive_cmd_line;
251 else
252 new_terminal->exec = noninteractive_cmd_line;
253
David Sodmanbbcb0522014-09-19 10:34:07 -0700254 status = tsm_screen_new(&new_terminal->term->screen,
255 log_tsm, new_terminal->term);
zhuo-hao471f1e22015-08-12 14:55:56 +0800256 if (status < 0) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700257 term_close(new_terminal);
258 return NULL;
259 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700260
David Sodmanbbcb0522014-09-19 10:34:07 -0700261 tsm_screen_set_max_sb(new_terminal->term->screen, scrollback_size);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700262
David Sodmanbbcb0522014-09-19 10:34:07 -0700263 status = tsm_vte_new(&new_terminal->term->vte, new_terminal->term->screen,
264 term_write_cb, new_terminal->term, log_tsm, new_terminal->term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700265
David Sodmanbbcb0522014-09-19 10:34:07 -0700266 if (status < 0) {
267 term_close(new_terminal);
268 return NULL;
269 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700270
David Sodmanbbcb0522014-09-19 10:34:07 -0700271 new_terminal->term->pty_bridge = shl_pty_bridge_new();
272 if (new_terminal->term->pty_bridge < 0) {
273 term_close(new_terminal);
274 return NULL;
275 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700276
David Sodmanbbcb0522014-09-19 10:34:07 -0700277 status = shl_pty_open(&new_terminal->term->pty,
Stéphane Marchesin78310662016-01-06 16:09:39 -0800278 term_read_cb, new_terminal, 1, 1);
David Sodman8ef20062015-01-06 09:23:40 -0800279
David Sodmanbbcb0522014-09-19 10:34:07 -0700280 if (status < 0) {
281 term_close(new_terminal);
282 return NULL;
283 } else if (status == 0) {
David Sodman8ef20062015-01-06 09:23:40 -0800284 term_run_child(new_terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700285 exit(1);
286 }
287
David Sodmanbbcb0522014-09-19 10:34:07 -0700288 status = shl_pty_bridge_add(new_terminal->term->pty_bridge, new_terminal->term->pty);
289 if (status) {
290 shl_pty_close(new_terminal->term->pty);
291 term_close(new_terminal);
292 return NULL;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700293 }
294
David Sodmanbbcb0522014-09-19 10:34:07 -0700295 new_terminal->term->pid = shl_pty_get_child(new_terminal->term->pty);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700296
Stéphane Marchesin78310662016-01-06 16:09:39 -0800297 status = term_resize(new_terminal);
Dominik Behr83010f82016-03-18 18:43:08 -0700298
David Sodmanbbcb0522014-09-19 10:34:07 -0700299 if (status < 0) {
300 shl_pty_close(new_terminal->term->pty);
301 term_close(new_terminal);
302 return NULL;
303 }
David Sodman8ef20062015-01-06 09:23:40 -0800304
305 if (interactive)
306 new_terminal->active = true;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700307
David Sodmanbbcb0522014-09-19 10:34:07 -0700308 return new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700309}
310
David Sodman8ef20062015-01-06 09:23:40 -0800311void term_activate(terminal_t* terminal)
312{
Dominik Behr4defb362016-01-13 12:36:14 -0800313 term_set_current_to(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800314 terminal->active = true;
Dominik Behr83010f82016-03-18 18:43:08 -0700315 fb_setmode(terminal->fb);
David Sodman8ef20062015-01-06 09:23:40 -0800316 term_redraw(terminal);
317}
318
David Sodmanf0a925a2015-05-04 11:19:19 -0700319void term_deactivate(terminal_t* terminal)
320{
321 if (!terminal->active)
322 return;
323
David Sodmanf0a925a2015-05-04 11:19:19 -0700324 terminal->active = false;
David Sodmanf0a925a2015-05-04 11:19:19 -0700325}
326
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800327void term_close(terminal_t* term)
David Sodmanbbcb0522014-09-19 10:34:07 -0700328{
329 if (!term)
330 return;
331
Dominik Behr83010f82016-03-18 18:43:08 -0700332 if (term->fb) {
333 fb_close(term->fb);
334 term->fb = NULL;
David Sodmanbf3f2842014-11-12 08:26:58 -0800335 }
336
David Sodmanbbcb0522014-09-19 10:34:07 -0700337 if (term->term) {
338 free(term->term);
339 term->term = NULL;
340 }
341
Haixia Shi95d680e2015-04-27 20:29:17 -0700342 font_free();
David Sodmanbbcb0522014-09-19 10:34:07 -0700343 free(term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700344}
David Sodmanbf3f2842014-11-12 08:26:58 -0800345
346bool term_is_child_done(terminal_t* terminal)
347{
348 int status;
349 int ret;
350 ret = waitpid(terminal->term->pid, &status, WNOHANG);
351
David Sodmanf0a925a2015-05-04 11:19:19 -0700352 if ((ret == -1) && (errno == ECHILD)) {
353 return false;
354 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800355 return ret != 0;
356}
357
358void term_page_up(terminal_t* terminal)
359{
360 tsm_screen_sb_page_up(terminal->term->screen, 1);
361 term_redraw(terminal);
362}
363
364void term_page_down(terminal_t* terminal)
365{
366 tsm_screen_sb_page_down(terminal->term->screen, 1);
367 term_redraw(terminal);
368}
369
370void term_line_up(terminal_t* terminal)
371{
372 tsm_screen_sb_up(terminal->term->screen, 1);
373 term_redraw(terminal);
374}
375
376void term_line_down(terminal_t* terminal)
377{
378 tsm_screen_sb_down(terminal->term->screen, 1);
379 term_redraw(terminal);
380}
381
382bool term_is_valid(terminal_t* terminal)
383{
384 return ((terminal != NULL) && (terminal->term != NULL));
385}
386
387int term_fd(terminal_t* terminal)
388{
389 if (term_is_valid(terminal))
390 return terminal->term->pty_bridge;
391 else
392 return -1;
393}
394
395void term_dispatch_io(terminal_t* terminal, fd_set* read_set)
396{
397 if (term_is_valid(terminal))
398 if (FD_ISSET(terminal->term->pty_bridge, read_set))
399 shl_pty_bridge_dispatch(terminal->term->pty_bridge, 0);
400}
401
402bool term_exception(terminal_t* terminal, fd_set* exception_set)
403{
404 if (term_is_valid(terminal)) {
405 if (terminal->term->pty_bridge >= 0) {
406 return FD_ISSET(terminal->term->pty_bridge,
407 exception_set);
408 }
409 }
410
411 return false;
412}
413
414bool term_is_active(terminal_t* terminal)
415{
416 if (term_is_valid(terminal))
417 return terminal->active;
418
419 return false;
420}
421
Dominik Behrb1abcba2016-04-14 14:57:21 -0700422void term_add_fds(terminal_t* terminal, fd_set* read_set, fd_set* exception_set, int* maxfd)
David Sodmanbf3f2842014-11-12 08:26:58 -0800423{
424 if (term_is_valid(terminal)) {
425 if (terminal->term->pty_bridge >= 0) {
Dominik Behrd7112672016-01-20 16:59:34 -0800426 *maxfd = MAX(*maxfd, terminal->term->pty_bridge);
David Sodmanbf3f2842014-11-12 08:26:58 -0800427 FD_SET(terminal->term->pty_bridge, read_set);
428 FD_SET(terminal->term->pty_bridge, exception_set);
429 }
430 }
431}
David Sodman8ef20062015-01-06 09:23:40 -0800432
433const char* term_get_ptsname(terminal_t* terminal)
434{
435 return ptsname(shl_pty_get_fd(terminal->term->pty));
436}
David Sodmanf0a925a2015-05-04 11:19:19 -0700437
438void term_set_background(terminal_t* terminal, uint32_t bg)
439{
440 terminal->background = bg;
441 terminal->background_valid = true;
442}
443
444int term_show_image(terminal_t* terminal, image_t* image)
445{
Dominik Behr83010f82016-03-18 18:43:08 -0700446 return image_show(image, terminal->fb);
David Sodmanf0a925a2015-05-04 11:19:19 -0700447}
448
449void term_write_message(terminal_t* terminal, char* message)
450{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800451 FILE* fp;
David Sodmanf0a925a2015-05-04 11:19:19 -0700452
453 fp = fopen(term_get_ptsname(terminal), "w");
454 if (fp) {
455 fputs(message, fp);
456 fclose(fp);
457 }
458}
459
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800460static void term_hide_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700461{
462 term_write_message(terminal, "\033[?25l");
463}
464
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800465__attribute__ ((unused))
466static void term_show_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700467{
468 term_write_message(terminal, "\033[?25h");
469}
David Sodman30a94ef2015-07-26 17:37:12 -0700470
Dominik Behr83010f82016-03-18 18:43:08 -0700471fb_t* term_getfb(terminal_t* terminal)
David Sodman30a94ef2015-07-26 17:37:12 -0700472{
Dominik Behr83010f82016-03-18 18:43:08 -0700473 return terminal->fb;
David Sodman30a94ef2015-07-26 17:37:12 -0700474}
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800475
476terminal_t* term_get_terminal(int num)
477{
478 return terminals[num];
479}
480
481void term_set_terminal(int num, terminal_t* terminal)
482{
483 terminals[num] = terminal;
484}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800485
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -0800486terminal_t* term_create_term(int vt)
487{
488 terminal_t* terminal;
489
490 terminal = term_get_terminal(vt - 1);
491 if (term_is_active(terminal))
492 return terminal;
493
494 if (terminal == NULL) {
Dominik Behr83010f82016-03-18 18:43:08 -0700495 term_set_terminal(vt - 1, term_init(false));
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -0800496 terminal = term_get_terminal(vt - 1);
497 if (!term_is_valid(terminal)) {
498 LOG(ERROR, "create_term: Term init failed");
499 }
500 }
501
502 return terminal;
503}
504
Dominik Behr83010f82016-03-18 18:43:08 -0700505terminal_t* term_create_splash_term()
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800506{
Dominik Behr83010f82016-03-18 18:43:08 -0700507 terminal_t* splash_terminal = term_init(false);
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800508 term_set_terminal(SPLASH_TERMINAL, splash_terminal);
509
510 // Hide the cursor on the splash screen
511 term_hide_cursor(splash_terminal);
512
513 return splash_terminal;
514}
515
516void term_destroy_splash_term()
517{
518 term_set_terminal(SPLASH_TERMINAL, NULL);
519}
520
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800521unsigned int term_get_max_terminals()
522{
523 return MAX_STD_TERMINALS;
524}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800525
Dominik Behr4defb362016-01-13 12:36:14 -0800526void term_set_current(uint32_t t)
527{
528 if (t >= MAX_TERMINALS)
529 LOG(ERROR, "set_current: larger than max");
530 else
531 current_terminal = t;
532}
533
534uint32_t term_get_current(void)
535{
536 return current_terminal;
537}
538
539terminal_t *term_get_current_terminal(void)
540{
541 return terminals[current_terminal];
542}
543
Dominik Behrb1abcba2016-04-14 14:57:21 -0700544void term_set_current_terminal(terminal_t* terminal)
Dominik Behr4defb362016-01-13 12:36:14 -0800545{
546 terminals[current_terminal] = terminal;
547}
548
549void term_set_current_to(terminal_t* terminal)
550{
551 if (!terminal) {
552 terminals[current_terminal] = NULL;
553 current_terminal = 0;
554 return;
555 }
556
557 for (int i = 0; i < MAX_TERMINALS; i++) {
558 if (terminal == terminals[i]) {
559 current_terminal = i;
560 return;
561 }
562 }
563 LOG(ERROR, "set_current_to: terminal not in array");
564}
Dominik Behr01a7a582016-01-28 17:02:21 -0800565
566void term_monitor_hotplug(void)
567{
568 unsigned int t;
569
Dominik Behr83010f82016-03-18 18:43:08 -0700570 if (!drm_rescan())
571 return;
572
Dominik Behr01a7a582016-01-28 17:02:21 -0800573 for (t = 0; t < MAX_TERMINALS; t++) {
Dominik Behr01a7a582016-01-28 17:02:21 -0800574 if (!terminals[t])
575 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700576 if (!terminals[t]->fb)
Dominik Behr01a7a582016-01-28 17:02:21 -0800577 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700578 fb_buffer_destroy(terminals[t]->fb);
579 }
580
581 for (t = 0; t < MAX_TERMINALS; t++) {
582 if (!terminals[t])
583 continue;
584 if (!terminals[t]->fb)
585 continue;
586 fb_buffer_init(terminals[t]->fb);
587 term_resize(terminals[t]);
588 if (current_terminal == t && terminals[t]->active)
589 fb_setmode(terminals[t]->fb);
590 terminals[t]->term->age = 0;
591 term_redraw(terminals[t]);
Dominik Behr01a7a582016-01-28 17:02:21 -0800592 }
593}
Dominik Behrb1abcba2016-04-14 14:57:21 -0700594
595void term_redrm(terminal_t* terminal)
596{
597 fb_buffer_destroy(terminal->fb);
598 fb_buffer_init(terminal->fb);
599 term_resize(terminal);
600 terminal->term->age = 0;
601 term_redraw(terminal);
602}
603
604void term_clear(terminal_t* terminal)
605{
606 tsm_screen_erase_screen(terminal->term->screen, false);
607 term_redraw(terminal);
608}