2007-07-27 09:50:37 -04:00
|
|
|
/** Terminal interface - low-level displaying implementation.
|
|
|
|
* @file */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2006-10-13 23:12:23 -04:00
|
|
|
#include <stdio.h>
|
2005-09-15 09:58:31 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "bookmarks/bookmarks.h"
|
2005-10-17 17:20:53 -04:00
|
|
|
#include "config/options.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "main/main.h"
|
2006-05-20 08:59:40 -04:00
|
|
|
#include "main/module.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "main/object.h"
|
|
|
|
#include "main/select.h"
|
|
|
|
#include "osdep/osdep.h"
|
|
|
|
#include "osdep/signals.h"
|
2011-11-13 03:01:27 -05:00
|
|
|
#ifdef CONFIG_SCRIPTING_SPIDERMONKEY
|
|
|
|
# include "scripting/smjs/smjs.h"
|
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "session/session.h"
|
|
|
|
#include "terminal/draw.h"
|
|
|
|
#include "terminal/event.h"
|
|
|
|
#include "terminal/hardio.h"
|
|
|
|
#include "terminal/kbd.h"
|
|
|
|
#include "terminal/screen.h"
|
|
|
|
#include "terminal/terminal.h"
|
2017-11-19 12:29:38 -05:00
|
|
|
#ifdef CONFIG_TERMINFO
|
|
|
|
#include "terminal/terminfo.h"
|
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "terminal/window.h"
|
|
|
|
#include "util/error.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
#include "util/string.h"
|
|
|
|
#include "viewer/text/textarea.h"
|
|
|
|
|
|
|
|
|
2007-07-26 15:39:08 -04:00
|
|
|
INIT_LIST_OF(struct terminal, terminals);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
static void check_if_no_terminal(void);
|
|
|
|
|
|
|
|
void
|
|
|
|
redraw_terminal(struct terminal *term)
|
|
|
|
{
|
|
|
|
struct term_event ev;
|
|
|
|
|
|
|
|
set_redraw_term_event(&ev, term->width, term->height);
|
|
|
|
term_send_event(term, &ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
redraw_terminal_cls(struct terminal *term)
|
|
|
|
{
|
|
|
|
struct term_event ev;
|
|
|
|
|
|
|
|
set_resize_term_event(&ev, term->width, term->height);
|
|
|
|
term_send_event(term, &ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cls_redraw_all_terminals(void)
|
|
|
|
{
|
|
|
|
struct terminal *term;
|
|
|
|
|
|
|
|
foreach (term, terminals)
|
|
|
|
redraw_terminal_cls(term);
|
|
|
|
}
|
|
|
|
|
bug 1054: Don't abort downloads when closing a terminal.
Except if they have external handlers.
When ELinks receives an event from a terminal, move that terminal to
the beginning of the global "terminals" list, so that the terminals
are always sorted according to the time of the most recent use. Note,
this affects the numbering of bookmark folders in session snapshots.
Add get_default_terminal(), which returns the most recently used
terminal that is still open. Use that in various places that
previously used terminals.prev or terminals.next. Four functions
fetch the size of the terminal for User-Agent headers, and
get_default_terminal() is not really right, but neither was the
original code; add TODO comments in those functions.
When the user chooses "Background and Notify", associate the download
with the terminal where the dialog box is. So any later messages will
then appear in that terminal, if it is still open. However, don't
change the terminal if the download has an external handler.
When a download gets some data, don't immediately check the associated
terminal. Instead, wait for the download to end. Then, if the
terminal of the download has been closed, use get_default_terminal()
instead. If there is no default terminal either, just skip any
message boxes.
2008-10-15 04:05:43 -04:00
|
|
|
/** Get the terminal in which message boxes should be displayed, if
|
|
|
|
* there is no specific reason to use some other terminal. This
|
|
|
|
* returns NULL if all terminals have been closed. (ELinks keeps
|
|
|
|
* running anyway if ui.sessions.keep_session_active is true.) */
|
|
|
|
struct terminal *
|
|
|
|
get_default_terminal(void)
|
|
|
|
{
|
|
|
|
if (list_empty(terminals))
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
return terminals.next;
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
struct terminal *
|
|
|
|
init_term(int fdin, int fdout)
|
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char name[MAX_TERM_LEN + 9] = "terminal.";
|
2022-01-16 15:08:50 -05:00
|
|
|
struct terminal *term = (struct terminal *)mem_calloc(1, sizeof(*term));
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (!term) {
|
|
|
|
check_if_no_terminal();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
term->screen = init_screen();
|
|
|
|
if (!term->screen) {
|
|
|
|
mem_free(term);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-11-19 12:29:38 -05:00
|
|
|
#ifdef CONFIG_TERMINFO
|
|
|
|
terminfo_setupterm(NULL, fdout);
|
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
init_list(term->windows);
|
|
|
|
|
|
|
|
term->fdin = fdin;
|
|
|
|
term->fdout = fdout;
|
|
|
|
term->master = (term->fdout == get_output_handle());
|
|
|
|
term->blocked = -1;
|
2006-08-27 08:18:02 -04:00
|
|
|
|
|
|
|
get_terminal_name(name + 9);
|
|
|
|
term->spec = get_opt_rec(config_options, name);
|
2005-09-15 09:58:31 -04:00
|
|
|
object_lock(term->spec);
|
|
|
|
|
bug 1054: Don't abort downloads when closing a terminal.
Except if they have external handlers.
When ELinks receives an event from a terminal, move that terminal to
the beginning of the global "terminals" list, so that the terminals
are always sorted according to the time of the most recent use. Note,
this affects the numbering of bookmark folders in session snapshots.
Add get_default_terminal(), which returns the most recently used
terminal that is still open. Use that in various places that
previously used terminals.prev or terminals.next. Four functions
fetch the size of the terminal for User-Agent headers, and
get_default_terminal() is not really right, but neither was the
original code; add TODO comments in those functions.
When the user chooses "Background and Notify", associate the download
with the terminal where the dialog box is. So any later messages will
then appear in that terminal, if it is still open. However, don't
change the terminal if the download has an external handler.
When a download gets some data, don't immediately check the associated
terminal. Instead, wait for the download to end. Then, if the
terminal of the download has been closed, use get_default_terminal()
instead. If there is no default terminal either, just skip any
message boxes.
2008-10-15 04:05:43 -04:00
|
|
|
/* It's a new terminal, so assume the user is using it right now,
|
|
|
|
* and sort it to the front of the list. */
|
2005-09-15 09:58:31 -04:00
|
|
|
add_to_list(terminals, term);
|
|
|
|
|
|
|
|
set_handlers(fdin, (select_handler_T) in_term, NULL,
|
|
|
|
(select_handler_T) destroy_terminal, term);
|
|
|
|
return term;
|
|
|
|
}
|
|
|
|
|
2008-12-28 10:42:29 -05:00
|
|
|
/** Get the codepage of a terminal. The UTF-8 I/O option does not
|
|
|
|
* affect this.
|
|
|
|
*
|
|
|
|
* @todo Perhaps cache the value in struct terminal?
|
|
|
|
*
|
|
|
|
* @bug Bug 1064: If the charset has been set as "System", this should
|
|
|
|
* apply the locale environment variables of the slave ELinks process,
|
|
|
|
* not those of the master ELinks process that parsed the configuration
|
|
|
|
* file. That is why the parameter points to struct terminal and not
|
|
|
|
* merely to its option tree (term->spec).
|
|
|
|
*
|
|
|
|
* @see get_translation_table(), get_cp_mime_name() */
|
|
|
|
int
|
|
|
|
get_terminal_codepage(const struct terminal *term)
|
|
|
|
{
|
2009-01-01 13:47:43 -05:00
|
|
|
return get_opt_codepage_tree(term->spec, "charset", NULL);
|
2008-12-28 10:42:29 -05:00
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
void
|
|
|
|
redraw_all_terminals(void)
|
|
|
|
{
|
|
|
|
struct terminal *term;
|
|
|
|
|
|
|
|
foreach (term, terminals)
|
|
|
|
redraw_screen(term);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
destroy_terminal(struct terminal *term)
|
|
|
|
{
|
2011-11-13 03:01:27 -05:00
|
|
|
#ifdef CONFIG_SCRIPTING_SPIDERMONKEY
|
|
|
|
smjs_detach_terminal_object(term);
|
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
#ifdef CONFIG_BOOKMARKS
|
|
|
|
bookmark_auto_save_tabs(term);
|
|
|
|
#endif
|
2008-09-30 03:06:20 -04:00
|
|
|
detach_downloads_from_terminal(term);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-09-01 07:58:09 -04:00
|
|
|
free_textarea_data(term);
|
2007-09-01 05:45:56 -04:00
|
|
|
|
2006-05-14 16:13:51 -04:00
|
|
|
/* delete_window doesn't update term->current_tab, but it
|
|
|
|
calls redraw_terminal, which requires term->current_tab
|
|
|
|
to be valid if there are any tabs left. So set a value
|
|
|
|
that will be valid for that long. */
|
|
|
|
term->current_tab = 0;
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
while (!list_empty(term->windows))
|
|
|
|
delete_window(term->windows.next);
|
|
|
|
|
|
|
|
/* mem_free_if(term->cwd); */
|
|
|
|
mem_free_if(term->title);
|
|
|
|
if (term->screen) done_screen(term->screen);
|
|
|
|
|
|
|
|
clear_handlers(term->fdin);
|
|
|
|
mem_free_if(term->interlink);
|
|
|
|
|
|
|
|
if (term->blocked != -1) {
|
|
|
|
close(term->blocked);
|
|
|
|
clear_handlers(term->blocked);
|
|
|
|
}
|
|
|
|
|
|
|
|
del_from_list(term);
|
|
|
|
close(term->fdin);
|
|
|
|
|
|
|
|
if (term->fdout != 1) {
|
|
|
|
if (term->fdout != term->fdin) close(term->fdout);
|
|
|
|
} else {
|
|
|
|
unhandle_terminal_signals(term);
|
|
|
|
free_all_itrms();
|
|
|
|
#ifndef NO_FORK_ON_EXIT
|
|
|
|
if (!list_empty(terminals)) {
|
|
|
|
if (fork()) exit(0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
object_unlock(term->spec);
|
|
|
|
mem_free(term);
|
|
|
|
check_if_no_terminal();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
destroy_all_terminals(void)
|
|
|
|
{
|
|
|
|
while (!list_empty(terminals))
|
|
|
|
destroy_terminal(terminals.next);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_if_no_terminal(void)
|
|
|
|
{
|
2005-10-17 17:20:53 -04:00
|
|
|
program.terminate = list_empty(terminals)
|
2007-08-28 12:41:18 -04:00
|
|
|
&& !get_opt_bool("ui.sessions.keep_session_active", NULL);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-02 10:20:27 -05:00
|
|
|
exec_thread(char *path, int p)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
int plen = strlen(path + 1) + 2;
|
|
|
|
|
2006-01-11 14:12:59 -05:00
|
|
|
#if defined(HAVE_SETPGID) && !defined(CONFIG_OS_BEOS) && !defined(HAVE_BEGINTHREAD)
|
2007-07-14 05:26:45 -04:00
|
|
|
if (path[0] == TERM_EXEC_NEWWIN) setpgid(0, 0);
|
2005-09-15 09:58:31 -04:00
|
|
|
#endif
|
2021-03-19 19:49:56 -04:00
|
|
|
if (path[0] == TERM_EXEC_BG)
|
|
|
|
exe_no_stdin(path + 1);
|
|
|
|
else
|
|
|
|
exe(path + 1);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (path[plen]) unlink(path + plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
close_handle(void *h)
|
|
|
|
{
|
|
|
|
close((long) h);
|
|
|
|
clear_handlers((long) h);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unblock_terminal(struct terminal *term)
|
|
|
|
{
|
|
|
|
close_handle((void *) (long) term->blocked);
|
|
|
|
term->blocked = -1;
|
|
|
|
set_handlers(term->fdin, (select_handler_T) in_term, NULL,
|
|
|
|
(select_handler_T) destroy_terminal, term);
|
2007-03-05 16:54:24 -05:00
|
|
|
unblock_itrm();
|
2005-09-15 09:58:31 -04:00
|
|
|
redraw_terminal_cls(term);
|
2007-09-01 05:10:54 -04:00
|
|
|
if (term->textarea_data) /* XXX */
|
2007-08-31 23:08:47 -04:00
|
|
|
textarea_edit(1, term, NULL, NULL, NULL);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2008-09-30 03:06:20 -04:00
|
|
|
#ifndef CONFIG_FASTMEM
|
|
|
|
void
|
|
|
|
assert_terminal_ptr_not_dangling(const struct terminal *suspect)
|
|
|
|
{
|
|
|
|
struct terminal *term;
|
|
|
|
|
|
|
|
if (suspect == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
foreach (term, terminals) {
|
|
|
|
if (term == suspect)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assertm(0, "Dangling pointer to struct terminal");
|
|
|
|
}
|
|
|
|
#endif /* !CONFIG_FASTMEM */
|
2006-01-06 19:47:36 -05:00
|
|
|
|
|
|
|
static void
|
|
|
|
exec_on_master_terminal(struct terminal *term,
|
2021-01-02 10:20:27 -05:00
|
|
|
char *path, int plen,
|
|
|
|
char *delete_, int dlen,
|
2007-07-14 05:26:45 -04:00
|
|
|
enum term_exec fg)
|
2006-01-06 19:47:36 -05:00
|
|
|
{
|
|
|
|
int blockh;
|
2006-01-06 19:57:11 -05:00
|
|
|
int param_size = plen + dlen + 2 /* 2 null char */ + 1 /* fg */;
|
2022-01-16 13:09:27 -05:00
|
|
|
char *param = (char *)fmem_alloc(param_size);
|
2006-01-06 19:47:36 -05:00
|
|
|
|
|
|
|
if (!param) return;
|
|
|
|
|
|
|
|
param[0] = fg;
|
|
|
|
memcpy(param + 1, path, plen + 1);
|
2016-04-20 12:57:32 -04:00
|
|
|
memcpy(param + 1 + plen + 1, delete_, dlen + 1);
|
2006-01-06 19:47:36 -05:00
|
|
|
|
2007-07-14 05:26:45 -04:00
|
|
|
if (fg == TERM_EXEC_FG) block_itrm();
|
2006-01-06 19:47:36 -05:00
|
|
|
|
|
|
|
blockh = start_thread((void (*)(void *, int)) exec_thread,
|
|
|
|
param, param_size);
|
2006-01-06 19:52:35 -05:00
|
|
|
fmem_free(param);
|
2006-01-06 19:47:36 -05:00
|
|
|
if (blockh == -1) {
|
2007-07-14 05:26:45 -04:00
|
|
|
if (fg == TERM_EXEC_FG) unblock_itrm();
|
2006-01-06 19:47:36 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-14 05:26:45 -04:00
|
|
|
if (fg == TERM_EXEC_FG) {
|
2006-01-06 19:47:36 -05:00
|
|
|
term->blocked = blockh;
|
|
|
|
set_handlers(blockh,
|
|
|
|
(select_handler_T) unblock_terminal,
|
|
|
|
NULL,
|
|
|
|
(select_handler_T) unblock_terminal,
|
|
|
|
term);
|
|
|
|
set_handlers(term->fdin, NULL, NULL,
|
|
|
|
(select_handler_T) destroy_terminal,
|
|
|
|
term);
|
2006-01-06 19:55:18 -05:00
|
|
|
|
2006-01-06 19:47:36 -05:00
|
|
|
} else {
|
|
|
|
set_handlers(blockh, close_handle, NULL,
|
|
|
|
close_handle, (void *) (long) blockh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
exec_on_slave_terminal( struct terminal *term,
|
2021-01-02 10:20:27 -05:00
|
|
|
char *path, int plen,
|
|
|
|
char *delete_, int dlen,
|
2007-07-14 05:26:45 -04:00
|
|
|
enum term_exec fg)
|
2006-01-06 19:47:36 -05:00
|
|
|
{
|
2007-07-13 13:28:45 -04:00
|
|
|
int data_size = plen + dlen + 1 /* 0 */ + 1 /* fg */ + 2 /* 2 null char */;
|
2022-01-16 13:09:27 -05:00
|
|
|
char *data = (char *)fmem_alloc(data_size);
|
2006-01-06 19:49:12 -05:00
|
|
|
|
|
|
|
if (!data) return;
|
2006-01-06 19:57:11 -05:00
|
|
|
|
2006-01-06 19:49:12 -05:00
|
|
|
data[0] = 0;
|
|
|
|
data[1] = fg;
|
2007-07-13 13:28:45 -04:00
|
|
|
memcpy(data + 2, path, plen + 1);
|
2016-04-20 12:57:32 -04:00
|
|
|
memcpy(data + 2 + plen + 1, delete_, dlen + 1);
|
2006-01-06 19:49:12 -05:00
|
|
|
hard_write(term->fdout, data, data_size);
|
|
|
|
fmem_free(data);
|
2006-01-06 19:47:36 -05:00
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
void
|
2021-01-02 10:20:27 -05:00
|
|
|
exec_on_terminal(struct terminal *term, char *path,
|
|
|
|
char *delete_, enum term_exec fg)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-06 19:28:54 -05:00
|
|
|
if (path) {
|
|
|
|
if (!*path) return;
|
2005-09-15 09:58:31 -04:00
|
|
|
} else {
|
2006-01-06 19:28:54 -05:00
|
|
|
path = "";
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-01-06 19:47:36 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
#ifdef NO_FG_EXEC
|
2007-07-14 05:26:45 -04:00
|
|
|
fg = TERM_EXEC_BG;
|
2005-09-15 09:58:31 -04:00
|
|
|
#endif
|
2006-01-06 19:47:36 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (term->master) {
|
2006-01-06 19:47:36 -05:00
|
|
|
if (!*path) {
|
2016-04-20 12:57:32 -04:00
|
|
|
dispatch_special(delete_);
|
2006-01-06 19:47:36 -05:00
|
|
|
return;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-01-06 19:47:36 -05:00
|
|
|
|
2007-07-18 11:42:54 -04:00
|
|
|
/* TODO: Should this be changed to allow TERM_EXEC_NEWWIN
|
|
|
|
* in a blocked terminal? There is similar code in
|
|
|
|
* in_sock(). --KON, 2007 */
|
2007-07-14 05:26:45 -04:00
|
|
|
if (fg != TERM_EXEC_BG && is_blocked()) {
|
2016-04-20 12:57:32 -04:00
|
|
|
unlink(delete_);
|
2006-01-06 19:54:44 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-01-06 19:47:36 -05:00
|
|
|
exec_on_master_terminal(term,
|
|
|
|
path, strlen(path),
|
2016-04-20 12:57:32 -04:00
|
|
|
delete_, strlen(delete_),
|
2006-01-06 19:47:36 -05:00
|
|
|
fg);
|
2005-09-15 09:58:31 -04:00
|
|
|
} else {
|
2006-01-06 19:47:36 -05:00
|
|
|
exec_on_slave_terminal( term,
|
|
|
|
path, strlen(path),
|
2016-04-20 12:57:32 -04:00
|
|
|
delete_, strlen(delete_),
|
2006-01-06 19:47:36 -05:00
|
|
|
fg);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
exec_shell(struct terminal *term)
|
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char *sh;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (!can_open_os_shell(term->environment)) return;
|
|
|
|
|
|
|
|
sh = get_shell();
|
|
|
|
if (sh && *sh)
|
2007-07-14 05:26:45 -04:00
|
|
|
exec_on_terminal(term, sh, "", TERM_EXEC_FG);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
do_terminal_function(struct terminal *term, unsigned char code,
|
2021-01-02 10:20:27 -05:00
|
|
|
char *data)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
int data_len = strlen(data);
|
2022-01-16 13:09:27 -05:00
|
|
|
char *x_data = (char *)fmem_alloc(data_len + 1 /* code */ + 1 /* null char */);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (!x_data) return;
|
|
|
|
x_data[0] = code;
|
|
|
|
memcpy(x_data + 1, data, data_len + 1);
|
2007-07-14 05:26:45 -04:00
|
|
|
exec_on_terminal(term, NULL, x_data, TERM_EXEC_BG);
|
2005-09-15 09:58:31 -04:00
|
|
|
fmem_free(x_data);
|
|
|
|
}
|
|
|
|
|
Bug 885: Proper charset support in xterm window title
When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU
Screen, it tries to update the title of the window to match the title
of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL"
sequence to the terminal. Unfortunately, xterm expects the Pt string
to be in the ISO-8859-1 charset, making it impossible to display e.g.
Cyrillic characters. In xterm patch #210 (2006-03-12) however, there
is a menu item and a resource that can make xterm take the Pt string
in UTF-8 instead, allowing characters from all around the world.
The downside is that ELinks apparently cannot ask xterm whether the
setting is on or off; so add a terminal._template_.latin1_title option
to ELinks and let the user edit that instead.
Complete list of changes:
- Add the terminal._template_.latin1_title option. But do not add
that to the terminal options window because it's already rather
crowded there.
- In set_window_title(), take a new codepage argument. Use it to
decode the title into Unicode characters, and remove only actual
control characters. For example, CP437 has graphical characters in
the 0x80...0x9F range, so don't remove those, even though ISO-8859-1
has control characters in the same range. Likewise, don't
misinterpret single bytes of UTF-8 characters as control characters.
- In set_window_title(), do not truncate the title to the width of the
window. The font is likely to be different and proportional anyway.
But do truncate before 1024 bytes, an xterm limit.
- In struct itrm, add a title_codepage member to remember which
charset the master said it was going to use in the terminal window
title. Initialize title_codepage in handle_trm(), update it in
dispatch_special() if the master sends the new request
TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls;
but not in the one that sets $TERM as the title, because that string
was not received from the master and should consist of ASCII
characters only.
- In set_terminal_title(), convert the caller-provided title to
ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the
slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion
can run out of memory, so return a success/error flag, rather than
void. In display_window_title(), check this result and don't update
caches on error.
- Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
|
|
|
/** @return negative on error; zero or positive on success. */
|
|
|
|
int
|
2021-01-02 10:20:27 -05:00
|
|
|
set_terminal_title(struct terminal *term, char *title)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
Bug 885: Proper charset support in xterm window title
When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU
Screen, it tries to update the title of the window to match the title
of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL"
sequence to the terminal. Unfortunately, xterm expects the Pt string
to be in the ISO-8859-1 charset, making it impossible to display e.g.
Cyrillic characters. In xterm patch #210 (2006-03-12) however, there
is a menu item and a resource that can make xterm take the Pt string
in UTF-8 instead, allowing characters from all around the world.
The downside is that ELinks apparently cannot ask xterm whether the
setting is on or off; so add a terminal._template_.latin1_title option
to ELinks and let the user edit that instead.
Complete list of changes:
- Add the terminal._template_.latin1_title option. But do not add
that to the terminal options window because it's already rather
crowded there.
- In set_window_title(), take a new codepage argument. Use it to
decode the title into Unicode characters, and remove only actual
control characters. For example, CP437 has graphical characters in
the 0x80...0x9F range, so don't remove those, even though ISO-8859-1
has control characters in the same range. Likewise, don't
misinterpret single bytes of UTF-8 characters as control characters.
- In set_window_title(), do not truncate the title to the width of the
window. The font is likely to be different and proportional anyway.
But do truncate before 1024 bytes, an xterm limit.
- In struct itrm, add a title_codepage member to remember which
charset the master said it was going to use in the terminal window
title. Initialize title_codepage in handle_trm(), update it in
dispatch_special() if the master sends the new request
TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls;
but not in the one that sets $TERM as the title, because that string
was not received from the master and should consist of ASCII
characters only.
- In set_terminal_title(), convert the caller-provided title to
ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the
slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion
can run out of memory, so return a success/error flag, rather than
void. In display_window_title(), check this result and don't update
caches on error.
- Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
|
|
|
int from_cp;
|
|
|
|
int to_cp;
|
2021-01-02 10:20:27 -05:00
|
|
|
char *converted = NULL;
|
Bug 885: Proper charset support in xterm window title
When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU
Screen, it tries to update the title of the window to match the title
of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL"
sequence to the terminal. Unfortunately, xterm expects the Pt string
to be in the ISO-8859-1 charset, making it impossible to display e.g.
Cyrillic characters. In xterm patch #210 (2006-03-12) however, there
is a menu item and a resource that can make xterm take the Pt string
in UTF-8 instead, allowing characters from all around the world.
The downside is that ELinks apparently cannot ask xterm whether the
setting is on or off; so add a terminal._template_.latin1_title option
to ELinks and let the user edit that instead.
Complete list of changes:
- Add the terminal._template_.latin1_title option. But do not add
that to the terminal options window because it's already rather
crowded there.
- In set_window_title(), take a new codepage argument. Use it to
decode the title into Unicode characters, and remove only actual
control characters. For example, CP437 has graphical characters in
the 0x80...0x9F range, so don't remove those, even though ISO-8859-1
has control characters in the same range. Likewise, don't
misinterpret single bytes of UTF-8 characters as control characters.
- In set_window_title(), do not truncate the title to the width of the
window. The font is likely to be different and proportional anyway.
But do truncate before 1024 bytes, an xterm limit.
- In struct itrm, add a title_codepage member to remember which
charset the master said it was going to use in the terminal window
title. Initialize title_codepage in handle_trm(), update it in
dispatch_special() if the master sends the new request
TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls;
but not in the one that sets $TERM as the title, because that string
was not received from the master and should consist of ASCII
characters only.
- In set_terminal_title(), convert the caller-provided title to
ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the
slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion
can run out of memory, so return a success/error flag, rather than
void. In display_window_title(), check this result and don't update
caches on error.
- Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
|
|
|
|
|
|
|
if (term->title && !strcmp(title, term->title)) return 0;
|
|
|
|
|
|
|
|
/* In which codepage was the title parameter given? */
|
|
|
|
from_cp = get_terminal_codepage(term);
|
|
|
|
|
|
|
|
/* In which codepage does the terminal want the title? */
|
2009-01-01 13:47:43 -05:00
|
|
|
if (get_opt_bool_tree(term->spec, "latin1_title", NULL))
|
Bug 885: Proper charset support in xterm window title
When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU
Screen, it tries to update the title of the window to match the title
of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL"
sequence to the terminal. Unfortunately, xterm expects the Pt string
to be in the ISO-8859-1 charset, making it impossible to display e.g.
Cyrillic characters. In xterm patch #210 (2006-03-12) however, there
is a menu item and a resource that can make xterm take the Pt string
in UTF-8 instead, allowing characters from all around the world.
The downside is that ELinks apparently cannot ask xterm whether the
setting is on or off; so add a terminal._template_.latin1_title option
to ELinks and let the user edit that instead.
Complete list of changes:
- Add the terminal._template_.latin1_title option. But do not add
that to the terminal options window because it's already rather
crowded there.
- In set_window_title(), take a new codepage argument. Use it to
decode the title into Unicode characters, and remove only actual
control characters. For example, CP437 has graphical characters in
the 0x80...0x9F range, so don't remove those, even though ISO-8859-1
has control characters in the same range. Likewise, don't
misinterpret single bytes of UTF-8 characters as control characters.
- In set_window_title(), do not truncate the title to the width of the
window. The font is likely to be different and proportional anyway.
But do truncate before 1024 bytes, an xterm limit.
- In struct itrm, add a title_codepage member to remember which
charset the master said it was going to use in the terminal window
title. Initialize title_codepage in handle_trm(), update it in
dispatch_special() if the master sends the new request
TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls;
but not in the one that sets $TERM as the title, because that string
was not received from the master and should consist of ASCII
characters only.
- In set_terminal_title(), convert the caller-provided title to
ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the
slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion
can run out of memory, so return a success/error flag, rather than
void. In display_window_title(), check this result and don't update
caches on error.
- Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
|
|
|
to_cp = get_cp_index("ISO-8859-1");
|
2009-01-01 13:47:43 -05:00
|
|
|
else if (get_opt_bool_tree(term->spec, "utf_8_io", NULL))
|
Bug 885: Proper charset support in xterm window title
When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU
Screen, it tries to update the title of the window to match the title
of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL"
sequence to the terminal. Unfortunately, xterm expects the Pt string
to be in the ISO-8859-1 charset, making it impossible to display e.g.
Cyrillic characters. In xterm patch #210 (2006-03-12) however, there
is a menu item and a resource that can make xterm take the Pt string
in UTF-8 instead, allowing characters from all around the world.
The downside is that ELinks apparently cannot ask xterm whether the
setting is on or off; so add a terminal._template_.latin1_title option
to ELinks and let the user edit that instead.
Complete list of changes:
- Add the terminal._template_.latin1_title option. But do not add
that to the terminal options window because it's already rather
crowded there.
- In set_window_title(), take a new codepage argument. Use it to
decode the title into Unicode characters, and remove only actual
control characters. For example, CP437 has graphical characters in
the 0x80...0x9F range, so don't remove those, even though ISO-8859-1
has control characters in the same range. Likewise, don't
misinterpret single bytes of UTF-8 characters as control characters.
- In set_window_title(), do not truncate the title to the width of the
window. The font is likely to be different and proportional anyway.
But do truncate before 1024 bytes, an xterm limit.
- In struct itrm, add a title_codepage member to remember which
charset the master said it was going to use in the terminal window
title. Initialize title_codepage in handle_trm(), update it in
dispatch_special() if the master sends the new request
TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls;
but not in the one that sets $TERM as the title, because that string
was not received from the master and should consist of ASCII
characters only.
- In set_terminal_title(), convert the caller-provided title to
ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the
slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion
can run out of memory, so return a success/error flag, rather than
void. In display_window_title(), check this result and don't update
caches on error.
- Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
|
|
|
to_cp = get_cp_index("UTF-8");
|
|
|
|
else
|
|
|
|
to_cp = from_cp;
|
|
|
|
|
|
|
|
if (from_cp != to_cp) {
|
|
|
|
struct conv_table *convert_table;
|
|
|
|
|
|
|
|
convert_table = get_translation_table(from_cp, to_cp);
|
|
|
|
if (!convert_table) return -1;
|
|
|
|
converted = convert_string(convert_table, title, strlen(title),
|
|
|
|
to_cp, CSM_NONE, NULL, NULL, NULL);
|
|
|
|
if (!converted) return -1;
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
mem_free_set(&term->title, stracpy(title));
|
Bug 885: Proper charset support in xterm window title
When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU
Screen, it tries to update the title of the window to match the title
of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL"
sequence to the terminal. Unfortunately, xterm expects the Pt string
to be in the ISO-8859-1 charset, making it impossible to display e.g.
Cyrillic characters. In xterm patch #210 (2006-03-12) however, there
is a menu item and a resource that can make xterm take the Pt string
in UTF-8 instead, allowing characters from all around the world.
The downside is that ELinks apparently cannot ask xterm whether the
setting is on or off; so add a terminal._template_.latin1_title option
to ELinks and let the user edit that instead.
Complete list of changes:
- Add the terminal._template_.latin1_title option. But do not add
that to the terminal options window because it's already rather
crowded there.
- In set_window_title(), take a new codepage argument. Use it to
decode the title into Unicode characters, and remove only actual
control characters. For example, CP437 has graphical characters in
the 0x80...0x9F range, so don't remove those, even though ISO-8859-1
has control characters in the same range. Likewise, don't
misinterpret single bytes of UTF-8 characters as control characters.
- In set_window_title(), do not truncate the title to the width of the
window. The font is likely to be different and proportional anyway.
But do truncate before 1024 bytes, an xterm limit.
- In struct itrm, add a title_codepage member to remember which
charset the master said it was going to use in the terminal window
title. Initialize title_codepage in handle_trm(), update it in
dispatch_special() if the master sends the new request
TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls;
but not in the one that sets $TERM as the title, because that string
was not received from the master and should consist of ASCII
characters only.
- In set_terminal_title(), convert the caller-provided title to
ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the
slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion
can run out of memory, so return a success/error flag, rather than
void. In display_window_title(), check this result and don't update
caches on error.
- Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
|
|
|
do_terminal_function(term, TERM_FN_TITLE_CODEPAGE,
|
|
|
|
get_cp_mime_name(to_cp));
|
|
|
|
do_terminal_function(term, TERM_FN_TITLE,
|
|
|
|
converted ? converted : title);
|
|
|
|
mem_free_if(converted);
|
|
|
|
return 0;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int terminal_pipe[2];
|
|
|
|
|
|
|
|
int
|
|
|
|
check_terminal_pipes(void)
|
|
|
|
{
|
|
|
|
return c_pipe(terminal_pipe);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
close_terminal_pipes(void)
|
|
|
|
{
|
|
|
|
close(terminal_pipe[0]);
|
|
|
|
close(terminal_pipe[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct terminal *
|
|
|
|
attach_terminal(int in, int out, int ctl, void *info, int len)
|
|
|
|
{
|
|
|
|
struct terminal *term;
|
|
|
|
|
|
|
|
if (set_nonblocking_fd(terminal_pipe[0]) < 0) return NULL;
|
|
|
|
if (set_nonblocking_fd(terminal_pipe[1]) < 0) return NULL;
|
|
|
|
handle_trm(in, out, out, terminal_pipe[1], ctl, info, len, 0);
|
|
|
|
|
|
|
|
term = init_term(terminal_pipe[0], out);
|
|
|
|
if (!term) {
|
|
|
|
close_terminal_pipes();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return term;
|
|
|
|
}
|
2006-05-20 08:59:40 -04:00
|
|
|
|
|
|
|
static struct module *terminal_submodules[] = {
|
|
|
|
&terminal_screen_module,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
struct module terminal_module = struct_module(
|
2007-03-22 18:51:56 -04:00
|
|
|
/* Because this module is listed in main_modules rather than
|
|
|
|
* in builtin_modules, its name does not appear in the user
|
|
|
|
* interface and so need not be translatable. */
|
|
|
|
/* name: */ "Terminal",
|
2006-05-20 08:59:40 -04:00
|
|
|
/* options: */ NULL,
|
|
|
|
/* hooks: */ NULL,
|
|
|
|
/* submodules: */ terminal_submodules,
|
|
|
|
/* data: */ NULL,
|
|
|
|
/* init: */ NULL,
|
|
|
|
/* done: */ NULL
|
|
|
|
);
|