1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "vt_term.h"
4
5 #include <pobl/bl_mem.h> /* malloc/free */
6 #include <pobl/bl_debug.h>
7 #include <pobl/bl_str.h> /* strdup */
8 #include <pobl/bl_sig_child.h>
9 #include <pobl/bl_path.h> /* bl_parse_uri */
10 #include <pobl/bl_dialog.h>
11
12 #include "vt_pty.h"
13 #include "vt_parser.h"
14 #include "vt_screen.h"
15
16 #ifdef OPEN_PTY_ASYNC
17
18 #ifdef USE_WIN32API
19 #include <windows.h>
20 #include <process.h> /* _beginthreadex */
21 #else
22 #include <pthread.h>
23 #endif
24
25 typedef struct {
26 vt_term_t *term;
27 char *cmd_path;
28 char **argv;
29 char **env;
30 char *host;
31 char *work_dir;
32 char *pass;
33 char *pubkey;
34 char *privkey;
35 u_int width_pix;
36 u_int height_pix;
37
38 } pty_args_t;
39
40 #endif
41
42 /* --- global variables --- */
43
44 #ifndef NO_IMAGE
45 /* XXX */
46 void (*vt_term_pty_closed_event)(vt_term_t *);
47 #endif
48
49 #if defined(__ANDROID__) && defined(USE_LIBSSH2)
50 /* XXX */
51 int start_with_local_pty = 0;
52 #endif
53
54 /* --- static functions --- */
55
56 #ifdef OPEN_PTY_ASYNC
57
pty_args_destroy(pty_args_t * args)58 static void pty_args_destroy(pty_args_t *args) {
59 int count;
60
61 free(args->cmd_path);
62 free(args->host);
63 free(args->work_dir);
64 free(args->pass);
65 free(args->pubkey);
66 free(args->privkey);
67
68 if (args->argv) {
69 for (count = 0; args->argv[count]; count++) {
70 free(args->argv[count]);
71 }
72 free(args->argv);
73 }
74
75 if (args->env) {
76 for (count = 0; args->env[count]; count++) {
77 free(args->env[count]);
78 }
79 free(args->env);
80 }
81
82 free(args);
83 }
84
pty_args_new(vt_term_t * term,const char * cmd_path,char ** argv,char ** env,const char * host,const char * work_dir,const char * pass,const char * pubkey,const char * privkey,u_int width_pix,u_int height_pix)85 static pty_args_t *pty_args_new(vt_term_t *term, const char *cmd_path, char **argv, char **env,
86 const char *host, const char *work_dir, const char *pass,
87 const char *pubkey, const char *privkey, u_int width_pix,
88 u_int height_pix) {
89 pty_args_t *args;
90 u_int num;
91 u_int count;
92
93 if (!(args = calloc(1, sizeof(pty_args_t)))) {
94 return NULL;
95 }
96
97 args->term = term;
98
99 if (cmd_path) {
100 args->cmd_path = strdup(cmd_path);
101 }
102
103 if (host) {
104 args->host = strdup(host);
105 }
106
107 if (work_dir) {
108 args->work_dir = strdup(work_dir);
109 }
110
111 if (pass) {
112 args->pass = strdup(pass);
113 }
114
115 if (pubkey) {
116 args->pubkey = strdup(pubkey);
117 }
118
119 if (privkey) {
120 args->privkey = strdup(privkey);
121 }
122
123 args->width_pix = width_pix;
124 args->height_pix = height_pix;
125
126 if (argv) {
127 for (num = 0; argv[num]; num++)
128 ;
129
130 if ((args->argv = malloc(sizeof(char *) * (num + 1)))) {
131 for (count = 0; count < num; count++) {
132 args->argv[count] = strdup(argv[count]);
133 }
134 args->argv[count] = NULL;
135 }
136 } else {
137 args->argv = NULL;
138 }
139
140 if (env) {
141 for (num = 0; env[num]; num++)
142 ;
143
144 if ((args->env = malloc(sizeof(char *) * (num + 1)))) {
145 for (count = 0; count < num; count++) {
146 args->env[count] = strdup(env[count]);
147 }
148 args->env[count] = NULL;
149 }
150 } else {
151 args->env = NULL;
152 }
153
154 return args;
155 }
156
157 #ifdef USE_WIN32API
158 static u_int __stdcall
159 #else
160 static void *
161 #endif
open_pty(void * p)162 open_pty(void *p) {
163 pty_args_t *args;
164 vt_pty_t *pty;
165 #ifdef USE_WIN32API
166 static HANDLE mutex;
167
168 if (!mutex) {
169 mutex = CreateMutex(NULL, FALSE, NULL);
170 }
171
172 WaitForSingleObject(mutex, INFINITE);
173 #else
174 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
175
176 pthread_detach(pthread_self());
177 pthread_mutex_lock(&mutex);
178 #endif
179
180 args = p;
181
182 pty =
183 vt_pty_new(args->cmd_path, args->argv, args->env, args->host, args->work_dir, args->pass,
184 args->pubkey, args->privkey, vt_screen_get_logical_cols(args->term->screen),
185 vt_screen_get_logical_rows(args->term->screen), args->width_pix, args->height_pix);
186
187 if (pty) {
188 if (args->pass) {
189 args->term->uri = strdup(args->host);
190 }
191
192 vt_term_plug_pty(args->term, pty);
193 } else {
194 bl_dialog(BL_DIALOG_ALERT, "Failed to open pty");
195
196 args->term->return_special_pid = 1;
197 bl_trigger_sig_child(-10);
198 args->term->return_special_pid = 0;
199 }
200
201 pty_args_destroy(args);
202
203 #ifdef USE_WIN32API
204 ReleaseMutex(mutex);
205 #else
206 pthread_mutex_unlock(&mutex);
207 #endif
208
209 return 0;
210 }
211
212 #endif
213
214 /* --- global functions --- */
215
vt_term_final(void)216 void vt_term_final(void) {
217 vt_parser_final();
218 vt_termcap_final();
219 }
220
vt_term_new(const char * term_type,u_int cols,u_int rows,u_int tab_size,u_int log_size,vt_char_encoding_t encoding,int is_auto_encoding,int use_auto_detect,int logging_vt_seq,vt_unicode_policy_t policy,u_int col_size_a,int use_char_combining,int use_multi_col_char,int use_ctl,vt_bidi_mode_t bidi_mode,const char * bidi_separators,int use_dynamic_comb,vt_bs_mode_t bs_mode,vt_vertical_mode_t vertical_mode,int use_local_echo,const char * win_name,const char * icon_name,int use_ansi_colors,vt_alt_color_mode_t alt_color_mode,int use_ot_layout,vt_cursor_style_t cursor_style,int ignore_broadcasted_chars)221 vt_term_t *vt_term_new(const char *term_type, u_int cols, u_int rows, u_int tab_size,
222 u_int log_size, vt_char_encoding_t encoding, int is_auto_encoding,
223 int use_auto_detect, int logging_vt_seq, vt_unicode_policy_t policy,
224 u_int col_size_a, int use_char_combining, int use_multi_col_char,
225 int use_ctl, vt_bidi_mode_t bidi_mode, const char *bidi_separators,
226 int use_dynamic_comb, vt_bs_mode_t bs_mode, vt_vertical_mode_t vertical_mode,
227 int use_local_echo, const char *win_name, const char *icon_name,
228 int use_ansi_colors, vt_alt_color_mode_t alt_color_mode, int use_ot_layout,
229 vt_cursor_style_t cursor_style, int ignore_broadcasted_chars) {
230 vt_termcap_ptr_t termcap;
231 vt_term_t *term;
232
233 if (!(termcap = vt_termcap_get(term_type))) {
234 return NULL;
235 }
236
237 if ((term = calloc(1, sizeof(vt_term_t))) == NULL) {
238 #ifdef DEBUG
239 bl_warn_printf(BL_DEBUG_TAG " malloc failed.\n");
240 #endif
241
242 return NULL;
243 }
244
245 if (!(term->screen = vt_screen_new(cols, rows, tab_size, log_size,
246 vt_termcap_bce_is_enabled(termcap), bs_mode))) {
247 #ifdef DEBUG
248 bl_warn_printf(BL_DEBUG_TAG " vt_screen_new failed.\n");
249 #endif
250
251 goto error;
252 }
253
254 term->use_ot_layout = use_ot_layout;
255
256 #ifndef NOT_CONVERT_TO_ISCII
257 #if defined(USE_HARFBUZZ) || defined(USE_UNISCRIBE)
258 if (!term->use_ot_layout)
259 #endif
260 {
261 policy |= CONVERT_UNICODE_TO_ISCII;
262 }
263 #endif
264
265 if (!(term->parser = vt_parser_new(term->screen, termcap, encoding, is_auto_encoding,
266 use_auto_detect, logging_vt_seq, policy, col_size_a,
267 use_char_combining, use_multi_col_char, win_name, icon_name,
268 use_ansi_colors, alt_color_mode, cursor_style,
269 ignore_broadcasted_chars, use_local_echo))) {
270 #ifdef DEBUG
271 bl_warn_printf(BL_DEBUG_TAG " vt_parser_new failed.\n");
272 #endif
273
274 goto error;
275 }
276
277 if (bidi_separators) {
278 term->bidi_separators = bl_str_unescape(bidi_separators);
279 }
280
281 term->vertical_mode = vertical_mode;
282 term->bidi_mode = bidi_mode;
283 term->use_ctl = use_ctl;
284 term->use_dynamic_comb = use_dynamic_comb;
285
286 return term;
287
288 error:
289 if (term->screen) {
290 vt_screen_destroy(term->screen);
291 }
292
293 if (term->parser) {
294 vt_parser_destroy(term->parser);
295 }
296
297 free(term);
298
299 return NULL;
300 }
301
vt_term_destroy(vt_term_t * term)302 void vt_term_destroy(vt_term_t *term) {
303 #ifndef NO_IMAGE
304 if (vt_term_pty_closed_event) {
305 (*vt_term_pty_closed_event)(term);
306 }
307 #endif
308
309 free(term->user_data);
310
311 if (term->pty) {
312 vt_pty_destroy(term->pty);
313 } else if (term->pty_listener) {
314 (*term->pty_listener->closed)(term->pty_listener->self);
315 }
316
317 free(term->uri);
318 free(term->icon_path);
319 free(term->bidi_separators);
320
321 vt_screen_destroy(term->screen);
322 vt_parser_destroy(term->parser);
323
324 free(term);
325 }
326
vt_term_zombie(vt_term_t * term)327 void vt_term_zombie(vt_term_t *term) {
328 if (term->pty) {
329 vt_pty_t *pty;
330
331 pty = term->pty;
332
333 /* Should be NULL because vt_pty_destroy calls term->pty_listener->closed. */
334 term->pty = NULL;
335
336 vt_pty_destroy(pty);
337 }
338 #ifdef DEBUG
339 else {
340 bl_debug_printf(BL_DEBUG_TAG " term is already zombie.\n");
341 }
342 #endif
343 }
344
345 /* The caller should swap width_pix and height_pix in vertical mode. */
vt_term_open_pty(vt_term_t * term,const char * cmd_path,char ** argv,char ** env,const char * host,const char * work_dir,const char * pass,const char * pubkey,const char * privkey,u_int width_pix,u_int height_pix)346 int vt_term_open_pty(vt_term_t *term, const char *cmd_path, char **argv, char **env,
347 const char *host, const char *work_dir, const char *pass, const char *pubkey,
348 const char *privkey, u_int width_pix, u_int height_pix) {
349 if (!term->pty) {
350 #ifdef OPEN_PTY_ASYNC
351 char *host_dup;
352 char *user;
353 char *server;
354 char *port;
355
356 if (pass && (host_dup = alloca(strlen(host) + 1)) &&
357 bl_parse_uri(NULL, &user, &server, &port, NULL, NULL, strcpy(host_dup, host))
358 #ifdef USE_LIBSSH2
359 && !vt_search_ssh_session(server, port, user)
360 #endif
361 ) {
362 pty_args_t *args;
363
364 if (!(args = pty_args_new(term, cmd_path, argv, env, host, work_dir, pass, pubkey, privkey,
365 width_pix, height_pix))) {
366 return 0;
367 }
368
369 #ifdef USE_WIN32API
370 {
371 HANDLE thrd;
372 u_int tid;
373
374 if ((thrd = _beginthreadex(NULL, 0, open_pty, args, 0, &tid))) {
375 CloseHandle(thrd);
376
377 return 1;
378 }
379
380 return 0;
381 }
382 #else
383 {
384 pthread_t thrd;
385
386 if (pthread_create(&thrd, NULL, open_pty, args) == 0) {
387 return 1;
388 } else {
389 return 0;
390 }
391 }
392 #endif
393 } else
394 #endif /* OPEN_PTY_ASYNC */
395 {
396 vt_pty_t *pty;
397
398 if (!(pty = vt_pty_new(cmd_path, argv, env, host, work_dir, pass, pubkey, privkey,
399 vt_screen_get_logical_cols(term->screen),
400 vt_screen_get_logical_rows(term->screen), width_pix, height_pix))) {
401 bl_dialog(BL_DIALOG_ALERT, "Failed to open pty");
402
403 return 0;
404 }
405
406 if (pass) {
407 term->uri = strdup(host);
408 }
409
410 vt_term_plug_pty(term, pty);
411 }
412 }
413
414 return 1;
415 }
416
vt_term_plug_pty(vt_term_t * term,vt_pty_t * pty)417 int vt_term_plug_pty(vt_term_t *term, vt_pty_t *pty /* Not NULL */) {
418 if (!term->pty) {
419 if (term->pty_listener) {
420 vt_pty_set_listener(pty, term->pty_listener);
421 term->pty_listener = NULL;
422 }
423
424 vt_parser_set_pty(term->parser, pty);
425
426 term->pty = pty;
427 }
428
429 return 1;
430 }
431
vt_term_attach(vt_term_t * term,vt_xterm_event_listener_t * xterm_listener,vt_config_event_listener_t * config_listener,vt_screen_event_listener_t * screen_listener,vt_pty_event_listener_t * pty_listener)432 int vt_term_attach(vt_term_t *term, vt_xterm_event_listener_t *xterm_listener,
433 vt_config_event_listener_t *config_listener,
434 vt_screen_event_listener_t *screen_listener,
435 vt_pty_event_listener_t *pty_listener) {
436 if (term->is_attached) {
437 /* already attached */
438 return 0;
439 }
440
441 vt_parser_set_xterm_listener(term->parser, xterm_listener);
442 vt_parser_set_config_listener(term->parser, config_listener);
443 vt_screen_set_listener(term->screen, screen_listener);
444
445 if (term->pty) {
446 vt_pty_set_listener(term->pty, pty_listener);
447 } else {
448 term->pty_listener = pty_listener;
449 }
450
451 term->is_attached = 1;
452
453 return 1;
454 }
455
vt_term_detach(vt_term_t * term)456 int vt_term_detach(vt_term_t *term) {
457 if (!term->is_attached) {
458 /* already detached. */
459 return 0;
460 }
461
462 vt_parser_set_xterm_listener(term->parser, NULL);
463 vt_parser_set_config_listener(term->parser, NULL);
464 vt_screen_set_listener(term->screen, NULL);
465
466 if (term->pty) {
467 vt_pty_set_listener(term->pty, NULL);
468 } else {
469 term->pty_listener = NULL;
470 }
471
472 term->is_attached = 0;
473
474 return 1;
475 }
476
vt_term_set_use_ot_layout(vt_term_t * term,int flag)477 void vt_term_set_use_ot_layout(vt_term_t *term, int flag) {
478 #if (defined(USE_HARFBUZZ) || defined(USE_UNISCRIBE)) && !defined(NOT_CONVERT_TO_ISCII)
479 vt_unicode_policy_t policy;
480
481 policy = vt_parser_get_unicode_policy(term->parser);
482
483 if (flag) {
484 policy &= ~CONVERT_UNICODE_TO_ISCII;
485 } else {
486 policy |= CONVERT_UNICODE_TO_ISCII;
487 }
488
489 vt_parser_set_unicode_policy(term->parser, policy);
490 #endif
491
492 term->use_ot_layout = flag;
493 }
494
vt_term_get_master_fd(vt_term_t * term)495 int vt_term_get_master_fd(vt_term_t *term) {
496 if (term->pty == NULL) {
497 return -1;
498 }
499
500 return vt_pty_get_master_fd(term->pty);
501 }
502
vt_term_get_slave_fd(vt_term_t * term)503 int vt_term_get_slave_fd(vt_term_t *term) {
504 if (term->pty == NULL) {
505 return -1;
506 }
507
508 return vt_pty_get_slave_fd(term->pty);
509 }
510
511 /*
512 * Always return non-NULL value.
513 * XXX Static data can be returned. (Not reentrant)
514 */
vt_term_get_slave_name(vt_term_t * term)515 char *vt_term_get_slave_name(vt_term_t *term) {
516 if (term->pty == NULL) {
517 return "/dev/zombie";
518 }
519
520 return vt_pty_get_slave_name(term->pty);
521 }
522
vt_term_get_child_pid(vt_term_t * term)523 pid_t vt_term_get_child_pid(vt_term_t *term) {
524 if (term->pty == NULL) {
525 #ifdef OPEN_PTY_ASYNC
526 return term->return_special_pid ? -10 : -1;
527 #else
528 return -1;
529 #endif
530 }
531
532 return vt_pty_get_pid(term->pty);
533 }
534
vt_term_get_pty_mode(vt_term_t * term)535 pid_t vt_term_get_pty_mode(vt_term_t *term) {
536 if (term->pty == NULL) {
537 return PTY_NONE;
538 }
539
540 return vt_pty_get_mode(term->pty);
541 }
542
vt_term_write(vt_term_t * term,u_char * buf,size_t len)543 size_t vt_term_write(vt_term_t *term, u_char *buf, size_t len) {
544 if (term->pty == NULL) {
545 return 0;
546 }
547
548 return vt_parser_write(term->parser, buf, len);
549 }
550
551 /* The caller should swap width_pix and height_pix in vertical mode. */
vt_term_resize(vt_term_t * term,u_int cols,u_int rows,u_int width_pix,u_int height_pix)552 int vt_term_resize(vt_term_t *term, u_int cols, u_int rows, u_int width_pix, u_int height_pix) {
553 int ret;
554
555 vt_screen_logical(term->screen);
556 ret = vt_screen_resize(term->screen, cols, rows);
557 vt_screen_render(term->screen);
558 vt_screen_visual(term->screen);
559
560 if (term->pty) {
561 /* Don't use cols and rows because status line might change rows in vt_screen_resize(). */
562 vt_set_pty_winsize(term->pty, vt_screen_get_logical_cols(term->screen),
563 vt_screen_get_logical_rows(term->screen), width_pix, height_pix);
564 }
565
566 return ret;
567 }
568
vt_term_unhighlight_cursor(vt_term_t * term,int revert_visual)569 int vt_term_unhighlight_cursor(vt_term_t *term, int revert_visual) {
570 vt_line_t *line;
571 int ret;
572
573 #ifdef DEBUG
574 if (term->screen->logvis && !term->screen->logvis->is_visual) {
575 bl_debug_printf(BL_DEBUG_TAG
576 " vt_term_unhighlight_cursor() should be called in visual context but"
577 " is called in logical context.\n");
578 }
579 #endif
580
581 vt_screen_logical(term->screen);
582
583 if ((line = vt_screen_get_cursor_line(term->screen)) == NULL || vt_line_is_empty(line)) {
584 ret = 0;
585 } else {
586 vt_line_set_modified(line, vt_screen_cursor_char_index(term->screen),
587 vt_screen_cursor_char_index(term->screen));
588
589 ret = 1;
590 }
591
592 if (revert_visual) {
593 /* vt_screen_render(term->screen); */
594 vt_screen_visual(term->screen);
595 }
596
597 return ret;
598 }
599
600 /*
601 * Not implemented yet.
602 */
603 #if 0
604 void vt_term_set_modified_region(vt_term_t *term, int beg_char_index, int beg_row, u_int nchars,
605 u_int nrows) {
606 return;
607 }
608 #endif
609
610 /*
611 * Not used.
612 */
613 #if 0
614 void vt_term_set_modified_region_in_screen(vt_term_t *term, int beg_char_index, int beg_row,
615 u_int nchars, u_int nrows) {
616 int row;
617 vt_line_t *line;
618 int revert_to_visual;
619
620 /*
621 * This function is usually called in visual context, and sometimes
622 * called in logical context. (see flush_scroll_cache() in x_screen.c)
623 */
624 if (!vt_screen_logical_visual_is_reversible(term->screen) && vt_screen_logical(term->screen)) {
625 revert_to_visual = 1;
626 } else {
627 revert_to_visual = 0;
628 }
629
630 for (row = beg_row; row < beg_row + nrows; row++) {
631 if ((line = vt_screen_get_line_in_screen(term->screen, row))) {
632 vt_line_set_modified(line, beg_char_index, beg_char_index + nchars - 1);
633 }
634 }
635
636 if (revert_to_visual) {
637 /* vt_screen_render(term->screen); */
638 vt_screen_visual(term->screen);
639 }
640 }
641 #endif
642
vt_term_set_modified_lines(vt_term_t * term,int beg,int end)643 void vt_term_set_modified_lines(vt_term_t *term, int beg, int end) {
644 int row;
645 vt_line_t *line;
646 int revert_to_visual;
647
648 /*
649 * This function is usually called in visual context, and sometimes
650 * called in logical context. (see flush_scroll_cache() in x_screen.c)
651 */
652 if (!vt_screen_logical_visual_is_reversible(term->screen) && vt_screen_logical(term->screen)) {
653 revert_to_visual = 1;
654 } else {
655 revert_to_visual = 0;
656 }
657
658 for (row = beg; row <= end; row++) {
659 if ((line = vt_screen_get_line(term->screen, row))) {
660 vt_line_set_modified_all(line);
661 }
662 }
663
664 if (revert_to_visual) {
665 /* vt_screen_render(term->screen); */
666 vt_screen_visual(term->screen);
667 }
668 }
669
vt_term_set_modified_lines_in_screen(vt_term_t * term,int beg,int end)670 void vt_term_set_modified_lines_in_screen(vt_term_t *term, int beg, int end) {
671 int row;
672 vt_line_t *line;
673 int revert_to_visual;
674
675 /*
676 * This function is usually called in visual context, and sometimes
677 * called in logical context. (see flush_scroll_cache() in x_screen.c)
678 */
679 if (!vt_screen_logical_visual_is_reversible(term->screen) && vt_screen_logical(term->screen)) {
680 revert_to_visual = 1;
681 } else {
682 revert_to_visual = 0;
683 }
684
685 for (row = beg; row <= end; row++) {
686 if ((line = vt_screen_get_line_in_screen(term->screen, row))) {
687 vt_line_set_modified_all(line);
688 }
689 }
690
691 if (revert_to_visual) {
692 /* vt_screen_render(term->screen); */
693 vt_screen_visual(term->screen);
694 }
695 }
696
vt_term_set_modified_all_lines_in_screen(vt_term_t * term)697 void vt_term_set_modified_all_lines_in_screen(vt_term_t *term) {
698 int revert_to_visual;
699
700 /*
701 * This function is usually called in visual context, and sometimes
702 * called in logical context. (see flush_scroll_cache() in x_screen.c)
703 */
704 if (!vt_screen_logical_visual_is_reversible(term->screen) && vt_screen_logical(term->screen)) {
705 revert_to_visual = 1;
706 } else {
707 revert_to_visual = 0;
708 }
709
710 vt_screen_set_modified_all(term->screen);
711
712 if (revert_to_visual) {
713 /* vt_screen_render(term->screen); */
714 vt_screen_visual(term->screen);
715 }
716 }
717
vt_term_updated_all(vt_term_t * term)718 void vt_term_updated_all(vt_term_t *term) {
719 int row;
720 vt_line_t *line;
721
722 #ifdef DEBUG
723 if (term->screen->logvis && !term->screen->logvis->is_visual) {
724 bl_debug_printf(BL_DEBUG_TAG
725 " vt_term_updated_all() should be called in visual context but"
726 " is called in logical context.\n");
727 }
728 #endif
729
730 if (!vt_screen_logical_visual_is_reversible(term->screen)) {
731 vt_screen_logical(term->screen);
732 }
733
734 for (row = 0; row < vt_screen_get_rows(term->screen); row++) {
735 line = vt_screen_get_line_in_screen(term->screen, row); /* Always non-NULL */
736 vt_line_set_updated(line);
737 }
738
739 if (!vt_screen_logical_visual_is_reversible(term->screen)) {
740 /* vt_screen_render(term->screen); */
741 vt_screen_visual(term->screen);
742 }
743 }
744
745 /*
746 * Return value:
747 * 1 => Updated
748 * 0 => Not updated(== not necessary to redraw)
749 */
vt_term_update_special_visual(vt_term_t * term)750 int vt_term_update_special_visual(vt_term_t *term) {
751 vt_logical_visual_t *logvis;
752 int had_logvis = 0;
753 int has_logvis = 0;
754
755 had_logvis = vt_screen_destroy_logical_visual(term->screen);
756
757 if (term->use_dynamic_comb) {
758 if ((logvis = vt_logvis_comb_new())) {
759 if (vt_screen_add_logical_visual(term->screen, logvis)) {
760 has_logvis = 1;
761
762 if (vt_parser_is_using_char_combining(term->parser)) {
763 bl_msg_printf(
764 "Set use_combining=false forcibly "
765 "to enable use_dynamic_comb.\n");
766 vt_parser_set_use_char_combining(term->parser, 0);
767 }
768 } else {
769 #ifdef DEBUG
770 bl_warn_printf(BL_DEBUG_TAG " vt_screen_add_logical_visual failed.\n");
771 #endif
772
773 (*logvis->destroy)(logvis);
774 }
775 }
776 #ifdef DEBUG
777 else {
778 bl_warn_printf(BL_DEBUG_TAG " vt_logvis_comb_new() failed.\n");
779 }
780 #endif
781 }
782
783 /* Vertical mode, BiDi and ISCII can't coexist. */
784
785 /* Similar if-else conditions exist in update_special_visual in x_screen.c. */
786 if (term->vertical_mode) {
787 if ((logvis = vt_logvis_vert_new(term->vertical_mode))) {
788 if (vt_screen_add_logical_visual(term->screen, logvis)) {
789 has_logvis = 1;
790 } else {
791 #ifdef DEBUG
792 bl_warn_printf(BL_DEBUG_TAG " vt_screen_add_logical_visual failed.\n");
793 #endif
794
795 (*logvis->destroy)(logvis);
796 }
797 }
798 #ifdef DEBUG
799 else {
800 bl_warn_printf(BL_DEBUG_TAG " vt_logvis_vert_new() failed.\n");
801 }
802 #endif
803 } else if (term->use_ctl && (vt_term_get_encoding(term) == VT_UTF8 ||
804 IS_ISCII_ENCODING(vt_term_get_encoding(term)))) {
805 if ((logvis = vt_logvis_ctl_new(term->bidi_mode, term->bidi_separators,
806 term->use_ot_layout ? term : NULL))) {
807 if (vt_screen_add_logical_visual(term->screen, logvis)) {
808 has_logvis = 1;
809 } else {
810 #ifdef DEBUG
811 bl_warn_printf(BL_DEBUG_TAG " vt_screen_add_logical_visual failed.\n");
812 #endif
813
814 (*logvis->destroy)(logvis);
815 }
816 }
817 #ifdef DEBUG
818 else {
819 bl_warn_printf(BL_DEBUG_TAG " vt_logvis_ctl_new() failed.\n");
820 }
821 #endif
822 }
823
824 if (had_logvis || has_logvis) {
825 vt_screen_render(term->screen);
826 vt_screen_visual(term->screen);
827
828 return 1;
829 } else {
830 return 0;
831 }
832 }
833
vt_term_enter_backscroll_mode(vt_term_t * term)834 int vt_term_enter_backscroll_mode(vt_term_t *term) {
835 /* XXX */
836 if (term->vertical_mode) {
837 bl_msg_printf("Not supported backscrolling in vertical mode.\n");
838
839 return 0;
840 }
841
842 return vt_enter_backscroll_mode(term->screen);
843 }
844
vt_term_set_icon_path(vt_term_t * term,const char * path)845 void vt_term_set_icon_path(vt_term_t *term, const char *path) {
846 free(term->icon_path);
847
848 if (path && *path) {
849 term->icon_path = strdup(path);
850 } else {
851 term->icon_path = NULL;
852 }
853 }
854
vt_term_set_bidi_separators(vt_term_t * term,const char * bidi_separators)855 void vt_term_set_bidi_separators(vt_term_t *term, const char *bidi_separators) {
856 free(term->bidi_separators);
857
858 if (bidi_separators && *bidi_separators) {
859 term->bidi_separators = bl_str_unescape(bidi_separators);
860 } else {
861 term->bidi_separators = NULL;
862 }
863 }
864
vt_term_get_config(vt_term_t * term,vt_term_t * output,char * key,int to_menu,int * flag)865 int vt_term_get_config(vt_term_t *term, vt_term_t *output, /* if term == output, NULL is set */
866 char *key, int to_menu, int *flag) {
867 char *value;
868
869 if (vt_parser_get_config(term->parser, output ? output->pty : NULL, key, to_menu, flag)) {
870 return 1;
871 }
872
873 if (strcmp(key, "vertical_mode") == 0) {
874 value = vt_get_vertical_mode_name(term->vertical_mode);
875 } else if (strcmp(key, "use_dynamic_comb") == 0) {
876 if (term->use_dynamic_comb) {
877 value = "true";
878 } else {
879 value = "false";
880 }
881 } else if (strcmp(key, "use_ctl") == 0) {
882 if (term->use_ctl) {
883 value = "true";
884 } else {
885 value = "false";
886 }
887 } else if (strcmp(key, "bidi_mode") == 0) {
888 value = vt_get_bidi_mode_name(term->bidi_mode);
889 } else if (strcmp(key, "bidi_separators") == 0) {
890 if ((value = term->bidi_separators) == NULL) {
891 value = "";
892 }
893 }
894 #ifdef USE_OT_LAYOUT
895 else if (strcmp(key, "use_ot_layout") == 0) {
896 if (term->use_ot_layout) {
897 value = "true";
898 } else {
899 value = "false";
900 }
901 } else if (strcmp(key, "ot_features") == 0) {
902 value = vt_get_ot_layout_attr(OT_FEATURES);
903 } else if (strcmp(key, "ot_script") == 0) {
904 value = vt_get_ot_layout_attr(OT_SCRIPT);
905 }
906 #endif
907 else if (strcmp(key, "pty_name") == 0) {
908 if (output) {
909 if ((value = vt_get_window_name(term->parser)) == NULL) {
910 value = "";
911 }
912 } else {
913 value = vt_term_get_slave_name(term);
914 }
915 } else if (strcmp(key, "icon_path") == 0) {
916 if ((value = term->icon_path) == NULL) {
917 value = "";
918 }
919 }
920 #if defined(__ANDROID__) && defined(USE_LIBSSH2)
921 else if (strcmp(key, "start_with_local_pty") == 0) {
922 value = start_with_local_pty ? "true" : "false";
923 }
924 #endif
925 else {
926 /* Continue to process it in x_screen.c */
927 return 0;
928 }
929
930 if (!output) {
931 output = term;
932 }
933
934 /* value is never set NULL above. */
935 #if 0
936 if (!value) {
937 vt_response_config(output->pty, "error", NULL, to_menu);
938 }
939 #endif
940
941 if (flag) {
942 *flag = value ? true_or_false(value) : -1;
943 } else {
944 vt_response_config(output->pty, key, value, to_menu);
945 }
946
947 return 1;
948 }
949
950 /* Called in visual context */
vt_term_set_config(vt_term_t * term,char * key,char * value)951 int vt_term_set_config(vt_term_t *term, char *key, char *value) {
952 if (vt_parser_set_config(term->parser, key, value)) {
953 /* do nothing */
954 }
955 #ifdef USE_OT_LAYOUT
956 else if (strcmp(key, "ot_script") == 0) {
957 vt_set_ot_layout_attr(value, OT_SCRIPT);
958 } else if (strcmp(key, "ot_features") == 0) {
959 vt_set_ot_layout_attr(value, OT_FEATURES);
960 }
961 #endif
962 else {
963 /* Continue to process it in x_screen.c */
964 return 0;
965 }
966
967 return 1;
968 }
969