X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/ab1dc14b220747e527d507d40905a24ba5c692d9..829733104db073f8abd67765eae162e7360281fa:/src/terminal.c?ds=sidebyside diff --git a/src/terminal.c b/src/terminal.c index 2c0c60e734..5dd9975a6f 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -1,12 +1,12 @@ /* Functions related to terminal devices. - Copyright (C) 2005-2012 Free Software Foundation, Inc. + Copyright (C) 2005-2016 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,25 +18,28 @@ along with GNU Emacs. If not, see . */ #include -#define TERMHOOKS_INLINE EXTERN_INLINE - #include #include "lisp.h" +#include "character.h" #include "frame.h" #include "termchar.h" #include "termhooks.h" -#include "charset.h" -#include "coding.h" #include "keyboard.h" -/* Chain of all terminals currently in use. */ +#if HAVE_STRUCT_UNIPAIR_UNICODE +# include +# include +# include +#endif + +/* Chain of all terminals currently in use. */ struct terminal *terminal_list; -/* The first unallocated terminal id. */ +/* The first unallocated terminal id. */ static int next_terminal_id; -/* The initial terminal device, created by initial_term_init. */ +/* The initial terminal device, created by initial_term_init. */ struct terminal *initial_terminal; static void delete_initial_terminal (struct terminal *); @@ -121,9 +124,9 @@ raw_cursor_to (struct frame *f, int row, int col) (*FRAME_TERMINAL (f)->raw_cursor_to_hook) (f, row, col); } -/* Erase operations */ +/* Erase operations. */ -/* Clear from cursor to end of frame. */ +/* Clear from cursor to end of frame. */ void clear_to_end (struct frame *f) { @@ -131,7 +134,7 @@ clear_to_end (struct frame *f) (*FRAME_TERMINAL (f)->clear_to_end_hook) (f); } -/* Clear entire frame */ +/* Clear entire frame. */ void clear_frame (struct frame *f) @@ -194,49 +197,90 @@ ins_del_lines (struct frame *f, int vpos, int n) (*FRAME_TERMINAL (f)->ins_del_lines_hook) (f, vpos, n); } +/* Return the terminal object specified by TERMINAL. TERMINAL may + be a terminal object, a frame, or nil for the terminal device of + the current frame. If TERMINAL is neither from the above or the + resulting terminal object is deleted, return NULL. */ - - -/* Return the terminal object specified by TERMINAL. TERMINAL may be - a terminal object, a frame, or nil for the terminal device of the - current frame. If THROW is zero, return NULL for failure, - otherwise throw an error. */ - -struct terminal * -get_terminal (Lisp_Object terminal, int throw) +static struct terminal * +decode_terminal (Lisp_Object terminal) { - struct terminal *result = NULL; + struct terminal *t; if (NILP (terminal)) terminal = selected_frame; + t = (TERMINALP (terminal) + ? XTERMINAL (terminal) + : FRAMEP (terminal) ? FRAME_TERMINAL (XFRAME (terminal)) : NULL); + return t && t->name ? t : NULL; +} - if (TERMINALP (terminal)) - result = XTERMINAL (terminal); - else if (FRAMEP (terminal)) - result = FRAME_TERMINAL (XFRAME (terminal)); +/* Like above, but throw an error if TERMINAL is not valid or deleted. */ - if (result && !result->name) - result = NULL; +struct terminal * +decode_live_terminal (Lisp_Object terminal) +{ + struct terminal *t = decode_terminal (terminal); - if (result == NULL && throw) + if (!t) wrong_type_argument (Qterminal_live_p, terminal); + return t; +} + +/* Like decode_terminal, but ensure that the resulting terminal object refers + to a text-based terminal device. */ + +struct terminal * +decode_tty_terminal (Lisp_Object terminal) +{ + struct terminal *t = decode_live_terminal (terminal); - return result; + return (t->type == output_termcap || t->type == output_msdos_raw) ? t : NULL; } - +/* Return an active (not suspended) text-based terminal device that uses + the tty device with the given NAME, or NULL if the named terminal device + is not opened. */ + +struct terminal * +get_named_terminal (const char *name) +{ + struct terminal *t; + + eassert (name); + + for (t = terminal_list; t; t = t->next_terminal) + { + if ((t->type == output_termcap || t->type == output_msdos_raw) + && !strcmp (t->display_info.tty->name, name) + && TERMINAL_ACTIVE_P (t)) + return t; + } + return NULL; +} + +/* Allocate basically initialized terminal. */ + +static struct terminal * +allocate_terminal (void) +{ + return ALLOCATE_ZEROED_PSEUDOVECTOR + (struct terminal, next_terminal, PVEC_TERMINAL); +} -/* Create a new terminal object and add it to the terminal list. */ +/* Create a new terminal object of TYPE and add it to the terminal list. RIF + may be NULL if this terminal type doesn't support window-based redisplay. */ struct terminal * -create_terminal (void) +create_terminal (enum output_method type, struct redisplay_interface *rif) { struct terminal *terminal = allocate_terminal (); Lisp_Object terminal_coding, keyboard_coding; terminal->next_terminal = terminal_list; terminal_list = terminal; - + terminal->type = type; + terminal->rif = rif; terminal->id = next_terminal_id++; terminal->keyboard_coding = xmalloc (sizeof (struct coding_system)); @@ -280,7 +324,7 @@ delete_terminal (struct terminal *terminal) xfree (terminal->name); terminal->name = NULL; - /* Check for live frames that are still on this terminal. */ + /* Check for live frames that are still on this terminal. */ FOR_EACH_FRAME (tail, frame) { struct frame *f = XFRAME (frame); @@ -308,8 +352,6 @@ delete_terminal (struct terminal *terminal) } } -Lisp_Object Qrun_hook_with_args; -static Lisp_Object Qdelete_terminal_functions; DEFUN ("delete-terminal", Fdelete_terminal, Sdelete_terminal, 0, 2, 0, doc: /* Delete TERMINAL by deleting all frames on it and closing the terminal. TERMINAL may be a terminal object, a frame, or nil (meaning the @@ -319,7 +361,7 @@ Normally, you may not delete a display if all other displays are suspended, but if the second argument FORCE is non-nil, you may do so. */) (Lisp_Object terminal, Lisp_Object force) { - struct terminal *t = get_terminal (terminal, 0); + struct terminal *t = decode_terminal (terminal); if (!t) return Qnil; @@ -360,14 +402,7 @@ If FRAME is nil, the selected frame is used. The terminal device is represented by its integer identifier. */) (Lisp_Object frame) { - struct terminal *t; - - if (NILP (frame)) - frame = selected_frame; - - CHECK_LIVE_FRAME (frame); - - t = FRAME_TERMINAL (XFRAME (frame)); + struct terminal *t = FRAME_TERMINAL (decode_live_frame (frame)); if (!t) return Qnil; @@ -387,9 +422,7 @@ sort of output terminal it uses. See the documentation of `framep' for possible return values. */) (Lisp_Object object) { - struct terminal *t; - - t = get_terminal (object, 0); + struct terminal *t = decode_terminal (object); if (!t) return Qnil; @@ -405,8 +438,6 @@ possible return values. */) return Qw32; case output_msdos_raw: return Qpc; - case output_mac: - return Qmac; case output_ns: return Qns; default: @@ -438,8 +469,7 @@ TERMINAL may be a terminal object, a frame, or nil (meaning the selected frame's terminal). */) (Lisp_Object terminal) { - struct terminal *t - = TERMINALP (terminal) ? XTERMINAL (terminal) : get_terminal (terminal, 1); + struct terminal *t = decode_live_terminal (terminal); return t->name ? build_string (t->name) : Qnil; } @@ -476,9 +506,7 @@ TERMINAL can be a terminal object, a frame, or nil (meaning the selected frame's terminal). */) (Lisp_Object terminal) { - struct terminal *t - = TERMINALP (terminal) ? XTERMINAL (terminal) : get_terminal (terminal, 1); - return Fcopy_alist (t->param_alist); + return Fcopy_alist (decode_live_terminal (terminal)->param_alist); } DEFUN ("terminal-parameter", Fterminal_parameter, Sterminal_parameter, 2, 2, 0, @@ -487,12 +515,8 @@ TERMINAL can be a terminal object, a frame, or nil (meaning the selected frame's terminal). */) (Lisp_Object terminal, Lisp_Object parameter) { - Lisp_Object value; - struct terminal *t - = TERMINALP (terminal) ? XTERMINAL (terminal) : get_terminal (terminal, 1); CHECK_SYMBOL (parameter); - value = Fcdr (Fassq (parameter, t->param_alist)); - return value; + return Fcdr (Fassq (parameter, decode_live_terminal (terminal)->param_alist)); } DEFUN ("set-terminal-parameter", Fset_terminal_parameter, @@ -504,12 +528,77 @@ TERMINAL can be a terminal object, a frame or nil (meaning the selected frame's terminal). */) (Lisp_Object terminal, Lisp_Object parameter, Lisp_Object value) { - struct terminal *t - = TERMINALP (terminal) ? XTERMINAL (terminal) : get_terminal (terminal, 1); - return store_terminal_param (t, parameter, value); + return store_terminal_param (decode_live_terminal (terminal), parameter, value); } - +#if HAVE_STRUCT_UNIPAIR_UNICODE + +/* Compute the glyph code table for T. */ + +static void +calculate_glyph_code_table (struct terminal *t) +{ + Lisp_Object glyphtab = Qt; + enum { initial_unipairs = 1000 }; + int entry_ct = initial_unipairs; + struct unipair unipair_buffer[initial_unipairs]; + struct unipair *entries = unipair_buffer; + struct unipair *alloced = 0; + + while (true) + { + int fd = fileno (t->display_info.tty->output); + struct unimapdesc unimapdesc = { entry_ct, entries }; + if (ioctl (fd, GIO_UNIMAP, &unimapdesc) == 0) + { + glyphtab = Fmake_char_table (Qnil, make_number (-1)); + for (int i = 0; i < unimapdesc.entry_ct; i++) + char_table_set (glyphtab, entries[i].unicode, + make_number (entries[i].fontpos)); + break; + } + if (errno != ENOMEM) + break; + entry_ct = unimapdesc.entry_ct; + entries = alloced = xrealloc (alloced, entry_ct * sizeof *alloced); + } + + xfree (alloced); + t->glyph_code_table = glyphtab; +} +#endif + +/* Return the glyph code in T of character CH, or -1 if CH does not + have a font position in T, or nil if T does not report glyph codes. */ + +Lisp_Object +terminal_glyph_code (struct terminal *t, int ch) +{ +#if HAVE_STRUCT_UNIPAIR_UNICODE + if (t->type == output_termcap) + { + /* As a hack, recompute the table when CH is the maximum + character. */ + if (NILP (t->glyph_code_table) || ch == MAX_CHAR) + calculate_glyph_code_table (t); + + if (! EQ (t->glyph_code_table, Qt)) + return char_table_ref (t->glyph_code_table, ch); + } +#endif + + return Qnil; +} + +/* Initial frame has no device-dependent output data, but has + face cache which should be freed when the frame is deleted. */ + +static void +initial_free_frame_resources (struct frame *f) +{ + eassert (FRAME_INITIAL_P (f)); + free_frame_faces (f); +} /* Create the bootstrap display terminal for the initial frame. Returns a terminal of type output_initial. */ @@ -520,12 +609,12 @@ init_initial_terminal (void) if (initialized || terminal_list || tty_list) emacs_abort (); - initial_terminal = create_terminal (); - initial_terminal->type = output_initial; + initial_terminal = create_terminal (output_initial, NULL); initial_terminal->name = xstrdup ("initial_terminal"); initial_terminal->kboard = initial_kboard; initial_terminal->delete_terminal_hook = &delete_initial_terminal; - /* All other hooks are NULL. */ + initial_terminal->delete_frame_hook = &initial_free_frame_resources; + /* Other hooks are NULL by default. */ return initial_terminal; } @@ -558,6 +647,8 @@ Each function is called with argument, the terminal. This may be called just before actually deleting the terminal, or some time later. */); Vdelete_terminal_functions = Qnil; + + DEFSYM (Qterminal_live_p, "terminal-live-p"); DEFSYM (Qdelete_terminal_functions, "delete-terminal-functions"); DEFSYM (Qrun_hook_with_args, "run-hook-with-args");