Declare element types of lists.
[elinks.git] / src / terminal / terminal.c
blobbd7e73b8e432b5f79f07920a2c4e07585a711358
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 "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_OF(struct terminal, terminals);
41 static void check_if_no_terminal(void);
43 void
44 redraw_terminal(struct terminal *term)
46 struct term_event ev;
48 set_redraw_term_event(&ev, term->width, term->height);
49 term_send_event(term, &ev);
52 void
53 redraw_terminal_cls(struct terminal *term)
55 struct term_event ev;
57 set_resize_term_event(&ev, term->width, term->height);
58 term_send_event(term, &ev);
61 void
62 cls_redraw_all_terminals(void)
64 struct terminal *term;
66 foreach (term, terminals)
67 redraw_terminal_cls(term);
70 struct terminal *
71 init_term(int fdin, int fdout)
73 unsigned char name[MAX_TERM_LEN + 9] = "terminal.";
74 struct terminal *term = mem_calloc(1, sizeof(*term));
76 if (!term) {
77 check_if_no_terminal();
78 return NULL;
81 term->screen = init_screen();
82 if (!term->screen) {
83 mem_free(term);
84 return NULL;
87 init_list(term->windows);
89 term->fdin = fdin;
90 term->fdout = fdout;
91 term->master = (term->fdout == get_output_handle());
92 term->blocked = -1;
94 get_terminal_name(name + 9);
95 term->spec = get_opt_rec(config_options, name);
96 object_lock(term->spec);
98 add_to_list(terminals, term);
100 set_handlers(fdin, (select_handler_T) in_term, NULL,
101 (select_handler_T) destroy_terminal, term);
102 return term;
105 void
106 redraw_all_terminals(void)
108 struct terminal *term;
110 foreach (term, terminals)
111 redraw_screen(term);
114 void
115 destroy_terminal(struct terminal *term)
117 #ifdef CONFIG_BOOKMARKS
118 bookmark_auto_save_tabs(term);
119 #endif
121 /* delete_window doesn't update term->current_tab, but it
122 calls redraw_terminal, which requires term->current_tab
123 to be valid if there are any tabs left. So set a value
124 that will be valid for that long. */
125 term->current_tab = 0;
127 while (!list_empty(term->windows))
128 delete_window(term->windows.next);
130 /* mem_free_if(term->cwd); */
131 mem_free_if(term->title);
132 if (term->screen) done_screen(term->screen);
134 clear_handlers(term->fdin);
135 mem_free_if(term->interlink);
137 if (term->blocked != -1) {
138 close(term->blocked);
139 clear_handlers(term->blocked);
142 del_from_list(term);
143 close(term->fdin);
145 if (term->fdout != 1) {
146 if (term->fdout != term->fdin) close(term->fdout);
147 } else {
148 unhandle_terminal_signals(term);
149 free_all_itrms();
150 #ifndef NO_FORK_ON_EXIT
151 if (!list_empty(terminals)) {
152 if (fork()) exit(0);
154 #endif
157 object_unlock(term->spec);
158 mem_free(term);
159 check_if_no_terminal();
162 void
163 destroy_all_terminals(void)
165 while (!list_empty(terminals))
166 destroy_terminal(terminals.next);
169 static void
170 check_if_no_terminal(void)
172 program.terminate = list_empty(terminals)
173 && !get_opt_bool("ui.sessions.keep_session_active");
176 void
177 exec_thread(unsigned char *path, int p)
179 int plen = strlen(path + 1) + 2;
181 #if defined(HAVE_SETPGID) && !defined(CONFIG_OS_BEOS) && !defined(HAVE_BEGINTHREAD)
182 if (path[0] == TERM_EXEC_NEWWIN) setpgid(0, 0);
183 #endif
184 exe(path + 1);
185 if (path[plen]) unlink(path + plen);
188 void
189 close_handle(void *h)
191 close((long) h);
192 clear_handlers((long) h);
195 static void
196 unblock_terminal(struct terminal *term)
198 close_handle((void *) (long) term->blocked);
199 term->blocked = -1;
200 set_handlers(term->fdin, (select_handler_T) in_term, NULL,
201 (select_handler_T) destroy_terminal, term);
202 unblock_itrm();
203 redraw_terminal_cls(term);
204 if (textarea_editor) /* XXX */
205 textarea_edit(1, NULL, NULL, NULL, NULL);
209 static void
210 exec_on_master_terminal(struct terminal *term,
211 unsigned char *path, int plen,
212 unsigned char *delete, int dlen,
213 enum term_exec fg)
215 int blockh;
216 int param_size = plen + dlen + 2 /* 2 null char */ + 1 /* fg */;
217 unsigned char *param = fmem_alloc(param_size);
219 if (!param) return;
221 param[0] = fg;
222 memcpy(param + 1, path, plen + 1);
223 memcpy(param + 1 + plen + 1, delete, dlen + 1);
225 if (fg == TERM_EXEC_FG) block_itrm();
227 blockh = start_thread((void (*)(void *, int)) exec_thread,
228 param, param_size);
229 fmem_free(param);
230 if (blockh == -1) {
231 if (fg == TERM_EXEC_FG) unblock_itrm();
232 return;
235 if (fg == TERM_EXEC_FG) {
236 term->blocked = blockh;
237 set_handlers(blockh,
238 (select_handler_T) unblock_terminal,
239 NULL,
240 (select_handler_T) unblock_terminal,
241 term);
242 set_handlers(term->fdin, NULL, NULL,
243 (select_handler_T) destroy_terminal,
244 term);
246 } else {
247 set_handlers(blockh, close_handle, NULL,
248 close_handle, (void *) (long) blockh);
252 static void
253 exec_on_slave_terminal( struct terminal *term,
254 unsigned char *path, int plen,
255 unsigned char *delete, int dlen,
256 enum term_exec fg)
258 int data_size = plen + dlen + 1 /* 0 */ + 1 /* fg */ + 2 /* 2 null char */;
259 unsigned char *data = fmem_alloc(data_size);
261 if (!data) return;
263 data[0] = 0;
264 data[1] = fg;
265 memcpy(data + 2, path, plen + 1);
266 memcpy(data + 2 + plen + 1, delete, dlen + 1);
267 hard_write(term->fdout, data, data_size);
268 fmem_free(data);
271 void
272 exec_on_terminal(struct terminal *term, unsigned char *path,
273 unsigned char *delete, enum term_exec fg)
275 if (path) {
276 if (!*path) return;
277 } else {
278 path = "";
281 #ifdef NO_FG_EXEC
282 fg = TERM_EXEC_BG;
283 #endif
285 if (term->master) {
286 if (!*path) {
287 dispatch_special(delete);
288 return;
291 /* TODO: Should this be changed to allow TERM_EXEC_NEWWIN
292 * in a blocked terminal? There is similar code in
293 * in_sock(). --KON, 2007 */
294 if (fg != TERM_EXEC_BG && is_blocked()) {
295 unlink(delete);
296 return;
299 exec_on_master_terminal(term,
300 path, strlen(path),
301 delete, strlen(delete),
302 fg);
303 } else {
304 exec_on_slave_terminal( term,
305 path, strlen(path),
306 delete, strlen(delete),
307 fg);
311 void
312 exec_shell(struct terminal *term)
314 unsigned char *sh;
316 if (!can_open_os_shell(term->environment)) return;
318 sh = get_shell();
319 if (sh && *sh)
320 exec_on_terminal(term, sh, "", TERM_EXEC_FG);
324 void
325 do_terminal_function(struct terminal *term, unsigned char code,
326 unsigned char *data)
328 int data_len = strlen(data);
329 unsigned char *x_data = fmem_alloc(data_len + 1 /* code */ + 1 /* null char */);
331 if (!x_data) return;
332 x_data[0] = code;
333 memcpy(x_data + 1, data, data_len + 1);
334 exec_on_terminal(term, NULL, x_data, TERM_EXEC_BG);
335 fmem_free(x_data);
338 void
339 set_terminal_title(struct terminal *term, unsigned char *title)
341 if (term->title && !strcmp(title, term->title)) return;
342 mem_free_set(&term->title, stracpy(title));
343 do_terminal_function(term, TERM_FN_TITLE, title);
346 static int terminal_pipe[2];
349 check_terminal_pipes(void)
351 return c_pipe(terminal_pipe);
354 void
355 close_terminal_pipes(void)
357 close(terminal_pipe[0]);
358 close(terminal_pipe[1]);
361 struct terminal *
362 attach_terminal(int in, int out, int ctl, void *info, int len)
364 struct terminal *term;
366 if (set_nonblocking_fd(terminal_pipe[0]) < 0) return NULL;
367 if (set_nonblocking_fd(terminal_pipe[1]) < 0) return NULL;
368 handle_trm(in, out, out, terminal_pipe[1], ctl, info, len, 0);
370 term = init_term(terminal_pipe[0], out);
371 if (!term) {
372 close_terminal_pipes();
373 return NULL;
376 return term;
379 static struct module *terminal_submodules[] = {
380 &terminal_screen_module,
381 NULL
384 struct module terminal_module = struct_module(
385 /* Because this module is listed in main_modules rather than
386 * in builtin_modules, its name does not appear in the user
387 * interface and so need not be translatable. */
388 /* name: */ "Terminal",
389 /* options: */ NULL,
390 /* hooks: */ NULL,
391 /* submodules: */ terminal_submodules,
392 /* data: */ NULL,
393 /* init: */ NULL,
394 /* done: */ NULL