blob: 6f51f526423798a338f93e105351ef9376ba824b [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 Behr83864df2016-04-21 12:35:08 -070014#include "dbus.h"
Dominik Behr83010f82016-03-18 18:43:08 -070015#include "fb.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070016#include "font.h"
17#include "input.h"
Dominik Behr83864df2016-04-21 12:35:08 -070018#include "main.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070019#include "shl_pty.h"
20#include "term.h"
21#include "util.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070022
Stéphane Marchesin08c08e72016-01-07 16:44:08 -080023static terminal_t* terminals[MAX_TERMINALS];
Dominik Behr4defb362016-01-13 12:36:14 -080024static uint32_t current_terminal = 0;
Stéphane Marchesin08c08e72016-01-07 16:44:08 -080025
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070026struct term {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080027 struct tsm_screen* screen;
28 struct tsm_vte* vte;
29 struct shl_pty* pty;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070030 int pty_bridge;
31 int pid;
32 tsm_age_t age;
33 int char_x, char_y;
34 int pitch;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080035 uint32_t* dst_image;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070036};
37
David Sodmanf0a925a2015-05-04 11:19:19 -070038struct _terminal_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080039 uint32_t background;
40 bool background_valid;
Dominik Behr83010f82016-03-18 18:43:08 -070041 fb_t* fb;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080042 struct term* term;
43 bool active;
44 char** exec;
David Sodmanf0a925a2015-05-04 11:19:19 -070045};
46
David Sodman8ef20062015-01-06 09:23:40 -080047
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080048static char* interactive_cmd_line[] = {
David Sodman8ef20062015-01-06 09:23:40 -080049 "/sbin/agetty",
50 "-",
51 "9600",
52 "xterm",
53 NULL
54};
55
56
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080057static char* noninteractive_cmd_line[] = {
David Sodman8ef20062015-01-06 09:23:40 -080058 "/bin/cat",
59 NULL
60};
61
Dominik Behr83864df2016-04-21 12:35:08 -070062static bool in_background = false;
63static bool hotplug_occured = false;
64
David Sodman8ef20062015-01-06 09:23:40 -080065
66static void __attribute__ ((noreturn)) term_run_child(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070067{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070068 /* XXX figure out how to fix "top" for xterm-256color */
69 setenv("TERM", "xterm", 1);
David Sodman8ef20062015-01-06 09:23:40 -080070 execve(terminal->exec[0], terminal->exec, environ);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070071 exit(1);
72}
73
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080074static int term_draw_cell(struct tsm_screen* screen, uint32_t id,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080075 const uint32_t* ch, size_t len,
76 unsigned int cwidth, unsigned int posx,
77 unsigned int posy,
78 const struct tsm_screen_attr* attr,
79 tsm_age_t age, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070080{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080081 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070082 uint32_t front_color, back_color;
David Sodmanf0a925a2015-05-04 11:19:19 -070083 uint8_t br, bb, bg;
Stéphane Marchesinedece332015-12-14 15:10:58 -080084 uint32_t luminance;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070085
David Sodmanbbcb0522014-09-19 10:34:07 -070086 if (age && terminal->term->age && age <= terminal->term->age)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070087 return 0;
88
David Sodmanf0a925a2015-05-04 11:19:19 -070089 if (terminal->background_valid) {
90 br = (terminal->background >> 16) & 0xFF;
91 bg = (terminal->background >> 8) & 0xFF;
92 bb = (terminal->background) & 0xFF;
Stéphane Marchesinedece332015-12-14 15:10:58 -080093 luminance = (3 * br + bb + 4 * bg) >> 3;
David Sodmanf0a925a2015-05-04 11:19:19 -070094
Stéphane Marchesinedece332015-12-14 15:10:58 -080095 /*
96 * FIXME: black is chosen on a dark background, but it uses the
97 * default color for light backgrounds
98 */
99 if (luminance > 128) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700100 front_color = 0;
101 back_color = terminal->background;
102 } else {
103 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
104 back_color = terminal->background;
105 }
106 } else {
107 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
108 back_color = (attr->br << 16) | (attr->bg << 8) | attr->bb;
109 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700110
111 if (attr->inverse) {
112 uint32_t tmp = front_color;
113 front_color = back_color;
114 back_color = tmp;
115 }
116
117 if (len)
David Sodmanbbcb0522014-09-19 10:34:07 -0700118 font_render(terminal->term->dst_image, posx, posy, terminal->term->pitch, *ch,
119 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700120 else
David Sodmanbbcb0522014-09-19 10:34:07 -0700121 font_fillchar(terminal->term->dst_image, posx, posy, terminal->term->pitch,
122 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700123
124 return 0;
125}
126
Stéphane Marchesine2a46cd2016-01-07 16:45:24 -0800127static void term_redraw(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700128{
Dominik Behr83010f82016-03-18 18:43:08 -0700129 uint32_t* fb_buffer;
130 fb_buffer = fb_lock(terminal->fb);
131 if (fb_buffer != NULL) {
132 terminal->term->dst_image = fb_buffer;
David Sodmanbbcb0522014-09-19 10:34:07 -0700133 terminal->term->age =
134 tsm_screen_draw(terminal->term->screen, term_draw_cell, terminal);
Dominik Behr83010f82016-03-18 18:43:08 -0700135 fb_unlock(terminal->fb);
David Sodmanbbcb0522014-09-19 10:34:07 -0700136 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700137}
138
David Sodmanbbcb0522014-09-19 10:34:07 -0700139void term_key_event(terminal_t* terminal, uint32_t keysym, int32_t unicode)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700140{
David Sodmanbbcb0522014-09-19 10:34:07 -0700141 if (tsm_vte_handle_keyboard(terminal->term->vte, keysym, 0, 0, unicode))
142 tsm_screen_sb_reset(terminal->term->screen);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700143
David Sodmanbbcb0522014-09-19 10:34:07 -0700144 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700145}
146
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800147static void term_read_cb(struct shl_pty* pty, char* u8, size_t len, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700148{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800149 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700150
David Sodmanbbcb0522014-09-19 10:34:07 -0700151 tsm_vte_input(terminal->term->vte, u8, len);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700152
David Sodmanbbcb0522014-09-19 10:34:07 -0700153 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700154}
155
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800156static void term_write_cb(struct tsm_vte* vte, const char* u8, size_t len,
157 void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700158{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800159 struct term* term = data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700160 int r;
161
162 r = shl_pty_write(term->pty, u8, len);
163 if (r < 0)
David Sodmanbbcb0522014-09-19 10:34:07 -0700164 LOG(ERROR, "OOM in pty-write (%d)", r);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700165
166 shl_pty_dispatch(term->pty);
167}
168
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800169static const char* sev2str_table[] = {
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700170 "FATAL",
171 "ALERT",
172 "CRITICAL",
173 "ERROR",
174 "WARNING",
175 "NOTICE",
176 "INFO",
177 "DEBUG"
178};
179
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800180static const char* sev2str(unsigned int sev)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700181{
182 if (sev > 7)
183 return "DEBUG";
184
185 return sev2str_table[sev];
186}
187
Dominik Behr00003502014-08-15 16:42:37 -0700188#ifdef __clang__
189__attribute__((__format__ (__printf__, 7, 0)))
190#endif
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800191static void log_tsm(void* data, const char* file, int line, const char* fn,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800192 const char* subs, unsigned int sev, const char* format,
193 va_list args)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700194{
195 fprintf(stderr, "%s: %s: ", sev2str(sev), subs);
196 vfprintf(stderr, format, args);
197 fprintf(stderr, "\n");
198}
199
Stéphane Marchesin78310662016-01-06 16:09:39 -0800200static int term_resize(terminal_t* term)
201{
202 uint32_t char_width, char_height;
203 int status;
204
Dominik Behr83010f82016-03-18 18:43:08 -0700205 font_init(fb_getscaling(term->fb));
Stéphane Marchesin78310662016-01-06 16:09:39 -0800206 font_get_size(&char_width, &char_height);
207
Dominik Behr83010f82016-03-18 18:43:08 -0700208 term->term->char_x = fb_getwidth(term->fb) / char_width;
209 term->term->char_y = fb_getheight(term->fb) / char_height;
210 term->term->pitch = fb_getpitch(term->fb);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800211
212 status = tsm_screen_resize(term->term->screen,
213 term->term->char_x, term->term->char_y);
214 if (status < 0) {
215 font_free();
216 return -1;
217 }
218
219 status = shl_pty_resize(term->term->pty, term->term->char_x,
220 term->term->char_y);
221 if (status < 0) {
222 font_free();
223 return -1;
224 }
225
226 return 0;
227}
228
Dominik Behr83010f82016-03-18 18:43:08 -0700229terminal_t* term_init(bool interactive)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700230{
231 const int scrollback_size = 200;
David Sodmanbbcb0522014-09-19 10:34:07 -0700232 int status;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800233 terminal_t* new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700234
David Sodmanbbcb0522014-09-19 10:34:07 -0700235 new_terminal = (terminal_t*)calloc(1, sizeof(*new_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800236 if (!new_terminal)
237 return NULL;
David Sodmanbbcb0522014-09-19 10:34:07 -0700238
David Sodmanf0a925a2015-05-04 11:19:19 -0700239 new_terminal->background_valid = false;
240
Dominik Behr83010f82016-03-18 18:43:08 -0700241 new_terminal->fb = fb_init();
David Sodmanf0a925a2015-05-04 11:19:19 -0700242
Dominik Behr83010f82016-03-18 18:43:08 -0700243 if (!new_terminal->fb) {
David Sodmanbf3f2842014-11-12 08:26:58 -0800244 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);
Dominik Behr83010f82016-03-18 18:43:08 -0700303
David Sodmanbbcb0522014-09-19 10:34:07 -0700304 if (status < 0) {
305 shl_pty_close(new_terminal->term->pty);
306 term_close(new_terminal);
307 return NULL;
308 }
David Sodman8ef20062015-01-06 09:23:40 -0800309
310 if (interactive)
311 new_terminal->active = true;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700312
David Sodmanbbcb0522014-09-19 10:34:07 -0700313 return new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700314}
315
David Sodman8ef20062015-01-06 09:23:40 -0800316void term_activate(terminal_t* terminal)
317{
Dominik Behr4defb362016-01-13 12:36:14 -0800318 term_set_current_to(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800319 terminal->active = true;
Dominik Behr83010f82016-03-18 18:43:08 -0700320 fb_setmode(terminal->fb);
David Sodman8ef20062015-01-06 09:23:40 -0800321 term_redraw(terminal);
322}
323
David Sodmanf0a925a2015-05-04 11:19:19 -0700324void term_deactivate(terminal_t* terminal)
325{
326 if (!terminal->active)
327 return;
328
David Sodmanf0a925a2015-05-04 11:19:19 -0700329 terminal->active = false;
David Sodmanf0a925a2015-05-04 11:19:19 -0700330}
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
Dominik Behr83010f82016-03-18 18:43:08 -0700337 if (term->fb) {
338 fb_close(term->fb);
339 term->fb = NULL;
David Sodmanbf3f2842014-11-12 08:26:58 -0800340 }
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
Dominik Behrb1abcba2016-04-14 14:57:21 -0700427void term_add_fds(terminal_t* terminal, fd_set* read_set, fd_set* exception_set, int* maxfd)
David Sodmanbf3f2842014-11-12 08:26:58 -0800428{
429 if (term_is_valid(terminal)) {
430 if (terminal->term->pty_bridge >= 0) {
Dominik Behrd7112672016-01-20 16:59:34 -0800431 *maxfd = MAX(*maxfd, terminal->term->pty_bridge);
David Sodmanbf3f2842014-11-12 08:26:58 -0800432 FD_SET(terminal->term->pty_bridge, read_set);
433 FD_SET(terminal->term->pty_bridge, exception_set);
434 }
435 }
436}
David Sodman8ef20062015-01-06 09:23:40 -0800437
438const char* term_get_ptsname(terminal_t* terminal)
439{
440 return ptsname(shl_pty_get_fd(terminal->term->pty));
441}
David Sodmanf0a925a2015-05-04 11:19:19 -0700442
443void term_set_background(terminal_t* terminal, uint32_t bg)
444{
445 terminal->background = bg;
446 terminal->background_valid = true;
447}
448
449int term_show_image(terminal_t* terminal, image_t* image)
450{
Dominik Behr83010f82016-03-18 18:43:08 -0700451 return image_show(image, terminal->fb);
David Sodmanf0a925a2015-05-04 11:19:19 -0700452}
453
454void term_write_message(terminal_t* terminal, char* message)
455{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800456 FILE* fp;
David Sodmanf0a925a2015-05-04 11:19:19 -0700457
458 fp = fopen(term_get_ptsname(terminal), "w");
459 if (fp) {
460 fputs(message, fp);
461 fclose(fp);
462 }
463}
464
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800465static void term_hide_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700466{
467 term_write_message(terminal, "\033[?25l");
468}
469
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800470__attribute__ ((unused))
471static void term_show_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700472{
473 term_write_message(terminal, "\033[?25h");
474}
David Sodman30a94ef2015-07-26 17:37:12 -0700475
Dominik Behr83010f82016-03-18 18:43:08 -0700476fb_t* term_getfb(terminal_t* terminal)
David Sodman30a94ef2015-07-26 17:37:12 -0700477{
Dominik Behr83010f82016-03-18 18:43:08 -0700478 return terminal->fb;
David Sodman30a94ef2015-07-26 17:37:12 -0700479}
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800480
481terminal_t* term_get_terminal(int num)
482{
483 return terminals[num];
484}
485
486void term_set_terminal(int num, terminal_t* terminal)
487{
488 terminals[num] = terminal;
489}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800490
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -0800491terminal_t* term_create_term(int vt)
492{
493 terminal_t* terminal;
494
495 terminal = term_get_terminal(vt - 1);
496 if (term_is_active(terminal))
497 return terminal;
498
499 if (terminal == NULL) {
Dominik Behr83010f82016-03-18 18:43:08 -0700500 term_set_terminal(vt - 1, term_init(false));
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -0800501 terminal = term_get_terminal(vt - 1);
502 if (!term_is_valid(terminal)) {
503 LOG(ERROR, "create_term: Term init failed");
504 }
505 }
506
507 return terminal;
508}
509
Dominik Behr83010f82016-03-18 18:43:08 -0700510terminal_t* term_create_splash_term()
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800511{
Dominik Behr83010f82016-03-18 18:43:08 -0700512 terminal_t* splash_terminal = term_init(false);
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800513 term_set_terminal(SPLASH_TERMINAL, splash_terminal);
514
515 // Hide the cursor on the splash screen
516 term_hide_cursor(splash_terminal);
517
518 return splash_terminal;
519}
520
521void term_destroy_splash_term()
522{
523 term_set_terminal(SPLASH_TERMINAL, NULL);
524}
525
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800526unsigned int term_get_max_terminals()
527{
528 return MAX_STD_TERMINALS;
529}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800530
Dominik Behr4defb362016-01-13 12:36:14 -0800531void term_set_current(uint32_t t)
532{
533 if (t >= MAX_TERMINALS)
534 LOG(ERROR, "set_current: larger than max");
535 else
536 current_terminal = t;
537}
538
539uint32_t term_get_current(void)
540{
541 return current_terminal;
542}
543
544terminal_t *term_get_current_terminal(void)
545{
546 return terminals[current_terminal];
547}
548
Dominik Behrb1abcba2016-04-14 14:57:21 -0700549void term_set_current_terminal(terminal_t* terminal)
Dominik Behr4defb362016-01-13 12:36:14 -0800550{
551 terminals[current_terminal] = terminal;
552}
553
554void term_set_current_to(terminal_t* terminal)
555{
556 if (!terminal) {
557 terminals[current_terminal] = NULL;
558 current_terminal = 0;
559 return;
560 }
561
562 for (int i = 0; i < MAX_TERMINALS; i++) {
563 if (terminal == terminals[i]) {
564 current_terminal = i;
565 return;
566 }
567 }
568 LOG(ERROR, "set_current_to: terminal not in array");
569}
Dominik Behr01a7a582016-01-28 17:02:21 -0800570
571void term_monitor_hotplug(void)
572{
573 unsigned int t;
574
Dominik Behr83864df2016-04-21 12:35:08 -0700575 if (in_background) {
576 hotplug_occured = true;
577 return;
578 }
579
Dominik Behr83010f82016-03-18 18:43:08 -0700580 if (!drm_rescan())
581 return;
582
Dominik Behr01a7a582016-01-28 17:02:21 -0800583 for (t = 0; t < MAX_TERMINALS; t++) {
Dominik Behr01a7a582016-01-28 17:02:21 -0800584 if (!terminals[t])
585 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700586 if (!terminals[t]->fb)
Dominik Behr01a7a582016-01-28 17:02:21 -0800587 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700588 fb_buffer_destroy(terminals[t]->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700589 font_free();
Dominik Behr83010f82016-03-18 18:43:08 -0700590 }
591
592 for (t = 0; t < MAX_TERMINALS; t++) {
593 if (!terminals[t])
594 continue;
595 if (!terminals[t]->fb)
596 continue;
597 fb_buffer_init(terminals[t]->fb);
598 term_resize(terminals[t]);
599 if (current_terminal == t && terminals[t]->active)
600 fb_setmode(terminals[t]->fb);
601 terminals[t]->term->age = 0;
602 term_redraw(terminals[t]);
Dominik Behr01a7a582016-01-28 17:02:21 -0800603 }
604}
Dominik Behrb1abcba2016-04-14 14:57:21 -0700605
606void term_redrm(terminal_t* terminal)
607{
608 fb_buffer_destroy(terminal->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700609 font_free();
Dominik Behrb1abcba2016-04-14 14:57:21 -0700610 fb_buffer_init(terminal->fb);
611 term_resize(terminal);
612 terminal->term->age = 0;
613 term_redraw(terminal);
614}
615
616void term_clear(terminal_t* terminal)
617{
618 tsm_screen_erase_screen(terminal->term->screen, false);
619 term_redraw(terminal);
620}
Dominik Behr83864df2016-04-21 12:35:08 -0700621
622void term_background(void)
623{
624 if (in_background)
625 return;
626 in_background = true;
627 dbus_take_display_ownership();
628}
629
630void term_foreground(void)
631{
632 if (!in_background)
633 return;
634 in_background = false;
635 if (!dbus_release_display_ownership()) {
636 LOG(ERROR, "Chrome did not release master. Frecon will try to steal it.");
637 set_drm_master_relax();
638 }
639 if (hotplug_occured) {
640 hotplug_occured = false;
641 term_monitor_hotplug();
642 }
643}