blob: 7446c665c358a47ef47913338c517ff45598163d [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;
Dominik Behrbb728f32019-09-03 17:52:13 -070039 int w_in_char, h_in_char;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070040};
41
David Sodmanf0a925a2015-05-04 11:19:19 -070042struct _terminal_t {
Dominik Behrda6df412016-08-02 12:56:42 -070043 unsigned vt;
44 bool active;
Dominik Behrda55e6c2017-02-28 18:12:10 -080045 bool input_enable;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080046 uint32_t background;
47 bool background_valid;
Dominik Behr83010f82016-03-18 18:43:08 -070048 fb_t* fb;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080049 struct term* term;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080050 char** exec;
David Sodmanf0a925a2015-05-04 11:19:19 -070051};
52
David Sodman8ef20062015-01-06 09:23:40 -080053
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080054static char* interactive_cmd_line[] = {
David Sodman8ef20062015-01-06 09:23:40 -080055 "/sbin/agetty",
56 "-",
57 "9600",
58 "xterm",
59 NULL
60};
61
Dominik Behr83864df2016-04-21 12:35:08 -070062static bool in_background = false;
63static bool hotplug_occured = false;
64
David Sodman8ef20062015-01-06 09:23:40 -080065
66static void __attribute__ ((noreturn)) term_run_child(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070067{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070068 /* XXX figure out how to fix "top" for xterm-256color */
69 setenv("TERM", "xterm", 1);
Dominik Behr32680e32016-08-16 12:18:41 -070070 if (terminal->exec) {
71 execve(terminal->exec[0], terminal->exec, environ);
72 exit(1);
73 } else {
74 while (1)
75 sleep(1000000);
76 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070077}
78
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080079static int term_draw_cell(struct tsm_screen* screen, uint32_t id,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080080 const uint32_t* ch, size_t len,
81 unsigned int cwidth, unsigned int posx,
82 unsigned int posy,
83 const struct tsm_screen_attr* attr,
84 tsm_age_t age, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070085{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080086 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070087 uint32_t front_color, back_color;
David Sodmanf0a925a2015-05-04 11:19:19 -070088 uint8_t br, bb, bg;
Stéphane Marchesinedece332015-12-14 15:10:58 -080089 uint32_t luminance;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070090
David Sodmanbbcb0522014-09-19 10:34:07 -070091 if (age && terminal->term->age && age <= terminal->term->age)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070092 return 0;
93
David Sodmanf0a925a2015-05-04 11:19:19 -070094 if (terminal->background_valid) {
95 br = (terminal->background >> 16) & 0xFF;
96 bg = (terminal->background >> 8) & 0xFF;
97 bb = (terminal->background) & 0xFF;
Stéphane Marchesinedece332015-12-14 15:10:58 -080098 luminance = (3 * br + bb + 4 * bg) >> 3;
David Sodmanf0a925a2015-05-04 11:19:19 -070099
Stéphane Marchesinedece332015-12-14 15:10:58 -0800100 /*
101 * FIXME: black is chosen on a dark background, but it uses the
102 * default color for light backgrounds
103 */
104 if (luminance > 128) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700105 front_color = 0;
106 back_color = terminal->background;
107 } else {
108 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
109 back_color = terminal->background;
110 }
111 } else {
112 front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb;
113 back_color = (attr->br << 16) | (attr->bg << 8) | attr->bb;
114 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700115
116 if (attr->inverse) {
117 uint32_t tmp = front_color;
118 front_color = back_color;
119 back_color = tmp;
120 }
121
122 if (len)
Dominik Behrbb728f32019-09-03 17:52:13 -0700123 font_render(terminal->fb, posx, posy, *ch,
David Sodmanbbcb0522014-09-19 10:34:07 -0700124 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700125 else
Dominik Behrbb728f32019-09-03 17:52:13 -0700126 font_fillchar(terminal->fb, posx, posy,
David Sodmanbbcb0522014-09-19 10:34:07 -0700127 front_color, back_color);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700128
129 return 0;
130}
131
Stéphane Marchesine2a46cd2016-01-07 16:45:24 -0800132static void term_redraw(terminal_t* terminal)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700133{
Dominik Behrbb728f32019-09-03 17:52:13 -0700134 if (fb_lock(terminal->fb)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700135 terminal->term->age =
136 tsm_screen_draw(terminal->term->screen, term_draw_cell, terminal);
Dominik Behr83010f82016-03-18 18:43:08 -0700137 fb_unlock(terminal->fb);
David Sodmanbbcb0522014-09-19 10:34:07 -0700138 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700139}
140
David Sodmanbbcb0522014-09-19 10:34:07 -0700141void term_key_event(terminal_t* terminal, uint32_t keysym, int32_t unicode)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700142{
Dominik Behrda55e6c2017-02-28 18:12:10 -0800143 if (!terminal->input_enable)
144 return;
145
David Sodmanbbcb0522014-09-19 10:34:07 -0700146 if (tsm_vte_handle_keyboard(terminal->term->vte, keysym, 0, 0, unicode))
147 tsm_screen_sb_reset(terminal->term->screen);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700148
David Sodmanbbcb0522014-09-19 10:34:07 -0700149 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700150}
151
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800152static void term_read_cb(struct shl_pty* pty, char* u8, size_t len, void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700153{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800154 terminal_t* terminal = (terminal_t*)data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700155
David Sodmanbbcb0522014-09-19 10:34:07 -0700156 tsm_vte_input(terminal->term->vte, u8, len);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700157
David Sodmanbbcb0522014-09-19 10:34:07 -0700158 term_redraw(terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700159}
160
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800161static void term_write_cb(struct tsm_vte* vte, const char* u8, size_t len,
162 void* data)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700163{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800164 struct term* term = data;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700165 int r;
166
167 r = shl_pty_write(term->pty, u8, len);
168 if (r < 0)
David Sodmanbbcb0522014-09-19 10:34:07 -0700169 LOG(ERROR, "OOM in pty-write (%d)", r);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700170
171 shl_pty_dispatch(term->pty);
172}
173
Dominik Behrd2530902016-05-05 14:01:06 -0700174static void term_esc_show_image(terminal_t* terminal, char* params)
175{
176 char* tok;
177 image_t* image;
178 int status;
179
180 image = image_create();
181 if (!image) {
182 LOG(ERROR, "Out of memory when creating an image.\n");
183 return;
184 }
185 for (tok = strtok(params, ";"); tok; tok = strtok(NULL, ";")) {
186 if (strncmp("file=", tok, 5) == 0) {
187 image_set_filename(image, tok + 5);
188 } else if (strncmp("location=", tok, 9) == 0) {
189 uint32_t x, y;
190 if (sscanf(tok + 9, "%u,%u", &x, &y) != 2) {
191 LOG(ERROR, "Error parsing image location.\n");
192 goto done;
193 }
194 image_set_location(image, x, y);
195 } else if (strncmp("offset=", tok, 7) == 0) {
196 int32_t x, y;
197 if (sscanf(tok + 7, "%d,%d", &x, &y) != 2) {
198 LOG(ERROR, "Error parsing image offset.\n");
199 goto done;
200 }
201 image_set_offset(image, x, y);
202 } else if (strncmp("scale=", tok, 6) == 0) {
203 uint32_t s;
204 if (sscanf(tok + 6, "%u", &s) != 1) {
205 LOG(ERROR, "Error parsing image scale.\n");
206 goto done;
207 }
208 if (s == 0)
209 s = image_get_auto_scale(term_getfb(terminal));
210 image_set_scale(image, s);
211 }
212 }
213
214 status = image_load_image_from_file(image);
215 if (status != 0) {
216 LOG(WARNING, "Term ESC image_load_image_from_file %s failed: %d:%s.",
217 image_get_filename(image), status, strerror(status));
218 } else {
219 term_show_image(terminal, image);
220 }
221done:
222 image_destroy(image);
223}
224
225static void term_esc_draw_box(terminal_t* terminal, char* params)
226{
227 char* tok;
228 uint32_t color = 0;
229 uint32_t w = 1;
230 uint32_t h = 1;
231 uint32_t locx, locy;
232 bool use_location = false;
233 int32_t offx, offy;
234 bool use_offset = false;
235 uint32_t scale = 1;
Dominik Behrbb728f32019-09-03 17:52:13 -0700236 fb_stepper_t s;
Dominik Behrd2530902016-05-05 14:01:06 -0700237 int32_t startx, starty;
Dominik Behrd2530902016-05-05 14:01:06 -0700238
239 for (tok = strtok(params, ";"); tok; tok = strtok(NULL, ";")) {
240 if (strncmp("color=", tok, 6) == 0) {
241 color = strtoul(tok + 6, NULL, 0);
242 } else if (strncmp("size=", tok, 5) == 0) {
243 if (sscanf(tok + 5, "%u,%u", &w, &h) != 2) {
244 LOG(ERROR, "Error parsing box size.\n");
245 goto done;
246 }
247 } else if (strncmp("location=", tok, 9) == 0) {
248 if (sscanf(tok + 9, "%u,%u", &locx, &locy) != 2) {
249 LOG(ERROR, "Error parsing box location.\n");
250 goto done;
251 }
252 use_location = true;
253 } else if (strncmp("offset=", tok, 7) == 0) {
254 if (sscanf(tok + 7, "%d,%d", &offx, &offy) != 2) {
255 LOG(ERROR, "Error parsing box offset.\n");
256 goto done;
257 }
258 use_offset = true;
259 } else if (strncmp("scale=", tok, 6) == 0) {
260 if (sscanf(tok + 6, "%u", &scale) != 1) {
261 LOG(ERROR, "Error parsing box scale.\n");
262 goto done;
263 }
264 if (scale == 0)
265 scale = image_get_auto_scale(term_getfb(terminal));
266 }
267 }
268
269 w *= scale;
270 h *= scale;
271 offx *= scale;
272 offy *= scale;
273
Dominik Behrbb728f32019-09-03 17:52:13 -0700274 if (!fb_lock(terminal->fb))
Dominik Behrd2530902016-05-05 14:01:06 -0700275 goto done;
276
277 if (use_offset && use_location) {
278 LOG(WARNING, "Box offset and location set, using location.");
279 use_offset = false;
280 }
281
282 if (use_location) {
283 startx = locx;
284 starty = locy;
285 } else {
Mattias Nissler066044c2017-07-04 15:23:02 +0200286 startx = (fb_getwidth(terminal->fb) - w)/2;
287 starty = (fb_getheight(terminal->fb) - h)/2;
Dominik Behrd2530902016-05-05 14:01:06 -0700288 }
289
290 if (use_offset) {
291 startx += offx;
292 starty += offy;
293 }
294
Dominik Behrbb728f32019-09-03 17:52:13 -0700295 if (!fb_stepper_init(&s, terminal->fb, startx, starty, w, h))
Dominik Behrd2530902016-05-05 14:01:06 -0700296 goto done_fb;
Dominik Behrd2530902016-05-05 14:01:06 -0700297
Dominik Behrbb728f32019-09-03 17:52:13 -0700298 do {
299 do {
300 } while (fb_stepper_step_x(&s, color));
301 } while (fb_stepper_step_y(&s));
302
Dominik Behrd2530902016-05-05 14:01:06 -0700303done_fb:
304 fb_unlock(terminal->fb);
305done:
306 ;
307}
308
Dominik Behrda55e6c2017-02-28 18:12:10 -0800309static void term_esc_input(terminal_t* terminal, char* params)
310{
311 if (strcmp(params, "1") == 0 ||
312 strcasecmp(params, "on") == 0 ||
313 strcasecmp(params, "true") == 0)
314 term_input_enable(terminal, true);
315 else if (strcmp(params, "0") == 0 ||
316 strcasecmp(params, "off") == 0 ||
317 strcasecmp(params, "false") == 0)
318 term_input_enable(terminal, false);
319 else
320 LOG(ERROR, "Invalid parameter for input escape.\n");
321}
322
Dominik Behr3a2c61c2017-06-22 15:13:48 -0700323/*
324 * Assume all one or two digit sequences followed by ; are xterm OSC escapes.
325 */
326static bool is_xterm_osc(char *osc)
327{
328 if (isdigit(osc[0])) {
329 if (osc[1] == ';')
330 return true;
331 if (isdigit(osc[1]) && osc[2] == ';')
332 return true;
333 }
334 return false;
335}
336
Dominik Behrd2530902016-05-05 14:01:06 -0700337static void term_osc_cb(struct tsm_vte *vte, const uint32_t *osc_string,
338 size_t osc_len, void *data)
339{
340 terminal_t* terminal = (terminal_t*)data;
341 size_t i;
342 char *osc;
343
344 for (i = 0; i < osc_len; i++)
345 if (osc_string[i] >= 128)
346 return; /* we only want to deal with ASCII */
347
348 osc = malloc(osc_len + 1);
349 if (!osc) {
Dominik Behr3a2c61c2017-06-22 15:13:48 -0700350 LOG(WARNING, "Out of memory when processing OSC.\n");
Dominik Behrd2530902016-05-05 14:01:06 -0700351 return;
352 }
353
354 for (i = 0; i < osc_len; i++)
355 osc[i] = (char)osc_string[i];
356 osc[i] = '\0';
357
358 if (strncmp(osc, "image:", 6) == 0)
359 term_esc_show_image(terminal, osc + 6);
360 else if (strncmp(osc, "box:", 4) == 0)
361 term_esc_draw_box(terminal, osc + 4);
Dominik Behrda55e6c2017-02-28 18:12:10 -0800362 else if (strncmp(osc, "input:", 6) == 0)
363 term_esc_input(terminal, osc + 6);
Dominik Behr3a2c61c2017-06-22 15:13:48 -0700364 else if (is_xterm_osc(osc))
365 ; /* Ignore it. */
Dominik Behrd2530902016-05-05 14:01:06 -0700366 else
367 LOG(WARNING, "Unknown OSC escape sequence \"%s\", ignoring.", osc);
368
369 free(osc);
370}
371
Dominik Behr00003502014-08-15 16:42:37 -0700372#ifdef __clang__
373__attribute__((__format__ (__printf__, 7, 0)))
374#endif
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800375static void log_tsm(void* data, const char* file, int line, const char* fn,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800376 const char* subs, unsigned int sev, const char* format,
377 va_list args)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700378{
Chris Morin255d9f02019-02-04 23:29:27 -0800379 char buffer[KMSG_LINE_MAX];
380 int len = snprintf(buffer, KMSG_LINE_MAX, "<%i>frecon[%d]: %s: ", sev,
381 getpid(), subs);
382 if (len < 0)
383 return;
384 if (len < KMSG_LINE_MAX - 1)
385 vsnprintf(buffer+len, KMSG_LINE_MAX - len, format, args);
386 fprintf(stderr, "%s\n", buffer);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700387}
388
Haixia Shi95285872016-11-08 15:26:35 -0800389static int term_resize(terminal_t* term, int scaling)
Stéphane Marchesin78310662016-01-06 16:09:39 -0800390{
391 uint32_t char_width, char_height;
392 int status;
393
Haixia Shi95285872016-11-08 15:26:35 -0800394 if (!scaling)
395 scaling = fb_getscaling(term->fb);
396
397 font_init(scaling);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800398 font_get_size(&char_width, &char_height);
399
Dominik Behrbb728f32019-09-03 17:52:13 -0700400 term->term->w_in_char = fb_getwidth(term->fb) / char_width;
401 term->term->h_in_char = fb_getheight(term->fb) / char_height;
Stéphane Marchesin78310662016-01-06 16:09:39 -0800402
403 status = tsm_screen_resize(term->term->screen,
Dominik Behrbb728f32019-09-03 17:52:13 -0700404 term->term->w_in_char, term->term->h_in_char);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800405 if (status < 0) {
406 font_free();
407 return -1;
408 }
409
Dominik Behrbb728f32019-09-03 17:52:13 -0700410 status = shl_pty_resize(term->term->pty, term->term->w_in_char,
411 term->term->h_in_char);
Stéphane Marchesin78310662016-01-06 16:09:39 -0800412 if (status < 0) {
413 font_free();
414 return -1;
415 }
416
417 return 0;
418}
419
Dominik Behrda6df412016-08-02 12:56:42 -0700420void term_set_num_terminals(unsigned new_num)
421{
422 if (new_num < 1)
423 term_num_terminals = 1;
424 else if (new_num > TERM_MAX_TERMINALS)
425 term_num_terminals = TERM_MAX_TERMINALS;
426 else
427 term_num_terminals = new_num;
428}
429
430static bool term_is_interactive(unsigned int vt)
431{
432 if (command_flags.no_login)
433 return false;
434
435 if (vt == TERM_SPLASH_TERMINAL)
436 return command_flags.enable_vt1;
437
438 return true;
439}
440
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100441/*
442 * Set the area not covered by any characters, possibly existing on the right
443 * side and bottom of the screen, to the background color.
444 */
445static void term_clear_border(terminal_t* terminal)
446{
Dominik Behrbb728f32019-09-03 17:52:13 -0700447 fb_stepper_t s;
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100448 uint32_t char_width, char_height;
449 font_get_size(&char_width, &char_height);
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100450
Dominik Behrbb728f32019-09-03 17:52:13 -0700451 if (!fb_lock(terminal->fb))
452 return;
453
454 if (fb_stepper_init(&s, terminal->fb,
455 terminal->term->w_in_char * char_width, 0,
456 fb_getwidth(terminal->fb) - terminal->term->w_in_char * char_width, terminal->term->h_in_char * char_height)) {
457 do {
458 do {
459 } while (fb_stepper_step_x(&s, terminal->background));
460 } while (fb_stepper_step_y(&s));
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100461 }
Dominik Behrbb728f32019-09-03 17:52:13 -0700462
463 if (fb_stepper_init(&s, terminal->fb,
464 0, terminal->term->h_in_char * char_height,
465 fb_getwidth(terminal->fb), fb_getheight(terminal->fb) - terminal->term->h_in_char * char_height)) {
466 do {
467 do {
468 } while (fb_stepper_step_x(&s, terminal->background));
469 } while (fb_stepper_step_y(&s));
470 }
471
472 fb_unlock(terminal->fb);
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100473}
474
Dominik Behrda6df412016-08-02 12:56:42 -0700475terminal_t* term_init(unsigned vt, int pts_fd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700476{
477 const int scrollback_size = 200;
David Sodmanbbcb0522014-09-19 10:34:07 -0700478 int status;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800479 terminal_t* new_terminal;
Dominik Behrda6df412016-08-02 12:56:42 -0700480 bool interactive = term_is_interactive(vt);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700481
David Sodmanbbcb0522014-09-19 10:34:07 -0700482 new_terminal = (terminal_t*)calloc(1, sizeof(*new_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800483 if (!new_terminal)
484 return NULL;
David Sodmanbbcb0522014-09-19 10:34:07 -0700485
Dominik Behrda6df412016-08-02 12:56:42 -0700486 new_terminal->vt = vt;
David Sodmanf0a925a2015-05-04 11:19:19 -0700487 new_terminal->background_valid = false;
Dominik Behrda55e6c2017-02-28 18:12:10 -0800488 new_terminal->input_enable = true;
David Sodmanf0a925a2015-05-04 11:19:19 -0700489
Dominik Behr83010f82016-03-18 18:43:08 -0700490 new_terminal->fb = fb_init();
David Sodmanf0a925a2015-05-04 11:19:19 -0700491
Dominik Behr83010f82016-03-18 18:43:08 -0700492 if (!new_terminal->fb) {
Dominik Behrf9329912016-08-25 17:31:52 -0700493 LOG(ERROR, "Failed to create fb on VT%u.", vt);
David Sodmanbf3f2842014-11-12 08:26:58 -0800494 term_close(new_terminal);
495 return NULL;
496 }
497
498 new_terminal->term = (struct term*)calloc(1, sizeof(*new_terminal->term));
499 if (!new_terminal->term) {
500 term_close(new_terminal);
501 return NULL;
502 }
503
Dominik Behrda6df412016-08-02 12:56:42 -0700504 if (interactive)
David Sodman8ef20062015-01-06 09:23:40 -0800505 new_terminal->exec = interactive_cmd_line;
506 else
Dominik Behr32680e32016-08-16 12:18:41 -0700507 new_terminal->exec = NULL;
David Sodman8ef20062015-01-06 09:23:40 -0800508
David Sodmanbbcb0522014-09-19 10:34:07 -0700509 status = tsm_screen_new(&new_terminal->term->screen,
510 log_tsm, new_terminal->term);
zhuo-hao471f1e22015-08-12 14:55:56 +0800511 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700512 LOG(ERROR, "Failed to create new screen on 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
David Sodmanbbcb0522014-09-19 10:34:07 -0700517 tsm_screen_set_max_sb(new_terminal->term->screen, scrollback_size);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700518
David Sodmanbbcb0522014-09-19 10:34:07 -0700519 status = tsm_vte_new(&new_terminal->term->vte, new_terminal->term->screen,
520 term_write_cb, new_terminal->term, log_tsm, new_terminal->term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700521
David Sodmanbbcb0522014-09-19 10:34:07 -0700522 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700523 LOG(ERROR, "Failed to create new VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700524 term_close(new_terminal);
525 return NULL;
526 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700527
Dominik Behrda55e6c2017-02-28 18:12:10 -0800528 if (command_flags.enable_osc)
Dominik Behrd2530902016-05-05 14:01:06 -0700529 tsm_vte_set_osc_cb(new_terminal->term->vte, term_osc_cb, (void *)new_terminal);
530
David Sodmanbbcb0522014-09-19 10:34:07 -0700531 new_terminal->term->pty_bridge = shl_pty_bridge_new();
532 if (new_terminal->term->pty_bridge < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700533 LOG(ERROR, "Failed to create pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700534 term_close(new_terminal);
535 return NULL;
536 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700537
David Sodmanbbcb0522014-09-19 10:34:07 -0700538 status = shl_pty_open(&new_terminal->term->pty,
Dominik Behrda6df412016-08-02 12:56:42 -0700539 term_read_cb, new_terminal, 1, 1, pts_fd);
David Sodman8ef20062015-01-06 09:23:40 -0800540
David Sodmanbbcb0522014-09-19 10:34:07 -0700541 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700542 LOG(ERROR, "Failed to open pty on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700543 term_close(new_terminal);
544 return NULL;
545 } else if (status == 0) {
David Sodman8ef20062015-01-06 09:23:40 -0800546 term_run_child(new_terminal);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700547 exit(1);
548 }
549
Dominik Behrda6df412016-08-02 12:56:42 -0700550 status = mkdir(FRECON_RUN_DIR, S_IRWXU);
551 if (status == 0 || (status < 0 && errno == EEXIST)) {
552 char path[32];
553 snprintf(path, sizeof(path), FRECON_VT_PATH, vt);
Dominik Behrb23b05b2016-08-15 16:29:02 -0700554 unlink(path); /* In case it already exists. Ignore return codes. */
Dominik Behrda6df412016-08-02 12:56:42 -0700555 if (symlink(ptsname(shl_pty_get_fd(new_terminal->term->pty)), path) < 0)
556 LOG(ERROR, "Failed to symlink pts name %s to %s, %d:%s",
557 path,
558 ptsname(shl_pty_get_fd(new_terminal->term->pty)),
559 errno, strerror(errno));
560 }
561
David Sodmanbbcb0522014-09-19 10:34:07 -0700562 status = shl_pty_bridge_add(new_terminal->term->pty_bridge, new_terminal->term->pty);
563 if (status) {
Dominik Behrf9329912016-08-25 17:31:52 -0700564 LOG(ERROR, "Failed to add pty bridge on VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700565 term_close(new_terminal);
566 return NULL;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700567 }
568
David Sodmanbbcb0522014-09-19 10:34:07 -0700569 new_terminal->term->pid = shl_pty_get_child(new_terminal->term->pty);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700570
Haixia Shi95285872016-11-08 15:26:35 -0800571 status = term_resize(new_terminal, 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700572
David Sodmanbbcb0522014-09-19 10:34:07 -0700573 if (status < 0) {
Dominik Behrf9329912016-08-25 17:31:52 -0700574 LOG(ERROR, "Failed to resize VT%u.", vt);
David Sodmanbbcb0522014-09-19 10:34:07 -0700575 term_close(new_terminal);
576 return NULL;
577 }
David Sodman8ef20062015-01-06 09:23:40 -0800578
David Sodmanbbcb0522014-09-19 10:34:07 -0700579 return new_terminal;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700580}
581
David Sodman8ef20062015-01-06 09:23:40 -0800582void term_activate(terminal_t* terminal)
583{
Dominik Behr4defb362016-01-13 12:36:14 -0800584 term_set_current_to(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800585 terminal->active = true;
Dominik Behr83010f82016-03-18 18:43:08 -0700586 fb_setmode(terminal->fb);
David Sodman8ef20062015-01-06 09:23:40 -0800587 term_redraw(terminal);
588}
589
David Sodmanf0a925a2015-05-04 11:19:19 -0700590void term_deactivate(terminal_t* terminal)
591{
592 if (!terminal->active)
593 return;
594
David Sodmanf0a925a2015-05-04 11:19:19 -0700595 terminal->active = false;
David Sodmanf0a925a2015-05-04 11:19:19 -0700596}
597
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800598void term_close(terminal_t* term)
David Sodmanbbcb0522014-09-19 10:34:07 -0700599{
Dominik Behrda6df412016-08-02 12:56:42 -0700600 char path[32];
David Sodmanbbcb0522014-09-19 10:34:07 -0700601 if (!term)
602 return;
603
Dominik Behrda6df412016-08-02 12:56:42 -0700604 snprintf(path, sizeof(path), FRECON_VT_PATH, term->vt);
605 unlink(path);
606
Dominik Behr83010f82016-03-18 18:43:08 -0700607 if (term->fb) {
608 fb_close(term->fb);
609 term->fb = NULL;
David Sodmanbf3f2842014-11-12 08:26:58 -0800610 }
611
David Sodmanbbcb0522014-09-19 10:34:07 -0700612 if (term->term) {
Dominik Behrda6df412016-08-02 12:56:42 -0700613 if (term->term->pty) {
614 if (term->term->pty_bridge >= 0) {
615 shl_pty_bridge_remove(term->term->pty_bridge, term->term->pty);
616 shl_pty_bridge_free(term->term->pty_bridge);
617 term->term->pty_bridge = -1;
618 }
619 shl_pty_close(term->term->pty);
620 term->term->pty = NULL;
621 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700622 free(term->term);
623 term->term = NULL;
624 }
625
Haixia Shi95d680e2015-04-27 20:29:17 -0700626 font_free();
David Sodmanbbcb0522014-09-19 10:34:07 -0700627 free(term);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700628}
David Sodmanbf3f2842014-11-12 08:26:58 -0800629
630bool term_is_child_done(terminal_t* terminal)
631{
632 int status;
633 int ret;
634 ret = waitpid(terminal->term->pid, &status, WNOHANG);
635
David Sodmanf0a925a2015-05-04 11:19:19 -0700636 if ((ret == -1) && (errno == ECHILD)) {
637 return false;
638 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800639 return ret != 0;
640}
641
642void term_page_up(terminal_t* terminal)
643{
644 tsm_screen_sb_page_up(terminal->term->screen, 1);
645 term_redraw(terminal);
646}
647
648void term_page_down(terminal_t* terminal)
649{
650 tsm_screen_sb_page_down(terminal->term->screen, 1);
651 term_redraw(terminal);
652}
653
654void term_line_up(terminal_t* terminal)
655{
656 tsm_screen_sb_up(terminal->term->screen, 1);
657 term_redraw(terminal);
658}
659
660void term_line_down(terminal_t* terminal)
661{
662 tsm_screen_sb_down(terminal->term->screen, 1);
663 term_redraw(terminal);
664}
665
666bool term_is_valid(terminal_t* terminal)
667{
668 return ((terminal != NULL) && (terminal->term != NULL));
669}
670
671int term_fd(terminal_t* terminal)
672{
673 if (term_is_valid(terminal))
674 return terminal->term->pty_bridge;
675 else
676 return -1;
677}
678
679void term_dispatch_io(terminal_t* terminal, fd_set* read_set)
680{
681 if (term_is_valid(terminal))
682 if (FD_ISSET(terminal->term->pty_bridge, read_set))
683 shl_pty_bridge_dispatch(terminal->term->pty_bridge, 0);
684}
685
686bool term_exception(terminal_t* terminal, fd_set* exception_set)
687{
688 if (term_is_valid(terminal)) {
689 if (terminal->term->pty_bridge >= 0) {
690 return FD_ISSET(terminal->term->pty_bridge,
691 exception_set);
692 }
693 }
694
695 return false;
696}
697
698bool term_is_active(terminal_t* terminal)
699{
700 if (term_is_valid(terminal))
701 return terminal->active;
702
703 return false;
704}
705
Dominik Behrb1abcba2016-04-14 14:57:21 -0700706void term_add_fds(terminal_t* terminal, fd_set* read_set, fd_set* exception_set, int* maxfd)
David Sodmanbf3f2842014-11-12 08:26:58 -0800707{
708 if (term_is_valid(terminal)) {
709 if (terminal->term->pty_bridge >= 0) {
Dominik Behrd7112672016-01-20 16:59:34 -0800710 *maxfd = MAX(*maxfd, terminal->term->pty_bridge);
David Sodmanbf3f2842014-11-12 08:26:58 -0800711 FD_SET(terminal->term->pty_bridge, read_set);
712 FD_SET(terminal->term->pty_bridge, exception_set);
713 }
714 }
715}
David Sodman8ef20062015-01-06 09:23:40 -0800716
717const char* term_get_ptsname(terminal_t* terminal)
718{
719 return ptsname(shl_pty_get_fd(terminal->term->pty));
720}
David Sodmanf0a925a2015-05-04 11:19:19 -0700721
722void term_set_background(terminal_t* terminal, uint32_t bg)
723{
724 terminal->background = bg;
725 terminal->background_valid = true;
726}
727
728int term_show_image(terminal_t* terminal, image_t* image)
729{
Dominik Behr83010f82016-03-18 18:43:08 -0700730 return image_show(image, terminal->fb);
David Sodmanf0a925a2015-05-04 11:19:19 -0700731}
732
733void term_write_message(terminal_t* terminal, char* message)
734{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800735 FILE* fp;
David Sodmanf0a925a2015-05-04 11:19:19 -0700736
737 fp = fopen(term_get_ptsname(terminal), "w");
738 if (fp) {
739 fputs(message, fp);
740 fclose(fp);
741 }
742}
743
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800744static void term_hide_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700745{
746 term_write_message(terminal, "\033[?25l");
747}
748
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800749__attribute__ ((unused))
750static void term_show_cursor(terminal_t* terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700751{
752 term_write_message(terminal, "\033[?25h");
753}
David Sodman30a94ef2015-07-26 17:37:12 -0700754
Dominik Behr83010f82016-03-18 18:43:08 -0700755fb_t* term_getfb(terminal_t* terminal)
David Sodman30a94ef2015-07-26 17:37:12 -0700756{
Dominik Behr83010f82016-03-18 18:43:08 -0700757 return terminal->fb;
David Sodman30a94ef2015-07-26 17:37:12 -0700758}
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800759
760terminal_t* term_get_terminal(int num)
761{
762 return terminals[num];
763}
764
765void term_set_terminal(int num, terminal_t* terminal)
766{
767 terminals[num] = terminal;
768}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800769
Dominik Behrda6df412016-08-02 12:56:42 -0700770int term_create_splash_term(int pts_fd)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800771{
Dominik Behrda6df412016-08-02 12:56:42 -0700772 terminal_t* terminal = term_init(TERM_SPLASH_TERMINAL, pts_fd);
773
774 if (!terminal) {
775 LOG(ERROR, "Could not create splash term.");
776 return -1;
777 }
778 term_set_terminal(TERM_SPLASH_TERMINAL, terminal);
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800779
780 // Hide the cursor on the splash screen
Dominik Behrda6df412016-08-02 12:56:42 -0700781 term_hide_cursor(terminal);
782 return 0;
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800783}
784
Dominik Behrda6df412016-08-02 12:56:42 -0700785void term_destroy_splash_term(void)
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800786{
Dominik Behrda6df412016-08-02 12:56:42 -0700787 terminal_t *terminal;
788 if (command_flags.enable_vt1) {
789 return;
790 }
Jacek Fedorynski83776b72019-03-06 22:56:56 +0100791 terminal = term_get_terminal(TERM_SPLASH_TERMINAL);
Dominik Behrda6df412016-08-02 12:56:42 -0700792 term_set_terminal(TERM_SPLASH_TERMINAL, NULL);
793 term_close(terminal);
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800794}
Stéphane Marchesinf75c8512016-01-07 16:53:21 -0800795
Dominik Behr4defb362016-01-13 12:36:14 -0800796void term_set_current(uint32_t t)
797{
Dominik Behrda6df412016-08-02 12:56:42 -0700798 if (t >= TERM_MAX_TERMINALS)
799 LOG(ERROR, "set_current: larger than array size");
800 else
801 if (t >= term_num_terminals)
802 LOG(ERROR, "set_current: larger than num terminals");
Dominik Behr4defb362016-01-13 12:36:14 -0800803 else
804 current_terminal = t;
805}
806
807uint32_t term_get_current(void)
808{
809 return current_terminal;
810}
811
812terminal_t *term_get_current_terminal(void)
813{
814 return terminals[current_terminal];
815}
816
Dominik Behrb1abcba2016-04-14 14:57:21 -0700817void term_set_current_terminal(terminal_t* terminal)
Dominik Behr4defb362016-01-13 12:36:14 -0800818{
819 terminals[current_terminal] = terminal;
820}
821
822void term_set_current_to(terminal_t* terminal)
823{
824 if (!terminal) {
Haixia Shi95285872016-11-08 15:26:35 -0800825 if (terminals[current_terminal])
826 term_close(terminals[current_terminal]);
Dominik Behr4defb362016-01-13 12:36:14 -0800827 terminals[current_terminal] = NULL;
828 current_terminal = 0;
829 return;
830 }
831
Dominik Behrda6df412016-08-02 12:56:42 -0700832 for (unsigned i = 0; i < term_num_terminals; i++) {
Dominik Behr4defb362016-01-13 12:36:14 -0800833 if (terminal == terminals[i]) {
834 current_terminal = i;
835 return;
836 }
837 }
838 LOG(ERROR, "set_current_to: terminal not in array");
839}
Dominik Behr01a7a582016-01-28 17:02:21 -0800840
Dominik Behrda6df412016-08-02 12:56:42 -0700841int term_switch_to(unsigned int vt)
842{
843 terminal_t *terminal;
844 if (vt == term_get_current()) {
845 terminal = term_get_current_terminal();
Dominik Behrf9329912016-08-25 17:31:52 -0700846 if (term_is_valid(terminal)) {
847 if (!term_is_active(terminal))
848 term_activate(terminal);
849 return vt;
850 }
Dominik Behrda6df412016-08-02 12:56:42 -0700851 }
852
853 if (vt >= term_num_terminals)
854 return -EINVAL;
855
856 terminal = term_get_current_terminal();
857 if (term_is_active(terminal))
858 term_deactivate(terminal);
859
860 if (vt == TERM_SPLASH_TERMINAL
861 && !term_get_terminal(TERM_SPLASH_TERMINAL)
862 && !command_flags.enable_vt1) {
863 term_set_current(vt);
864 /* Splash term is already gone, returning to Chrome. */
Dominik Behr33847332016-12-12 17:27:56 -0800865 term_background(false);
Dominik Behrda6df412016-08-02 12:56:42 -0700866 return vt;
867 }
868
869 term_foreground();
870
871 term_set_current(vt);
872 terminal = term_get_current_terminal();
873 if (!terminal) {
874 /* No terminal where we are switching to, create new one. */
875 term_set_current_terminal(term_init(vt, -1));
876 terminal = term_get_current_terminal();
Dominik Behrda6df412016-08-02 12:56:42 -0700877 if (!term_is_valid(terminal)) {
Dominik Behrf9329912016-08-25 17:31:52 -0700878 LOG(ERROR, "Term init failed VT%u.", vt);
Dominik Behrda6df412016-08-02 12:56:42 -0700879 return -1;
880 }
Dominik Behrf9329912016-08-25 17:31:52 -0700881 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700882 } else {
883 term_activate(terminal);
Dominik Behrda6df412016-08-02 12:56:42 -0700884 }
885
886 return vt;
887}
888
Dominik Behr01a7a582016-01-28 17:02:21 -0800889void term_monitor_hotplug(void)
890{
891 unsigned int t;
892
Dominik Behr83864df2016-04-21 12:35:08 -0700893 if (in_background) {
894 hotplug_occured = true;
895 return;
896 }
897
Dominik Behr83010f82016-03-18 18:43:08 -0700898 if (!drm_rescan())
899 return;
900
Dominik Behrda6df412016-08-02 12:56:42 -0700901 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr01a7a582016-01-28 17:02:21 -0800902 if (!terminals[t])
903 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700904 if (!terminals[t]->fb)
Dominik Behr01a7a582016-01-28 17:02:21 -0800905 continue;
Dominik Behr83010f82016-03-18 18:43:08 -0700906 fb_buffer_destroy(terminals[t]->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700907 font_free();
Dominik Behr83010f82016-03-18 18:43:08 -0700908 }
909
Dominik Behrda6df412016-08-02 12:56:42 -0700910 for (t = 0; t < term_num_terminals; t++) {
Dominik Behr83010f82016-03-18 18:43:08 -0700911 if (!terminals[t])
912 continue;
913 if (!terminals[t]->fb)
914 continue;
915 fb_buffer_init(terminals[t]->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800916 term_resize(terminals[t], 0);
Dominik Behr83010f82016-03-18 18:43:08 -0700917 if (current_terminal == t && terminals[t]->active)
918 fb_setmode(terminals[t]->fb);
919 terminals[t]->term->age = 0;
920 term_redraw(terminals[t]);
Dominik Behr01a7a582016-01-28 17:02:21 -0800921 }
922}
Dominik Behrb1abcba2016-04-14 14:57:21 -0700923
924void term_redrm(terminal_t* terminal)
925{
926 fb_buffer_destroy(terminal->fb);
Dominik Behra3f65712016-04-25 17:42:14 -0700927 font_free();
Dominik Behrb1abcba2016-04-14 14:57:21 -0700928 fb_buffer_init(terminal->fb);
Haixia Shi95285872016-11-08 15:26:35 -0800929 term_resize(terminal, 0);
Dominik Behrb1abcba2016-04-14 14:57:21 -0700930 terminal->term->age = 0;
931 term_redraw(terminal);
932}
933
934void term_clear(terminal_t* terminal)
935{
Jacek Fedorynski9a0c4222018-11-17 19:13:01 +0100936 term_clear_border(terminal);
Dominik Behrb1abcba2016-04-14 14:57:21 -0700937 tsm_screen_erase_screen(terminal->term->screen, false);
938 term_redraw(terminal);
939}
Dominik Behr83864df2016-04-21 12:35:08 -0700940
Haixia Shi95285872016-11-08 15:26:35 -0800941void term_zoom(bool zoom_in)
942{
943 int scaling = font_get_scaling();
944 if (zoom_in && scaling < 4)
945 scaling++;
946 else if (!zoom_in && scaling > 1)
947 scaling--;
948 else
949 return;
950
951 unsigned int t;
952 for (t = 0; t < term_num_terminals; t++) {
953 if (terminals[t])
954 font_free();
955 }
956 for (t = 0; t < term_num_terminals; t++) {
957 terminal_t* term = terminals[t];
958 if (term) {
959 term_resize(term, scaling);
960 term->term->age = 0;
961 term_redraw(term);
962 }
963 }
964}
965
Dominik Behr33847332016-12-12 17:27:56 -0800966/*
967 * Put frecon in background. Give up DRM master.
968 * onetry - if true, do not retry to notify Chrome multiple times. For use at
969 * time when Chrome may be not around yet to receive the message.
970 */
971void term_background(bool onetry)
Dominik Behr83864df2016-04-21 12:35:08 -0700972{
Dominik Behr33847332016-12-12 17:27:56 -0800973 int retry = onetry ? 1 : 5;
Dominik Behr83864df2016-04-21 12:35:08 -0700974 if (in_background)
975 return;
976 in_background = true;
Dominik Behrda3c0102016-06-08 15:05:38 -0700977 drm_dropmaster(NULL);
Dominik Behra818a1e2016-10-26 19:46:22 -0700978 while (!dbus_take_display_ownership() && retry--) {
Dominik Behr33847332016-12-12 17:27:56 -0800979 if (onetry)
980 break;
Dominik Behra818a1e2016-10-26 19:46:22 -0700981 LOG(ERROR, "Chrome failed to take display ownership. %s",
982 retry ? "Trying again." : "Giving up, Chrome is probably dead.");
Dominik Behr33847332016-12-12 17:27:56 -0800983 if (retry > 0)
984 usleep(500 * 1000);
Dominik Behra818a1e2016-10-26 19:46:22 -0700985 }
Dominik Behr83864df2016-04-21 12:35:08 -0700986}
987
988void term_foreground(void)
989{
Dominik Behrda3c0102016-06-08 15:05:38 -0700990 int ret;
Dominik Behr33847332016-12-12 17:27:56 -0800991 int retry = 5;
Dominik Behra818a1e2016-10-26 19:46:22 -0700992
Dominik Behr83864df2016-04-21 12:35:08 -0700993 if (!in_background)
994 return;
995 in_background = false;
Dominik Behra818a1e2016-10-26 19:46:22 -0700996
Dominik Behr57b5c722018-08-08 18:52:31 -0700997 /* LOG(INFO, "TIMING: Console switch time start."); */ /* Keep around for timing it in the future. */
Dominik Behra818a1e2016-10-26 19:46:22 -0700998 while (!dbus_release_display_ownership() && retry--) {
999 LOG(ERROR, "Chrome did not release master. %s",
1000 retry ? "Trying again." : "Frecon will steal master.");
Dominik Behr33847332016-12-12 17:27:56 -08001001 if (retry > 0)
1002 usleep(500 * 1000);
Dominik Behr83864df2016-04-21 12:35:08 -07001003 }
Dominik Behrda3c0102016-06-08 15:05:38 -07001004
Dominik Behr57b5c722018-08-08 18:52:31 -07001005 /* LOG(INFO, "TIMING: Console switch setmaster."); */
Dominik Behrda3c0102016-06-08 15:05:38 -07001006 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}