1 /* Terminal interface - low-level displaying implementation. */
16 #include "bookmarks/bookmarks.h"
17 #include "config/options.h"
18 #include "intl/gettext/libintl.h"
19 #include "main/main.h"
20 #include "main/module.h"
21 #include "main/object.h"
22 #include "main/select.h"
23 #include "osdep/osdep.h"
24 #include "osdep/signals.h"
25 #include "session/session.h"
26 #include "terminal/draw.h"
27 #include "terminal/event.h"
28 #include "terminal/hardio.h"
29 #include "terminal/kbd.h"
30 #include "terminal/screen.h"
31 #include "terminal/terminal.h"
32 #include "terminal/window.h"
33 #include "util/error.h"
34 #include "util/memory.h"
35 #include "util/string.h"
36 #include "viewer/text/textarea.h"
39 INIT_LIST_HEAD(terminals
);
41 static void check_if_no_terminal(void);
44 was_utf8(int in
, int out
)
46 /* Taken from setedit.
47 * Set cursor in the up left corner. Write "\357\200\240" == U+F020.
48 * Read cursor position. For UTF-8 x will be 2.
49 * For normal mode it will be 4. */
50 static unsigned char *str
= "\033[1;1H\357\200\240\033[6n";
51 unsigned char buf
[20];
54 hard_write(out
, str
, strlen(str
));
57 if (sscanf(buf
,"\033[%d;%dR",&y
,&x
)==2) {
64 redraw_terminal(struct terminal
*term
)
68 set_redraw_term_event(&ev
, term
->width
, term
->height
);
69 term_send_event(term
, &ev
);
73 redraw_terminal_cls(struct terminal
*term
)
77 set_resize_term_event(&ev
, term
->width
, term
->height
);
78 term_send_event(term
, &ev
);
82 cls_redraw_all_terminals(void)
84 struct terminal
*term
;
86 foreach (term
, terminals
)
87 redraw_terminal_cls(term
);
91 init_term(int fdin
, int fdout
)
93 unsigned char name
[MAX_TERM_LEN
+ 9] = "terminal.";
94 struct terminal
*term
= mem_calloc(1, sizeof(*term
));
97 check_if_no_terminal();
101 term
->screen
= init_screen();
107 init_list(term
->windows
);
111 term
->master
= (term
->fdout
== get_output_handle());
114 get_terminal_name(name
+ 9);
115 term
->spec
= get_opt_rec(config_options
, name
);
116 object_lock(term
->spec
);
118 /* The hack to restore console in the right mode */
119 if (get_opt_int_tree(term
->spec
, "type") == TERM_LINUX
) {
120 term
->linux_was_utf8
= was_utf8(get_input_handle(), get_output_handle());
123 add_to_list(terminals
, term
);
125 set_handlers(fdin
, (select_handler_T
) in_term
, NULL
,
126 (select_handler_T
) destroy_terminal
, term
);
131 redraw_all_terminals(void)
133 struct terminal
*term
;
135 foreach (term
, terminals
)
140 destroy_terminal(struct terminal
*term
)
142 #ifdef CONFIG_BOOKMARKS
143 bookmark_auto_save_tabs(term
);
146 /* delete_window doesn't update term->current_tab, but it
147 calls redraw_terminal, which requires term->current_tab
148 to be valid if there are any tabs left. So set a value
149 that will be valid for that long. */
150 term
->current_tab
= 0;
152 while (!list_empty(term
->windows
))
153 delete_window(term
->windows
.next
);
155 /* mem_free_if(term->cwd); */
156 mem_free_if(term
->title
);
157 if (term
->screen
) done_screen(term
->screen
);
159 clear_handlers(term
->fdin
);
160 mem_free_if(term
->interlink
);
162 if (term
->blocked
!= -1) {
163 close(term
->blocked
);
164 clear_handlers(term
->blocked
);
170 if (get_opt_int_tree(term
->spec
, "type") == TERM_LINUX
) {
171 if (term
->linux_was_utf8
) {
172 hard_write(term
->fdout
, "\033%G", 3);
174 hard_write(term
->fdout
, "\033%@", 3);
178 if (term
->fdout
!= 1) {
179 if (term
->fdout
!= term
->fdin
) close(term
->fdout
);
181 unhandle_terminal_signals(term
);
183 #ifndef NO_FORK_ON_EXIT
184 if (!list_empty(terminals
)) {
190 object_unlock(term
->spec
);
192 check_if_no_terminal();
196 destroy_all_terminals(void)
198 while (!list_empty(terminals
))
199 destroy_terminal(terminals
.next
);
203 check_if_no_terminal(void)
205 program
.terminate
= list_empty(terminals
)
206 && !get_opt_bool("ui.sessions.keep_session_active");
210 exec_thread(unsigned char *path
, int p
)
212 int plen
= strlen(path
+ 1) + 2;
214 #if defined(HAVE_SETPGID) && !defined(CONFIG_OS_BEOS) && !defined(HAVE_BEGINTHREAD)
215 if (path
[0] == 2) setpgid(0, 0);
218 if (path
[plen
]) unlink(path
+ plen
);
222 close_handle(void *h
)
225 clear_handlers((long) h
);
229 unblock_terminal(struct terminal
*term
)
231 close_handle((void *) (long) term
->blocked
);
233 set_handlers(term
->fdin
, (select_handler_T
) in_term
, NULL
,
234 (select_handler_T
) destroy_terminal
, term
);
235 unblock_itrm(term
->fdin
);
236 redraw_terminal_cls(term
);
237 if (textarea_editor
) /* XXX */
238 textarea_edit(1, NULL
, NULL
, NULL
, NULL
);
243 exec_on_master_terminal(struct terminal
*term
,
244 unsigned char *path
, int plen
,
245 unsigned char *delete, int dlen
,
249 int param_size
= plen
+ dlen
+ 2 /* 2 null char */ + 1 /* fg */;
250 unsigned char *param
= fmem_alloc(param_size
);
255 memcpy(param
+ 1, path
, plen
+ 1);
256 memcpy(param
+ 1 + plen
+ 1, delete, dlen
+ 1);
258 if (fg
== 1) block_itrm(term
->fdin
);
260 blockh
= start_thread((void (*)(void *, int)) exec_thread
,
264 if (fg
== 1) unblock_itrm(term
->fdin
);
269 term
->blocked
= blockh
;
271 (select_handler_T
) unblock_terminal
,
273 (select_handler_T
) unblock_terminal
,
275 set_handlers(term
->fdin
, NULL
, NULL
,
276 (select_handler_T
) destroy_terminal
,
280 set_handlers(blockh
, close_handle
, NULL
,
281 close_handle
, (void *) (long) blockh
);
286 exec_on_slave_terminal( struct terminal
*term
,
287 unsigned char *path
, int plen
,
288 unsigned char *delete, int dlen
,
291 int data_size
= plen
+ dlen
+ 1 /* 0 */ + 1 /* fg */ + 2 /* 2 null char */;
292 unsigned char *data
= fmem_alloc(data_size
);
298 memcpy(data
+ 2, path
, plen
+ 1);
299 memcpy(data
+ 2 + plen
+ 1, delete, dlen
+ 1);
300 hard_write(term
->fdout
, data
, data_size
);
305 exec_on_terminal(struct terminal
*term
, unsigned char *path
,
306 unsigned char *delete, int fg
)
320 dispatch_special(delete);
324 if (fg
&& is_blocked()) {
329 exec_on_master_terminal(term
,
331 delete, strlen(delete),
334 exec_on_slave_terminal( term
,
336 delete, strlen(delete),
342 exec_shell(struct terminal
*term
)
346 if (!can_open_os_shell(term
->environment
)) return;
350 exec_on_terminal(term
, sh
, "", 1);
355 do_terminal_function(struct terminal
*term
, unsigned char code
,
358 int data_len
= strlen(data
);
359 unsigned char *x_data
= fmem_alloc(data_len
+ 1 /* code */ + 1 /* null char */);
363 memcpy(x_data
+ 1, data
, data_len
+ 1);
364 exec_on_terminal(term
, NULL
, x_data
, 0);
369 set_terminal_title(struct terminal
*term
, unsigned char *title
)
371 if (term
->title
&& !strcmp(title
, term
->title
)) return;
372 mem_free_set(&term
->title
, stracpy(title
));
373 do_terminal_function(term
, TERM_FN_TITLE
, title
);
376 static int terminal_pipe
[2];
379 check_terminal_pipes(void)
381 return c_pipe(terminal_pipe
);
385 close_terminal_pipes(void)
387 close(terminal_pipe
[0]);
388 close(terminal_pipe
[1]);
392 attach_terminal(int in
, int out
, int ctl
, void *info
, int len
)
394 struct terminal
*term
;
396 if (set_nonblocking_fd(terminal_pipe
[0]) < 0) return NULL
;
397 if (set_nonblocking_fd(terminal_pipe
[1]) < 0) return NULL
;
398 handle_trm(in
, out
, out
, terminal_pipe
[1], ctl
, info
, len
, 0);
400 term
= init_term(terminal_pipe
[0], out
);
402 close_terminal_pipes();
409 static struct module
*terminal_submodules
[] = {
410 &terminal_screen_module
,
414 struct module terminal_module
= struct_module(
415 /* name: */ "Terminal",
418 /* submodules: */ terminal_submodules
,