blob: 77fd46595e53e1d31e36703b9cfd2b417747972d [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
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800394static const char* sev2str_table[] = {
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700395 "FATAL",
396 "ALERT",
397 "CRITICAL",
398 "ERROR",
399 "WARNING",
400 "NOTICE",
401 "INFO",
402 "DEBUG"
403};
404
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800405static const char* sev2str(unsigned int sev)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700406{
407 if (sev > 7)
408 return "DEBUG";
409
410 return sev2str_table[sev];
411}
412
Dominik Behr00003502014-08-15 16:42:37 -0700413#ifdef __clang__
414__attribute__((__format__ (__printf__, 7, 0)))
415#endif
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800416static void log_tsm(void* data, const char* file, int line, const char* fn,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800417 const char* subs, unsigned int sev, const char* format,
418 va_list args)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700419{
420 fprintf(stderr, "%s: %s: ", sev2str(sev), subs);
421 vfprintf(stderr, format, args);
422 fprintf(stderr, "\n");
423}
424
Haixia Shi95285872016-11-08 15:26:35 -0800425static int term_resize(terminal_t* term, int scaling)
Stéphane Marchesin78310662016-01-06 16:09:39 -0800426{
427 uint32_t char_width, char_height;
428 int status;
429
Haixia Shi95285872016-11-08 15:26:35 -0800430 if (!scaling)
431 scaling = fb_getscaling(term->fb);
432
433 font_init(scaling);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800434 font_get_size(&char_width, &char_height);
435
Dominik Behr83010f82016-03-18 18:43:08 -0700436 term->term->char_x = fb_getwidth(term->fb) / char_width;
437 term->term->char_y = fb_getheight(term->fb) / char_height;
438 term->term->pitch = fb_getpitch(term->fb);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800439
440 status = tsm_screen_resize(term->term->screen,
441 term->term->char_x, term->term->char_y);
442 if (status < 0) {
443 font_free();
444 return -1;
445 }
446
447 status = shl_pty_resize(term->term->pty, term->term->char_x,
448 term->term->char_y);
449 if (status < 0) {
450 font_free();
451 return -1;
452 }
453
454 return 0;
455}
456
Dominik Behrda6df412016-08-02 12:56:42 -0700457void term_set_num_terminals(unsigned new_num)
458{
459 if (new_num < 1)
460 term_num_terminals = 1;
461 else if (new_num > TERM_MAX_TERMINALS)
462 term_num_terminals = TERM_MAX_TERMINALS;
463 else
464 term_num_terminals = new_num;
465}
466
467static bool term_is_interactive(unsigned int vt)
468{
469 if (command_flags.no_login)
470 return false;
471
472 if (vt == TERM_SPLASH_TERMINAL)
473 return command_flags.enable_vt1;
474
475 return true;
476}
477
478terminal_t* term_init(unsigned vt, int pts_fd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700479{
480 const int scrollback_size = 200;
David Sodmanbbcb0522014-09-19 10:34:07 -0700481 int status;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800482 terminal_t* new_terminal;
Dominik Behrda6df412016-08-02 12:56:42 -0700483 bool interactive = term_is_interactive(vt);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700484
David Sodmanbbcb0522014-09-19 10:34:07 -0700485 new_terminal = (terminal_t*)calloc(1, sizeof(*new_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800486 if (!new_terminal)
487 return NULL;
David Sodmanbbcb0522014-09-19 10:34:07 -0700488
Dominik Behrda6df412016-08-02 12:56:42 -0700489 new_terminal->vt = vt;
David Sodmanf0a925a2015-05-04 11:19:19 -0700490 new_terminal->background_valid = false;
Dominik Behrda55e6c2017-02-28 18:12:10 -0800491 new_terminal->input_enable = true;
David Sodmanf0a925a2015-05-04 11:19:19 -0700492
Dominik Behr83010f82016-03-18 18:43:08 -0700493 new_terminal->fb = fb_init();
David Sodmanf0a925a2015-05-04 11:19:19 -0700494
Dominik Behr83010f82016-03-18 18:43:08 -0700495 if (!new_terminal->fb) {
Dominik Behrf9329912016-08-25 17:31:52 -0700496 LOG(ERROR, "Failed to create fb on VT%u.", vt);
David Sodmanbf3f2842014-11-12 08:26:58 -0800497 term_close(new_terminal);
498 return NULL;
499 }
500
501 new_terminal->term = (struct term*)calloc(1, sizeof(*new_terminal->term));
502 if (!new_terminal->term) {
503 term_close(new_terminal);
504 return NULL;
505 }
506
Dominik Behrda6df412016-08-02 12:56:42 -0700507 if (interactive)
David Sodman8ef20062015-01-06 09:23:40 -0800508 new_terminal->exec = interactive_cmd_line;
509 else
Dominik Behr32680e32016-08-16 12:18:41 -0700510 new_terminal->exec = NULL;
David Sodman8ef20062015-01-06 09:23:40 -0800511
David Sodmanbbcb0522014-09-19 10:34:07 -0700512 status = tsm_screen_new(&new_terminal->term->screen,
513 log_tsm, new_terminal->term);
zhuo-hao471f1e22015-08-12 14:55:56 +0800514 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700515 LOG(ERROR, "Failed to create new screen on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700516 term_close(new_terminal);
517 return NULL;
518 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700519
David Sodmanbbcb0522014-09-19 10:34:07 -0700520 tsm_screen_set_max_sb(new_terminal->term->screen, scrollback_size);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700521
David Sodmanbbcb0522014-09-19 10:34:07 -0700522 status = tsm_vte_new(&new_terminal->term->vte, new_terminal->term->screen,
523 term_write_cb, new_terminal->term, log_tsm, new_terminal->term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700524
David Sodmanbbcb0522014-09-19 10:34:07 -0700525 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700526 LOG(ERROR, "Failed to create new VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700527 term_close(new_terminal);
528 return NULL;
529 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700530
Dominik Behrda55e6c2017-02-28 18:12:10 -0800531 if (command_flags.enable_osc)
Dominik Behrd2530902016-05-05 14:01:06 -0700532 tsm_vte_set_osc_cb(new_terminal->term->vte, term_osc_cb, (void *)new_terminal);
533
David Sodmanbbcb0522014-09-19 10:34:07 -0700534 new_terminal->term->pty_bridge = shl_pty_bridge_new();
535 if (new_terminal->term->pty_bridge < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700536 LOG(ERROR, "Failed to create pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700537 term_close(new_terminal);
538 return NULL;
539 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700540
David Sodmanbbcb0522014-09-19 10:34:07 -0700541 status = shl_pty_open(&new_terminal->term->pty,
Dominik Behrda6df412016-08-02 12:56:42 -0700542 term_read_cb, new_terminal, 1, 1, pts_fd);
David Sodman8ef20062015-01-06 09:23:40 -0800543
David Sodmanbbcb0522014-09-19 10:34:07 -0700544 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700545 LOG(ERROR, "Failed to open pty on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700546 term_close(new_terminal);
547 return NULL;
548 } else if (status == 0) {
David Sodman8ef20062015-01-06 09:23:40 -0800549 term_run_child(new_terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700550 exit(1);
551 }
552
Dominik Behrda6df412016-08-02 12:56:42 -0700553 status = mkdir(FRECON_RUN_DIR, S_IRWXU);
554 if (status == 0 || (status < 0 && errno == EEXIST)) {
555 char path[32];
556 snprintf(path, sizeof(path), FRECON_VT_PATH, vt);
Dominik Behrb23b05b2016-08-15 16:29:02 -0700557 unlink(path); /* In case it already exists. Ignore return codes. */
Dominik Behrda6df412016-08-02 12:56:42 -0700558 if (symlink(ptsname(shl_pty_get_fd(new_terminal->term->pty)), path) < 0)
559 LOG(ERROR, "Failed to symlink pts name %s to %s, %d:%s",
560 path,
561 ptsname(shl_pty_get_fd(new_terminal->term->pty)),
562 errno, strerror(errno));
563 }
564
David Sodmanbbcb0522014-09-19 10:34:07 -0700565 status = shl_pty_bridge_add(new_terminal->term->pty_bridge, new_terminal->term->pty);
566 if (status) {
Dominik Behrf9329912016-08-25 17:31:52 -0700567 LOG(ERROR, "Failed to add pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700568 term_close(new_terminal);
569 return NULL;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700570 }
571
David Sodmanbbcb0522014-09-19 10:34:07 -0700572 new_terminal->term->pid = shl_pty_get_child(new_terminal->term->pty);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700573
Haixia Shi95285872016-11-08 15:26:35 -0800574 status = term_resize(new_terminal, 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700575
David Sodmanbbcb0522014-09-19 10:34:07 -0700576 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700577 LOG(ERROR, "Failed to resize VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700578 term_close(new_terminal);
579 return NULL;
580 }
David Sodman8ef20062015-01-06 09:23:40 -0800581
David Sodmanbbcb0522014-09-19 10:34:07 -0700582 return new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700583}
584
David Sodman8ef20062015-01-06 09:23:40 -0800585void term_activate(terminal_t* terminal)
586{
Dominik Behr4defb362016-01-13 12:36:14 -0800587 term_set_current_to(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800588 terminal->active = true;
Dominik Behr83010f82016-03-18 18:43:08 -0700589 fb_setmode(terminal->fb);
David Sodman8ef20062015-01-06 09:23:40 -0800590 term_redraw(terminal);
591}
592
David Sodmanf0a925a2015-05-04 11:19:19 -0700593void term_deactivate(terminal_t* terminal)
594{
595 if (!terminal->active)
596 return;
597
David Sodmanf0a925a2015-05-04 11:19:19 -0700598 terminal->active = false;
David Sodmanf0a925a2015-05-04 11:19:19 -0700599}
600
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800601void term_close(terminal_t* term)
David Sodmanbbcb0522014-09-19 10:34:07 -0700602{
Dominik Behrda6df412016-08-02 12:56:42 -0700603 char path[32];
David Sodmanbbcb0522014-09-19 10:34:07 -0700604 if (!term)
605 return;
606
Dominik Behrda6df412016-08-02 12:56:42 -0700607 snprintf(path, sizeof(path), FRECON_VT_PATH, term->vt);
608 unlink(path);
609
Dominik Behr83010f82016-03-18 18:43:08 -0700610 if (term->fb) {
611 fb_close(term->fb);
612 term->fb = NULL;
David Sodmanbf3f2842014-11-12 08:26:58 -0800613 }
614
David Sodmanbbcb0522014-09-19 10:34:07 -0700615 if (term->term) {
Dominik Behrda6df412016-08-02 12:56:42 -0700616 if (term->term->pty) {
617 if (term->term->pty_bridge >= 0) {
618 shl_pty_bridge_remove(term->term->pty_bridge, term->term->pty);
619 shl_pty_bridge_free(term->term->pty_bridge);
620 term->term->pty_bridge = -1;
621 }
622 shl_pty_close(term->term->pty);
623 term->term->pty = NULL;
624 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700625 free(term->term);
626 term->term = NULL;
627 }
628
Haixia Shi95d680e2015-04-27 20:29:17 -0700629 font_free();
David Sodmanbbcb0522014-09-19 10:34:07 -0700630 free(term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700631}
David Sodmanbf3f2842014-11-12 08:26:58 -0800632
633bool term_is_child_done(terminal_t* terminal)
634{
635 int status;
636 int ret;
637 ret = waitpid(terminal->term->pid, &status, WNOHANG);
638
David Sodmanf0a925a2015-05-04 11:19:19 -0700639 if ((ret == -1) && (errno == ECHILD)) {
640 return false;
641 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800642 return ret != 0;
643}
644
645void term_page_up(terminal_t* terminal)
646{
647 tsm_screen_sb_page_up(terminal->term->screen, 1);
648 term_redraw(terminal);
649}
650
651void term_page_down(terminal_t* terminal)
652{
653 tsm_screen_sb_page_down(terminal->term->screen, 1);
654 term_redraw(terminal);
655}
656
657void term_line_up(terminal_t* terminal)
658{
659 tsm_screen_sb_up(terminal->term->screen, 1);
660 term_redraw(terminal);
661}
662
663void term_line_down(terminal_t* terminal)
664{
665 tsm_screen_sb_down(terminal->term->screen, 1);
666 term_redraw(terminal);
667}
668
669bool term_is_valid(terminal_t* terminal)
670{
671 return ((terminal != NULL) && (terminal->term != NULL));
672}
673
674int term_fd(terminal_t* terminal)
675{
676 if (term_is_valid(terminal))
677 return terminal->term->pty_bridge;
678 else
679 return -1;
680}
681
682void term_dispatch_io(terminal_t* terminal, fd_set* read_set)
683{
684 if (term_is_valid(terminal))
685 if (FD_ISSET(terminal->term->pty_bridge, read_set))
686 shl_pty_bridge_dispatch(terminal->term->pty_bridge, 0);
687}
688
689bool term_exception(terminal_t* terminal, fd_set* exception_set)
690{
691 if (term_is_valid(terminal)) {
692 if (terminal->term->pty_bridge >= 0) {
693 return FD_ISSET(terminal->term->pty_bridge,
694 exception_set);
695 }
696 }
697
698 return false;
699}
700
701bool term_is_active(terminal_t* terminal)
702{
703 if (term_is_valid(terminal))
704 return terminal->active;
705
706 return false;
707}
708
Dominik Behrb1abcba2016-04-14 14:57:21 -0700709void term_add_fds(terminal_t* terminal, fd_set* read_set, fd_set* exception_set, int* maxfd)
David Sodmanbf3f2842014-11-12 08:26:58 -0800710{
711 if (term_is_valid(terminal)) {
712 if (terminal->term->pty_bridge >= 0) {
Dominik Behrd7112672016-01-20 16:59:34 -0800713 *maxfd = MAX(*maxfd, terminal->term->pty_bridge);
David Sodmanbf3f2842014-11-12 08:26:58 -0800714 FD_SET(terminal->term->pty_bridge, read_set);
715 FD_SET(terminal->term->pty_bridge, exception_set);
716 }
717 }
718}
David Sodman8ef20062015-01-06 09:23:40 -0800719
720const char* term_get_ptsname(terminal_t* terminal)
721{
722 return ptsname(shl_pty_get_fd(terminal->term->pty));
723}
David Sodmanf0a925a2015-05-04 11:19:19 -0700724
725void term_set_background(terminal_t* terminal, uint32_t bg)
726{
727 terminal->background = bg;
728 terminal->background_valid = true;
729}
730
731int term_show_image(terminal_t* terminal, image_t* image)
732{
Dominik Behr83010f82016-03-18 18:43:08 -0700733 return image_show(image, terminal->fb);
David Sodmanf0a925a2015-05-04 11:19:19 -0700734}
735
736void term_write_message(terminal_t* terminal, char* message)
737{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800738 FILE* fp;
David Sodmanf0a925a2015-05-04 11:19:19 -0700739
740 fp = fopen(term_get_ptsname(terminal), "w");
741 if (fp) {
742 fputs(message, fp);
743 fclose(fp);
744 }
745}
746
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800747static void term_hide_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700748{
749 term_write_message(terminal, "\033[?25l");
750}
751
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800752__attribute__ ((unused))
753static void term_show_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700754{
755 term_write_message(terminal, "\033[?25h");
756}
David Sodman30a94ef2015-07-26 17:37:12 -0700757
Dominik Behr83010f82016-03-18 18:43:08 -0700758fb_t* term_getfb(terminal_t* terminal)
David Sodman30a94ef2015-07-26 17:37:12 -0700759{
Dominik Behr83010f82016-03-18 18:43:08 -0700760 return terminal->fb;
David Sodman30a94ef2015-07-26 17:37:12 -0700761}
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800762
763terminal_t* term_get_terminal(int num)
764{
765 return terminals[num];
766}
767
768void term_set_terminal(int num, terminal_t* terminal)
769{
770 terminals[num] = terminal;
771}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800772
Dominik Behrda6df412016-08-02 12:56:42 -0700773int term_create_splash_term(int pts_fd)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800774{
Dominik Behrda6df412016-08-02 12:56:42 -0700775 terminal_t* terminal = term_init(TERM_SPLASH_TERMINAL, pts_fd);
776
777 if (!terminal) {
778 LOG(ERROR, "Could not create splash term.");
779 return -1;
780 }
781 term_set_terminal(TERM_SPLASH_TERMINAL, terminal);
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800782
783 // Hide the cursor on the splash screen
Dominik Behrda6df412016-08-02 12:56:42 -0700784 term_hide_cursor(terminal);
785 return 0;
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800786}
787
Dominik Behrda6df412016-08-02 12:56:42 -0700788void term_destroy_splash_term(void)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800789{
Dominik Behrda6df412016-08-02 12:56:42 -0700790 terminal_t *terminal;
791 if (command_flags.enable_vt1) {
792 return;
793 }
794 terminal = term_get_terminal(TERM_SPLASH_TERMINAL);
795 term_set_terminal(TERM_SPLASH_TERMINAL, NULL);
796 term_close(terminal);
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800797}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800798
Dominik Behr4defb362016-01-13 12:36:14 -0800799void term_set_current(uint32_t t)
800{
Dominik Behrda6df412016-08-02 12:56:42 -0700801 if (t >= TERM_MAX_TERMINALS)
802 LOG(ERROR, "set_current: larger than array size");
803 else
804 if (t >= term_num_terminals)
805 LOG(ERROR, "set_current: larger than num terminals");
Dominik Behr4defb362016-01-13 12:36:14 -0800806 else
807 current_terminal = t;
808}
809
810uint32_t term_get_current(void)
811{
812 return current_terminal;
813}
814
815terminal_t *term_get_current_terminal(void)
816{
817 return terminals[current_terminal];
818}
819
Dominik Behrb1abcba2016-04-14 14:57:21 -0700820void term_set_current_terminal(terminal_t* terminal)
Dominik Behr4defb362016-01-13 12:36:14 -0800821{
822 terminals[current_terminal] = terminal;
823}
824
825void term_set_current_to(terminal_t* terminal)
826{
827 if (!terminal) {
Haixia Shi95285872016-11-08 15:26:35 -0800828 if (terminals[current_terminal])
829 term_close(terminals[current_terminal]);
Dominik Behr4defb362016-01-13 12:36:14 -0800830 terminals[current_terminal] = NULL;
831 current_terminal = 0;
832 return;
833 }
834
Dominik Behrda6df412016-08-02 12:56:42 -0700835 for (unsigned i = 0; i < term_num_terminals; i++) {
Dominik Behr4defb362016-01-13 12:36:14 -0800836 if (terminal == terminals[i]) {
837 current_terminal = i;
838 return;
839 }
840 }
841 LOG(ERROR, "set_current_to: terminal not in array");
842}
Dominik Behr01a7a582016-01-28 17:02:21 -0800843
Dominik Behrda6df412016-08-02 12:56:42 -0700844int term_switch_to(unsigned int vt)
845{
846 terminal_t *terminal;
847 if (vt == term_get_current()) {
848 terminal = term_get_current_terminal();
Dominik Behrf9329912016-08-25 17:31:52 -0700849 if (term_is_valid(terminal)) {
850 if (!term_is_active(terminal))
851 term_activate(terminal);
852 return vt;
853 }
Dominik Behrda6df412016-08-02 12:56:42 -0700854 }
855
856 if (vt >= term_num_terminals)
857 return -EINVAL;
858
859 terminal = term_get_current_terminal();
860 if (term_is_active(terminal))
861 term_deactivate(terminal);
862
863 if (vt == TERM_SPLASH_TERMINAL
864 && !term_get_terminal(TERM_SPLASH_TERMINAL)
865 && !command_flags.enable_vt1) {
866 term_set_current(vt);
867 /* Splash term is already gone, returning to Chrome. */
Dominik Behr33847332016-12-12 17:27:56 -0800868 term_background(false);
Dominik Behrda6df412016-08-02 12:56:42 -0700869 return vt;
870 }
871
872 term_foreground();
873
874 term_set_current(vt);
875 terminal = term_get_current_terminal();
876 if (!terminal) {
877 /* No terminal where we are switching to, create new one. */
878 term_set_current_terminal(term_init(vt, -1));
879 terminal = term_get_current_terminal();
Dominik Behrda6df412016-08-02 12:56:42 -0700880 if (!term_is_valid(terminal)) {
Dominik Behrf9329912016-08-25 17:31:52 -0700881 LOG(ERROR, "Term init failed VT%u.", vt);
Dominik Behrda6df412016-08-02 12:56:42 -0700882 return -1;
883 }
Dominik Behrf9329912016-08-25 17:31:52 -0700884 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700885 } else {
886 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700887 }
888
889 return vt;
890}
891
Dominik Behr01a7a582016-01-28 17:02:21 -0800892void term_monitor_hotplug(void)
893{
894 unsigned int t;
895
Dominik Behr83864df2016-04-21 12:35:08 -0700896 if (in_background) {
897 hotplug_occured = true;
898 return;
899 }
900
Dominik Behr83010f82016-03-18 18:43:08 -0700901 if (!drm_rescan())
902 return;
903
Dominik Behrda6df412016-08-02 12:56:42 -0700904 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr01a7a582016-01-28 17:02:21 -0800905 if (!terminals[t])
906 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700907 if (!terminals[t]->fb)
Dominik Behr01a7a582016-01-28 17:02:21 -0800908 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700909 fb_buffer_destroy(terminals[t]->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700910 font_free();
Dominik Behr83010f82016-03-18 18:43:08 -0700911 }
912
Dominik Behrda6df412016-08-02 12:56:42 -0700913 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr83010f82016-03-18 18:43:08 -0700914 if (!terminals[t])
915 continue;
916 if (!terminals[t]->fb)
917 continue;
918 fb_buffer_init(terminals[t]->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800919 term_resize(terminals[t], 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700920 if (current_terminal == t && terminals[t]->active)
921 fb_setmode(terminals[t]->fb);
922 terminals[t]->term->age = 0;
923 term_redraw(terminals[t]);
Dominik Behr01a7a582016-01-28 17:02:21 -0800924 }
925}
Dominik Behrb1abcba2016-04-14 14:57:21 -0700926
927void term_redrm(terminal_t* terminal)
928{
929 fb_buffer_destroy(terminal->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700930 font_free();
Dominik Behrb1abcba2016-04-14 14:57:21 -0700931 fb_buffer_init(terminal->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800932 term_resize(terminal, 0);
Dominik Behrb1abcba2016-04-14 14:57:21 -0700933 terminal->term->age = 0;
934 term_redraw(terminal);
935}
936
937void term_clear(terminal_t* terminal)
938{
939 tsm_screen_erase_screen(terminal->term->screen, false);
940 term_redraw(terminal);
941}
Dominik Behr83864df2016-04-21 12:35:08 -0700942
Haixia Shi95285872016-11-08 15:26:35 -0800943void term_zoom(bool zoom_in)
944{
945 int scaling = font_get_scaling();
946 if (zoom_in && scaling < 4)
947 scaling++;
948 else if (!zoom_in && scaling > 1)
949 scaling--;
950 else
951 return;
952
953 unsigned int t;
954 for (t = 0; t < term_num_terminals; t++) {
955 if (terminals[t])
956 font_free();
957 }
958 for (t = 0; t < term_num_terminals; t++) {
959 terminal_t* term = terminals[t];
960 if (term) {
961 term_resize(term, scaling);
962 term->term->age = 0;
963 term_redraw(term);
964 }
965 }
966}
967
Dominik Behr33847332016-12-12 17:27:56 -0800968/*
969 * Put frecon in background. Give up DRM master.
970 * onetry - if true, do not retry to notify Chrome multiple times. For use at
971 * time when Chrome may be not around yet to receive the message.
972 */
973void term_background(bool onetry)
Dominik Behr83864df2016-04-21 12:35:08 -0700974{
Dominik Behr33847332016-12-12 17:27:56 -0800975 int retry = onetry ? 1 : 5;
Dominik Behr83864df2016-04-21 12:35:08 -0700976 if (in_background)
977 return;
978 in_background = true;
Dominik Behrda3c0102016-06-08 15:05:38 -0700979 drm_dropmaster(NULL);
Dominik Behra818a1e2016-10-26 19:46:22 -0700980 while (!dbus_take_display_ownership() && retry--) {
Dominik Behr33847332016-12-12 17:27:56 -0800981 if (onetry)
982 break;
Dominik Behra818a1e2016-10-26 19:46:22 -0700983 LOG(ERROR, "Chrome failed to take display ownership. %s",
984 retry ? "Trying again." : "Giving up, Chrome is probably dead.");
Dominik Behr33847332016-12-12 17:27:56 -0800985 if (retry > 0)
986 usleep(500 * 1000);
Dominik Behra818a1e2016-10-26 19:46:22 -0700987 }
Dominik Behr83864df2016-04-21 12:35:08 -0700988}
989
990void term_foreground(void)
991{
Dominik Behrda3c0102016-06-08 15:05:38 -0700992 int ret;
Dominik Behr33847332016-12-12 17:27:56 -0800993 int retry = 5;
Dominik Behra818a1e2016-10-26 19:46:22 -0700994
Dominik Behr83864df2016-04-21 12:35:08 -0700995 if (!in_background)
996 return;
997 in_background = false;
Dominik Behra818a1e2016-10-26 19:46:22 -0700998
999 while (!dbus_release_display_ownership() && retry--) {
1000 LOG(ERROR, "Chrome did not release master. %s",
1001 retry ? "Trying again." : "Frecon will steal master.");
Dominik Behr33847332016-12-12 17:27:56 -08001002 if (retry > 0)
1003 usleep(500 * 1000);
Dominik Behr83864df2016-04-21 12:35:08 -07001004 }
Dominik Behrda3c0102016-06-08 15:05:38 -07001005
1006 ret = drm_setmaster(NULL);
Dominik Behrda3c0102016-06-08 15:05:38 -07001007 if (ret < 0)
1008 LOG(ERROR, "Could not set master when switching to foreground %m.");
1009
Dominik Behr83864df2016-04-21 12:35:08 -07001010 if (hotplug_occured) {
1011 hotplug_occured = false;
1012 term_monitor_hotplug();
1013 }
1014}
Dominik Behr1883c042016-04-27 12:31:02 -07001015
1016void term_suspend_done(void* ignore)
1017{
1018 term_monitor_hotplug();
1019}
Dominik Behrda55e6c2017-02-28 18:12:10 -08001020
1021void term_input_enable(terminal_t* terminal, bool input_enable)
1022{
1023 terminal->input_enable = input_enable;
1024}