(VALBITS, GCTYPEBITS): Deleted; default is better.
[bpt/emacs.git] / src / term.c
index 0d414ab..ae0032b 100644 (file)
@@ -1,5 +1,5 @@
 /* terminal control module for terminals described by TERMCAP
-   Copyright (C) 1985, 1986, 1987, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,9 +18,9 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
+#include <config.h>
 #include <stdio.h>
 #include <ctype.h>
-#include "config.h"
 #include "termchar.h"
 #include "termopts.h"
 #include "cm.h"
@@ -31,6 +31,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "termhooks.h"
 #include "keyboard.h"
 
+extern Lisp_Object Fmake_sparse_keymap ();
+
 #define max(a, b) ((a) > (b) ? (a) : (b))
 #define min(a, b) ((a) < (b) ? (a) : (b))
 
@@ -40,7 +42,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define OUTPUT_IF(a) { if (a) tputs (a, FRAME_HEIGHT (selected_frame) - curY, cmputc); }
 #define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
 
-/* Terminal charateristics that higher levels want to look at.
+/* Terminal characteristics that higher levels want to look at.
    These are all extern'd in termchar.h */
 
 int must_write_spaces;         /* Nonzero means spaces in the text
@@ -52,13 +54,12 @@ int line_ins_del_ok;                /* Terminal can insert and delete lines */
 int char_ins_del_ok;           /* Terminal can insert and delete chars */
 int scroll_region_ok;          /* Terminal supports setting the
                                   scroll window */
+int scroll_region_cost;                /* Cost of setting a scroll window,
+                                  measured in characters */
 int memory_below_frame;                /* Terminal remembers lines
                                   scrolled off bottom */
 int fast_clear_end_of_line;    /* Terminal has a `ce' string */
 
-int dont_calculate_costs;      /* Nonzero means don't bother computing */
-                               /* various cost tables; we won't use them.  */
-
 /* Nonzero means no need to redraw the entire frame on resuming
    a suspended Emacs.  This is useful on terminals with multiple pages,
    where one page is used for Emacs and another for all else. */
@@ -93,6 +94,8 @@ int (*set_terminal_window_hook) ();
 
 int (*read_socket_hook) ();
 
+int (*frame_up_to_date_hook) ();
+
 /* Return the current position of the mouse.
 
    Set *f to the frame the mouse is in, or zero if the mouse is in no
@@ -279,8 +282,25 @@ int specified_window;
 
 FRAME_PTR updating_frame;
 
+/* Provided for lisp packages.  */
+static int system_uses_terminfo;
+
 char *tparam ();
+
+extern char *tgetstr ();
 \f
+
+#ifdef WINDOWSNT
+/* We aren't X windows, but we aren't termcap either.  This makes me
+   uncertain as to what value to use for frame.output_method.  For
+   this file, we'll define FRAME_TERMCAP_P to be zero so that our
+   output hooks get called instead of the termcap functions.  Probably
+   the best long-term solution is to define an output_windows_nt...  */
+
+#undef FRAME_TERMCAP_P
+#define FRAME_TERMCAP_P(_f_) 0
+#endif /* WINDOWSNT */
+
 ring_bell ()
 {
   if (! FRAME_TERMCAP_P (selected_frame))
@@ -382,7 +402,7 @@ set_scroll_region (start, stop)
       buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_WIDTH (selected_frame));
     }
   OUTPUT (buf);
-  free (buf);
+  xfree (buf);
   losecursor ();
 }
 \f
@@ -587,7 +607,7 @@ clear_to_end ()
 {
   register int i;
 
-  if (clear_to_end_hook && FRAME_TERMCAP_P (updating_frame))
+  if (clear_to_end_hook && FRAME_TERMCAP_P (updating_frame))
     {
       (*clear_to_end_hook) ();
       return;
@@ -787,7 +807,7 @@ insert_glyphs (start, len)
     {
       buf = tparam (TS_ins_multi_chars, 0, 0, len);
       OUTPUT1 (buf);
-      free (buf);
+      xfree (buf);
       if (start)
        write_glyphs (start, len);
       return;
@@ -851,7 +871,7 @@ delete_glyphs (n)
     {
       buf = tparam (TS_del_multi_chars, 0, 0, n);
       OUTPUT1 (buf);
-      free (buf);
+      xfree (buf);
     }
   else
     for (i = 0; i < n; i++)
@@ -896,7 +916,7 @@ ins_del_lines (vpos, n)
       background_highlight ();
       buf = tparam (multi, 0, 0, i);
       OUTPUT (buf);
-      free (buf);
+      xfree (buf);
     }
   else if (single)
     {
@@ -1061,27 +1081,25 @@ calculate_ins_del_char_costs (frame)
     *p++ = (ins_startup_cost += ins_cost_per_char);
 }
 
-#ifdef HAVE_X_WINDOWS
-extern int x_screen_planes;
-#endif
-
 extern do_line_insertion_deletion_costs ();
 
 calculate_costs (frame)
      FRAME_PTR frame;
 {
-  register char *f = TS_set_scroll_region ?
-                       TS_set_scroll_region
-                    : TS_set_scroll_region_1;
+  register char *f = (TS_set_scroll_region
+                     ? TS_set_scroll_region
+                     : TS_set_scroll_region_1);
 
-  if (dont_calculate_costs)
-    return;
+  FRAME_COST_BAUD_RATE (frame) = baud_rate;
 
+  scroll_region_cost = string_cost (f);
 #ifdef HAVE_X_WINDOWS
   if (FRAME_X_P (frame))
     {
       do_line_insertion_deletion_costs (frame, 0, ".5*", 0, ".5*",
-                                       0, 0, x_screen_planes);
+                                       0, 0,
+                                       x_screen_planes (frame));
+      scroll_region_cost = 0;
       return;
     }
 #endif
@@ -1229,6 +1247,9 @@ static struct fkey_table keys[] = {
   "k9",        "f9",
   };
 
+static char **term_get_fkeys_arg;
+static Lisp_Object term_get_fkeys_1 ();
+
 /* Find the escape codes sent by the function keys for Vfunction_key_map.
    This function scans the termcap function key sequence entries, and 
    adds entries to Vfunction_key_map for each function key it finds.  */
@@ -1237,21 +1258,42 @@ void
 term_get_fkeys (address)
      char **address;
 {
-  extern char *tgetstr ();
+  /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
+     errors during the call.  The only errors should be from Fdefine_key
+     when given a key sequence containing an invalid prefix key.  If the
+     termcap defines function keys which use a prefix that is already bound
+     to a command by the default bindings, we should silently ignore that
+     function key specification, rather than giving the user an error and
+     refusing to run at all on such a terminal.  */
+
+  extern Lisp_Object Fidentity ();
+  term_get_fkeys_arg = address;
+  internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
+}
+
+static Lisp_Object
+term_get_fkeys_1 ()
+{
   int i;
 
+  char **address = term_get_fkeys_arg;
+
+  /* This can happen if CANNOT_DUMP or with strange options.  */
+  if (!initialized)
+    Vfunction_key_map = Fmake_sparse_keymap (Qnil);
+
   for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
     {
       char *sequence = tgetstr (keys[i].cap, address);
       if (sequence)
-       Fdefine_key (Vfunction_key_map,
-                    build_string (sequence),
-                    Fmake_vector (make_number (1), intern (keys[i].name)));
+       Fdefine_key (Vfunction_key_map, build_string (sequence),
+                    Fmake_vector (make_number (1),
+                                  intern (keys[i].name)));
     }
 
   /* The uses of the "k0" capability are inconsistent; sometimes it
      describes F10, whereas othertimes it describes F0 and "k;" describes F10.
-     We will attempt to politely accomodate both systems by testing for
+     We will attempt to politely accommodate both systems by testing for
      "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
      */
   {
@@ -1261,15 +1303,13 @@ term_get_fkeys (address)
 
     if (k_semi)
       {
-       Fdefine_key (Vfunction_key_map,
-                    build_string (k_semi),
+       Fdefine_key (Vfunction_key_map, build_string (k_semi),
                     Fmake_vector (make_number (1), intern ("f10")));
        k0_name = "f0";
       }
 
     if (k0)
-      Fdefine_key (Vfunction_key_map,
-                  build_string (k0),
+      Fdefine_key (Vfunction_key_map, build_string (k0),
                   Fmake_vector (make_number (1), intern (k0_name)));
   }
 
@@ -1277,7 +1317,7 @@ term_get_fkeys (address)
   {
     char fcap[3], fkey[4];
 
-    fcap[0] = 'k'; fcap[2] = '\0';
+    fcap[0] = 'F'; fcap[2] = '\0';
     for (i = 11; i < 64; i++)
       {
        if (i <= 19)
@@ -1287,13 +1327,16 @@ term_get_fkeys (address)
        else
          fcap[1] = 'a' + i - 11;
 
-       if (tgetstr(fcap))
-         {
-           (void) sprintf(fkey, "f%d", i);         
-           Fdefine_key (Vfunction_key_map,
-                        build_string (fcap),
-                        Fmake_vector (make_number (1), intern (fkey)));
-         }
+       {
+         char *sequence = tgetstr (fcap, address);
+         if (sequence)
+           {
+             sprintf (fkey, "f%d", i);
+             Fdefine_key (Vfunction_key_map, build_string (sequence),
+                          Fmake_vector (make_number (1),
+                                        intern (fkey)));
+           }
+       }
       }
    }
 
@@ -1301,18 +1344,35 @@ term_get_fkeys (address)
    * Various mappings to try and get a better fit.
    */
   {
-#define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
-      if (!tgetstr(cap1) && tgetstr(cap2)) \
-           Fdefine_key (Vfunction_key_map, \
-                        build_string (cap2), \
-                        Fmake_vector (make_number (1), intern (sym)))
+#define CONDITIONAL_REASSIGN(cap1, cap2, sym)                          \
+      if (!tgetstr (cap1, address))                                    \
+       {                                                               \
+         char *sequence = tgetstr (cap2, address);                     \
+         if (sequence)                                                 \
+           Fdefine_key (Vfunction_key_map, build_string (sequence),    \
+                        Fmake_vector (make_number (1), \
+                                      intern (sym)));  \
+       }
          
       /* if there's no key_next keycap, map key_npage to `next' keysym */
-      CONDITIONAL_REASSIGN("%5", "kN", "next");
+      CONDITIONAL_REASSIGN ("%5", "kN", "next");
       /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
-      CONDITIONAL_REASSIGN("%8", "kP", "previous");
+      CONDITIONAL_REASSIGN ("%8", "kP", "prior");
       /* if there's no key_dc keycap, map key_ic to `insert' keysym */
-      CONDITIONAL_REASSIGN("kD", "kI", "insert");
+      CONDITIONAL_REASSIGN ("kD", "kI", "insert");
+
+      /* IBM has their own non-standard dialect of terminfo.
+        If the standard name isn't found, try the IBM name.  */
+      CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
+      CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
+      CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
+      CONDITIONAL_REASSIGN ("%7", "ki", "menu");
+      CONDITIONAL_REASSIGN ("@7", "kw", "end");
+      CONDITIONAL_REASSIGN ("F1", "k<", "f11");
+      CONDITIONAL_REASSIGN ("F2", "k>", "f12");
+      CONDITIONAL_REASSIGN ("%1", "kq", "help");
+      CONDITIONAL_REASSIGN ("*6", "kU", "select");
+#undef CONDITIONAL_REASSIGN
   }
 }
 
@@ -1326,16 +1386,53 @@ term_init (terminal_type)
   register char *p;
   int status;
 
-  extern char *tgetstr ();
+#ifdef WINDOWSNT
+  initialize_win_nt_display ();
+
+  Wcm_clear ();
+
+  area = (char *) malloc (2044);
+
+  if (area == 0)
+    abort ();
+
+  FrameRows = FRAME_HEIGHT (selected_frame);
+  FrameCols = FRAME_WIDTH (selected_frame);
+  specified_window = FRAME_HEIGHT (selected_frame);
+
+  delete_in_insert_mode = 1;
+
+  UseTabs = 0;
+  scroll_region_ok = 0;
+
+  /* Seems to insert lines when it's not supposed to, messing
+     up the display.  In doing a trace, it didn't seem to be
+     called much, so I don't think we're losing anything by
+     turning it off.  */
+
+  line_ins_del_ok = 0;
+  char_ins_del_ok = 1;
+
+  baud_rate = 19200;
+
+  FRAME_CAN_HAVE_SCROLL_BARS (selected_frame) = 0;
+  FRAME_HAS_VERTICAL_SCROLL_BARS (selected_frame) = 0;
+
+  return;
+#endif /* WINDOWSNT */
 
   Wcm_clear ();
-  dont_calculate_costs = 0;
 
   status = tgetent (buffer, terminal_type);
   if (status < 0)
     fatal ("Cannot open termcap database file.\n");
   if (status == 0)
-    fatal ("Terminal type %s is not defined.\n", terminal_type);
+    fatal ("Terminal type %s is not defined.\n\
+If that is not the actual type of terminal you have,\n\
+use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
+`setenv TERM ...') to specify the correct type.  It may be necessary\n\
+to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
+          terminal_type);
 
 #ifdef TERMINFO
   area = (char *) malloc (2044);
@@ -1430,6 +1527,11 @@ term_init (terminal_type)
   if (FRAME_HEIGHT (selected_frame) <= 0)
     FRAME_HEIGHT (selected_frame) = tgetnum ("li");
 
+  if (FRAME_HEIGHT (selected_frame) < 3
+      || FRAME_WIDTH (selected_frame) < 3)
+    fatal ("Screen size %dx%d is too small.\n",
+          FRAME_HEIGHT (selected_frame), FRAME_WIDTH (selected_frame));
+
   min_padding_speed = tgetnum ("pb");
   TN_standout_width = tgetnum ("sg");
   TabWidth = tgetnum ("tw");
@@ -1467,6 +1569,17 @@ term_init (terminal_type)
       TS_standout_mode = tgetstr ("us", address);
     }
 
+  /* If no `se' string, try using a `me' string instead.
+     If that fails, we can't use standout mode at all.  */
+  if (TS_end_standout_mode == 0)
+    {
+      char *s = tgetstr ("me", address);
+      if (s != 0)
+       TS_end_standout_mode = s;
+      else
+       TS_standout_mode = 0;
+    }
+
   if (TF_teleray)
     {
       Wcm.cm_tab = 0;
@@ -1546,8 +1659,9 @@ or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
     fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
 It lacks the ability to position the cursor.\n\
 If that is not the actual type of terminal you have,\n\
-use the C-shell command `setenv TERM ...' to specify the correct type.\n\
-It may be necessary to do `unsetenv TERMCAP' as well.\n",
+use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
+`setenv TERM ...') to specify the correct type.  It may be necessary\n\
+to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
           terminal_type);
 #endif
   if (FRAME_HEIGHT (selected_frame) <= 0
@@ -1600,3 +1714,15 @@ fatal (str, arg1, arg2)
   fflush (stderr);
   exit (1);
 }
+
+syms_of_term ()
+{
+  DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo,
+    "Non-nil means the system uses terminfo rather than termcap.\n\
+This variable can be used by terminal emulator packages.");
+#ifdef TERMINFO
+  system_uses_terminfo = 1;
+#else
+  system_uses_terminfo = 0;
+#endif
+}