tty: six virtual terminals, and the plumbing that makes them terminals
/dev/tty1..tty6, Alt+F1..F6 or `chvt N`. Each is an independent terminal --
its own screen, cursor, line discipline, foreground process group and
session. Two shells on two terminals are unrelated processes that share a
keyboard and a screen.
What made it possible is a backing store. The console drew straight into the
framebuffer and scrolled by moving pixels, which works exactly as long as
nothing else wants the screen: there was nowhere to put terminal 2 while
terminal 1 was visible, and nothing to repaint terminal 1 from. Each terminal
owns a grid of cells now and the framebuffer shows whichever grid is active,
so vt_switch() is set-index, repaint, return -- nothing is saved on the way
out because the outgoing grid has been current all along.
The rule the layer is built on: a terminal does not know whether it is
visible. Writes land in the grid, the cursor moves, the grid scrolls, all
unconditionally; drawing is one question asked at the bottom of vt.c. Every
alternative spreads "am I on screen" through the escape parser, and then a
terminal switched away from mid-sequence comes back wrong.
Everything that was a single global is per-terminal now: tty_fg_pgrp (deleted),
termios, the input ring, the escape parser, the UTF-8 decoder, and the cursor
-- which also stops being pixels in gfx.c and becomes cells in the terminal.
TIOCSCTTY was `return 0` and now records proc->ctty, which is what /dev/tty
resolves through; /dev/tty was an alias for /dev/console with the same minor,
and they are different questions.
kbd.c names Alt+F1..F6 as KEY_ALT_F1+n, above 0xFF on purpose -- every byte
value is already a character or a UTF-8 continuation, and a chord colliding
with one would be typed into the terminal instead of switching away from it.
What the chord means is decided in console.c, where the terminals are.
VT_ACTIVATE / VT_WAITACTIVE / VT_GETSTATE / VT_OPENQRY, Linux's numbers.
The argument to ACTIVATE is by value, not a pointer -- same shape as TCFLSH.
Two bugs found by screenshotting the result rather than reading the log:
- zsh emits 0x0F to leave alt-charset mode, because that is what the `linux`
terminfo says rmacs is, and the console drew CP437 glyph 0x0F: a sun, in
the prompt, on every line. A terminal never draws a C0 control character.
- SGR 7 was unimplemented, so zsh's partial-line marker rendered as a bare
'#' instead of a reversed block. Reverse video swaps the colours at draw
time, not at store time, so turning it off restores what was underneath.
Verified by screendump: tty1 and tty2 show different screens, and switching
back repaints tty1's earlier content from its grid. schfs-check passes.
docs/architecture/terminals.md, including what it does not do -- no
scrollback, no reflow, no VT_PROCESS mode for a display server to veto a
switch, which Schcom will need before it owns Alt+F7.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
This commit is contained in:
parent
14f0e4d0e2
commit
1c1b0c9570
24 changed files with 1460 additions and 458 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# The interactive shell on the system console.
|
||||
# The interactive shell on /dev/tty1, the first virtual terminal.
|
||||
|
||||
Label = os.schos.console-shell
|
||||
# zsh, not /bin/sh. mksh stays as /bin/sh and is what schinit falls back to
|
||||
|
|
@ -23,9 +23,9 @@ Environment = SHELL=/bin/zsh
|
|||
# terminal input at all. Without this the shell echoes and executes nothing.
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/console
|
||||
StandardOut = /dev/console
|
||||
StandardError = /dev/console
|
||||
StandardIn = /dev/tty1
|
||||
StandardOut = /dev/tty1
|
||||
StandardError = /dev/tty1
|
||||
|
||||
# Seconds between respawns. Guards against a shell that dies instantly
|
||||
# defaults to 10. One is enough for a shell someone just exited on purpose.
|
||||
|
|
|
|||
25
etc/schinit/tty2-shell.job
Normal file
25
etc/schinit/tty2-shell.job
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# A second interactive shell, on /dev/tty2.
|
||||
#
|
||||
# This is what virtual terminals are for. Alt+F2 shows it; Alt+F1 comes back.
|
||||
# The two shells are unrelated processes with their own sessions, their own
|
||||
# foreground process groups and their own line discipline -- which is exactly
|
||||
# what /dev/tty1 and /dev/tty2 being different terminals means.
|
||||
|
||||
Label = os.schos.tty2-shell
|
||||
Program = /bin/zsh
|
||||
Args = -zsh
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
Environment = HOME=/root
|
||||
Environment = SHELL=/bin/zsh
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/tty2
|
||||
StandardOut = /dev/tty2
|
||||
StandardError = /dev/tty2
|
||||
|
||||
ThrottleInterval = 1
|
||||
|
|
@ -109,5 +109,8 @@ zstyle ':completion:*:descriptions' format '%F{244}%d%f'
|
|||
# the only thing here that ever turns red -- same rule as the rest of the
|
||||
# system: normal states are calm, only failure is loud.
|
||||
setopt PROMPT_SUBST
|
||||
PROMPT='%F{magenta}%B%n@schos%b%f %F{cyan}%~%f %(?.%F{green}❯.%F{red}❯)%f '
|
||||
# The chevron is », not ❯. The console font is CP437 and has a glyph for
|
||||
# the first and none for the second, so ❯ renders as '?' -- correctly, since
|
||||
# drawing a *different* character would be worse, but it still looks broken.
|
||||
PROMPT='%F{magenta}%B%n@schos%b%f %F{cyan}%~%f %(?.%F{green}».%F{red}»)%f '
|
||||
RPROMPT=''
|
||||
|
|
|
|||
Loading…
Reference in a new issue