Function: make-terminal-frame

make-terminal-frame is a function defined in frame.c.

Signature

(make-terminal-frame PARMS)

Documentation

Create an additional terminal frame, possibly on another terminal.

This function takes one argument, an alist specifying frame parameters.

You can create multiple frames on a single text terminal, but only one of them (the selected terminal frame) is actually displayed.

In practice, generally you don't need to specify any parameters, except when you want to create a new frame on another terminal. In that case, the tty parameter specifies the device file to open, and the tty-type parameter specifies the terminal type. Example:

   (make-terminal-frame '((tty . "/dev/pts/5") (tty-type . "xterm")))

Note that changing the size of one terminal frame automatically affects all frames on the same terminal device.

Probably introduced at or before Emacs version 23.1.

Source Code

// Defined in /usr/src/emacs/src/frame.c
// Skipping highlighting due to helpful-max-highlight.
{
#ifdef HAVE_ANDROID
  error ("Text terminals are not supported on this platform");
  return Qnil;
#else
  struct terminal *t = NULL;
  struct frame *sf = SELECTED_FRAME ();

#ifdef MSDOS
  if (sf->output_method != output_msdos_raw
      && sf->output_method != output_termcap)
    emacs_abort ();
#else /* not MSDOS */

#ifdef WINDOWSNT                           /* This should work now! */
  if (sf->output_method != output_termcap)
    error ("Not using an ASCII terminal now; cannot make a new ASCII frame");
#endif
#endif /* not MSDOS */

  {
    Lisp_Object terminal;

    terminal = Fassq (Qterminal, parms);
    if (CONSP (terminal))
      {
        terminal = XCDR (terminal);
        t = decode_live_terminal (terminal);
      }
#ifdef MSDOS
    if (t && t != the_only_display_info.terminal)
      /* msdos.c assumes a single tty_display_info object.  */
      error ("Multiple terminals are not supported on this platform");
    if (!t)
      t = the_only_display_info.terminal;
# endif
  }

  if (!t)
    {
      char *name = 0, *type = 0;
      Lisp_Object tty, tty_type;
      USE_SAFE_ALLOCA;

      tty = get_future_frame_param
        (Qtty, parms, (FRAME_TERMCAP_P (XFRAME (selected_frame))
                       ? FRAME_TTY (XFRAME (selected_frame))->name
                       : NULL));
      if (!NILP (tty))
	SAFE_ALLOCA_STRING (name, tty);

      tty_type = get_future_frame_param
        (Qtty_type, parms, (FRAME_TERMCAP_P (XFRAME (selected_frame))
                            ? FRAME_TTY (XFRAME (selected_frame))->type
                            : NULL));
      if (!NILP (tty_type))
	SAFE_ALLOCA_STRING (type, tty_type);

      t = init_tty (name, type, 0); /* Errors are not fatal.  */
      SAFE_FREE ();
    }

  /* Make a new frame.  We need to know up front if a parent frame is
     specified because we behave differently in this case, e.g., child
     frames don't obscure other frames.  */
  Lisp_Object parent = Fcdr (Fassq (Qparent_frame, parms));
  struct frame *f = make_terminal_frame (t, parent, parms);

  if (!noninteractive)
    init_frame_faces (f);

  /* Visibility of root frames cannot be set with a frame parameter.
     Their visibility solely depends on whether or not they are the
     top_frame on the terminal.  */
  if (FRAME_PARENT_FRAME (f))
    {
      Lisp_Object visible = Fassq (Qvisibility, parms);
      if (CONSP (visible))
	SET_FRAME_VISIBLE (f, !NILP (visible));

      /* FIXME/tty: The only way, for now, to get borders on a tty is
	 to allow decorations.  */
      Lisp_Object undecorated = Fassq (Qundecorated, parms);
      if (CONSP (undecorated) && !NILP (XCDR (undecorated)))
	f->undecorated = true;

      /* Unused at present.  */
      Lisp_Object no_focus = Fassq (Qno_accept_focus, parms);
      if (CONSP (no_focus) && !NILP (XCDR (no_focus)))
	f->no_accept_focus = true;

      Lisp_Object no_split = Fassq (Qunsplittable, parms);
      if (CONSP (no_split) && !NILP (XCDR (no_split)))
	f->no_split = true;
    }

  /* Determine width and height of the frame.  For root frames use the
     width/height of the terminal.  For child frames, take it from frame
     parameters.  Note that a default (80x25) has been set in
     make_frame.  We handle root frames in this way because otherwise we
     would end up needing glyph matrices for the terminal, which is both
     more work and has its downsides (think of clipping frames to the
     terminal size).  */
  int x = 0, y = 0, width, height;
  if (FRAME_PARENT_FRAME (f))
    tty_child_frame_rect (f, parms, &x, &y, &width, &height);
  else
    get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height);
  adjust_frame_size (f, width, height - FRAME_TOP_MARGIN (f), 5, 0,
		     Qterminal_frame);
  adjust_frame_glyphs (f);

  calculate_costs (f);

  f->left_pos = x;
  f->top_pos = y;

  store_in_alist (&parms, Qtty_type, build_string (t->display_info.tty->type));
  store_in_alist (&parms, Qtty,
		  (t->display_info.tty->name
		   ? build_string (t->display_info.tty->name)
		   : Qnil));

  /* Make the frame face hash be frame-specific, so that each
     frame could change its face definitions independently.  */
  fset_face_hash_table (f, Fcopy_hash_table (sf->face_hash_table));
  /* Simple copy_hash_table isn't enough, because we need the contents of
     the vectors which are the values in face_hash_table to
     be copied as well.  */
  ptrdiff_t idx = 0;
  struct Lisp_Hash_Table *table = XHASH_TABLE (f->face_hash_table);
  for (idx = 0; idx < table->count; ++idx)
    set_hash_value_slot (table, idx, Fcopy_sequence (HASH_VALUE (table, idx)));

  /* On terminal frames the `minibuffer' frame parameter is always
     virtually t.  Avoid that a different value in parms causes
     complaints, see Bug#24758.  */
  if (!FRAME_PARENT_FRAME (f))
    store_in_alist (&parms, Qminibuffer, Qt);

  Lisp_Object frame;
  XSETFRAME (frame, f);
  Fmodify_frame_parameters (frame, parms);

  f->can_set_window_size = true;
  f->after_make_frame = true;

  return frame;
#endif
}