blob: a237fcbfa6bc02aed493c9157abe7bf1f95c8235 [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>
Dominik Behrda6df412016-08-02 12:56:42 -07008#include <fcntl.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07009#include <libtsm.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070010#include <stdio.h>
Dominik Behrda6df412016-08-02 12:56:42 -070011#include <stdlib.h>
Dominik Behr93899452014-08-18 22:16:21 -070012#include <sys/select.h>
Dominik Behrda6df412016-08-02 12:56:42 -070013#include <sys/stat.h>
David Sodmanbf3f2842014-11-12 08:26:58 -080014#include <sys/types.h>
15#include <sys/wait.h>
Dominik Behr32680e32016-08-16 12:18:41 -070016#include <unistd.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070017
Dominik Behr83864df2016-04-21 12:35:08 -070018#include "dbus.h"
Dominik Behr83010f82016-03-18 18:43:08 -070019#include "fb.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070020#include "font.h"
Dominik Behrd2530902016-05-05 14:01:06 -070021#include "image.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070022#include "input.h"
Dominik Behr83864df2016-04-21 12:35:08 -070023#include "main.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070024#include "shl_pty.h"
25#include "term.h"
26#include "util.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070027
Dominik Behrda6df412016-08-02 12:56:42 -070028unsigned int term_num_terminals = 4;
29static terminal_t* terminals[TERM_MAX_TERMINALS];
Dominik Behr4defb362016-01-13 12:36:14 -080030static uint32_t current_terminal = 0;
Stéphane Marchesin08c08e72016-01-07 16:44:08 -080031
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070032struct term {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080033 struct tsm_screen* screen;
34 struct tsm_vte* vte;
35 struct shl_pty* pty;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070036 int pty_bridge;
37 int pid;
38 tsm_age_t age;
39 int char_x, char_y;
40 int pitch;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080041 uint32_t* dst_image;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070042};
43
David Sodmanf0a925a2015-05-04 11:19:19 -070044struct _terminal_t {
Dominik Behrda6df412016-08-02 12:56:42 -070045 unsigned vt;
46 bool active;
Dominik Behrda55e6c2017-02-28 18:12:10 -080047 bool input_enable;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080048 uint32_t background;
49 bool background_valid;
Dominik Behr83010f82016-03-18 18:43:08 -070050 fb_t* fb;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080051 struct term* term;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080052 char** exec;
David Sodmanf0a925a2015-05-04 11:19:19 -070053};
54
David Sodman8ef20062015-01-06 09:23:40 -080055
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080056static char* interactive_cmd_line[] = {
David Sodman8ef20062015-01-06 09:23:40 -080057 "/sbin/agetty",
58 "-",
59 "9600",
60 "xterm",
61 NULL
62};
63
Dominik Behr83864df2016-04-21 12:35:08 -070064static bool in_background = false;
65static bool hotplug_occured = false;
66
David Sodman8ef20062015-01-06 09:23:40 -080067
68static void __attribute__ ((noreturn)) term_run_child(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070069{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070070 /* XXX figure out how to fix "top" for xterm-256color */
71 setenv("TERM", "xterm", 1);
Dominik Behr32680e32016-08-16 12:18:41 -070072 if (terminal->exec) {
73 execve(terminal->exec[0], terminal->exec, environ);
74 exit(1);
75 } else {
76 while (1)
77 sleep(1000000);
78 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070079}
80
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080081static int term_draw_cell(struct tsm_screen* screen, uint32_t id,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080082 const uint32_t* ch, size_t len,
83 unsigned int cwidth, unsigned int posx,
84 unsigned int posy,
85 const struct tsm_screen_attr* attr,
86 tsm_age_t age, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070087{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080088 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070089 uint32_t front_color, back_color;
David Sodmanf0a925a2015-05-04 11:19:19 -070090 uint8_t br, bb, bg;
Stéphane Marchesinedece332015-12-14 15:10:58 -080091 uint32_t luminance;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070092
David Sodmanbbcb0522014-09-19 10:34:07 -070093 if (age && terminal->term->age && age <= terminal->term->age)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070094 return 0;
95
David Sodmanf0a925a2015-05-04 11:19:19 -070096 if (terminal->background_valid) {
97 br = (terminal->background >> 16) & 0xFF;
98 bg = (terminal->background >> 8) & 0xFF;
99 bb = (terminal->background) & 0xFF;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800100 luminance = (3 * br + bb + 4 * bg) >> 3;
David Sodmanf0a925a2015-05-04 11:19:19 -0700101
Stéphane Marchesinedece332015-12-14 15:10:58 -0800102 /*
103 * FIXME: black is chosen on a dark background, but it uses the
104 * default color for light backgrounds
105 */
106 if (luminance > 128) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700107 front_color = 0;
108 back_color = terminal->background;
109 } else {
110 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
111 back_color = terminal->background;
112 }
113 } else {
114 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
115 back_color = (attr->br << 16) | (attr->bg << 8) | attr->bb;
116 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700117
118 if (attr->inverse) {
119 uint32_t tmp = front_color;
120 front_color = back_color;
121 back_color = tmp;
122 }
123
124 if (len)
David Sodmanbbcb0522014-09-19 10:34:07 -0700125 font_render(terminal->term->dst_image, posx, posy, terminal->term->pitch, *ch,
126 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700127 else
David Sodmanbbcb0522014-09-19 10:34:07 -0700128 font_fillchar(terminal->term->dst_image, posx, posy, terminal->term->pitch,
129 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700130
131 return 0;
132}
133
Stéphane Marchesine2a46cd2016-01-07 16:45:24 -0800134static void term_redraw(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700135{
Dominik Behr83010f82016-03-18 18:43:08 -0700136 uint32_t* fb_buffer;
137 fb_buffer = fb_lock(terminal->fb);
138 if (fb_buffer != NULL) {
139 terminal->term->dst_image = fb_buffer;
David Sodmanbbcb0522014-09-19 10:34:07 -0700140 terminal->term->age =
141 tsm_screen_draw(terminal->term->screen, term_draw_cell, terminal);
Dominik Behr83010f82016-03-18 18:43:08 -0700142 fb_unlock(terminal->fb);
David Sodmanbbcb0522014-09-19 10:34:07 -0700143 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700144}
145
David Sodmanbbcb0522014-09-19 10:34:07 -0700146void term_key_event(terminal_t* terminal, uint32_t keysym, int32_t unicode)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700147{
Dominik Behrda55e6c2017-02-28 18:12:10 -0800148 if (!terminal->input_enable)
149 return;
150
David Sodmanbbcb0522014-09-19 10:34:07 -0700151 if (tsm_vte_handle_keyboard(terminal->term->vte, keysym, 0, 0, unicode))
152 tsm_screen_sb_reset(terminal->term->screen);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700153
David Sodmanbbcb0522014-09-19 10:34:07 -0700154 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700155}
156
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800157static void term_read_cb(struct shl_pty* pty, char* u8, size_t len, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700158{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800159 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700160
David Sodmanbbcb0522014-09-19 10:34:07 -0700161 tsm_vte_input(terminal->term->vte, u8, len);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700162
David Sodmanbbcb0522014-09-19 10:34:07 -0700163 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700164}
165
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800166static void term_write_cb(struct tsm_vte* vte, const char* u8, size_t len,
167 void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700168{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800169 struct term* term = data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700170 int r;
171
172 r = shl_pty_write(term->pty, u8, len);
173 if (r < 0)
David Sodmanbbcb0522014-09-19 10:34:07 -0700174 LOG(ERROR, "OOM in pty-write (%d)", r);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700175
176 shl_pty_dispatch(term->pty);
177}
178
Dominik Behrd2530902016-05-05 14:01:06 -0700179static void term_esc_show_image(terminal_t* terminal, char* params)
180{
181 char* tok;
182 image_t* image;
183 int status;
184
185 image = image_create();
186 if (!image) {
187 LOG(ERROR, "Out of memory when creating an image.\n");
188 return;
189 }
190 for (tok = strtok(params, ";"); tok; tok = strtok(NULL, ";")) {
191 if (strncmp("file=", tok, 5) == 0) {
192 image_set_filename(image, tok + 5);
193 } else if (strncmp("location=", tok, 9) == 0) {
194 uint32_t x, y;
195 if (sscanf(tok + 9, "%u,%u", &x, &y) != 2) {
196 LOG(ERROR, "Error parsing image location.\n");
197 goto done;
198 }
199 image_set_location(image, x, y);
200 } else if (strncmp("offset=", tok, 7) == 0) {
201 int32_t x, y;
202 if (sscanf(tok + 7, "%d,%d", &x, &y) != 2) {
203 LOG(ERROR, "Error parsing image offset.\n");
204 goto done;
205 }
206 image_set_offset(image, x, y);
207 } else if (strncmp("scale=", tok, 6) == 0) {
208 uint32_t s;
209 if (sscanf(tok + 6, "%u", &s) != 1) {
210 LOG(ERROR, "Error parsing image scale.\n");
211 goto done;
212 }
213 if (s == 0)
214 s = image_get_auto_scale(term_getfb(terminal));
215 image_set_scale(image, s);
216 }
217 }
218
219 status = image_load_image_from_file(image);
220 if (status != 0) {
221 LOG(WARNING, "Term ESC image_load_image_from_file %s failed: %d:%s.",
222 image_get_filename(image), status, strerror(status));
223 } else {
224 term_show_image(terminal, image);
225 }
226done:
227 image_destroy(image);
228}
229
230static void term_esc_draw_box(terminal_t* terminal, char* params)
231{
232 char* tok;
233 uint32_t color = 0;
234 uint32_t w = 1;
235 uint32_t h = 1;
236 uint32_t locx, locy;
237 bool use_location = false;
238 int32_t offx, offy;
239 bool use_offset = false;
240 uint32_t scale = 1;
241 uint32_t* buffer;
242 int32_t startx, starty;
243 uint32_t pitch4;
244
245 for (tok = strtok(params, ";"); tok; tok = strtok(NULL, ";")) {
246 if (strncmp("color=", tok, 6) == 0) {
247 color = strtoul(tok + 6, NULL, 0);
248 } else if (strncmp("size=", tok, 5) == 0) {
249 if (sscanf(tok + 5, "%u,%u", &w, &h) != 2) {
250 LOG(ERROR, "Error parsing box size.\n");
251 goto done;
252 }
253 } else if (strncmp("location=", tok, 9) == 0) {
254 if (sscanf(tok + 9, "%u,%u", &locx, &locy) != 2) {
255 LOG(ERROR, "Error parsing box location.\n");
256 goto done;
257 }
258 use_location = true;
259 } else if (strncmp("offset=", tok, 7) == 0) {
260 if (sscanf(tok + 7, "%d,%d", &offx, &offy) != 2) {
261 LOG(ERROR, "Error parsing box offset.\n");
262 goto done;
263 }
264 use_offset = true;
265 } else if (strncmp("scale=", tok, 6) == 0) {
266 if (sscanf(tok + 6, "%u", &scale) != 1) {
267 LOG(ERROR, "Error parsing box scale.\n");
268 goto done;
269 }
270 if (scale == 0)
271 scale = image_get_auto_scale(term_getfb(terminal));
272 }
273 }
274
275 w *= scale;
276 h *= scale;
277 offx *= scale;
278 offy *= scale;
279
280 buffer = fb_lock(terminal->fb);
281 if (buffer == NULL)
282 goto done;
283
284 if (use_offset && use_location) {
285 LOG(WARNING, "Box offset and location set, using location.");
286 use_offset = false;
287 }
288
289 if (use_location) {
290 startx = locx;
291 starty = locy;
292 } else {
Mattias Nissler066044c2017-07-04 15:23:02 +0200293 startx = (fb_getwidth(terminal->fb) - w)/2;
294 starty = (fb_getheight(terminal->fb) - h)/2;
Dominik Behrd2530902016-05-05 14:01:06 -0700295 }
296
297 if (use_offset) {
298 startx += offx;
299 starty += offy;
300 }
301
302 pitch4 = fb_getpitch(terminal->fb) / 4;
303
304 /* Completely outside buffer, do nothing */
305 if (startx + w <= 0 || startx >= fb_getwidth(terminal->fb))
306 goto done_fb;
307 if (starty + h <= 0 || starty >= fb_getheight(terminal->fb))
308 goto done_fb;
309 /* Make sure we are inside buffer. */
310 if (startx < 0)
311 startx = 0;
Mattias Nissler066044c2017-07-04 15:23:02 +0200312 if (w > (uint32_t)(fb_getwidth(terminal->fb) - startx))
Dominik Behrd2530902016-05-05 14:01:06 -0700313 w = fb_getwidth(terminal->fb) - startx;
314 if (starty < 0)
315 starty = 0;
Mattias Nissler066044c2017-07-04 15:23:02 +0200316 if (h > (uint32_t)(fb_getheight(terminal->fb) - starty))
Dominik Behrd2530902016-05-05 14:01:06 -0700317 h = fb_getheight(terminal->fb) - starty;
318
319 for (uint32_t y = 0; y < h; y++) {
320 uint32_t *o = buffer + (starty + y) * pitch4
321 + startx;
322 for (uint32_t x = 0; x < w; x++)
323 o[x] = color;
324 }
325done_fb:
326 fb_unlock(terminal->fb);
327done:
328 ;
329}
330
Dominik Behrda55e6c2017-02-28 18:12:10 -0800331static void term_esc_input(terminal_t* terminal, char* params)
332{
333 if (strcmp(params, "1") == 0 ||
334 strcasecmp(params, "on") == 0 ||
335 strcasecmp(params, "true") == 0)
336 term_input_enable(terminal, true);
337 else if (strcmp(params, "0") == 0 ||
338 strcasecmp(params, "off") == 0 ||
339 strcasecmp(params, "false") == 0)
340 term_input_enable(terminal, false);
341 else
342 LOG(ERROR, "Invalid parameter for input escape.\n");
343}
344
Dominik Behr3a2c61c2017-06-22 15:13:48 -0700345/*
346 * Assume all one or two digit sequences followed by ; are xterm OSC escapes.
347 */
348static bool is_xterm_osc(char *osc)
349{
350 if (isdigit(osc[0])) {
351 if (osc[1] == ';')
352 return true;
353 if (isdigit(osc[1]) && osc[2] == ';')
354 return true;
355 }
356 return false;
357}
358
Dominik Behrd2530902016-05-05 14:01:06 -0700359static void term_osc_cb(struct tsm_vte *vte, const uint32_t *osc_string,
360 size_t osc_len, void *data)
361{
362 terminal_t* terminal = (terminal_t*)data;
363 size_t i;
364 char *osc;
365
366 for (i = 0; i < osc_len; i++)
367 if (osc_string[i] >= 128)
368 return; /* we only want to deal with ASCII */
369
370 osc = malloc(osc_len + 1);
371 if (!osc) {
Dominik Behr3a2c61c2017-06-22 15:13:48 -0700372 LOG(WARNING, "Out of memory when processing OSC.\n");
Dominik Behrd2530902016-05-05 14:01:06 -0700373 return;
374 }
375
376 for (i = 0; i < osc_len; i++)
377 osc[i] = (char)osc_string[i];
378 osc[i] = '\0';
379
380 if (strncmp(osc, "image:", 6) == 0)
381 term_esc_show_image(terminal, osc + 6);
382 else if (strncmp(osc, "box:", 4) == 0)
383 term_esc_draw_box(terminal, osc + 4);
Dominik Behrda55e6c2017-02-28 18:12:10 -0800384 else if (strncmp(osc, "input:", 6) == 0)
385 term_esc_input(terminal, osc + 6);
Dominik Behr3a2c61c2017-06-22 15:13:48 -0700386 else if (is_xterm_osc(osc))
387 ; /* Ignore it. */
Dominik Behrd2530902016-05-05 14:01:06 -0700388 else
389 LOG(WARNING, "Unknown OSC escape sequence \"%s\", ignoring.", osc);
390
391 free(osc);
392}
393
Dominik Behr00003502014-08-15 16:42:37 -0700394#ifdef __clang__
395__attribute__((__format__ (__printf__, 7, 0)))
396#endif
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800397static void log_tsm(void* data, const char* file, int line, const char* fn,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800398 const char* subs, unsigned int sev, const char* format,
399 va_list args)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700400{
Chris Morin255d9f02019-02-04 23:29:27 -0800401 char buffer[KMSG_LINE_MAX];
402 int len = snprintf(buffer, KMSG_LINE_MAX, "<%i>frecon[%d]: %s: ", sev,
403 getpid(), subs);
404 if (len < 0)
405 return;
406 if (len < KMSG_LINE_MAX - 1)
407 vsnprintf(buffer+len, KMSG_LINE_MAX - len, format, args);
408 fprintf(stderr, "%s\n", buffer);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700409}
410
Haixia Shi95285872016-11-08 15:26:35 -0800411static int term_resize(terminal_t* term, int scaling)
Stéphane Marchesin78310662016-01-06 16:09:39 -0800412{
413 uint32_t char_width, char_height;
414 int status;
415
Haixia Shi95285872016-11-08 15:26:35 -0800416 if (!scaling)
417 scaling = fb_getscaling(term->fb);
418
419 font_init(scaling);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800420 font_get_size(&char_width, &char_height);
421
Dominik Behr83010f82016-03-18 18:43:08 -0700422 term->term->char_x = fb_getwidth(term->fb) / char_width;
423 term->term->char_y = fb_getheight(term->fb) / char_height;
424 term->term->pitch = fb_getpitch(term->fb);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800425
426 status = tsm_screen_resize(term->term->screen,
427 term->term->char_x, term->term->char_y);
428 if (status < 0) {
429 font_free();
430 return -1;
431 }
432
433 status = shl_pty_resize(term->term->pty, term->term->char_x,
434 term->term->char_y);
435 if (status < 0) {
436 font_free();
437 return -1;
438 }
439
440 return 0;
441}
442
Dominik Behrda6df412016-08-02 12:56:42 -0700443void term_set_num_terminals(unsigned new_num)
444{
445 if (new_num < 1)
446 term_num_terminals = 1;
447 else if (new_num > TERM_MAX_TERMINALS)
448 term_num_terminals = TERM_MAX_TERMINALS;
449 else
450 term_num_terminals = new_num;
451}
452
453static bool term_is_interactive(unsigned int vt)
454{
455 if (command_flags.no_login)
456 return false;
457
458 if (vt == TERM_SPLASH_TERMINAL)
459 return command_flags.enable_vt1;
460
461 return true;
462}
463
464terminal_t* term_init(unsigned vt, int pts_fd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700465{
466 const int scrollback_size = 200;
David Sodmanbbcb0522014-09-19 10:34:07 -0700467 int status;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800468 terminal_t* new_terminal;
Dominik Behrda6df412016-08-02 12:56:42 -0700469 bool interactive = term_is_interactive(vt);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700470
David Sodmanbbcb0522014-09-19 10:34:07 -0700471 new_terminal = (terminal_t*)calloc(1, sizeof(*new_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800472 if (!new_terminal)
473 return NULL;
David Sodmanbbcb0522014-09-19 10:34:07 -0700474
Dominik Behrda6df412016-08-02 12:56:42 -0700475 new_terminal->vt = vt;
David Sodmanf0a925a2015-05-04 11:19:19 -0700476 new_terminal->background_valid = false;
Dominik Behrda55e6c2017-02-28 18:12:10 -0800477 new_terminal->input_enable = true;
David Sodmanf0a925a2015-05-04 11:19:19 -0700478
Dominik Behr83010f82016-03-18 18:43:08 -0700479 new_terminal->fb = fb_init();
David Sodmanf0a925a2015-05-04 11:19:19 -0700480
Dominik Behr83010f82016-03-18 18:43:08 -0700481 if (!new_terminal->fb) {
Dominik Behrf9329912016-08-25 17:31:52 -0700482 LOG(ERROR, "Failed to create fb on VT%u.", vt);
David Sodmanbf3f2842014-11-12 08:26:58 -0800483 term_close(new_terminal);
484 return NULL;
485 }
486
487 new_terminal->term = (struct term*)calloc(1, sizeof(*new_terminal->term));
488 if (!new_terminal->term) {
489 term_close(new_terminal);
490 return NULL;
491 }
492
Dominik Behrda6df412016-08-02 12:56:42 -0700493 if (interactive)
David Sodman8ef20062015-01-06 09:23:40 -0800494 new_terminal->exec = interactive_cmd_line;
495 else
Dominik Behr32680e32016-08-16 12:18:41 -0700496 new_terminal->exec = NULL;
David Sodman8ef20062015-01-06 09:23:40 -0800497
David Sodmanbbcb0522014-09-19 10:34:07 -0700498 status = tsm_screen_new(&new_terminal->term->screen,
499 log_tsm, new_terminal->term);
zhuo-hao471f1e22015-08-12 14:55:56 +0800500 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700501 LOG(ERROR, "Failed to create new screen on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700502 term_close(new_terminal);
503 return NULL;
504 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700505
David Sodmanbbcb0522014-09-19 10:34:07 -0700506 tsm_screen_set_max_sb(new_terminal->term->screen, scrollback_size);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700507
David Sodmanbbcb0522014-09-19 10:34:07 -0700508 status = tsm_vte_new(&new_terminal->term->vte, new_terminal->term->screen,
509 term_write_cb, new_terminal->term, log_tsm, new_terminal->term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700510
David Sodmanbbcb0522014-09-19 10:34:07 -0700511 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700512 LOG(ERROR, "Failed to create new VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700513 term_close(new_terminal);
514 return NULL;
515 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700516
Dominik Behrda55e6c2017-02-28 18:12:10 -0800517 if (command_flags.enable_osc)
Dominik Behrd2530902016-05-05 14:01:06 -0700518 tsm_vte_set_osc_cb(new_terminal->term->vte, term_osc_cb, (void *)new_terminal);
519
David Sodmanbbcb0522014-09-19 10:34:07 -0700520 new_terminal->term->pty_bridge = shl_pty_bridge_new();
521 if (new_terminal->term->pty_bridge < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700522 LOG(ERROR, "Failed to create pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700523 term_close(new_terminal);
524 return NULL;
525 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700526
David Sodmanbbcb0522014-09-19 10:34:07 -0700527 status = shl_pty_open(&new_terminal->term->pty,
Dominik Behrda6df412016-08-02 12:56:42 -0700528 term_read_cb, new_terminal, 1, 1, pts_fd);
David Sodman8ef20062015-01-06 09:23:40 -0800529
David Sodmanbbcb0522014-09-19 10:34:07 -0700530 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700531 LOG(ERROR, "Failed to open pty on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700532 term_close(new_terminal);
533 return NULL;
534 } else if (status == 0) {
David Sodman8ef20062015-01-06 09:23:40 -0800535 term_run_child(new_terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700536 exit(1);
537 }
538
Dominik Behrda6df412016-08-02 12:56:42 -0700539 status = mkdir(FRECON_RUN_DIR, S_IRWXU);
540 if (status == 0 || (status < 0 && errno == EEXIST)) {
541 char path[32];
542 snprintf(path, sizeof(path), FRECON_VT_PATH, vt);
Dominik Behrb23b05b2016-08-15 16:29:02 -0700543 unlink(path); /* In case it already exists. Ignore return codes. */
Dominik Behrda6df412016-08-02 12:56:42 -0700544 if (symlink(ptsname(shl_pty_get_fd(new_terminal->term->pty)), path) < 0)
545 LOG(ERROR, "Failed to symlink pts name %s to %s, %d:%s",
546 path,
547 ptsname(shl_pty_get_fd(new_terminal->term->pty)),
548 errno, strerror(errno));
549 }
550
David Sodmanbbcb0522014-09-19 10:34:07 -0700551 status = shl_pty_bridge_add(new_terminal->term->pty_bridge, new_terminal->term->pty);
552 if (status) {
Dominik Behrf9329912016-08-25 17:31:52 -0700553 LOG(ERROR, "Failed to add pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700554 term_close(new_terminal);
555 return NULL;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700556 }
557
David Sodmanbbcb0522014-09-19 10:34:07 -0700558 new_terminal->term->pid = shl_pty_get_child(new_terminal->term->pty);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700559
Haixia Shi95285872016-11-08 15:26:35 -0800560 status = term_resize(new_terminal, 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700561
David Sodmanbbcb0522014-09-19 10:34:07 -0700562 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700563 LOG(ERROR, "Failed to resize VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700564 term_close(new_terminal);
565 return NULL;
566 }
David Sodman8ef20062015-01-06 09:23:40 -0800567
David Sodmanbbcb0522014-09-19 10:34:07 -0700568 return new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700569}
570
David Sodman8ef20062015-01-06 09:23:40 -0800571void term_activate(terminal_t* terminal)
572{
Dominik Behr4defb362016-01-13 12:36:14 -0800573 term_set_current_to(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800574 terminal->active = true;
Dominik Behr83010f82016-03-18 18:43:08 -0700575 fb_setmode(terminal->fb);
David Sodman8ef20062015-01-06 09:23:40 -0800576 term_redraw(terminal);
577}
578
David Sodmanf0a925a2015-05-04 11:19:19 -0700579void term_deactivate(terminal_t* terminal)
580{
581 if (!terminal->active)
582 return;
583
David Sodmanf0a925a2015-05-04 11:19:19 -0700584 terminal->active = false;
David Sodmanf0a925a2015-05-04 11:19:19 -0700585}
586
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800587void term_close(terminal_t* term)
David Sodmanbbcb0522014-09-19 10:34:07 -0700588{
Dominik Behrda6df412016-08-02 12:56:42 -0700589 char path[32];
David Sodmanbbcb0522014-09-19 10:34:07 -0700590 if (!term)
591 return;
592
Dominik Behrda6df412016-08-02 12:56:42 -0700593 snprintf(path, sizeof(path), FRECON_VT_PATH, term->vt);
594 unlink(path);
595
Dominik Behr83010f82016-03-18 18:43:08 -0700596 if (term->fb) {
597 fb_close(term->fb);
598 term->fb = NULL;
David Sodmanbf3f2842014-11-12 08:26:58 -0800599 }
600
David Sodmanbbcb0522014-09-19 10:34:07 -0700601 if (term->term) {
Dominik Behrda6df412016-08-02 12:56:42 -0700602 if (term->term->pty) {
603 if (term->term->pty_bridge >= 0) {
604 shl_pty_bridge_remove(term->term->pty_bridge, term->term->pty);
605 shl_pty_bridge_free(term->term->pty_bridge);
606 term->term->pty_bridge = -1;
607 }
608 shl_pty_close(term->term->pty);
609 term->term->pty = NULL;
610 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700611 free(term->term);
612 term->term = NULL;
613 }
614
Haixia Shi95d680e2015-04-27 20:29:17 -0700615 font_free();
David Sodmanbbcb0522014-09-19 10:34:07 -0700616 free(term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700617}
David Sodmanbf3f2842014-11-12 08:26:58 -0800618
619bool term_is_child_done(terminal_t* terminal)
620{
621 int status;
622 int ret;
623 ret = waitpid(terminal->term->pid, &status, WNOHANG);
624
David Sodmanf0a925a2015-05-04 11:19:19 -0700625 if ((ret == -1) && (errno == ECHILD)) {
626 return false;
627 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800628 return ret != 0;
629}
630
631void term_page_up(terminal_t* terminal)
632{
633 tsm_screen_sb_page_up(terminal->term->screen, 1);
634 term_redraw(terminal);
635}
636
637void term_page_down(terminal_t* terminal)
638{
639 tsm_screen_sb_page_down(terminal->term->screen, 1);
640 term_redraw(terminal);
641}
642
643void term_line_up(terminal_t* terminal)
644{
645 tsm_screen_sb_up(terminal->term->screen, 1);
646 term_redraw(terminal);
647}
648
649void term_line_down(terminal_t* terminal)
650{
651 tsm_screen_sb_down(terminal->term->screen, 1);
652 term_redraw(terminal);
653}
654
655bool term_is_valid(terminal_t* terminal)
656{
657 return ((terminal != NULL) && (terminal->term != NULL));
658}
659
660int term_fd(terminal_t* terminal)
661{
662 if (term_is_valid(terminal))
663 return terminal->term->pty_bridge;
664 else
665 return -1;
666}
667
668void term_dispatch_io(terminal_t* terminal, fd_set* read_set)
669{
670 if (term_is_valid(terminal))
671 if (FD_ISSET(terminal->term->pty_bridge, read_set))
672 shl_pty_bridge_dispatch(terminal->term->pty_bridge, 0);
673}
674
675bool term_exception(terminal_t* terminal, fd_set* exception_set)
676{
677 if (term_is_valid(terminal)) {
678 if (terminal->term->pty_bridge >= 0) {
679 return FD_ISSET(terminal->term->pty_bridge,
680 exception_set);
681 }
682 }
683
684 return false;
685}
686
687bool term_is_active(terminal_t* terminal)
688{
689 if (term_is_valid(terminal))
690 return terminal->active;
691
692 return false;
693}
694
Dominik Behrb1abcba2016-04-14 14:57:21 -0700695void term_add_fds(terminal_t* terminal, fd_set* read_set, fd_set* exception_set, int* maxfd)
David Sodmanbf3f2842014-11-12 08:26:58 -0800696{
697 if (term_is_valid(terminal)) {
698 if (terminal->term->pty_bridge >= 0) {
Dominik Behrd7112672016-01-20 16:59:34 -0800699 *maxfd = MAX(*maxfd, terminal->term->pty_bridge);
David Sodmanbf3f2842014-11-12 08:26:58 -0800700 FD_SET(terminal->term->pty_bridge, read_set);
701 FD_SET(terminal->term->pty_bridge, exception_set);
702 }
703 }
704}
David Sodman8ef20062015-01-06 09:23:40 -0800705
706const char* term_get_ptsname(terminal_t* terminal)
707{
708 return ptsname(shl_pty_get_fd(terminal->term->pty));
709}
David Sodmanf0a925a2015-05-04 11:19:19 -0700710
711void term_set_background(terminal_t* terminal, uint32_t bg)
712{
713 terminal->background = bg;
714 terminal->background_valid = true;
715}
716
717int term_show_image(terminal_t* terminal, image_t* image)
718{
Dominik Behr83010f82016-03-18 18:43:08 -0700719 return image_show(image, terminal->fb);
David Sodmanf0a925a2015-05-04 11:19:19 -0700720}
721
722void term_write_message(terminal_t* terminal, char* message)
723{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800724 FILE* fp;
David Sodmanf0a925a2015-05-04 11:19:19 -0700725
726 fp = fopen(term_get_ptsname(terminal), "w");
727 if (fp) {
728 fputs(message, fp);
729 fclose(fp);
730 }
731}
732
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800733static void term_hide_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700734{
735 term_write_message(terminal, "\033[?25l");
736}
737
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800738__attribute__ ((unused))
739static void term_show_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700740{
741 term_write_message(terminal, "\033[?25h");
742}
David Sodman30a94ef2015-07-26 17:37:12 -0700743
Dominik Behr83010f82016-03-18 18:43:08 -0700744fb_t* term_getfb(terminal_t* terminal)
David Sodman30a94ef2015-07-26 17:37:12 -0700745{
Dominik Behr83010f82016-03-18 18:43:08 -0700746 return terminal->fb;
David Sodman30a94ef2015-07-26 17:37:12 -0700747}
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800748
749terminal_t* term_get_terminal(int num)
750{
751 return terminals[num];
752}
753
754void term_set_terminal(int num, terminal_t* terminal)
755{
756 terminals[num] = terminal;
757}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800758
Dominik Behrda6df412016-08-02 12:56:42 -0700759int term_create_splash_term(int pts_fd)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800760{
Dominik Behrda6df412016-08-02 12:56:42 -0700761 terminal_t* terminal = term_init(TERM_SPLASH_TERMINAL, pts_fd);
762
763 if (!terminal) {
764 LOG(ERROR, "Could not create splash term.");
765 return -1;
766 }
767 term_set_terminal(TERM_SPLASH_TERMINAL, terminal);
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800768
769 // Hide the cursor on the splash screen
Dominik Behrda6df412016-08-02 12:56:42 -0700770 term_hide_cursor(terminal);
771 return 0;
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800772}
773
Dominik Behrda6df412016-08-02 12:56:42 -0700774void term_destroy_splash_term(void)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800775{
Dominik Behrda6df412016-08-02 12:56:42 -0700776 terminal_t *terminal;
777 if (command_flags.enable_vt1) {
778 return;
779 }
780 terminal = term_get_terminal(TERM_SPLASH_TERMINAL);
781 term_set_terminal(TERM_SPLASH_TERMINAL, NULL);
782 term_close(terminal);
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800783}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800784
Dominik Behr4defb362016-01-13 12:36:14 -0800785void term_set_current(uint32_t t)
786{
Dominik Behrda6df412016-08-02 12:56:42 -0700787 if (t >= TERM_MAX_TERMINALS)
788 LOG(ERROR, "set_current: larger than array size");
789 else
790 if (t >= term_num_terminals)
791 LOG(ERROR, "set_current: larger than num terminals");
Dominik Behr4defb362016-01-13 12:36:14 -0800792 else
793 current_terminal = t;
794}
795
796uint32_t term_get_current(void)
797{
798 return current_terminal;
799}
800
801terminal_t *term_get_current_terminal(void)
802{
803 return terminals[current_terminal];
804}
805
Dominik Behrb1abcba2016-04-14 14:57:21 -0700806void term_set_current_terminal(terminal_t* terminal)
Dominik Behr4defb362016-01-13 12:36:14 -0800807{
808 terminals[current_terminal] = terminal;
809}
810
811void term_set_current_to(terminal_t* terminal)
812{
813 if (!terminal) {
Haixia Shi95285872016-11-08 15:26:35 -0800814 if (terminals[current_terminal])
815 term_close(terminals[current_terminal]);
Dominik Behr4defb362016-01-13 12:36:14 -0800816 terminals[current_terminal] = NULL;
817 current_terminal = 0;
818 return;
819 }
820
Dominik Behrda6df412016-08-02 12:56:42 -0700821 for (unsigned i = 0; i < term_num_terminals; i++) {
Dominik Behr4defb362016-01-13 12:36:14 -0800822 if (terminal == terminals[i]) {
823 current_terminal = i;
824 return;
825 }
826 }
827 LOG(ERROR, "set_current_to: terminal not in array");
828}
Dominik Behr01a7a582016-01-28 17:02:21 -0800829
Dominik Behrda6df412016-08-02 12:56:42 -0700830int term_switch_to(unsigned int vt)
831{
832 terminal_t *terminal;
833 if (vt == term_get_current()) {
834 terminal = term_get_current_terminal();
Dominik Behrf9329912016-08-25 17:31:52 -0700835 if (term_is_valid(terminal)) {
836 if (!term_is_active(terminal))
837 term_activate(terminal);
838 return vt;
839 }
Dominik Behrda6df412016-08-02 12:56:42 -0700840 }
841
842 if (vt >= term_num_terminals)
843 return -EINVAL;
844
845 terminal = term_get_current_terminal();
846 if (term_is_active(terminal))
847 term_deactivate(terminal);
848
849 if (vt == TERM_SPLASH_TERMINAL
850 && !term_get_terminal(TERM_SPLASH_TERMINAL)
851 && !command_flags.enable_vt1) {
852 term_set_current(vt);
853 /* Splash term is already gone, returning to Chrome. */
Dominik Behr33847332016-12-12 17:27:56 -0800854 term_background(false);
Dominik Behrda6df412016-08-02 12:56:42 -0700855 return vt;
856 }
857
858 term_foreground();
859
860 term_set_current(vt);
861 terminal = term_get_current_terminal();
862 if (!terminal) {
863 /* No terminal where we are switching to, create new one. */
864 term_set_current_terminal(term_init(vt, -1));
865 terminal = term_get_current_terminal();
Dominik Behrda6df412016-08-02 12:56:42 -0700866 if (!term_is_valid(terminal)) {
Dominik Behrf9329912016-08-25 17:31:52 -0700867 LOG(ERROR, "Term init failed VT%u.", vt);
Dominik Behrda6df412016-08-02 12:56:42 -0700868 return -1;
869 }
Dominik Behrf9329912016-08-25 17:31:52 -0700870 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700871 } else {
872 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700873 }
874
875 return vt;
876}
877
Dominik Behr01a7a582016-01-28 17:02:21 -0800878void term_monitor_hotplug(void)
879{
880 unsigned int t;
881
Dominik Behr83864df2016-04-21 12:35:08 -0700882 if (in_background) {
883 hotplug_occured = true;
884 return;
885 }
886
Dominik Behr83010f82016-03-18 18:43:08 -0700887 if (!drm_rescan())
888 return;
889
Dominik Behrda6df412016-08-02 12:56:42 -0700890 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr01a7a582016-01-28 17:02:21 -0800891 if (!terminals[t])
892 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700893 if (!terminals[t]->fb)
Dominik Behr01a7a582016-01-28 17:02:21 -0800894 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700895 fb_buffer_destroy(terminals[t]->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700896 font_free();
Dominik Behr83010f82016-03-18 18:43:08 -0700897 }
898
Dominik Behrda6df412016-08-02 12:56:42 -0700899 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr83010f82016-03-18 18:43:08 -0700900 if (!terminals[t])
901 continue;
902 if (!terminals[t]->fb)
903 continue;
904 fb_buffer_init(terminals[t]->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800905 term_resize(terminals[t], 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700906 if (current_terminal == t && terminals[t]->active)
907 fb_setmode(terminals[t]->fb);
908 terminals[t]->term->age = 0;
909 term_redraw(terminals[t]);
Dominik Behr01a7a582016-01-28 17:02:21 -0800910 }
911}
Dominik Behrb1abcba2016-04-14 14:57:21 -0700912
913void term_redrm(terminal_t* terminal)
914{
915 fb_buffer_destroy(terminal->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700916 font_free();
Dominik Behrb1abcba2016-04-14 14:57:21 -0700917 fb_buffer_init(terminal->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800918 term_resize(terminal, 0);
Dominik Behrb1abcba2016-04-14 14:57:21 -0700919 terminal->term->age = 0;
920 term_redraw(terminal);
921}
922
923void term_clear(terminal_t* terminal)
924{
925 tsm_screen_erase_screen(terminal->term->screen, false);
926 term_redraw(terminal);
927}
Dominik Behr83864df2016-04-21 12:35:08 -0700928
Haixia Shi95285872016-11-08 15:26:35 -0800929void term_zoom(bool zoom_in)
930{
931 int scaling = font_get_scaling();
932 if (zoom_in && scaling < 4)
933 scaling++;
934 else if (!zoom_in && scaling > 1)
935 scaling--;
936 else
937 return;
938
939 unsigned int t;
940 for (t = 0; t < term_num_terminals; t++) {
941 if (terminals[t])
942 font_free();
943 }
944 for (t = 0; t < term_num_terminals; t++) {
945 terminal_t* term = terminals[t];
946 if (term) {
947 term_resize(term, scaling);
948 term->term->age = 0;
949 term_redraw(term);
950 }
951 }
952}
953
Dominik Behr33847332016-12-12 17:27:56 -0800954/*
955 * Put frecon in background. Give up DRM master.
956 * onetry - if true, do not retry to notify Chrome multiple times. For use at
957 * time when Chrome may be not around yet to receive the message.
958 */
959void term_background(bool onetry)
Dominik Behr83864df2016-04-21 12:35:08 -0700960{
Dominik Behr33847332016-12-12 17:27:56 -0800961 int retry = onetry ? 1 : 5;
Dominik Behr83864df2016-04-21 12:35:08 -0700962 if (in_background)
963 return;
964 in_background = true;
Dominik Behrda3c0102016-06-08 15:05:38 -0700965 drm_dropmaster(NULL);
Dominik Behra818a1e2016-10-26 19:46:22 -0700966 while (!dbus_take_display_ownership() && retry--) {
Dominik Behr33847332016-12-12 17:27:56 -0800967 if (onetry)
968 break;
Dominik Behra818a1e2016-10-26 19:46:22 -0700969 LOG(ERROR, "Chrome failed to take display ownership. %s",
970 retry ? "Trying again." : "Giving up, Chrome is probably dead.");
Dominik Behr33847332016-12-12 17:27:56 -0800971 if (retry > 0)
972 usleep(500 * 1000);
Dominik Behra818a1e2016-10-26 19:46:22 -0700973 }
Dominik Behr83864df2016-04-21 12:35:08 -0700974}
975
976void term_foreground(void)
977{
Dominik Behrda3c0102016-06-08 15:05:38 -0700978 int ret;
Dominik Behr33847332016-12-12 17:27:56 -0800979 int retry = 5;
Dominik Behra818a1e2016-10-26 19:46:22 -0700980
Dominik Behr83864df2016-04-21 12:35:08 -0700981 if (!in_background)
982 return;
983 in_background = false;
Dominik Behra818a1e2016-10-26 19:46:22 -0700984
Dominik Behr57b5c722018-08-08 18:52:31 -0700985 /* LOG(INFO, "TIMING: Console switch time start."); */ /* Keep around for timing it in the future. */
Dominik Behra818a1e2016-10-26 19:46:22 -0700986 while (!dbus_release_display_ownership() && retry--) {
987 LOG(ERROR, "Chrome did not release master. %s",
988 retry ? "Trying again." : "Frecon will steal master.");
Dominik Behr33847332016-12-12 17:27:56 -0800989 if (retry > 0)
990 usleep(500 * 1000);
Dominik Behr83864df2016-04-21 12:35:08 -0700991 }
Dominik Behrda3c0102016-06-08 15:05:38 -0700992
Dominik Behr57b5c722018-08-08 18:52:31 -0700993 /* LOG(INFO, "TIMING: Console switch setmaster."); */
Dominik Behrda3c0102016-06-08 15:05:38 -0700994 ret = drm_setmaster(NULL);
Dominik Behrda3c0102016-06-08 15:05:38 -0700995 if (ret < 0)
996 LOG(ERROR, "Could not set master when switching to foreground %m.");
997
Dominik Behr83864df2016-04-21 12:35:08 -0700998 if (hotplug_occured) {
999 hotplug_occured = false;
1000 term_monitor_hotplug();
1001 }
1002}
Dominik Behr1883c042016-04-27 12:31:02 -07001003
1004void term_suspend_done(void* ignore)
1005{
1006 term_monitor_hotplug();
1007}
Dominik Behrda55e6c2017-02-28 18:12:10 -08001008
1009void term_input_enable(terminal_t* terminal, bool input_enable)
1010{
1011 terminal->input_enable = input_enable;
1012}