]> code.delx.au - gnu-emacs/blobdiff - src/terminal.c
; Revert "Ensure undo-boundary after insert-file-contents."
[gnu-emacs] / src / terminal.c
index 67577adf3b4255515217996d108dc877397528b3..5dd9975a6f44125cb39e916d6414b585bd1c9b9e 100644 (file)
@@ -1,12 +1,12 @@
 /* Functions related to terminal devices.
-   Copyright (C) 2005-2011 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
@@ -17,28 +17,40 @@ You should have received a copy of the GNU General Public License
 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
+
 #include <stdio.h>
-#include <setjmp.h>
 
 #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 <errno.h>
+# include <linux/kd.h>
+# include <sys/ioctl.h>
+#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 *);
 
+/* This setter is used only in this file, so it can be private.  */
+static void
+tset_param_alist (struct terminal *t, Lisp_Object val)
+{
+  t->param_alist = val;
+}
+
 \f
 
 void
@@ -112,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)
 {
@@ -122,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)
@@ -185,56 +197,94 @@ 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.  */
 
-\f
-
-/* 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.  */
 
-  return result;
+struct terminal *
+decode_tty_terminal (Lisp_Object terminal)
+{
+  struct terminal *t = decode_live_terminal (terminal);
+
+  return (t->type == output_termcap || t->type == output_msdos_raw) ? t : NULL;
 }
 
-\f
+/* 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);
 
-/* Create a new terminal object and add it to the terminal list. */
+  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 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->name = NULL;
   terminal->next_terminal = terminal_list;
   terminal_list = terminal;
-
+  terminal->type = type;
+  terminal->rif = rif;
   terminal->id = next_terminal_id++;
 
-  terminal->keyboard_coding =
-    (struct coding_system *) xmalloc (sizeof (struct coding_system));
-  terminal->terminal_coding =
-    (struct coding_system *) xmalloc (sizeof (struct coding_system));
+  terminal->keyboard_coding = xmalloc (sizeof (struct coding_system));
+  terminal->terminal_coding = xmalloc (sizeof (struct coding_system));
 
   /* If default coding systems for the terminal and the keyboard are
      already defined, use them in preference to the defaults.  This is
@@ -255,9 +305,6 @@ create_terminal (void)
   setup_coding_system (keyboard_coding, terminal->keyboard_coding);
   setup_coding_system (terminal_coding, terminal->terminal_coding);
 
-  terminal->param_alist = Qnil;
-  terminal->charset_list = Qnil;
-  terminal->Vselection_alist = Qnil;
   return terminal;
 }
 
@@ -277,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);
@@ -290,7 +337,7 @@ delete_terminal (struct terminal *terminal)
 
   for (tp = &terminal_list; *tp != terminal; tp = &(*tp)->next_terminal)
     if (! *tp)
-      abort ();
+      emacs_abort ();
   *tp = terminal->next_terminal;
 
   xfree (terminal->keyboard_coding);
@@ -305,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
@@ -316,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;
@@ -357,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;
@@ -384,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;
@@ -402,12 +438,10 @@ possible return values.  */)
       return Qw32;
     case output_msdos_raw:
       return Qpc;
-    case output_mac:
-      return Qmac;
     case output_ns:
       return Qns;
     default:
-      abort ();
+      emacs_abort ();
     }
 }
 
@@ -435,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;
 }
@@ -452,7 +485,7 @@ store_terminal_param (struct terminal *t, Lisp_Object parameter, Lisp_Object val
   Lisp_Object old_alist_elt = Fassq (parameter, t->param_alist);
   if (EQ (old_alist_elt, Qnil))
     {
-      t->param_alist = Fcons (Fcons (parameter, value), t->param_alist);
+      tset_param_alist (t, Fcons (Fcons (parameter, value), t->param_alist));
       return Qnil;
     }
   else
@@ -473,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,
@@ -484,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,
@@ -501,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);
 }
 
-\f
+#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.  */
@@ -515,14 +607,14 @@ struct terminal *
 init_initial_terminal (void)
 {
   if (initialized || terminal_list || tty_list)
-    abort ();
+    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;
 }
@@ -534,7 +626,7 @@ static void
 delete_initial_terminal (struct terminal *terminal)
 {
   if (terminal != initial_terminal)
-    abort ();
+    emacs_abort ();
 
   delete_terminal (terminal);
   initial_terminal = NULL;
@@ -555,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");