BZ_bzRead2 is based on BZ_bzRead from the bzlib library.
[elinks.git] / src / terminal / terminal.c
blobccbe30ef1f2d3a5c49b85b1b5cef474e846c90ec
1 /* Terminal interface - low-level displaying implementation. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #ifdef HAVE_UNISTD_H
12 #include <unistd.h>
13 #endif
15 #include "elinks.h"
17 #include "bookmarks/bookmarks.h"
18 #include "config/options.h"
19 #include "intl/gettext/libintl.h"
20 #include "main/main.h"
21 #include "main/module.h"
22 #include "main/object.h"
23 #include "main/select.h"
24 #include "osdep/osdep.h"
25 #include "osdep/signals.h"
26 #include "session/session.h"
27 #include "terminal/draw.h"
28 #include "terminal/event.h"
29 #include "terminal/hardio.h"
30 #include "terminal/kbd.h"
31 #include "terminal/screen.h"
32 #include "terminal/terminal.h"
33 #include "terminal/window.h"
34 #include "util/error.h"
35 #include "util/memory.h"
36 #include "util/string.h"
37 #include "viewer/text/textarea.h"
40 INIT_LIST_HEAD(terminals);
42 static void check_if_no_terminal(void);
44 void
45 redraw_terminal(struct terminal *term)
47 struct term_event ev;
49 set_redraw_term_event(&ev, term->width, term->height);
50 term_send_event(term, &ev);
53 void
54 redraw_terminal_cls(struct terminal *term)
56 struct term_event ev;
58 set_resize_term_event(&ev, term->width, term->height);
59 term_send_event(term, &ev);
62 void
63 cls_redraw_all_terminals(void)
65 struct terminal *term;
67 foreach (term, terminals)
68 redraw_terminal_cls(term);
71 struct terminal *
72 init_term(int fdin, int fdout)
74 unsigned char name[MAX_TERM_LEN + 9] = "terminal.";
75 struct terminal *term = mem_calloc(1, sizeof(*term));
77 if (!term) {
78 check_if_no_terminal();
79 return NULL;
82 term->screen = init_screen();
83 if (!term->screen) {
84 mem_free(term);
85 return NULL;
88 init_list(term->windows);
90 term->fdin = fdin;
91 term->fdout = fdout;
92 term->master = (term->fdout == get_output_handle());
93 term->blocked = -1;
95 get_terminal_name(name + 9);
96 term->spec = get_opt_rec(config_options, name);
97 object_lock(term->spec);
99 add_to_list(terminals, term);
101 set_handlers(fdin, (select_handler_T) in_term, NULL,
102 (select_handler_T) destroy_terminal, term);
103 return term;
106 void
107 redraw_all_terminals(void)
109 struct terminal *term;
111 foreach (term, terminals)
112 redraw_screen(term);
115 void
116 destroy_terminal(struct terminal *term)
118 #ifdef CONFIG_BOOKMARKS
119 bookmark_auto_save_tabs(term);
120 #endif
122 /* delete_window doesn't update term->current_tab, but it
123 calls redraw_terminal, which requires term->current_tab
124 to be valid if there are any tabs left. So set a value
125 that will be valid for that long. */
126 term->current_tab = 0;
128 while (!list_empty(term->windows))
129 delete_window(term->windows.next);
131 /* mem_free_if(term->cwd); */
132 mem_free_if(term->title);
133 if (term->screen) done_screen(term->screen);
135 clear_handlers(term->fdin);
136 mem_free_if(term->interlink);
138 if (term->blocked != -1) {
139 close(term->blocked);
140 clear_handlers(term->blocked);
143 del_from_list(term);
144 close(term->fdin);
146 if (term->fdout != 1) {
147 if (term->fdout != term->fdin) close(term->fdout);
148 } else {
149 unhandle_terminal_signals(term);
150 free_all_itrms();
151 #ifndef NO_FORK_ON_EXIT
152 if (!list_empty(terminals)) {
153 if (fork()) exit(0);
155 #endif
158 object_unlock(term->spec);
159 mem_free(term);
160 check_if_no_terminal();
163 void
164 destroy_all_terminals(void)
166 while (!list_empty(terminals))
167 destroy_terminal(terminals.next);
170 static void
171 check_if_no_terminal(void)
173 program.terminate = list_empty(terminals)
174 && !get_opt_bool("ui.sessions.keep_session_active");
177 void
178 exec_thread(unsigned char *path, int p)
180 int plen = strlen(path + 1) + 2;
182 #if defined(HAVE_SETPGID) && !defined(CONFIG_OS_BEOS) && !defined(HAVE_BEGINTHREAD)
183 if (path[0] == 2) setpgid(0, 0);
184 #endif
185 exe(path + 1);
186 if (path[plen]) unlink(path + plen);
189 void
190 close_handle(void *h)
192 close((long) h);
193 clear_handlers((long) h);
196 static void
197 unblock_terminal(struct terminal *term)
199 close_handle((void *) (long) term->blocked);
200 term->blocked = -1;
201 set_handlers(term->fdin, (select_handler_T) in_term, NULL,
202 (select_handler_T) destroy_terminal, term);
203 unblock_itrm(term->fdin);
204 redraw_terminal_cls(term);
205 if (textarea_editor) /* XXX */
206 textarea_edit(1, NULL, NULL, NULL, NULL);
210 static void
211 exec_on_master_terminal(struct terminal *term,
212 unsigned char *path, int plen,
213 unsigned char *delete, int dlen,
214 int fg)
216 int blockh;
217 int param_size = plen + dlen + 2 /* 2 null char */ + 1 /* fg */;
218 unsigned char *param = fmem_alloc(param_size);
220 if (!param) return;
222 param[0] = fg;
223 memcpy(param + 1, path, plen + 1);
224 memcpy(param + 1 + plen + 1, delete, dlen + 1);
226 if (fg == 1) block_itrm(term->fdin);
228 blockh = start_thread((void (*)(void *, int)) exec_thread,
229 param, param_size);
230 fmem_free(param);
231 if (blockh == -1) {
232 if (fg == 1) unblock_itrm(term->fdin);
233 return;
236 if (fg == 1) {
237 term->blocked = blockh;
238 set_handlers(blockh,
239 (select_handler_T) unblock_terminal,
240 NULL,
241 (select_handler_T) unblock_terminal,
242 term);
243 set_handlers(term->fdin, NULL, NULL,
244 (select_handler_T) destroy_terminal,
245 term);
247 } else {
248 set_handlers(blockh, close_handle, NULL,
249 close_handle, (void *) (long) blockh);
253 static void
254 exec_on_slave_terminal( struct terminal *term,
255 unsigned char *path, int plen,
256 unsigned char *delete, int dlen,
257 int fg)
259 int data_size = plen + dlen + 1 /* 0 */ + 1 /* fg */ + 2 /* 2 null char */;
260 unsigned char *data = fmem_alloc(data_size);
262 if (!data) return;
264 data[0] = 0;
265 data[1] = fg;
266 memcpy(data + 2, path, plen + 1);
267 memcpy(data + 2 + plen + 1, delete, dlen + 1);
268 hard_write(term->fdout, data, data_size);
269 fmem_free(data);
272 void
273 exec_on_terminal(struct terminal *term, unsigned char *path,
274 unsigned char *delete, int fg)
276 if (path) {
277 if (!*path) return;
278 } else {
279 path = "";
282 #ifdef NO_FG_EXEC
283 fg = 0;
284 #endif
286 if (term->master) {
287 if (!*path) {
288 dispatch_special(delete);
289 return;
292 if (fg && is_blocked()) {
293 unlink(delete);
294 return;
297 exec_on_master_terminal(term,
298 path, strlen(path),
299 delete, strlen(delete),
300 fg);
301 } else {
302 exec_on_slave_terminal( term,
303 path, strlen(path),
304 delete, strlen(delete),
305 fg);
309 void
310 exec_shell(struct terminal *term)
312 unsigned char *sh;
314 if (!can_open_os_shell(term->environment)) return;
316 sh = get_shell();
317 if (sh && *sh)
318 exec_on_terminal(term, sh, "", 1);
322 void
323 do_terminal_function(struct terminal *term, unsigned char code,
324 unsigned char *data)
326 int data_len = strlen(data);
327 unsigned char *x_data = fmem_alloc(data_len + 1 /* code */ + 1 /* null char */);
329 if (!x_data) return;
330 x_data[0] = code;
331 memcpy(x_data + 1, data, data_len + 1);
332 exec_on_terminal(term, NULL, x_data, 0);
333 fmem_free(x_data);
336 void
337 set_terminal_title(struct terminal *term, unsigned char *title)
339 if (term->title && !strcmp(title, term->title)) return;
340 mem_free_set(&term->title, stracpy(title));
341 do_terminal_function(term, TERM_FN_TITLE, title);
344 static int terminal_pipe[2];
347 check_terminal_pipes(void)
349 return c_pipe(terminal_pipe);
352 void
353 close_terminal_pipes(void)
355 close(terminal_pipe[0]);
356 close(terminal_pipe[1]);
359 struct terminal *
360 attach_terminal(int in, int out, int ctl, void *info, int len)
362 struct terminal *term;
364 if (set_nonblocking_fd(terminal_pipe[0]) < 0) return NULL;
365 if (set_nonblocking_fd(terminal_pipe[1]) < 0) return NULL;
366 handle_trm(in, out, out, terminal_pipe[1], ctl, info, len, 0);
368 term = init_term(terminal_pipe[0], out);
369 if (!term) {
370 close_terminal_pipes();
371 return NULL;
374 return term;
377 static struct module *terminal_submodules[] = {
378 &terminal_screen_module,
379 NULL
382 struct module terminal_module = struct_module(
383 /* name: */ "Terminal",
384 /* options: */ NULL,
385 /* hooks: */ NULL,
386 /* submodules: */ terminal_submodules,
387 /* data: */ NULL,
388 /* init: */ NULL,
389 /* done: */ NULL