blob: f1d04820140450ea0e10ad0af33f5c3dd70c7503 [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
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100464/*
465 * Set the area not covered by any characters, possibly existing on the right
466 * side and bottom of the screen, to the background color.
467 */
468static void term_clear_border(terminal_t* terminal)
469{
470 uint32_t char_width, char_height;
471 font_get_size(&char_width, &char_height);
472 int32_t width = fb_getwidth(terminal->fb);
473 int32_t height = fb_getheight(terminal->fb);
474 int32_t pitch4 = fb_getpitch(terminal->fb) / 4;
475 uint32_t* fb_buffer = fb_lock(terminal->fb);
476
477 if (fb_buffer) {
478 for (uint32_t y = 0; y < terminal->term->char_y * char_height;
479 y++) {
480 for (int32_t x = terminal->term->char_x * char_width;
481 x < width; x++) {
482 fb_buffer[y * pitch4 + x] = terminal->background;
483 }
484 }
485 for (int32_t y = terminal->term->char_y * char_height;
486 y < height; y++) {
487 for (int32_t x = 0; x < width; x++) {
488 fb_buffer[y * pitch4 + x] = terminal->background;
489 }
490 }
491 fb_unlock(terminal->fb);
492 }
493}
494
Dominik Behrda6df412016-08-02 12:56:42 -0700495terminal_t* term_init(unsigned vt, int pts_fd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700496{
497 const int scrollback_size = 200;
David Sodmanbbcb0522014-09-19 10:34:07 -0700498 int status;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800499 terminal_t* new_terminal;
Dominik Behrda6df412016-08-02 12:56:42 -0700500 bool interactive = term_is_interactive(vt);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700501
David Sodmanbbcb0522014-09-19 10:34:07 -0700502 new_terminal = (terminal_t*)calloc(1, sizeof(*new_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800503 if (!new_terminal)
504 return NULL;
David Sodmanbbcb0522014-09-19 10:34:07 -0700505
Dominik Behrda6df412016-08-02 12:56:42 -0700506 new_terminal->vt = vt;
David Sodmanf0a925a2015-05-04 11:19:19 -0700507 new_terminal->background_valid = false;
Dominik Behrda55e6c2017-02-28 18:12:10 -0800508 new_terminal->input_enable = true;
David Sodmanf0a925a2015-05-04 11:19:19 -0700509
Dominik Behr83010f82016-03-18 18:43:08 -0700510 new_terminal->fb = fb_init();
David Sodmanf0a925a2015-05-04 11:19:19 -0700511
Dominik Behr83010f82016-03-18 18:43:08 -0700512 if (!new_terminal->fb) {
Dominik Behrf9329912016-08-25 17:31:52 -0700513 LOG(ERROR, "Failed to create fb on VT%u.", vt);
David Sodmanbf3f2842014-11-12 08:26:58 -0800514 term_close(new_terminal);
515 return NULL;
516 }
517
518 new_terminal->term = (struct term*)calloc(1, sizeof(*new_terminal->term));
519 if (!new_terminal->term) {
520 term_close(new_terminal);
521 return NULL;
522 }
523
Dominik Behrda6df412016-08-02 12:56:42 -0700524 if (interactive)
David Sodman8ef20062015-01-06 09:23:40 -0800525 new_terminal->exec = interactive_cmd_line;
526 else
Dominik Behr32680e32016-08-16 12:18:41 -0700527 new_terminal->exec = NULL;
David Sodman8ef20062015-01-06 09:23:40 -0800528
David Sodmanbbcb0522014-09-19 10:34:07 -0700529 status = tsm_screen_new(&new_terminal->term->screen,
530 log_tsm, new_terminal->term);
zhuo-hao471f1e22015-08-12 14:55:56 +0800531 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700532 LOG(ERROR, "Failed to create new screen on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700533 term_close(new_terminal);
534 return NULL;
535 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700536
David Sodmanbbcb0522014-09-19 10:34:07 -0700537 tsm_screen_set_max_sb(new_terminal->term->screen, scrollback_size);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700538
David Sodmanbbcb0522014-09-19 10:34:07 -0700539 status = tsm_vte_new(&new_terminal->term->vte, new_terminal->term->screen,
540 term_write_cb, new_terminal->term, log_tsm, new_terminal->term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700541
David Sodmanbbcb0522014-09-19 10:34:07 -0700542 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700543 LOG(ERROR, "Failed to create new VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700544 term_close(new_terminal);
545 return NULL;
546 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700547
Dominik Behrda55e6c2017-02-28 18:12:10 -0800548 if (command_flags.enable_osc)
Dominik Behrd2530902016-05-05 14:01:06 -0700549 tsm_vte_set_osc_cb(new_terminal->term->vte, term_osc_cb, (void *)new_terminal);
550
David Sodmanbbcb0522014-09-19 10:34:07 -0700551 new_terminal->term->pty_bridge = shl_pty_bridge_new();
552 if (new_terminal->term->pty_bridge < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700553 LOG(ERROR, "Failed to create pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700554 term_close(new_terminal);
555 return NULL;
556 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700557
David Sodmanbbcb0522014-09-19 10:34:07 -0700558 status = shl_pty_open(&new_terminal->term->pty,
Dominik Behrda6df412016-08-02 12:56:42 -0700559 term_read_cb, new_terminal, 1, 1, pts_fd);
David Sodman8ef20062015-01-06 09:23:40 -0800560
David Sodmanbbcb0522014-09-19 10:34:07 -0700561 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700562 LOG(ERROR, "Failed to open pty on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700563 term_close(new_terminal);
564 return NULL;
565 } else if (status == 0) {
David Sodman8ef20062015-01-06 09:23:40 -0800566 term_run_child(new_terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700567 exit(1);
568 }
569
Dominik Behrda6df412016-08-02 12:56:42 -0700570 status = mkdir(FRECON_RUN_DIR, S_IRWXU);
571 if (status == 0 || (status < 0 && errno == EEXIST)) {
572 char path[32];
573 snprintf(path, sizeof(path), FRECON_VT_PATH, vt);
Dominik Behrb23b05b2016-08-15 16:29:02 -0700574 unlink(path); /* In case it already exists. Ignore return codes. */
Dominik Behrda6df412016-08-02 12:56:42 -0700575 if (symlink(ptsname(shl_pty_get_fd(new_terminal->term->pty)), path) < 0)
576 LOG(ERROR, "Failed to symlink pts name %s to %s, %d:%s",
577 path,
578 ptsname(shl_pty_get_fd(new_terminal->term->pty)),
579 errno, strerror(errno));
580 }
581
David Sodmanbbcb0522014-09-19 10:34:07 -0700582 status = shl_pty_bridge_add(new_terminal->term->pty_bridge, new_terminal->term->pty);
583 if (status) {
Dominik Behrf9329912016-08-25 17:31:52 -0700584 LOG(ERROR, "Failed to add pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700585 term_close(new_terminal);
586 return NULL;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700587 }
588
David Sodmanbbcb0522014-09-19 10:34:07 -0700589 new_terminal->term->pid = shl_pty_get_child(new_terminal->term->pty);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700590
Haixia Shi95285872016-11-08 15:26:35 -0800591 status = term_resize(new_terminal, 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700592
David Sodmanbbcb0522014-09-19 10:34:07 -0700593 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700594 LOG(ERROR, "Failed to resize VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700595 term_close(new_terminal);
596 return NULL;
597 }
David Sodman8ef20062015-01-06 09:23:40 -0800598
David Sodmanbbcb0522014-09-19 10:34:07 -0700599 return new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700600}
601
David Sodman8ef20062015-01-06 09:23:40 -0800602void term_activate(terminal_t* terminal)
603{
Dominik Behr4defb362016-01-13 12:36:14 -0800604 term_set_current_to(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800605 terminal->active = true;
Dominik Behr83010f82016-03-18 18:43:08 -0700606 fb_setmode(terminal->fb);
David Sodman8ef20062015-01-06 09:23:40 -0800607 term_redraw(terminal);
608}
609
David Sodmanf0a925a2015-05-04 11:19:19 -0700610void term_deactivate(terminal_t* terminal)
611{
612 if (!terminal->active)
613 return;
614
David Sodmanf0a925a2015-05-04 11:19:19 -0700615 terminal->active = false;
David Sodmanf0a925a2015-05-04 11:19:19 -0700616}
617
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800618void term_close(terminal_t* term)
David Sodmanbbcb0522014-09-19 10:34:07 -0700619{
Dominik Behrda6df412016-08-02 12:56:42 -0700620 char path[32];
David Sodmanbbcb0522014-09-19 10:34:07 -0700621 if (!term)
622 return;
623
Dominik Behrda6df412016-08-02 12:56:42 -0700624 snprintf(path, sizeof(path), FRECON_VT_PATH, term->vt);
625 unlink(path);
626
Dominik Behr83010f82016-03-18 18:43:08 -0700627 if (term->fb) {
628 fb_close(term->fb);
629 term->fb = NULL;
David Sodmanbf3f2842014-11-12 08:26:58 -0800630 }
631
David Sodmanbbcb0522014-09-19 10:34:07 -0700632 if (term->term) {
Dominik Behrda6df412016-08-02 12:56:42 -0700633 if (term->term->pty) {
634 if (term->term->pty_bridge >= 0) {
635 shl_pty_bridge_remove(term->term->pty_bridge, term->term->pty);
636 shl_pty_bridge_free(term->term->pty_bridge);
637 term->term->pty_bridge = -1;
638 }
639 shl_pty_close(term->term->pty);
640 term->term->pty = NULL;
641 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700642 free(term->term);
643 term->term = NULL;
644 }
645
Haixia Shi95d680e2015-04-27 20:29:17 -0700646 font_free();
David Sodmanbbcb0522014-09-19 10:34:07 -0700647 free(term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700648}
David Sodmanbf3f2842014-11-12 08:26:58 -0800649
650bool term_is_child_done(terminal_t* terminal)
651{
652 int status;
653 int ret;
654 ret = waitpid(terminal->term->pid, &status, WNOHANG);
655
David Sodmanf0a925a2015-05-04 11:19:19 -0700656 if ((ret == -1) && (errno == ECHILD)) {
657 return false;
658 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800659 return ret != 0;
660}
661
662void term_page_up(terminal_t* terminal)
663{
664 tsm_screen_sb_page_up(terminal->term->screen, 1);
665 term_redraw(terminal);
666}
667
668void term_page_down(terminal_t* terminal)
669{
670 tsm_screen_sb_page_down(terminal->term->screen, 1);
671 term_redraw(terminal);
672}
673
674void term_line_up(terminal_t* terminal)
675{
676 tsm_screen_sb_up(terminal->term->screen, 1);
677 term_redraw(terminal);
678}
679
680void term_line_down(terminal_t* terminal)
681{
682 tsm_screen_sb_down(terminal->term->screen, 1);
683 term_redraw(terminal);
684}
685
686bool term_is_valid(terminal_t* terminal)
687{
688 return ((terminal != NULL) && (terminal->term != NULL));
689}
690
691int term_fd(terminal_t* terminal)
692{
693 if (term_is_valid(terminal))
694 return terminal->term->pty_bridge;
695 else
696 return -1;
697}
698
699void term_dispatch_io(terminal_t* terminal, fd_set* read_set)
700{
701 if (term_is_valid(terminal))
702 if (FD_ISSET(terminal->term->pty_bridge, read_set))
703 shl_pty_bridge_dispatch(terminal->term->pty_bridge, 0);
704}
705
706bool term_exception(terminal_t* terminal, fd_set* exception_set)
707{
708 if (term_is_valid(terminal)) {
709 if (terminal->term->pty_bridge >= 0) {
710 return FD_ISSET(terminal->term->pty_bridge,
711 exception_set);
712 }
713 }
714
715 return false;
716}
717
718bool term_is_active(terminal_t* terminal)
719{
720 if (term_is_valid(terminal))
721 return terminal->active;
722
723 return false;
724}
725
Dominik Behrb1abcba2016-04-14 14:57:21 -0700726void term_add_fds(terminal_t* terminal, fd_set* read_set, fd_set* exception_set, int* maxfd)
David Sodmanbf3f2842014-11-12 08:26:58 -0800727{
728 if (term_is_valid(terminal)) {
729 if (terminal->term->pty_bridge >= 0) {
Dominik Behrd7112672016-01-20 16:59:34 -0800730 *maxfd = MAX(*maxfd, terminal->term->pty_bridge);
David Sodmanbf3f2842014-11-12 08:26:58 -0800731 FD_SET(terminal->term->pty_bridge, read_set);
732 FD_SET(terminal->term->pty_bridge, exception_set);
733 }
734 }
735}
David Sodman8ef20062015-01-06 09:23:40 -0800736
737const char* term_get_ptsname(terminal_t* terminal)
738{
739 return ptsname(shl_pty_get_fd(terminal->term->pty));
740}
David Sodmanf0a925a2015-05-04 11:19:19 -0700741
742void term_set_background(terminal_t* terminal, uint32_t bg)
743{
744 terminal->background = bg;
745 terminal->background_valid = true;
746}
747
748int term_show_image(terminal_t* terminal, image_t* image)
749{
Dominik Behr83010f82016-03-18 18:43:08 -0700750 return image_show(image, terminal->fb);
David Sodmanf0a925a2015-05-04 11:19:19 -0700751}
752
753void term_write_message(terminal_t* terminal, char* message)
754{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800755 FILE* fp;
David Sodmanf0a925a2015-05-04 11:19:19 -0700756
757 fp = fopen(term_get_ptsname(terminal), "w");
758 if (fp) {
759 fputs(message, fp);
760 fclose(fp);
761 }
762}
763
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800764static void term_hide_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700765{
766 term_write_message(terminal, "\033[?25l");
767}
768
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800769__attribute__ ((unused))
770static void term_show_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700771{
772 term_write_message(terminal, "\033[?25h");
773}
David Sodman30a94ef2015-07-26 17:37:12 -0700774
Dominik Behr83010f82016-03-18 18:43:08 -0700775fb_t* term_getfb(terminal_t* terminal)
David Sodman30a94ef2015-07-26 17:37:12 -0700776{
Dominik Behr83010f82016-03-18 18:43:08 -0700777 return terminal->fb;
David Sodman30a94ef2015-07-26 17:37:12 -0700778}
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800779
780terminal_t* term_get_terminal(int num)
781{
782 return terminals[num];
783}
784
785void term_set_terminal(int num, terminal_t* terminal)
786{
787 terminals[num] = terminal;
788}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800789
Dominik Behrda6df412016-08-02 12:56:42 -0700790int term_create_splash_term(int pts_fd)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800791{
Dominik Behrda6df412016-08-02 12:56:42 -0700792 terminal_t* terminal = term_init(TERM_SPLASH_TERMINAL, pts_fd);
793
794 if (!terminal) {
795 LOG(ERROR, "Could not create splash term.");
796 return -1;
797 }
798 term_set_terminal(TERM_SPLASH_TERMINAL, terminal);
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800799
800 // Hide the cursor on the splash screen
Dominik Behrda6df412016-08-02 12:56:42 -0700801 term_hide_cursor(terminal);
802 return 0;
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800803}
804
Dominik Behrda6df412016-08-02 12:56:42 -0700805void term_destroy_splash_term(void)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800806{
Dominik Behrda6df412016-08-02 12:56:42 -0700807 terminal_t *terminal;
808 if (command_flags.enable_vt1) {
809 return;
810 }
Jacek Fedorynski83776b72019-03-06 22:56:56 +0100811 terminal = term_get_terminal(TERM_SPLASH_TERMINAL);
Dominik Behrda6df412016-08-02 12:56:42 -0700812 term_set_terminal(TERM_SPLASH_TERMINAL, NULL);
813 term_close(terminal);
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800814}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800815
Dominik Behr4defb362016-01-13 12:36:14 -0800816void term_set_current(uint32_t t)
817{
Dominik Behrda6df412016-08-02 12:56:42 -0700818 if (t >= TERM_MAX_TERMINALS)
819 LOG(ERROR, "set_current: larger than array size");
820 else
821 if (t >= term_num_terminals)
822 LOG(ERROR, "set_current: larger than num terminals");
Dominik Behr4defb362016-01-13 12:36:14 -0800823 else
824 current_terminal = t;
825}
826
827uint32_t term_get_current(void)
828{
829 return current_terminal;
830}
831
832terminal_t *term_get_current_terminal(void)
833{
834 return terminals[current_terminal];
835}
836
Dominik Behrb1abcba2016-04-14 14:57:21 -0700837void term_set_current_terminal(terminal_t* terminal)
Dominik Behr4defb362016-01-13 12:36:14 -0800838{
839 terminals[current_terminal] = terminal;
840}
841
842void term_set_current_to(terminal_t* terminal)
843{
844 if (!terminal) {
Haixia Shi95285872016-11-08 15:26:35 -0800845 if (terminals[current_terminal])
846 term_close(terminals[current_terminal]);
Dominik Behr4defb362016-01-13 12:36:14 -0800847 terminals[current_terminal] = NULL;
848 current_terminal = 0;
849 return;
850 }
851
Dominik Behrda6df412016-08-02 12:56:42 -0700852 for (unsigned i = 0; i < term_num_terminals; i++) {
Dominik Behr4defb362016-01-13 12:36:14 -0800853 if (terminal == terminals[i]) {
854 current_terminal = i;
855 return;
856 }
857 }
858 LOG(ERROR, "set_current_to: terminal not in array");
859}
Dominik Behr01a7a582016-01-28 17:02:21 -0800860
Dominik Behrda6df412016-08-02 12:56:42 -0700861int term_switch_to(unsigned int vt)
862{
863 terminal_t *terminal;
864 if (vt == term_get_current()) {
865 terminal = term_get_current_terminal();
Dominik Behrf9329912016-08-25 17:31:52 -0700866 if (term_is_valid(terminal)) {
867 if (!term_is_active(terminal))
868 term_activate(terminal);
869 return vt;
870 }
Dominik Behrda6df412016-08-02 12:56:42 -0700871 }
872
873 if (vt >= term_num_terminals)
874 return -EINVAL;
875
876 terminal = term_get_current_terminal();
877 if (term_is_active(terminal))
878 term_deactivate(terminal);
879
880 if (vt == TERM_SPLASH_TERMINAL
881 && !term_get_terminal(TERM_SPLASH_TERMINAL)
882 && !command_flags.enable_vt1) {
883 term_set_current(vt);
884 /* Splash term is already gone, returning to Chrome. */
Dominik Behr33847332016-12-12 17:27:56 -0800885 term_background(false);
Dominik Behrda6df412016-08-02 12:56:42 -0700886 return vt;
887 }
888
889 term_foreground();
890
891 term_set_current(vt);
892 terminal = term_get_current_terminal();
893 if (!terminal) {
894 /* No terminal where we are switching to, create new one. */
895 term_set_current_terminal(term_init(vt, -1));
896 terminal = term_get_current_terminal();
Dominik Behrda6df412016-08-02 12:56:42 -0700897 if (!term_is_valid(terminal)) {
Dominik Behrf9329912016-08-25 17:31:52 -0700898 LOG(ERROR, "Term init failed VT%u.", vt);
Dominik Behrda6df412016-08-02 12:56:42 -0700899 return -1;
900 }
Dominik Behrf9329912016-08-25 17:31:52 -0700901 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700902 } else {
903 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700904 }
905
906 return vt;
907}
908
Dominik Behr01a7a582016-01-28 17:02:21 -0800909void term_monitor_hotplug(void)
910{
911 unsigned int t;
912
Dominik Behr83864df2016-04-21 12:35:08 -0700913 if (in_background) {
914 hotplug_occured = true;
915 return;
916 }
917
Dominik Behr83010f82016-03-18 18:43:08 -0700918 if (!drm_rescan())
919 return;
920
Dominik Behrda6df412016-08-02 12:56:42 -0700921 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr01a7a582016-01-28 17:02:21 -0800922 if (!terminals[t])
923 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700924 if (!terminals[t]->fb)
Dominik Behr01a7a582016-01-28 17:02:21 -0800925 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700926 fb_buffer_destroy(terminals[t]->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700927 font_free();
Dominik Behr83010f82016-03-18 18:43:08 -0700928 }
929
Dominik Behrda6df412016-08-02 12:56:42 -0700930 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr83010f82016-03-18 18:43:08 -0700931 if (!terminals[t])
932 continue;
933 if (!terminals[t]->fb)
934 continue;
935 fb_buffer_init(terminals[t]->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800936 term_resize(terminals[t], 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700937 if (current_terminal == t && terminals[t]->active)
938 fb_setmode(terminals[t]->fb);
939 terminals[t]->term->age = 0;
940 term_redraw(terminals[t]);
Dominik Behr01a7a582016-01-28 17:02:21 -0800941 }
942}
Dominik Behrb1abcba2016-04-14 14:57:21 -0700943
944void term_redrm(terminal_t* terminal)
945{
946 fb_buffer_destroy(terminal->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700947 font_free();
Dominik Behrb1abcba2016-04-14 14:57:21 -0700948 fb_buffer_init(terminal->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800949 term_resize(terminal, 0);
Dominik Behrb1abcba2016-04-14 14:57:21 -0700950 terminal->term->age = 0;
951 term_redraw(terminal);
952}
953
954void term_clear(terminal_t* terminal)
955{
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100956 term_clear_border(terminal);
Dominik Behrb1abcba2016-04-14 14:57:21 -0700957 tsm_screen_erase_screen(terminal->term->screen, false);
958 term_redraw(terminal);
959}
Dominik Behr83864df2016-04-21 12:35:08 -0700960
Haixia Shi95285872016-11-08 15:26:35 -0800961void term_zoom(bool zoom_in)
962{
963 int scaling = font_get_scaling();
964 if (zoom_in && scaling < 4)
965 scaling++;
966 else if (!zoom_in && scaling > 1)
967 scaling--;
968 else
969 return;
970
971 unsigned int t;
972 for (t = 0; t < term_num_terminals; t++) {
973 if (terminals[t])
974 font_free();
975 }
976 for (t = 0; t < term_num_terminals; t++) {
977 terminal_t* term = terminals[t];
978 if (term) {
979 term_resize(term, scaling);
980 term->term->age = 0;
981 term_redraw(term);
982 }
983 }
984}
985
Dominik Behr33847332016-12-12 17:27:56 -0800986/*
987 * Put frecon in background. Give up DRM master.
988 * onetry - if true, do not retry to notify Chrome multiple times. For use at
989 * time when Chrome may be not around yet to receive the message.
990 */
991void term_background(bool onetry)
Dominik Behr83864df2016-04-21 12:35:08 -0700992{
Dominik Behr33847332016-12-12 17:27:56 -0800993 int retry = onetry ? 1 : 5;
Dominik Behr83864df2016-04-21 12:35:08 -0700994 if (in_background)
995 return;
996 in_background = true;
Dominik Behrda3c0102016-06-08 15:05:38 -0700997 drm_dropmaster(NULL);
Dominik Behra818a1e2016-10-26 19:46:22 -0700998 while (!dbus_take_display_ownership() && retry--) {
Dominik Behr33847332016-12-12 17:27:56 -0800999 if (onetry)
1000 break;
Dominik Behra818a1e2016-10-26 19:46:22 -07001001 LOG(ERROR, "Chrome failed to take display ownership. %s",
1002 retry ? "Trying again." : "Giving up, Chrome is probably dead.");
Dominik Behr33847332016-12-12 17:27:56 -08001003 if (retry > 0)
1004 usleep(500 * 1000);
Dominik Behra818a1e2016-10-26 19:46:22 -07001005 }
Dominik Behr83864df2016-04-21 12:35:08 -07001006}
1007
1008void term_foreground(void)
1009{
Dominik Behrda3c0102016-06-08 15:05:38 -07001010 int ret;
Dominik Behr33847332016-12-12 17:27:56 -08001011 int retry = 5;
Dominik Behra818a1e2016-10-26 19:46:22 -07001012
Dominik Behr83864df2016-04-21 12:35:08 -07001013 if (!in_background)
1014 return;
1015 in_background = false;
Dominik Behra818a1e2016-10-26 19:46:22 -07001016
Dominik Behr57b5c722018-08-08 18:52:31 -07001017 /* LOG(INFO, "TIMING: Console switch time start."); */ /* Keep around for timing it in the future. */
Dominik Behra818a1e2016-10-26 19:46:22 -07001018 while (!dbus_release_display_ownership() && retry--) {
1019 LOG(ERROR, "Chrome did not release master. %s",
1020 retry ? "Trying again." : "Frecon will steal master.");
Dominik Behr33847332016-12-12 17:27:56 -08001021 if (retry > 0)
1022 usleep(500 * 1000);
Dominik Behr83864df2016-04-21 12:35:08 -07001023 }
Dominik Behrda3c0102016-06-08 15:05:38 -07001024
Dominik Behr57b5c722018-08-08 18:52:31 -07001025 /* LOG(INFO, "TIMING: Console switch setmaster."); */
Dominik Behrda3c0102016-06-08 15:05:38 -07001026 ret = drm_setmaster(NULL);
Dominik Behrda3c0102016-06-08 15:05:38 -07001027 if (ret < 0)
1028 LOG(ERROR, "Could not set master when switching to foreground %m.");
1029
Dominik Behr83864df2016-04-21 12:35:08 -07001030 if (hotplug_occured) {
1031 hotplug_occured = false;
1032 term_monitor_hotplug();
1033 }
1034}
Dominik Behr1883c042016-04-27 12:31:02 -07001035
1036void term_suspend_done(void* ignore)
1037{
1038 term_monitor_hotplug();
1039}
Dominik Behrda55e6c2017-02-28 18:12:10 -08001040
1041void term_input_enable(terminal_t* terminal, bool input_enable)
1042{
1043 terminal->input_enable = input_enable;
1044}