Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| 3 | * Use of this source code is governed by a BSD-style license that can be |
| 4 | * found in the LICENSE file. |
| 5 | */ |
| 6 | |
| 7 | #include <ctype.h> |
| 8 | #include <libtsm.h> |
| 9 | #include <paths.h> |
| 10 | #include <stdio.h> |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 11 | #include <sys/select.h> |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 12 | |
| 13 | #include "font.h" |
| 14 | #include "input.h" |
| 15 | #include "keysym.h" |
| 16 | #include "shl_pty.h" |
| 17 | #include "term.h" |
| 18 | #include "util.h" |
| 19 | #include "video.h" |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 20 | #include "dbus_interface.h" |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 21 | |
| 22 | struct term { |
| 23 | struct tsm_screen *screen; |
| 24 | struct tsm_vte *vte; |
| 25 | struct shl_pty *pty; |
| 26 | int pty_bridge; |
| 27 | int pid; |
| 28 | tsm_age_t age; |
| 29 | int char_x, char_y; |
| 30 | int pitch; |
| 31 | uint32_t *dst_image; |
| 32 | int shift_state; |
| 33 | int control_state; |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 34 | int alt_state; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 35 | }; |
| 36 | |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 37 | |
| 38 | static void __attribute__ ((noreturn)) term_run_child() |
| 39 | { |
| 40 | char **argv = (char *[]) { |
| 41 | getenv("SHELL") ? : _PATH_BSHELL, |
| 42 | "-il", |
| 43 | NULL |
| 44 | }; |
| 45 | |
| 46 | printf("Welcome to frecon!\n"); |
| 47 | printf("running %s\n", argv[0]); |
| 48 | /* XXX figure out how to fix "top" for xterm-256color */ |
| 49 | setenv("TERM", "xterm", 1); |
| 50 | execve(argv[0], argv, environ); |
| 51 | exit(1); |
| 52 | } |
| 53 | |
| 54 | static int term_draw_cell(struct tsm_screen *screen, uint32_t id, |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 55 | const uint32_t *ch, size_t len, |
| 56 | unsigned int cwidth, unsigned int posx, |
| 57 | unsigned int posy, |
| 58 | const struct tsm_screen_attr *attr, |
| 59 | tsm_age_t age, void *data) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 60 | { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 61 | terminal_t *terminal = (terminal_t*)data; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 62 | uint32_t front_color, back_color; |
| 63 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 64 | if (age && terminal->term->age && age <= terminal->term->age) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 65 | return 0; |
| 66 | |
| 67 | front_color = (attr->fr << 16) | (attr->fg << 8) | attr->fb; |
| 68 | back_color = (attr->br << 16) | (attr->bg << 8) | attr->bb; |
| 69 | |
| 70 | if (attr->inverse) { |
| 71 | uint32_t tmp = front_color; |
| 72 | front_color = back_color; |
| 73 | back_color = tmp; |
| 74 | } |
| 75 | |
| 76 | if (len) |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 77 | font_render(terminal->term->dst_image, posx, posy, terminal->term->pitch, *ch, |
| 78 | front_color, back_color); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 79 | else |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 80 | font_fillchar(terminal->term->dst_image, posx, posy, terminal->term->pitch, |
| 81 | front_color, back_color); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 82 | |
| 83 | return 0; |
| 84 | } |
| 85 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 86 | void term_redraw(terminal_t *terminal) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 87 | { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 88 | uint32_t *video_buffer; |
| 89 | video_buffer = video_lock(terminal->video); |
| 90 | if (video_buffer != NULL) { |
| 91 | terminal->term->dst_image = video_buffer; |
| 92 | terminal->term->age = |
| 93 | tsm_screen_draw(terminal->term->screen, term_draw_cell, terminal); |
| 94 | video_unlock(terminal->video); |
| 95 | } |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 96 | } |
| 97 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 98 | void term_key_event(terminal_t* terminal, uint32_t keysym, int32_t unicode) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 99 | { |
| 100 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 101 | if (tsm_vte_handle_keyboard(terminal->term->vte, keysym, 0, 0, unicode)) |
| 102 | tsm_screen_sb_reset(terminal->term->screen); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 103 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 104 | term_redraw(terminal); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | static void term_read_cb(struct shl_pty *pty, char *u8, size_t len, void *data) |
| 108 | { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 109 | terminal_t *terminal = (terminal_t*)data; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 110 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 111 | tsm_vte_input(terminal->term->vte, u8, len); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 112 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 113 | term_redraw(terminal); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | static void term_write_cb(struct tsm_vte *vte, const char *u8, size_t len, |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 117 | void *data) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 118 | { |
| 119 | struct term *term = data; |
| 120 | int r; |
| 121 | |
| 122 | r = shl_pty_write(term->pty, u8, len); |
| 123 | if (r < 0) |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 124 | LOG(ERROR, "OOM in pty-write (%d)", r); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 125 | |
| 126 | shl_pty_dispatch(term->pty); |
| 127 | } |
| 128 | |
| 129 | static const char *sev2str_table[] = { |
| 130 | "FATAL", |
| 131 | "ALERT", |
| 132 | "CRITICAL", |
| 133 | "ERROR", |
| 134 | "WARNING", |
| 135 | "NOTICE", |
| 136 | "INFO", |
| 137 | "DEBUG" |
| 138 | }; |
| 139 | |
| 140 | static const char *sev2str(unsigned int sev) |
| 141 | { |
| 142 | if (sev > 7) |
| 143 | return "DEBUG"; |
| 144 | |
| 145 | return sev2str_table[sev]; |
| 146 | } |
| 147 | |
Dominik Behr | 0000350 | 2014-08-15 16:42:37 -0700 | [diff] [blame] | 148 | #ifdef __clang__ |
| 149 | __attribute__((__format__ (__printf__, 7, 0))) |
| 150 | #endif |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 151 | static void log_tsm(void *data, const char *file, int line, const char *fn, |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 152 | const char *subs, unsigned int sev, const char *format, |
| 153 | va_list args) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 154 | { |
| 155 | fprintf(stderr, "%s: %s: ", sev2str(sev), subs); |
| 156 | vfprintf(stderr, format, args); |
| 157 | fprintf(stderr, "\n"); |
| 158 | } |
| 159 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 160 | static int term_special_key(terminal_t *terminal, struct input_key_event *ev) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 161 | { |
Dominik Behr | 9851438 | 2014-09-24 01:17:50 -0700 | [diff] [blame] | 162 | unsigned int i; |
| 163 | |
| 164 | uint32_t ignore_keys[] = { |
| 165 | BTN_TOUCH, // touchpad events |
| 166 | BTN_TOOL_FINGER, |
| 167 | BTN_TOOL_DOUBLETAP, |
| 168 | BTN_TOOL_TRIPLETAP, |
| 169 | BTN_TOOL_QUADTAP, |
| 170 | BTN_TOOL_QUINTTAP, |
| 171 | BTN_LEFT, // mouse buttons |
| 172 | BTN_RIGHT, |
| 173 | BTN_MIDDLE, |
| 174 | BTN_SIDE, |
| 175 | BTN_EXTRA, |
| 176 | BTN_FORWARD, |
| 177 | BTN_BACK, |
| 178 | BTN_TASK |
| 179 | }; |
| 180 | |
| 181 | for (i = 0; i < ARRAY_SIZE(ignore_keys); i++) |
| 182 | if (ev->code == ignore_keys[i]) |
| 183 | return 1; |
| 184 | |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 185 | switch (ev->code) { |
| 186 | case KEY_LEFTSHIFT: |
| 187 | case KEY_RIGHTSHIFT: |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 188 | terminal->term->shift_state = ! !ev->value; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 189 | return 1; |
| 190 | case KEY_LEFTCTRL: |
| 191 | case KEY_RIGHTCTRL: |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 192 | terminal->term->control_state = ! !ev->value; |
| 193 | return 1; |
| 194 | case KEY_LEFTALT: |
| 195 | case KEY_RIGHTALT: |
| 196 | terminal->term->alt_state = ! !ev->value; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 197 | return 1; |
| 198 | } |
| 199 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 200 | if (terminal->term->shift_state && ev->value) { |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 201 | switch (ev->code) { |
| 202 | case KEY_PAGEUP: |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 203 | tsm_screen_sb_page_up(terminal->term->screen, 1); |
| 204 | term_redraw(terminal); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 205 | return 1; |
| 206 | case KEY_PAGEDOWN: |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 207 | tsm_screen_sb_page_down(terminal->term->screen, 1); |
| 208 | term_redraw(terminal); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 209 | return 1; |
| 210 | case KEY_UP: |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 211 | tsm_screen_sb_up(terminal->term->screen, 1); |
| 212 | term_redraw(terminal); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 213 | return 1; |
| 214 | case KEY_DOWN: |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 215 | tsm_screen_sb_down(terminal->term->screen, 1); |
| 216 | term_redraw(terminal); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 217 | return 1; |
| 218 | } |
| 219 | } |
| 220 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 221 | if (terminal->term->alt_state && terminal->term->control_state && ev->value) { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 222 | switch (ev->code) { |
| 223 | case KEY_F1: |
| 224 | input_ungrab(); |
| 225 | terminal->active = false; |
Stéphane Marchesin | 6639913 | 2014-11-06 12:03:26 -0800 | [diff] [blame] | 226 | (void)dbus_method_call0(terminal->dbus, |
| 227 | kLibCrosServiceName, |
| 228 | kLibCrosServicePath, |
| 229 | kLibCrosServiceInterface, |
| 230 | kTakeDisplayOwnership); |
| 231 | break; |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 232 | case KEY_F2: |
| 233 | case KEY_F3: |
| 234 | case KEY_F4: |
| 235 | case KEY_F5: |
| 236 | case KEY_F6: |
| 237 | case KEY_F7: |
| 238 | case KEY_F8: |
| 239 | case KEY_F9: |
| 240 | case KEY_F10: |
Stéphane Marchesin | 6639913 | 2014-11-06 12:03:26 -0800 | [diff] [blame] | 241 | (void)dbus_method_call0(terminal->dbus, |
| 242 | kLibCrosServiceName, |
| 243 | kLibCrosServicePath, |
| 244 | kLibCrosServiceInterface, |
| 245 | kReleaseDisplayOwnership); |
| 246 | break; |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 247 | } |
David Sodman | 003faed | 2014-11-03 09:02:10 -0800 | [diff] [blame] | 248 | |
Stéphane Marchesin | 6639913 | 2014-11-06 12:03:26 -0800 | [diff] [blame] | 249 | if (ev->code == KEY_F2) { |
| 250 | terminal->active = true; |
| 251 | input_grab(); |
| 252 | video_setmode(terminal->video); |
| 253 | term_redraw(terminal); |
| 254 | } |
| 255 | return 1; |
David Sodman | 003faed | 2014-11-03 09:02:10 -0800 | [diff] [blame] | 256 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 257 | } |
| 258 | |
| 259 | |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 260 | return 0; |
| 261 | } |
| 262 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 263 | static void term_get_keysym_and_unicode(terminal_t* terminal, |
| 264 | struct input_key_event *event, |
| 265 | uint32_t *keysym, uint32_t *unicode) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 266 | { |
| 267 | struct { |
| 268 | uint32_t code; |
| 269 | uint32_t keysym; |
| 270 | } non_ascii_keys[] = { |
| 271 | { KEY_ESC, KEYSYM_ESC}, |
| 272 | { KEY_HOME, KEYSYM_HOME}, |
| 273 | { KEY_LEFT, KEYSYM_LEFT}, |
| 274 | { KEY_UP, KEYSYM_UP}, |
| 275 | { KEY_RIGHT, KEYSYM_RIGHT}, |
| 276 | { KEY_DOWN, KEYSYM_DOWN}, |
| 277 | { KEY_PAGEUP, KEYSYM_PAGEUP}, |
| 278 | { KEY_PAGEDOWN, KEYSYM_PAGEDOWN}, |
| 279 | { KEY_END, KEYSYM_END}, |
| 280 | { KEY_INSERT, KEYSYM_INSERT}, |
| 281 | { KEY_DELETE, KEYSYM_DELETE}, |
| 282 | }; |
| 283 | |
| 284 | for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) { |
| 285 | if (non_ascii_keys[i].code == event->code) { |
| 286 | *keysym = non_ascii_keys[i].keysym; |
| 287 | *unicode = -1; |
| 288 | return; |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | if (event->code >= ARRAY_SIZE(keysym_table) / 2) { |
| 293 | *keysym = '?'; |
| 294 | } else { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 295 | *keysym = keysym_table[event->code * 2 + terminal->term->shift_state]; |
| 296 | if ((terminal->term->control_state) && isascii(*keysym)) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 297 | *keysym = tolower(*keysym) - 'a' + 1; |
| 298 | } |
| 299 | |
| 300 | *unicode = *keysym; |
| 301 | } |
| 302 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 303 | int term_run(terminal_t* terminal) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 304 | { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 305 | int pty_fd = terminal->term->pty_bridge; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 306 | fd_set read_set, exception_set; |
| 307 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 308 | video_setmode(terminal->video); |
| 309 | |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 310 | while (1) { |
| 311 | FD_ZERO(&read_set); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 312 | FD_ZERO(&exception_set); |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 313 | FD_SET(pty_fd, &read_set); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 314 | FD_SET(pty_fd, &exception_set); |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 315 | int maxfd = input_setfds(&read_set, &exception_set); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 316 | |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 317 | maxfd = MAX(maxfd, pty_fd) + 1; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 318 | |
| 319 | select(maxfd, &read_set, NULL, &exception_set, NULL); |
| 320 | |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 321 | if (FD_ISSET(pty_fd, &exception_set)) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 322 | return -1; |
| 323 | |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 324 | struct input_key_event *event; |
| 325 | event = input_get_event(&read_set, &exception_set); |
| 326 | if (event) { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 327 | if (!term_special_key(terminal, event) && event->value) { |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 328 | uint32_t keysym, unicode; |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 329 | if (terminal->active) { |
| 330 | term_get_keysym_and_unicode(terminal, event, |
| 331 | &keysym, |
| 332 | &unicode); |
| 333 | term_key_event(terminal, keysym, unicode); |
| 334 | } |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 335 | } |
Dominik Behr | 9389945 | 2014-08-18 22:16:21 -0700 | [diff] [blame] | 336 | |
| 337 | input_put_event(event); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 338 | } |
| 339 | |
| 340 | if (FD_ISSET(pty_fd, &read_set)) { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 341 | shl_pty_bridge_dispatch(terminal->term->pty_bridge, 0); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 342 | } |
| 343 | } |
| 344 | return 0; |
| 345 | } |
| 346 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 347 | terminal_t* term_init(video_t* video) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 348 | { |
| 349 | const int scrollback_size = 200; |
| 350 | uint32_t char_width, char_height; |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 351 | int status; |
| 352 | terminal_t *new_terminal; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 353 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 354 | new_terminal = (terminal_t*)calloc(1, sizeof(*new_terminal)); |
| 355 | new_terminal->video = video; |
| 356 | new_terminal->term = (struct term*)calloc(1, sizeof(*new_terminal->term)); |
| 357 | |
| 358 | font_init(video_getscaling(video)); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 359 | font_get_size(&char_width, &char_height); |
| 360 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 361 | new_terminal->term->char_x = video_getwidth(video) / char_width; |
| 362 | new_terminal->term->char_y = video_getheight(video) / char_height; |
| 363 | new_terminal->term->pitch = video_getpitch(video); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 364 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 365 | status = tsm_screen_new(&new_terminal->term->screen, |
| 366 | log_tsm, new_terminal->term); |
| 367 | if (new_terminal < 0) { |
| 368 | term_close(new_terminal); |
| 369 | return NULL; |
| 370 | } |
| 371 | |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 372 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 373 | tsm_screen_set_max_sb(new_terminal->term->screen, scrollback_size); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 374 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 375 | status = tsm_vte_new(&new_terminal->term->vte, new_terminal->term->screen, |
| 376 | term_write_cb, new_terminal->term, log_tsm, new_terminal->term); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 377 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 378 | if (status < 0) { |
| 379 | term_close(new_terminal); |
| 380 | return NULL; |
| 381 | } |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 382 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 383 | new_terminal->term->pty_bridge = shl_pty_bridge_new(); |
| 384 | if (new_terminal->term->pty_bridge < 0) { |
| 385 | term_close(new_terminal); |
| 386 | return NULL; |
| 387 | } |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 388 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 389 | status = shl_pty_open(&new_terminal->term->pty, |
| 390 | term_read_cb, new_terminal, new_terminal->term->char_x, |
| 391 | new_terminal->term->char_y); |
| 392 | if (status < 0) { |
| 393 | term_close(new_terminal); |
| 394 | return NULL; |
| 395 | } else if (status == 0) { |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 396 | term_run_child(); |
| 397 | exit(1); |
| 398 | } |
| 399 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 400 | status = shl_pty_bridge_add(new_terminal->term->pty_bridge, new_terminal->term->pty); |
| 401 | if (status) { |
| 402 | shl_pty_close(new_terminal->term->pty); |
| 403 | term_close(new_terminal); |
| 404 | return NULL; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 405 | } |
| 406 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 407 | new_terminal->term->pid = shl_pty_get_child(new_terminal->term->pty); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 408 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 409 | status = tsm_screen_resize(new_terminal->term->screen, |
| 410 | new_terminal->term->char_x, new_terminal->term->char_y); |
| 411 | if (status < 0) { |
| 412 | shl_pty_close(new_terminal->term->pty); |
| 413 | term_close(new_terminal); |
| 414 | return NULL; |
| 415 | } |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 416 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 417 | status = shl_pty_resize(new_terminal->term->pty, new_terminal->term->char_x, new_terminal->term->char_y); |
| 418 | if (status < 0) { |
| 419 | shl_pty_close(new_terminal->term->pty); |
| 420 | term_close(new_terminal); |
| 421 | return NULL; |
| 422 | } |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 423 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 424 | return new_terminal; |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 425 | } |
| 426 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 427 | void term_set_dbus(terminal_t *term, dbus_t* dbus) |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 428 | { |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 429 | term->dbus = dbus; |
| 430 | } |
| 431 | |
| 432 | void term_close(terminal_t *term) |
| 433 | { |
| 434 | if (!term) |
| 435 | return; |
| 436 | |
| 437 | if (term->term) { |
| 438 | free(term->term); |
| 439 | term->term = NULL; |
| 440 | } |
| 441 | |
| 442 | free(term); |
Stéphane Marchesin | ae37e6c | 2014-08-08 18:19:40 -0700 | [diff] [blame] | 443 | } |